diff options
| author | Frans Kaashoek <kaashoek@fransk-6.local> | 2010-07-02 14:51:53 -0400 | 
|---|---|---|
| committer | Frans Kaashoek <kaashoek@fransk-6.local> | 2010-07-02 14:51:53 -0400 | 
| commit | 40889627ba50db29a64bc6a1553c2b21e6a99b78 (patch) | |
| tree | 7cb8f51492af706cafdcaf1b01a5cac8073d5a38 | |
| parent | b7a517f2277670e156f150ee2cb7aae6426c6aef (diff) | |
| download | xv6-labs-40889627ba50db29a64bc6a1553c2b21e6a99b78.tar.gz xv6-labs-40889627ba50db29a64bc6a1553c2b21e6a99b78.tar.bz2 xv6-labs-40889627ba50db29a64bc6a1553c2b21e6a99b78.zip | |
Initial version of single-cpu xv6 with page tables
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | bootasm.S | 2 | ||||
| -rw-r--r-- | defs.h | 22 | ||||
| -rw-r--r-- | exec.c | 90 | ||||
| -rw-r--r-- | file.c | 1 | ||||
| -rw-r--r-- | forktest.c | 8 | ||||
| -rw-r--r-- | ide.c | 3 | ||||
| -rw-r--r-- | kalloc.c | 36 | ||||
| -rw-r--r-- | lapic.c | 1 | ||||
| -rw-r--r-- | main.c | 26 | ||||
| -rw-r--r-- | mmu.h | 88 | ||||
| -rw-r--r-- | mp.c | 1 | ||||
| -rw-r--r-- | param.h | 2 | ||||
| -rw-r--r-- | proc.c | 72 | ||||
| -rw-r--r-- | proc.h | 2 | ||||
| -rw-r--r-- | sh.c | 5 | ||||
| -rw-r--r-- | spinlock.c | 2 | ||||
| -rw-r--r-- | swtch.S | 8 | ||||
| -rw-r--r-- | syscall.c | 16 | ||||
| -rw-r--r-- | sysfile.c | 5 | ||||
| -rw-r--r-- | trap.c | 9 | ||||
| -rw-r--r-- | x86.h | 55 | 
22 files changed, 307 insertions, 152 deletions
| @@ -25,12 +25,13 @@ OBJS = \  	trap.o\  	uart.o\  	vectors.o\ +	vm.o\  # Cross-compiling (e.g., on Mac OS X) -#TOOLPREFIX = i386-jos-elf- +TOOLPREFIX = i386-jos-elf-  # Using native tools (e.g., on X86 Linux) -TOOLPREFIX =  +#TOOLPREFIX =   CC = $(TOOLPREFIX)gcc  AS = $(TOOLPREFIX)gas @@ -88,5 +88,5 @@ gdt:    SEG_ASM(STA_W, 0x0, 0xffffffff)         # data seg  gdtdesc: -  .word   (gdtdesc - gdt - 1)                            # sizeof(gdt) - 1 +  .word   (gdtdesc - gdt - 1)             # sizeof(gdt) - 1    .long   gdt                             # address gdt @@ -60,9 +60,10 @@ extern uchar    ioapicid;  void            ioapicinit(void);  // kalloc.c +extern int      nfreemem;  char*           kalloc(int);  void            kfree(char*, int); -void            kinit(void); +void            kinit(char*,uint);  // kbd.c  void            kbdintr(void); @@ -101,8 +102,6 @@ int             kill(int);  void            pinit(void);  void            procdump(void);  void            scheduler(void) __attribute__((noreturn)); -void            ksegment(void); -void            usegment(void);  void            sleep(void*, struct spinlock*);  void            userinit(void);  int             wait(void); @@ -111,6 +110,7 @@ void            yield(void);  // swtch.S  void            swtch(struct context**, struct context*); +void            jstack(uint);  // spinlock.c  void            acquire(struct spinlock*); @@ -152,6 +152,22 @@ void            uartinit(void);  void            uartintr(void);  void            uartputc(int); +// vm.c +#define PGROUNDUP(sz)  ((sz+PGSIZE-1) & ~(PGSIZE-1)) +void            pminit(void); +void            swkstack(void); +void            vminit(void); +void            printpgdir(uint*); +uint*           setupkvm(void);    // XXX need pde_t* +char*           uva2ka(uint*, char*); +int             allocuvm(uint*, char*, uint);  // XXX need pde_t* +void            freevm(uint*); +void            inituvm(uint*, char*, char*, uint); +int             loaduvm(uint*, char*, struct inode *ip, uint, uint); +uint*           copyuvm(uint*,uint); +void            ksegment(void); +void            loadvm(struct proc*); +  // number of elements in fixed-size array  #define NELEM(x) (sizeof(x)/sizeof((x)[0])) @@ -11,12 +11,13 @@ exec(char *path, char **argv)  {    char *mem, *s, *last;    int i, argc, arglen, len, off; -  uint sz, sp, argp; +  uint sz, sp, spoffset, argp;    struct elfhdr elf;    struct inode *ip;    struct proghdr ph; +  pde_t *pgdir, *oldpgdir; -  mem = 0; +  pgdir = 0;    sz = 0;    if((ip = namei(path)) == 0) @@ -29,37 +30,8 @@ exec(char *path, char **argv)    if(elf.magic != ELF_MAGIC)      goto bad; -  // Compute memory size of new process. -  // Program segments. -  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ -    if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) -      goto bad; -    if(ph.type != ELF_PROG_LOAD) -      continue; -    if(ph.memsz < ph.filesz) -      goto bad; -    sz += ph.memsz; -  } -   -  // Arguments. -  arglen = 0; -  for(argc=0; argv[argc]; argc++) -    arglen += strlen(argv[argc]) + 1; -  arglen = (arglen+3) & ~3; -  sz += arglen; -  sz += 4*(argc+1);  // argv data -  sz += 4;  // argv -  sz += 4;  // argc - -  // Stack. -  sz += PAGE; -   -  // Allocate program memory. -  sz = (sz+PAGE-1) & ~(PAGE-1); -  mem = kalloc(sz); -  if(mem == 0) +  if (!(pgdir = setupkvm()))      goto bad; -  memset(mem, 0, sz);    // Load program into memory.    for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ @@ -67,37 +39,48 @@ exec(char *path, char **argv)        goto bad;      if(ph.type != ELF_PROG_LOAD)        continue; -    if(ph.va + ph.memsz < ph.va || ph.va + ph.memsz > sz) -      goto bad;      if(ph.memsz < ph.filesz)        goto bad; -    if(readi(ip, mem + ph.va, ph.offset, ph.filesz) != ph.filesz) +    if (!allocuvm(pgdir, (char *)ph.va, ph.memsz)) +      goto bad; +    sz += PGROUNDUP(ph.memsz); +    if (!loaduvm(pgdir, (char *)ph.va, ip, ph.offset, ph.filesz))        goto bad; -    memset(mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);    }    iunlockput(ip); -   -  // Initialize stack. + +  // Allocate and initialize stack at sz +  if (!allocuvm(pgdir, (char *)sz, PGSIZE)) +    goto bad; +  mem = uva2ka(pgdir, (char *)sz); +  spoffset = sz; +  sz += PGSIZE; + +  arglen = 0; +  for(argc=0; argv[argc]; argc++) +    arglen += strlen(argv[argc]) + 1; +  arglen = (arglen+3) & ~3; +    sp = sz;    argp = sz - arglen - 4*(argc+1);    // Copy argv strings and pointers to stack. -  *(uint*)(mem+argp + 4*argc) = 0;  // argv[argc] +  *(uint*)(mem+argp-spoffset + 4*argc) = 0;  // argv[argc]    for(i=argc-1; i>=0; i--){      len = strlen(argv[i]) + 1;      sp -= len; -    memmove(mem+sp, argv[i], len); -    *(uint*)(mem+argp + 4*i) = sp;  // argv[i] +    memmove(mem+sp-spoffset, argv[i], len); +    *(uint*)(mem+argp-spoffset + 4*i) = sp;  // argv[i]    }    // Stack frame for main(argc, argv), below arguments.    sp = argp;    sp -= 4; -  *(uint*)(mem+sp) = argp; +  *(uint*)(mem+sp-spoffset) = argp;    sp -= 4; -  *(uint*)(mem+sp) = argc; +  *(uint*)(mem+sp-spoffset) = argc;    sp -= 4; -  *(uint*)(mem+sp) = 0xffffffff;   // fake return pc +  *(uint*)(mem+sp-spoffset) = 0xffffffff;   // fake return pc    // Save program name for debugging.    for(last=s=path; *s; s++) @@ -105,18 +88,25 @@ exec(char *path, char **argv)        last = s+1;    safestrcpy(proc->name, last, sizeof(proc->name)); -  // Commit to the new image. -  kfree(proc->mem, proc->sz); -  proc->mem = mem; +  // Commit to the user image. +  oldpgdir = proc->pgdir; +  proc->pgdir = pgdir;    proc->sz = sz;    proc->tf->eip = elf.entry;  // main    proc->tf->esp = sp; -  usegment(); + +  // printstack(); + +  loadvm(proc); + +  freevm(oldpgdir); + +  // printstack();  +    return 0;   bad: -  if(mem) -    kfree(mem, sz); +  freevm(pgdir);    iunlockput(ip);    return -1;  } @@ -116,7 +116,6 @@ filewrite(struct file *f, char *addr, int n)      return pipewrite(f->pipe, addr, n);    if(f->type == FD_INODE){      ilock(f->ip); -    cprintf("filewrite: %d\n", n);      if((r = writei(f->ip, addr, f->off, n)) > 0)        f->off += r;      iunlock(f->ip); @@ -5,6 +5,8 @@  #include "stat.h"  #include "user.h" +#define N  1000 +  void  printf(int fd, char *s, ...)  { @@ -18,7 +20,7 @@ forktest(void)    printf(1, "fork test\n"); -  for(n=0; n<1000; n++){ +  for(n=0; n<N; n++){      pid = fork();      if(pid < 0)        break; @@ -26,8 +28,8 @@ forktest(void)        exit();    } -  if(n == 1000){ -    printf(1, "fork claimed to work 1000 times!\n"); +  if(n == N){ +    printf(1, "fork claimed to work N times!\n", N);      exit();    } @@ -147,8 +147,9 @@ iderw(struct buf *b)    // Wait for request to finish.    // Assuming will not sleep too long: ignore proc->killed. -  while((b->flags & (B_VALID|B_DIRTY)) != B_VALID) +  while((b->flags & (B_VALID|B_DIRTY)) != B_VALID) {      sleep(b, &idelock); +  }    release(&idelock);  } @@ -8,6 +8,7 @@  #include "types.h"  #include "defs.h"  #include "param.h" +#include "mmu.h"  #include "spinlock.h"  struct run { @@ -20,21 +21,28 @@ struct {    struct run *freelist;  } kmem; +int nfreemem; + +static void +printfreelist(void) +{ +  struct run *r, **rp; +  cprintf("freelist:\n"); +  for(rp=&kmem.freelist; (r=*rp) != 0; rp=&r->next){ +    cprintf("0x%x %d=0x%x\n", r, r->len, r->len); +  } +} +  // Initialize free list of physical pages.  // This code cheats by just considering one megabyte of  // pages after end.  Real systems would determine the  // amount of memory available in the system and use it all.  void -kinit(void) +kinit(char *p, uint len)  { -  extern char end[]; -  uint len; -  char *p; -    initlock(&kmem.lock, "kmem"); -  p = (char*)(((uint)end + PAGE) & ~(PAGE-1)); -  len = 256*PAGE; // assume computer has 256 pages of RAM, 1 MB -  cprintf("mem = %d\n", len); +  cprintf("end 0x%x free = %d(0x%x)\n", p, len); +  nfreemem = 0;    kfree(p, len);  } @@ -47,19 +55,23 @@ kfree(char *v, int len)  {    struct run *r, *rend, **rp, *p, *pend; -  if(len <= 0 || len % PAGE) +  if(len <= 0 || len % PGSIZE)      panic("kfree");    // Fill with junk to catch dangling refs.    memset(v, 1, len);    acquire(&kmem.lock); +  nfreemem += len;    p = (struct run*)v;    pend = (struct run*)(v + len);    for(rp=&kmem.freelist; (r=*rp) != 0 && r <= pend; rp=&r->next){      rend = (struct run*)((char*)r + r->len); -    if(r <= p && p < rend) +    if(r <= p && p < rend) { +      cprintf("freeing a free page: r = 0x%x p = 0x%x rend = 0x%x\n",  +	      r, p, rend);        panic("freeing free page"); +    }      if(rend == p){  // r before p: expand r to include p        r->len += len;        if(r->next && r->next == pend){  // r now next to r->next? @@ -93,7 +105,7 @@ kalloc(int n)    char *p;    struct run *r, **rp; -  if(n % PAGE || n <= 0) +  if(n % PGSIZE || n <= 0)      panic("kalloc");    acquire(&kmem.lock); @@ -103,6 +115,7 @@ kalloc(int n)        p = (char*)r + r->len;        if(r->len == 0)          *rp = r->next; +      nfreemem -= n;        release(&kmem.lock);        return p;      } @@ -112,3 +125,4 @@ kalloc(int n)    cprintf("kalloc: out of memory\n");    return 0;  } + @@ -48,6 +48,7 @@ lapicw(int index, int value)  void  lapicinit(int c)  { +  cprintf("lapicinit: %d 0x%x\n", c, lapic);    if(!lapic)       return; @@ -19,20 +19,27 @@ main(void)    ioapicinit();    // another interrupt controller    consoleinit();   // I/O devices & their interrupts    uartinit();      // serial port -cprintf("cpus %p cpu %p\n", cpus, cpu); -  cprintf("\ncpu%d: starting xv6\n\n", cpu->id); +  pminit();        // physical memory for kernel +  jkstack();       // Jump to mainc on a proper-allocated kernel stack  +} -  kinit();         // physical memory allocator +void +mainc(void) +{ +  cprintf("cpus %p cpu %p\n", cpus, cpu); +  cprintf("\ncpu%d: starting xv6\n\n", cpu->id); +  vminit();        // virtual memory    pinit();         // process table    tvinit();        // trap vectors    binit();         // buffer cache    fileinit();      // file table    iinit();         // inode cache    ideinit();       // disk +  cprintf("ismp: %d\n", ismp);    if(!ismp)      timerinit();   // uniprocessor timer    userinit();      // first user process -  bootothers();    // start other processors +  // bootothers();    // start other processors  XXX fix where to boot from    // Finish setting up this processor in mpmain.    mpmain(); @@ -43,9 +50,12 @@ cprintf("cpus %p cpu %p\n", cpus, cpu);  static void  mpmain(void)  { -  if(cpunum() != mpbcpu()) +  if(cpunum() != mpbcpu()) { +    ksegment(); +    cprintf("other cpu\n"); +    vminit();      lapicinit(cpunum()); -  ksegment(); +  }    cprintf("cpu%d: mpmain\n", cpu->id);    idtinit();    xchg(&cpu->booted, 1); @@ -74,11 +84,15 @@ bootothers(void)      stack = kalloc(KSTACKSIZE);      *(void**)(code-4) = stack + KSTACKSIZE;      *(void**)(code-8) = mpmain; +    cprintf("lapicstartap\n");      lapicstartap(c->id, (uint)code); +    cprintf("lapicstartap done\n");      // Wait for cpu to get through bootstrap.      while(c->booted == 0)        ; + +    cprintf("lapicstartap booted\n");    }  } @@ -62,6 +62,8 @@ struct segdesc {  #define STA_R       0x2     // Readable (executable segments)  #define STA_A       0x1     // Accessed +//  +  // System segment type bits  #define STS_T16A    0x1     // Available 16-bit TSS  #define STS_LDT     0x2     // Local Descriptor Table @@ -76,6 +78,92 @@ struct segdesc {  #define STS_IG32    0xE     // 32-bit Interrupt Gate  #define STS_TG32    0xF     // 32-bit Trap Gate + +// A linear address 'la' has a three-part structure as follows: +// +// +--------10------+-------10-------+---------12----------+ +// | Page Directory |   Page Table   | Offset within Page  | +// |      Index     |      Index     |                     | +// +----------------+----------------+---------------------+ +//  \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/ +//  \----------- PPN(la) -----------/ +// +// The PDX, PTX, PGOFF, and PPN macros decompose linear addresses as shown. +// To construct a linear address la from PDX(la), PTX(la), and PGOFF(la), +// use PGADDR(PDX(la), PTX(la), PGOFF(la)). + +// page number field of address +#define PPN(la)		(((uint) (la)) >> PTXSHIFT) +#define VPN(la)		PPN(la)		// used to index into vpt[] + +// page directory index +#define PDX(la)		((((uint) (la)) >> PDXSHIFT) & 0x3FF) +#define VPD(la)		PDX(la)		// used to index into vpd[] + +// page table index +#define PTX(la)		((((uint) (la)) >> PTXSHIFT) & 0x3FF) + +// offset in page +#define PGOFF(la)	(((uint) (la)) & 0xFFF) + +// construct linear address from indexes and offset +#define PGADDR(d, t, o)	((uint) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) + +// mapping from physical addresses to virtual addresses is the identity one +// (really linear addresses, but we map linear to physical also directly) +#define PADDR(a)       ((uint) a) + +// Page directory and page table constants. +#define NPDENTRIES	1024		// page directory entries per page directory +#define NPTENTRIES	1024		// page table entries per page table + +#define PGSIZE		4096		// bytes mapped by a page +#define PGSHIFT		12		// log2(PGSIZE) + +#define PTSIZE		(PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry +#define PTSHIFT		22		// log2(PTSIZE) + +#define PTXSHIFT	12		// offset of PTX in a linear address +#define PDXSHIFT	22		// offset of PDX in a linear address + +// Page table/directory entry flags. +#define PTE_P		0x001	// Present +#define PTE_W		0x002	// Writeable +#define PTE_U		0x004	// User +#define PTE_PWT		0x008	// Write-Through +#define PTE_PCD		0x010	// Cache-Disable +#define PTE_A		0x020	// Accessed +#define PTE_D		0x040	// Dirty +#define PTE_PS		0x080	// Page Size +#define PTE_MBZ		0x180	// Bits must be zero + +// The PTE_AVAIL bits aren't used by the kernel or interpreted by the +// hardware, so user processes are allowed to set them arbitrarily. +#define PTE_AVAIL	0xE00	// Available for software use + +// Only flags in PTE_USER may be used in system calls. +#define PTE_USER	(PTE_AVAIL | PTE_P | PTE_W | PTE_U) + +// Address in page table or page directory entry +#define PTE_ADDR(pte)	((uint) (pte) & ~0xFFF) + +typedef uint pte_t; +typedef uint pde_t; + +// Control Register flags +#define CR0_PE		0x00000001	// Protection Enable +#define CR0_MP		0x00000002	// Monitor coProcessor +#define CR0_EM		0x00000004	// Emulation +#define CR0_TS		0x00000008	// Task Switched +#define CR0_ET		0x00000010	// Extension Type +#define CR0_NE		0x00000020	// Numeric Errror +#define CR0_WP		0x00010000	// Write Protect +#define CR0_AM		0x00040000	// Alignment Mask +#define CR0_NW		0x20000000	// Not Writethrough +#define CR0_CD		0x40000000	// Cache Disable +#define CR0_PG		0x80000000	// Paging + +  // PAGEBREAK: 40  // Task state segment format  struct taskstate { @@ -39,6 +39,7 @@ mpsearch1(uchar *addr, int len)  {    uchar *e, *p; +  cprintf("mpsearch1 0x%x %d\n", addr, len);    e = addr+len;    for(p = addr; p < e; p += sizeof(struct mp))      if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0) @@ -1,5 +1,5 @@  #define NPROC        64  // maximum number of processes -#define PAGE       4096  // granularity of user-space memory allocation +#define PAGE       4096  // conveniently chosen to be equal to PGSIZE  #define KSTACKSIZE PAGE  // size of per-process kernel stack  #define NCPU          8  // maximum number of CPUs  #define NOFILE       16  // open files per process @@ -60,39 +60,6 @@ procdump(void)    }  } -// Set up CPU's kernel segment descriptors. -// Run once at boot time on each CPU. -void -ksegment(void) -{ -  struct cpu *c; - -  c = &cpus[cpunum()]; -  c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0x100000 + 64*1024-1, 0); -  c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); -  c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 8, 0); -  lgdt(c->gdt, sizeof(c->gdt)); -  loadgs(SEG_KCPU << 3); -   -  // Initialize cpu-local storage. -  cpu = c; -  proc = 0; -} - -// Set up CPU's segment descriptors and current process task state. -void -usegment(void) -{ -  pushcli(); -  cpu->gdt[SEG_UCODE] = SEG(STA_X|STA_R, proc->mem, proc->sz-1, DPL_USER); -  cpu->gdt[SEG_UDATA] = SEG(STA_W, proc->mem, proc->sz-1, DPL_USER); -  cpu->gdt[SEG_TSS] = SEG16(STS_T32A, &cpu->ts, sizeof(cpu->ts)-1, 0); -  cpu->gdt[SEG_TSS].s = 0; -  cpu->ts.ss0 = SEG_KDATA << 3; -  cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE; -  ltr(SEG_TSS << 3); -  popcli(); -}  //PAGEBREAK: 32  // Look in the process table for an UNUSED proc. @@ -149,20 +116,19 @@ userinit(void)    p = allocproc();    initproc = p; - -  // Initialize memory from initcode.S -  p->sz = PAGE; -  p->mem = kalloc(p->sz); -  memset(p->mem, 0, p->sz); -  memmove(p->mem, _binary_initcode_start, (int)_binary_initcode_size); - +  if (!(p->pgdir = setupkvm())) +    panic("userinit: out of memory?"); +  if (!allocuvm(p->pgdir, 0x0, (int)_binary_initcode_size)) +    panic("userinit: out of memory?"); +  inituvm(p->pgdir, 0x0, _binary_initcode_start, (int)_binary_initcode_size); +  p->sz = PGROUNDUP((int)_binary_initcode_size);    memset(p->tf, 0, sizeof(*p->tf));    p->tf->cs = (SEG_UCODE << 3) | DPL_USER;    p->tf->ds = (SEG_UDATA << 3) | DPL_USER;    p->tf->es = p->tf->ds;    p->tf->ss = p->tf->ds;    p->tf->eflags = FL_IF; -  p->tf->esp = p->sz; +  p->tf->esp = PGSIZE;    p->tf->eip = 0;  // beginning of initcode.S    safestrcpy(p->name, "initcode", sizeof(p->name)); @@ -176,17 +142,10 @@ userinit(void)  int  growproc(int n)  { -  char *newmem; - -  newmem = kalloc(proc->sz + n); -  if(newmem == 0) +  if (!allocuvm(proc->pgdir, (char *)proc->sz, n))      return -1; -  memmove(newmem, proc->mem, proc->sz); -  memset(newmem + proc->sz, 0, n); -  kfree(proc->mem, proc->sz); -  proc->mem = newmem;    proc->sz += n; -  usegment(); +  loadvm(proc);    return 0;  } @@ -204,14 +163,13 @@ fork(void)      return -1;    // Copy process state from p. -  np->sz = proc->sz; -  if((np->mem = kalloc(np->sz)) == 0){ +  if (!(np->pgdir = copyuvm(proc->pgdir, proc->sz))) {      kfree(np->kstack, KSTACKSIZE);      np->kstack = 0;      np->state = UNUSED;      return -1;    } -  memmove(np->mem, proc->mem, np->sz); +  np->sz = proc->sz;    np->parent = proc;    *np->tf = *proc->tf; @@ -225,7 +183,7 @@ fork(void)    pid = np->pid;    np->state = RUNNABLE; - +  safestrcpy(np->name, proc->name, sizeof(proc->name));    return pid;  } @@ -256,7 +214,7 @@ scheduler(void)        // to release ptable.lock and then reacquire it        // before jumping back to us.        proc = p; -      usegment(); +      loadvm(p);        p->state = RUNNING;        swtch(&cpu->scheduler, proc->context); @@ -284,7 +242,6 @@ sched(void)      panic("sched running");    if(readeflags()&FL_IF)      panic("sched interruptible"); -    intena = cpu->intena;    swtch(&proc->context, cpu->scheduler);    cpu->intena = intena; @@ -455,9 +412,10 @@ wait(void)        if(p->state == ZOMBIE){          // Found one.          pid = p->pid; -        kfree(p->mem, p->sz);          kfree(p->kstack, KSTACKSIZE); +	freevm(p->pgdir);          p->state = UNUSED; +	p->kstack = 0;          p->pid = 0;          p->parent = 0;          p->name[0] = 0; @@ -30,8 +30,8 @@ enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };  // Per-process state  struct proc { -  char *mem;                   // Start of process memory (kernel address)    uint sz;                     // Size of process memory (bytes) +  pde_t* pgdir;                // linear address of proc's pgdir    char *kstack;                // Bottom of kernel stack for this process    enum procstate state;        // Process state    volatile int pid;            // Process ID @@ -330,7 +330,7 @@ parsecmd(char *s)  {    char *es;    struct cmd *cmd; -   +    es = s + strlen(s);    cmd = parseline(&s, es);    peek(&s, es, ""); @@ -363,7 +363,7 @@ struct cmd*  parsepipe(char **ps, char *es)  {    struct cmd *cmd; -   +    cmd = parseexec(ps, es);    if(peek(ps, es, "|")){      gettoken(ps, es, 0, 0); @@ -420,6 +420,7 @@ parseexec(char **ps, char *es)    int tok, argc;    struct execcmd *cmd;    struct cmd *ret; +  int *x = (int *) peek;    if(peek(ps, es, "("))      return parseblock(ps, es); @@ -71,7 +71,7 @@ getcallerpcs(void *v, uint pcs[])    ebp = (uint*)v - 2;    for(i = 0; i < 10; i++){ -    if(ebp == 0 || ebp == (uint*)0xffffffff) +    if(ebp == 0 || ebp < 0x100000 || ebp == (uint*)0xffffffff)        break;      pcs[i] = ebp[1];     // saved %eip      ebp = (uint*)ebp[0]; // saved %ebp @@ -26,3 +26,11 @@ swtch:    popl %ebx    popl %ebp    ret + +# Jump on a new stack, fake C calling conventions +.globl jstack +jstack:	 +  movl 4(%esp), %esp +  subl $16, %esp	# space for arguments +  movl $0, %ebp	        # terminate functions that follow ebp's +  call mainc	        # continue at mainc @@ -18,10 +18,12 @@ fetchint(struct proc *p, uint addr, int *ip)  {    if(addr >= p->sz || addr+4 > p->sz)      return -1; -  *ip = *(int*)(p->mem + addr); +  *ip = *(int*)(addr);    return 0;  } +// XXX should we copy the string? +  // Fetch the nul-terminated string at addr from process p.  // Doesn't actually copy the string - just sets *pp to point at it.  // Returns length of string, not including nul. @@ -32,8 +34,10 @@ fetchstr(struct proc *p, uint addr, char **pp)    if(addr >= p->sz)      return -1; -  *pp = p->mem + addr; -  ep = p->mem + p->sz; +  // *pp = p->mem + addr; +  // ep = p->mem + p->sz; +  *pp = (char **) addr; +  ep = p->sz;    for(s = *pp; s < ep; s++)      if(*s == 0)        return s - *pp; @@ -44,7 +48,8 @@ fetchstr(struct proc *p, uint addr, char **pp)  int  argint(int n, int *ip)  { -  return fetchint(proc, proc->tf->esp + 4 + 4*n, ip); +  int x = fetchint(proc, proc->tf->esp + 4 + 4*n, ip); +  return x;  }  // Fetch the nth word-sized system call argument as a pointer @@ -59,7 +64,8 @@ argptr(int n, char **pp, int size)      return -1;    if((uint)i >= proc->sz || (uint)i+size >= proc->sz)      return -1; -  *pp = proc->mem + i; +  // *pp = proc->mem + i;   // XXXXX +  *pp = (char *) i;   // XXXXX    return 0;  } @@ -264,7 +264,6 @@ sys_open(void)    if(argstr(0, &path) < 0 || argint(1, &omode) < 0)      return -1; -    if(omode & O_CREATE){      if((ip = create(path, T_FILE, 0, 0)) == 0)        return -1; @@ -291,7 +290,6 @@ sys_open(void)    f->off = 0;    f->readable = !(omode & O_WRONLY);    f->writable = (omode & O_WRONLY) || (omode & O_RDWR); -    return fd;  } @@ -350,8 +348,9 @@ sys_exec(void)    int i;    uint uargv, uarg; -  if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) +  if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) {      return -1; +  }    memset(argv, 0, sizeof(argv));    for(i=0;; i++){      if(i >= NELEM(argv)) @@ -78,13 +78,14 @@ trap(struct trapframe *tf)    default:      if(proc == 0 || (tf->cs&3) == 0){        // In kernel, it must be our mistake. -      cprintf("unexpected trap %d from cpu %d eip %x\n", -              tf->trapno, cpu->id, tf->eip); +      cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n", +              tf->trapno, cpu->id, tf->eip, rcr2());        panic("trap");      }      // In user space, assume process misbehaved. -    cprintf("pid %d %s: trap %d err %d on cpu %d eip %x -- kill proc\n", -            proc->pid, proc->name, tf->trapno, tf->err, cpu->id, tf->eip); +    cprintf("pid %d %s: trap %d err %d on cpu %d eip 0x%x addr 0x%x--kill proc\n", +            proc->pid, proc->name, tf->trapno, tf->err, cpu->id, tf->eip,  +	    rcr2());      proc->killed = 1;    } @@ -121,6 +121,61 @@ sti(void)    asm volatile("sti");  } +static inline void lcr0(uint val) +{ +  asm volatile("movl %0,%%cr0" : : "r" (val)); +} + +static inline uint rcr0(void) +{ +  uint val; +  asm volatile("movl %%cr0,%0" : "=r" (val)); +  return val; +} + +static inline uint rcr2(void) +{ +  uint val; +  asm volatile("movl %%cr2,%0" : "=r" (val)); +  return val; +} + +static inline void lcr3(uint val)  +{ +  asm volatile("movl %0,%%cr3" : : "r" (val)); +} + +static inline uint rcr3(void) +{ +  uint val; +  asm volatile("movl %%cr3,%0" : "=r" (val)); +  return val; +} + +static inline void lebp(uint val) +{ +  asm volatile("movl %0,%%ebp" : : "r" (val)); +} + +static inline uint rebp(void) +{ +  uint val; +  asm volatile("movl %%ebp,%0" : "=r" (val)); +  return val; +} + +static inline void lesp(uint val) +{ +  asm volatile("movl %0,%%esp" : : "r" (val)); +} + +static inline uint resp(void) +{ +  uint val; +  asm volatile("movl %%esp,%0" : "=r" (val)); +  return val; +} +  //PAGEBREAK: 36  // Layout of the trap frame built on the stack by the  // hardware and by trapasm.S, and passed to trap(). | 
