/n/sources/plan9/sys/src/9/pc/fns.h:83,88 - pc/fns.h:83,89 void kbdinit(void); #define kmapinval() void lgdt(ushort[3]); + void lldt(ulong); void lidt(ushort[3]); void links(void); void ltr(ulong); /n/sources/plan9/sys/src/9/pc/fns.h:142,147 - pc/fns.h:143,149 void procrestore(Proc*); void procsave(Proc*); void procsetup(Proc*); + void procfork(Proc*); void putcr0(ulong); void putcr3(ulong); void putcr4(ulong); /n/sources/plan9/sys/src/9/pc/fns.h:166,172 - pc/fns.h:168,174 ulong upaalloc(int, int); void upafree(ulong, int); void upareserve(ulong, int); - #define userureg(ur) (((ur)->cs & 0xFFFF) == UESEL) + #define userureg(ur) (((ur)->cs & 3) == 3) void vectortable(void); void* vmap(ulong, int); int vmapsync(ulong); /n/sources/plan9/sys/src/9/pc/dat.h:108,113 - pc/dat.h:108,119 int nuart; /* number of uart devices */ }; + struct Segdesc + { + ulong d0; + ulong d1; + }; + /* * MMU stuff in proc */ /n/sources/plan9/sys/src/9/pc/dat.h:120,125 - pc/dat.h:126,136 Page* kmaptable; /* page table used by kmap */ uint lastkmap; /* last entry used by kmap */ int nkmap; /* number of current kmaps */ + + Segdesc *ldt; /* local descriptor table */ + int nldt; /* number of ldt descriptors allocated */ + + Segdesc gdt[NPROCSEG]; /* per process descriptors */ }; /* /n/sources/plan9/sys/src/9/pc/dat.h:162,173 - pc/dat.h:173,178 ulong ldt; /* selector for task's LDT */ ulong iomap; /* I/O map base address + T-bit */ } Tss; - - struct Segdesc - { - ulong d0; - ulong d1; - }; struct Mach { /n/sources/plan9/sys/src/9/pc/mem.h:84,91 - pc/mem.h:84,93 #define APMCSEG16 7 /* APM 16-bit code segment */ #define APMDSEG 8 /* APM data segment */ #define KESEG16 9 /* kernel executable 16-bit */ - #define NGDT 10 /* number of GDT entries required */ - /* #define APM40SEG 8 /* APM segment 0x40 */ + #define LDTSEG 10 /* local descriptor table */ + #define PROCSEG0 11 /* per process descriptor0 */ + #define NPROCSEG 3 /* number of per process descriptors */ + #define NGDT 14 /* number of GDT entries required */ #define SELGDT (0<<2) /* selector is in gdt */ #define SELLDT (1<<2) /* selector is in ldt */ /n/sources/plan9/sys/src/9/pc/mem.h:102,107 - pc/mem.h:104,110 #define APMCSEL16 SELECTOR(APMCSEG16, SELGDT, 0) #define APMDSEL SELECTOR(APMDSEG, SELGDT, 0) /* #define APM40SEL SELECTOR(APM40SEG, SELGDT, 0) */ + #define LDTSEL SELECTOR(LDTSEG, SELGDT, 0) /* * fields in segment descriptors /n/sources/plan9/sys/src/9/pc/mem.h:108,117 - pc/mem.h:111,121 */ #define SEGDATA (0x10<<8) /* data/stack segment */ #define SEGEXEC (0x18<<8) /* executable segment */ - #define SEGTSS (0x9<<8) /* TSS segment */ + #define SEGTSS (0x09<<8) /* TSS segment */ #define SEGCG (0x0C<<8) /* call gate */ #define SEGIG (0x0E<<8) /* interrupt gate */ #define SEGTG (0x0F<<8) /* trap gate */ + #define SEGLDT (0x02<<8) /* local descriptor table */ #define SEGTYPE (0x1F<<8) #define SEGP (1<<15) /* segment present */ /n/sources/plan9/sys/src/9/pc/io.h:10,15 - pc/io.h:10,17 VectorCNA = 7, /* coprocessor not available */ Vector2F = 8, /* double fault */ VectorCSO = 9, /* coprocessor segment overrun */ + VectorSNP = 11, /* segment not present */ + VectorGPF = 13, /* general protection fault */ VectorPF = 14, /* page fault */ Vector15 = 15, /* reserved */ VectorCERR = 16, /* coprocessor error */ /n/sources/plan9/sys/src/9/pc/trap.c:326,332 - pc/trap.c:326,332 } m->perf.intrts = perfticks(); - user = (ureg->cs & 0xFFFF) == UESEL; + user = userureg(ureg); if(user){ up->dbgreg = ureg; cycles(&up->kentry); /n/sources/plan9/sys/src/9/pc/trap.c:335,340 - pc/trap.c:335,341 clockintr = 0; vno = ureg->trap; + if(ctl = vctl[vno]){ if(ctl->isintr){ m->intr++; /n/sources/plan9/sys/src/9/pc/trap.c:424,429 - pc/trap.c:425,480 while(m->machno != 0) ; } + + /* + * general protection fault in kernel mode + * can be caused by loading invalid segments + * when returning to userspace. as the user + * can change the descriptors now we take + * it here to prevent the damage to the + * kernel. -cinap + */ + if(vno == VectorGPF || vno == VectorSNP){ + ulong *sp; + uchar *pc; + + /* l.s */ + extern void load_fs(ulong); + extern void load_gs(ulong); + + /* + * CS, SS, DS and ES are initialized by strayintr + * in l.s. initialize the others too so we dont trap + * again when restoring the old context. + */ + load_fs(NULLSEL); + load_gs(NULLSEL); + + pc = (uchar*)ureg->pc; + sp = (ulong*)&ureg->sp; + + /* + * we test for the instructions used by forkret() + * to load the segments. this needs to be changed + * if forkret changes! + */ + + /* POP */ + if((pc[0] == 0x0f && (pc[1] == 0xa9 /*GS*/ || + pc[1] == 0xa1 /*FS*/)) || (pc[0] == 0x07) /*ES*/ || + (pc[0] == 0x1f) /*DS*/){ + sp[0] = NULLSEL; + return; + } + + /* IRET */ + if(pc[0] == 0xcf){ + sp[1] = UESEL; /*CS*/ + sp[4] = UDSEL; /*SS*/ + return; + } + } + dumpregs(ureg); if(!user){ ureg->sp = (ulong)&ureg->sp; /n/sources/plan9/sys/src/9/pc/trap.c:461,467 - pc/trap.c:512,522 iprint("cpu%d: registers for kernel\n", m->machno); iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", ureg->flags, ureg->trap, ureg->ecode, ureg->pc); - iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); + if(userureg(ureg)){ + iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); + } else { + iprint(" SP=%luX\n", (ulong)&ureg->sp); + } iprint(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n", ureg->ax, ureg->bx, ureg->cx, ureg->dx); iprint(" SI %8.8luX DI %8.8luX BP %8.8luX\n", /n/sources/plan9/sys/src/9/pc/trap.c:496,501 - pc/trap.c:551,557 } } iprint("\n ur %#p up %#p\n", ureg, up); + iprint("\n"); } /n/sources/plan9/sys/src/9/pc/trap.c:619,625 - pc/trap.c:675,681 addr = getcr2(); read = !(ureg->ecode & 2); - user = (ureg->cs & 0xFFFF) == UESEL; + user = userureg(ureg); if(!user){ if(vmapsync(addr)) return; /n/sources/plan9/sys/src/9/pc/trap.c:665,671 - pc/trap.c:721,727 int i, s; ulong scallnr; - if((ureg->cs & 0xFFFF) != UESEL) + if(!userureg(ureg)) panic("syscall: cs 0x%4.4luX", ureg->cs); cycles(&up->kentry); /n/sources/plan9/sys/src/9/pc/trap.c:828,833 - pc/trap.c:884,893 *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ ureg->usp = sp; ureg->pc = (ulong)up->notify; + + ureg->cs = UESEL; + ureg->ss = ureg->ds = ureg->es = UDSEL; + up->notified = 1; up->nnote--; memmove(&up->lastnote, &up->note[0], sizeof(Note)); /n/sources/plan9/sys/src/9/pc/trap.c:867,889 - pc/trap.c:927,936 pexit("Suicide", 0); } - /* - * Check the segment selectors are all valid, otherwise - * a fault will be taken on attempting to return to the - * user process. - * Take care with the comparisons as different processor - * generations push segment descriptors in different ways. - */ - if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL - || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL - || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){ - pprint("bad segment selector in noted\n"); - qunlock(&up->debug); - pexit("Suicide", 0); - } - /* don't let user change system flags */ nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5); + nureg->cs |= 3; + nureg->ss |= 3; memmove(ureg, nureg, sizeof(Ureg)); /n/sources/plan9/sys/src/9/pc/trap.c:946,951 - pc/trap.c:993,1003 ureg = up->dbgreg; ureg->usp = (ulong)sp; ureg->pc = entry; + + ureg->cs = UESEL; + ureg->ss = ureg->ds = ureg->es = UDSEL; + ureg->fs = ureg->gs = NULLSEL; + return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */ } /n/sources/plan9/sys/src/9/pc/trap.c:967,989 - pc/trap.c:1019,1034 void setregisters(Ureg* ureg, char* pureg, char* uva, int n) { - ulong cs, ds, es, flags, fs, gs, ss; + ulong flags; - ss = ureg->ss; flags = ureg->flags; - cs = ureg->cs; - ds = ureg->ds; - es = ureg->es; - fs = ureg->fs; - gs = ureg->gs; + memmove(pureg, uva, n); - ureg->gs = gs; - ureg->fs = fs; - ureg->es = es; - ureg->ds = ds; - ureg->cs = cs; - ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00); - ureg->ss = ss; + + /* don't allow chaning system flags */ + ureg->flags = (ureg->flags & 0xCD5) | (flags & ~0xCD5); + ureg->cs |= 3; + ureg->ss |= 3; } static void /n/sources/plan9/sys/src/9/pc/trap.c:1024,1029 - pc/trap.c:1069,1075 cureg = (Ureg*)(p->sched.sp+2*BY2WD); memmove(cureg, ureg, sizeof(Ureg)); + /* return value of syscall in child */ cureg->ax = 0; /n/sources/plan9/sys/src/9/pc/mmu.c:294,299 - pc/mmu.c:294,301 mmuswitch(Proc* proc) { ulong *pdb; + ulong x; + int n; if(proc->newtlb){ mmuptefree(proc); /n/sources/plan9/sys/src/9/pc/mmu.c:307,312 - pc/mmu.c:309,323 taskswitch(proc->mmupdb->pa, (ulong)(proc->kstack+KSTACK)); }else taskswitch(PADDR(m->pdb), (ulong)(proc->kstack+KSTACK)); + + memmove(&m->gdt[PROCSEG0], proc->gdt, sizeof(proc->gdt)); + if((x = (ulong)proc->ldt) && (n = proc->nldt) > 0){ + m->gdt[LDTSEG].d0 = (x<<16)|((n * sizeof(Segdesc)) - 1); + m->gdt[LDTSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGLDT|SEGPL(0)|SEGP; + lldt(LDTSEL); + } else { + lldt(NULLSEL); + } } /* /n/sources/plan9/sys/src/9/pc/mmu.c:362,367 - pc/mmu.c:373,384 if(--page->ref) panic("mmurelease: page->ref %d", page->ref); pagechainhead(page); + } + if(proc->ldt){ + lldt(NULLSEL); + free(proc->ldt); + proc->ldt = nil; + proc->nldt = 0; } if(proc->mmufree && palloc.r.p) wakeup(&palloc.r); /n/sources/plan9/sys/src/9/pc/l.s:601,606 - pc/l.s:601,611 MOVL (AX), GDTR RET + TEXT lldt(SB), $0 /* LDTR - local descriptor table */ + MOVL sel+0(FP), AX + BYTE $0x0F; BYTE $0x00; BYTE $0xD0 /* LLDT AX */ + RET + TEXT lidt(SB), $0 /* IDTR - interrupt descriptor table */ MOVL idtptr+0(FP), AX MOVL (AX), IDTR /n/sources/plan9/sys/src/9/pc/l.s:989,994 - pc/l.s:994,1009 _nothingready: STI HLT + RET + + TEXT load_fs(SB), $0 + MOVW fs+0(FP), AX + MOVW AX, FS + RET + + TEXT load_gs(SB), $0 + MOVW gs+0(FP), AX + MOVW AX, GS RET /* /tmp/diff100000066833:0 - pc/segdesc.c:1,272 + #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>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<= 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>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); + } + + /* + * devproc hook + * extern long (*psegdescread)(Proc*, int, void*, long, vlong); + * extern long (*psegdescwrite)(Proc*, int, void*, long, vlong); + */ + + void + segdesclink(void) + { + /* + * devproc hook + * psegdescread = descread; + * psegdescwrite = descwrite; + */ + addarchfile("gdt", 0666, gdtread, gdtwrite); + addarchfile("ldt", 0666, ldtread, ldtwrite); + } /n/sources/plan9/sys/src/9/pc/main.c:440,453 - pc/main.c:440,446 + conf.nswap + conf.nswppo*sizeof(Page); mainmem->maxsize = kpages; - if(!cpuserver){ - /* - * give terminals lots of image memory, too; the dynamic - * allocation will balance the load properly, hopefully. - * be careful with 32-bit overflow. - */ - imagmem->maxsize = kpages; - } + imagmem->maxsize = kpages; } static char* mathmsg[] = /n/sources/plan9/sys/src/9/pc/main.c:575,588 - pc/main.c:568,582 trapenable(VectorCSO, mathover, 0, "mathover"); } - /* - * set up floating point for a new process - */ void procsetup(Proc*p) { p->fpstate = FPinit; fpoff(); + + memset(p->gdt, 0, sizeof(p->gdt)); + p->ldt = nil; + p->nldt = 0; } void /n/sources/plan9/sys/src/9/pc/main.c:592,597 - pc/main.c:586,592 if(p->kp) return; + cycles(&t); p->pcycles -= t; } /n/sources/plan9/sys/src/9/pc/main.c:637,642 - pc/main.c:632,651 mmuflushtlb(PADDR(m->pdb)); } + void + procfork(Proc *p) + { + /* inherit user descriptors */ + memmove(p->gdt, up->gdt, sizeof(p->gdt)); + + /* copy local descriptor table */ + if(up->ldt != nil && up->nldt > 0){ + p->ldt = malloc(sizeof(Segdesc) * up->nldt); + memmove(p->ldt, up->ldt, sizeof(Segdesc) * up->nldt); + p->nldt = up->nldt; + } + } + static void shutdown(int ispanic) { /n/sources/plan9/sys/src/9/pc/main.c:648,660 - pc/main.c:657,662 else if(m->machno == 0 && (active.machs & (1<machno)) == 0) active.ispanic = 0; once = active.machs & (1<machno); - /* - * setting exiting will make hzclock() on each processor call exit(0), - * which calls shutdown(0) and arch->reset(), which on mp systems is - * mpshutdown, from which there is no return: the processor is idled - * or initiates a reboot. clearing our bit in machs avoids calling - * exit(0) from hzclock() on this processor. - */ active.machs &= ~(1<machno); active.exiting = 1; unlock(&active); /n/sources/plan9/sys/src/9/pc/main.c:661,668 - pc/main.c:663,668 if(once) iprint("cpu%d: exiting\n", m->machno); - - /* wait for any other processors to shutdown */ spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); /n/sources/plan9/sys/src/9/pc/main.c:670,683 - pc/main.c:670,683 break; } + if(getconf("*debug")) + delay(5*60*1000); + if(active.ispanic){ if(!cpuserver) for(;;) halt(); - if(getconf("*debug")) - delay(5*60*1000); - else - delay(10000); + delay(10000); }else delay(1000); } /n/sources/plan9/sys/src/9/pc/main.c:690,715 - pc/main.c:690,700 writeconf(); - /* - * the boot processor is cpu0. execute this function on it - * so that the new kernel has the same cpu0. this only matters - * because the hardware has a notion of which processor was the - * boot processor and we look at it at start up. - */ - if (m->machno != 0) { - procwired(up, 0); - sched(); - } - shutdown(0); /* * should be the only processor running now */ - if (m->machno != 0) - print("on cpu%d (not 0)!\n", m->machno); - if (active.machs) - print("still have active ap processors!\n"); print("shutting down...\n"); delay(200); /n/sources/plan9/sys/src/9/pc/main.c:721,727 - pc/main.c:706,711 /* shutdown devices */ chandevshutdown(); - arch->introff(); /* * Modify the machine page table to directly map the low 4MB of memory /n/sources/plan9/sys/src/9/ppc/main.c:297,302 - ppc/main.c:297,308 p->pcycles -= t; } + void + procfork(Proc *) + { + } + + /* * Save the mach dependent part of the process state. */ /n/sources/plan9/sys/src/9/ppc/fns.h:77,82 - ppc/fns.h:77,83 void pcicfgw8(Pcidev*, int, int); void procsave(Proc*); void procsetup(Proc*); + void procfork(Proc*); void putdcmp(ulong); void putdec(ulong); void puthash1(ulong); /n/sources/plan9/sys/src/9/alphapc/main.c:295,300 - alphapc/main.c:295,306 } void + procfork(Proc *) + { + } + + + void setupboot(int halt) { int n = 0; // cpu id of primary cpu, not just m->machno /n/sources/plan9/sys/src/9/alphapc/fns.h:88,93 - alphapc/fns.h:88,94 #define procrestore(p) void procsave(Proc*); void procsetup(Proc*); + void procfork(Proc*); void restfpregs(FPsave*); uvlong rpcc(uvlong*); void screeninit(void); /n/sources/plan9/sys/src/9/bitsy/main.c:252,257 - bitsy/main.c:252,263 USED(p); } + void + procfork(Proc *) + { + } + + /* place holder */ /* * dummy since rdb is not included /n/sources/plan9/sys/src/9/bitsy/fns.h:85,90 - bitsy/fns.h:85,91 #define procrestore(p) void procsave(Proc*); void procsetup(Proc*); + void procfork(Proc*); void putdac(ulong); void putttb(ulong); void putpid(ulong); /n/sources/plan9/sys/src/9/mtx/main.c:274,279 - mtx/main.c:274,285 } void + procfork(Proc *) + { + } + + + void confinit(void) { char *p; /n/sources/plan9/sys/src/9/mtx/fns.h:86,91 - mtx/fns.h:86,92 #define procrestore(p) void procsave(Proc*); void procsetup(Proc*); + void procfork(Proc*); void putdec(ulong); void puthid0(ulong); void puthid1(ulong); /n/sources/plan9/sys/src/9/port/sysproc.c:187,192 - port/sysproc.c:187,195 kstrdup(&p->text, up->text); kstrdup(&p->user, up->user); + + procfork(p); + /* * since the bss/data segments are now shareable, * any mmu info about this process is now stale