plan9fox/sys/src/9/pc/segdesc.c
2011-07-12 15:46:22 +02:00

262 lines
5 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
/*
* flags:
* P = present
* A = accessed (for code/data)
* E = expand down (for data)
* W = writable (for data)
* R = readable (for code)
* C = conforming (for code)
* G = limit granularity in pages (for code/data)
* D = 32 bit operand size (for code)
* B = 32 bit stack pointer (for data)
* Y = busy (for tss and tss16)
* U = available for use by system software
*/
static struct {
char *name;
char *flags;
} descrtypes[] = {
"data", "--------AWE01--P----U.BG--------",
"code", "--------ARC11--P----U.DG--------",
"tss16", "--------1Y000--P----U..G--------",
"ldt", "--------01000--P----U..G--------",
"callg16", "--------00100--P----U..G--------",
"taskg", "--------10100--P----U..G--------",
"intrg16", "--------01100--P----U..G--------",
"trapg16", "--------11100--P----U..G--------",
"tss", "--------1Y010--P----U..G--------",
"callg", "--------00110--P----U..G--------",
"intrg", "--------01110--P----U..G--------",
"trapg", "--------11110--P----U..G--------",
};
/*
* format:
* idx[4] type[8] flags[8] dpl[1] base[8] limit[5]\n
*/
enum
{
RECLEN = 4+1 + 8+1 + 8+1 + 1+1 + 8+1 + 5+1,
};
static long
descwrite(Proc *proc, int local, void *v, long n, vlong)
{
int i, j, t;
char buf[RECLEN+1];
char c, *p, *s, *e, *f[6];
Segdesc d;
int dpl;
ulong base;
ulong limit;
s = (char*)v;
e = s + n;
if(waserror()){
if(proc == up)
flushmmu();
nexterror();
}
while(s < e){
for(p = s; p < e && *p != '\n'; p++);
;
if((p - s) > RECLEN)
error(Ebadarg);
memmove(buf, s, p - s);
buf[p-s] = 0;
s = p+1;
if(getfields(buf, f, nelem(f), 1, " ") != nelem(f))
error(Ebadarg);
i = strtoul(f[0], nil, 16);
for(t=0; t<nelem(descrtypes); t++)
if(strcmp(descrtypes[t].name, f[1]) == 0)
break;
if(t == nelem(descrtypes))
error(Ebadarg);
dpl = atoi(f[3]);
base = strtoul(f[4], nil, 16);
limit = strtoul(f[5], nil, 16);
d.d0 = ((base & 0xFFFF)<<16) | (limit & 0xFFFF);
d.d1 = (base & 0xFF000000) | (limit & 0xF0000) | ((dpl & 3)<<13) | ((base & 0xFF0000)>>16);
for(j=0; c = descrtypes[t].flags[j]; j++){
switch(c){
default:
if(strchr(f[2], c) == nil){
case '0':
case '.':
d.d1 &= ~(1<<j);
break;
} else {
case '1':
d.d1 |= (1<<j);
break;
}
case '-':
continue;
}
}
/* dont allow system segments */
if((d.d1 & SEGP) && ((dpl != 3) || !(d.d1 & (1<<12))))
error(Eperm);
if(local){
Segdesc *new, *old;
int c;
if(i < 0 || i >= 8192)
error(Ebadarg);
if(i >= (c = ((old = proc->ldt) ? proc->nldt : 0))){
if((new = malloc(sizeof(Segdesc) * (i+1))) == nil)
error(Enomem);
if(c > 0)
memmove(new, old, sizeof(Segdesc) * c);
memset(new + c, 0, sizeof(Segdesc) * ((i+1) - c));
proc->ldt = new;
proc->nldt = i+1;
free(old);
}
proc->ldt[i] = d;
} else {
if(i < PROCSEG0 || i >= PROCSEG0 + NPROCSEG)
error(Ebadarg);
proc->gdt[i - PROCSEG0] = d;
}
}
poperror();
if(proc == up)
flushmmu();
return n;
}
static long
descread(Proc *proc, int local, void *v, long n, vlong o)
{
int i, j, k, t;
char *s;
int dpl;
ulong base;
ulong limit;
s = v;
for(i = 0;;i++){
Segdesc d;
if(local){
if(proc->ldt == nil || i >= proc->nldt)
break;
d = proc->ldt[i];
} else {
if(i < PROCSEG0)
i = PROCSEG0;
if(i >= PROCSEG0 + NPROCSEG)
break;
d = proc->gdt[i - PROCSEG0];
}
if(o >= RECLEN){
o -= RECLEN;
continue;
}
if(s + RECLEN+1 >= (char*)v + n)
break;
for(t=0; t<nelem(descrtypes); t++){
for(j=0; descrtypes[t].flags[j]; j++){
if(descrtypes[t].flags[j]=='0' && (d.d1 & (1<<j)) != 0)
break;
if(descrtypes[t].flags[j]=='1' && (d.d1 & (1<<j)) == 0)
break;
}
if(descrtypes[t].flags[j] == 0)
break;
}
if(t == nelem(descrtypes))
t = 0;
s += sprint(s, "%.4lux ", (ulong)i);
s += sprint(s, "%-8s ", descrtypes[t].name);
k = 0;
for(j=0; descrtypes[t].flags[j]; j++){
switch(descrtypes[t].flags[j]){
case '-':
case '.':
case '0':
case '1':
continue;
}
if(d.d1 & (1 << j))
s[k++] = descrtypes[t].flags[j];
}
if(k == 0)
s[k++] = '-';
while(k < 9)
s[k++] = ' ';
s += k;
dpl = (d.d1 & 0x6000)>>13;
base = ((d.d0 & 0xFFFF0000)>>16) | ((d.d1 & 0xFF)<<16) | (d.d1 & 0xFF000000);
limit = (d.d1 & 0xF0000) | (d.d0 & 0xFFFF);
s += sprint(s, "%.1d ", dpl);
s += sprint(s, "%.8lux ", base);
s += sprint(s, "%.5lux\n", limit);
}
return s-(char*)v;
}
static long
gdtread(Chan*, void *v, long n, vlong o)
{
return descread(up, 0, v, n, o);
}
static long
gdtwrite(Chan*, void *v, long n, vlong o)
{
return descwrite(up, 0, v, n, o);
}
static long
ldtread(Chan*, void *v, long n, vlong o)
{
return descread(up, 1, v, n, o);
}
static long
ldtwrite(Chan*, void *v, long n, vlong o)
{
return descwrite(up, 1, v, n, o);
}
void
segdesclink(void)
{
addarchfile("gdt", 0666, gdtread, gdtwrite);
addarchfile("ldt", 0666, ldtread, ldtwrite);
}