Initial version of single-cpu xv6 with page tables
This commit is contained in:
		
							parent
							
								
									b7a517f227
								
							
						
					
					
						commit
						40889627ba
					
				
					 22 changed files with 307 additions and 152 deletions
				
			
		
							
								
								
									
										5
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										22
									
								
								defs.h
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								defs.h
									
										
									
									
									
								
							|  | @ -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])) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										90
									
								
								exec.c
									
										
									
									
									
								
							
							
						
						
									
										90
									
								
								exec.c
									
										
									
									
									
								
							|  | @ -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; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										1
									
								
								file.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								file.c
									
										
									
									
									
								
							|  | @ -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(); | ||||
|   } | ||||
|    | ||||
|  |  | |||
							
								
								
									
										3
									
								
								ide.c
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								ide.c
									
										
									
									
									
								
							|  | @ -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); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										36
									
								
								kalloc.c
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								kalloc.c
									
										
									
									
									
								
							|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										1
									
								
								lapic.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								lapic.c
									
										
									
									
									
								
							|  | @ -48,6 +48,7 @@ lapicw(int index, int value) | |||
| void | ||||
| lapicinit(int c) | ||||
| { | ||||
|   cprintf("lapicinit: %d 0x%x\n", c, lapic); | ||||
|   if(!lapic)  | ||||
|     return; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										26
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								main.c
									
										
									
									
									
								
							|  | @ -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"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										88
									
								
								mmu.h
									
										
									
									
									
								
							
							
						
						
									
										88
									
								
								mmu.h
									
										
									
									
									
								
							|  | @ -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 { | ||||
|  |  | |||
							
								
								
									
										1
									
								
								mp.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								mp.c
									
										
									
									
									
								
							|  | @ -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) | ||||
|  |  | |||
							
								
								
									
										2
									
								
								param.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								param.h
									
										
									
									
									
								
							|  | @ -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
 | ||||
|  |  | |||
							
								
								
									
										72
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										72
									
								
								proc.c
									
										
									
									
									
								
							|  | @ -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; | ||||
|  |  | |||
							
								
								
									
										2
									
								
								proc.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								proc.h
									
										
									
									
									
								
							|  | @ -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
 | ||||
|  |  | |||
							
								
								
									
										5
									
								
								sh.c
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								sh.c
									
										
									
									
									
								
							|  | @ -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
 | ||||
|  |  | |||
							
								
								
									
										8
									
								
								swtch.S
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								swtch.S
									
										
									
									
									
								
							|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										16
									
								
								syscall.c
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								syscall.c
									
										
									
									
									
								
							|  | @ -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)) | ||||
|  |  | |||
							
								
								
									
										9
									
								
								trap.c
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								trap.c
									
										
									
									
									
								
							|  | @ -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; | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										55
									
								
								x86.h
									
										
									
									
									
								
							
							
						
						
									
										55
									
								
								x86.h
									
										
									
									
									
								
							|  | @ -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().
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Frans Kaashoek
						Frans Kaashoek