more comments
This commit is contained in:
		
							parent
							
								
									7e019461c8
								
							
						
					
					
						commit
						31085bb416
					
				
					 13 changed files with 151 additions and 81 deletions
				
			
		
							
								
								
									
										6
									
								
								elf.h
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								elf.h
									
										
									
									
									
								
							|  | @ -1,9 +1,8 @@ | |||
| //
 | ||||
| // format of an ELF executable file
 | ||||
| //
 | ||||
| // Format of an ELF executable file
 | ||||
| 
 | ||||
| #define ELF_MAGIC 0x464C457FU  // "\x7FELF" in little endian
 | ||||
| 
 | ||||
| // File header
 | ||||
| struct elfhdr { | ||||
|   uint magic;  // must equal ELF_MAGIC
 | ||||
|   uchar elf[12]; | ||||
|  | @ -22,6 +21,7 @@ struct elfhdr { | |||
|   ushort shstrndx; | ||||
| }; | ||||
| 
 | ||||
| // Program section header
 | ||||
| struct proghdr { | ||||
|   uint type; | ||||
|   uint offset; | ||||
|  |  | |||
							
								
								
									
										53
									
								
								fs.h
									
										
									
									
									
								
							
							
						
						
									
										53
									
								
								fs.h
									
										
									
									
									
								
							|  | @ -1,12 +1,17 @@ | |||
| // on-disk file system format
 | ||||
| // On-disk file system format. 
 | ||||
| // This header is shared between kernel and user space.
 | ||||
| 
 | ||||
| // Block 0 is unused.
 | ||||
| // Block 1 is super block.
 | ||||
| // Inodes start at block 2.
 | ||||
| 
 | ||||
| #define BSIZE 512  // block size
 | ||||
| 
 | ||||
| // sector 1 (2nd sector)
 | ||||
| struct superblock{ | ||||
|   uint size; | ||||
|   uint nblocks; | ||||
|   uint ninodes; | ||||
| // File system super block
 | ||||
| struct superblock { | ||||
|   uint size;         // Size of file system (bytes???) xxx
 | ||||
|   uint nblocks;      // Number of blocks
 | ||||
|   uint ninodes;      // Number of inodes.
 | ||||
| }; | ||||
| 
 | ||||
| #define NADDRS (NDIRECT+1) | ||||
|  | @ -15,24 +20,31 @@ struct superblock{ | |||
| #define NINDIRECT (BSIZE / sizeof(uint)) | ||||
| #define MAXFILE (NDIRECT  + NINDIRECT) | ||||
| 
 | ||||
| // On-disk inode structure
 | ||||
| struct dinode { | ||||
|   short type; | ||||
|   short major; | ||||
|   short minor; | ||||
|   short nlink; | ||||
|   uint size; | ||||
|   uint addrs[NADDRS]; | ||||
|   short type;           // File type
 | ||||
|   short major;          // Major device number (T_DEV only)
 | ||||
|   short minor;          // Minor device number (T_DEV only)
 | ||||
|   short nlink;          // Number of links to inode in file system
 | ||||
|   uint size;            // Size of file (bytes)
 | ||||
|   uint addrs[NADDRS];   // Data block addresses
 | ||||
| }; | ||||
| 
 | ||||
| #define T_DIR 1 | ||||
| #define T_FILE 2 | ||||
| #define T_DEV 3 | ||||
| #define T_DIR  1   // Directory
 | ||||
| #define T_FILE 2   // File
 | ||||
| #define T_DEV  3   // Special device
 | ||||
| 
 | ||||
| // sector 0 is unused, sector 1 is superblock, inodes start at sector 2
 | ||||
| #define IPB (BSIZE / sizeof(struct dinode)) | ||||
| #define IBLOCK(inum) (inum / IPB + 2)   // start of inode
 | ||||
| #define BPB (BSIZE*8) | ||||
| #define BBLOCK(b,ninodes) (b/BPB + (ninodes/IPB) + 3)  // start of bitmap
 | ||||
| // Inodes per block.
 | ||||
| #define IPB           (BSIZE / sizeof(struct dinode)) | ||||
| 
 | ||||
| // Block containing inode i
 | ||||
| #define IBLOCK(i)     ((i) / IPB + 2) | ||||
| 
 | ||||
| // Bitmap bits per block
 | ||||
| #define BPB           (BSIZE*8) | ||||
| 
 | ||||
| // Block containing bit for block b
 | ||||
| #define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3) | ||||
| 
 | ||||
| #define DIRSIZ 14 | ||||
| 
 | ||||
|  | @ -41,4 +53,5 @@ struct dirent { | |||
|   char name[DIRSIZ]; | ||||
| }; | ||||
| 
 | ||||
| extern uint rootdev;  // Device number of root file system
 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								kalloc.c
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								kalloc.c
									
										
									
									
									
								
							|  | @ -40,6 +40,10 @@ kinit(void) | |||
|   kfree(start, mem * PAGE); | ||||
| } | ||||
| 
 | ||||
| // Free the len bytes of memory pointed at by cp,
 | ||||
| // which normally should have been returned by a
 | ||||
| // call to kalloc(cp).  (The exception is when
 | ||||
| // initializing the allocator; see kinit above.)
 | ||||
| void | ||||
| kfree(char *cp, int len) | ||||
| { | ||||
|  |  | |||
							
								
								
									
										1
									
								
								mkdir.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								mkdir.c
									
										
									
									
									
								
							|  | @ -2,6 +2,7 @@ | |||
| #include "stat.h" | ||||
| #include "user.h" | ||||
| 
 | ||||
| int | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
|   int i; | ||||
|  |  | |||
							
								
								
									
										5
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								proc.c
									
										
									
									
									
								
							|  | @ -136,7 +136,9 @@ copyproc(struct proc *p) | |||
|   return np; | ||||
| } | ||||
| 
 | ||||
| uint | ||||
| // Grow current process's memory by n bytes.
 | ||||
| // Return old size on success, -1 on failure.
 | ||||
| int | ||||
| growproc(int n) | ||||
| { | ||||
|   struct proc *cp = curproc[cpu()]; | ||||
|  | @ -154,6 +156,7 @@ growproc(int n) | |||
|   return cp->sz - n; | ||||
| } | ||||
| 
 | ||||
| //PAGEBREAK: 42
 | ||||
| // Per-CPU process scheduler.
 | ||||
| // Each CPU calls scheduler() after setting itself up.
 | ||||
| // Scheduler never returns.  It loops, doing:
 | ||||
|  |  | |||
							
								
								
									
										76
									
								
								proc.h
									
										
									
									
									
								
							
							
						
						
									
										76
									
								
								proc.h
									
										
									
									
									
								
							|  | @ -1,18 +1,19 @@ | |||
| // segments in proc->gdt
 | ||||
| #define SEG_KCODE 1 // kernel code
 | ||||
| #define SEG_KDATA 2 // kernel data+stack
 | ||||
| // Segments in proc->gdt
 | ||||
| #define SEG_KCODE 1  // kernel code
 | ||||
| #define SEG_KDATA 2  // kernel data+stack
 | ||||
| #define SEG_UCODE 3 | ||||
| #define SEG_UDATA 4 | ||||
| #define SEG_TSS   5   // this process's task state
 | ||||
| #define SEG_TSS   5  // this process's task state
 | ||||
| #define NSEGS     6 | ||||
| 
 | ||||
| // Saved registers for kernel context switches.
 | ||||
| // Don't need to save all the %fs etc. segment registers,
 | ||||
| // because they are constant across kernel contexts.
 | ||||
| // Save all the regular registers so we don't need to care
 | ||||
| // which are caller save.
 | ||||
| // Don't save %eax, because that's the return register.
 | ||||
| // The layout of jmpbuf is known to setjmp.S.
 | ||||
| struct jmpbuf { | ||||
|   // saved registers for kernel context switches
 | ||||
|   // don't need to save all the fs etc. registers because
 | ||||
|   // they are constant across kernel contexts
 | ||||
|   // save all the regular registers so we don't care which are caller save
 | ||||
|   // don't save eax because that's the return register
 | ||||
|   // layout known to setjmp.S
 | ||||
|   int ebx; | ||||
|   int ecx; | ||||
|   int edx; | ||||
|  | @ -25,39 +26,42 @@ struct jmpbuf { | |||
| 
 | ||||
| enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; | ||||
| 
 | ||||
| struct proc{ | ||||
|   char *mem;    // start of process's memory (a kernel address)
 | ||||
|     // process memory is laid out contiguously:
 | ||||
|     //   text
 | ||||
|     //   original data and bss
 | ||||
|     //   fixed-size stack
 | ||||
|     //   expandable heap
 | ||||
|   uint sz;      // user memory size
 | ||||
|   char *kstack; // kernel stack
 | ||||
|   enum proc_state state; | ||||
|   int pid; | ||||
|   int ppid; | ||||
|   void *chan; // sleep
 | ||||
|   int killed; | ||||
|   struct file *ofile[NOFILE]; | ||||
|   struct inode *cwd; | ||||
|   struct jmpbuf jmpbuf; | ||||
|   struct trapframe *tf; // points into kstack, used to find user regs
 | ||||
| // Per-process state
 | ||||
| struct proc { | ||||
|   char *mem;                // Start of process memory (kernel address)
 | ||||
|   uint sz;                  // Size of process memory (bytes)
 | ||||
|   char *kstack;             // Bottom of kernel stack for this process
 | ||||
|   enum proc_state state;    // Process state
 | ||||
|   int pid;                  // Process ID
 | ||||
|   int ppid;                 // Parent pid
 | ||||
|   void *chan;               // If non-zero, sleeping on chan
 | ||||
|   int killed;               // If non-zero, have been killed
 | ||||
|   struct file *ofile[NOFILE];  // Open files
 | ||||
|   struct inode *cwd;        // Current directory
 | ||||
|   struct jmpbuf jmpbuf;     // Jump here to run process
 | ||||
|   struct trapframe *tf;     // Trap frame for current interrupt
 | ||||
| }; | ||||
| 
 | ||||
| // Process memory is laid out contiguously:
 | ||||
| //   text
 | ||||
| //   original data and bss
 | ||||
| //   fixed-size stack
 | ||||
| //   expandable heap
 | ||||
| 
 | ||||
| extern struct proc proc[]; | ||||
| extern struct proc *curproc[NCPU];  // can be NULL if no proc running.
 | ||||
| extern struct proc *curproc[NCPU];  // Current (running) process per CPU
 | ||||
| 
 | ||||
| #define MPSTACK 512 | ||||
| 
 | ||||
| // Per-CPU state
 | ||||
| struct cpu { | ||||
|   uchar apicid;       // Local APIC ID
 | ||||
|   struct jmpbuf jmpbuf; | ||||
|   struct taskstate ts;  // only to give cpu address of kernel stack
 | ||||
|   struct segdesc gdt[NSEGS]; | ||||
|   char mpstack[MPSTACK]; // per-cpu start-up stack
 | ||||
|   volatile int booted; | ||||
|   int nlock; // # of locks currently held
 | ||||
|   uchar apicid;               // Local APIC ID
 | ||||
|   struct jmpbuf jmpbuf;       // Jump here to enter scheduler
 | ||||
|   struct taskstate ts;        // Used by x86 to find stack for interrupt
 | ||||
|   struct segdesc gdt[NSEGS];  // x86 global descriptor table
 | ||||
|   char mpstack[MPSTACK];      // Per-CPU startup stack
 | ||||
|   volatile int booted;        // Has the CPU started?
 | ||||
|   int nlock;                  // Number of locks currently held
 | ||||
| }; | ||||
| 
 | ||||
| extern struct cpu cpus[NCPU]; | ||||
|  |  | |||
							
								
								
									
										27
									
								
								setjmp.S
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								setjmp.S
									
										
									
									
									
								
							|  | @ -1,3 +1,20 @@ | |||
| #   int  setjmp(struct jmpbuf *jmp);
 | ||||
| #   void longjmp(struct jmpbuf *jmp);
 | ||||
| #  | ||||
| # Setjmp saves its stack environment in jmp | ||||
| # for later use by longjmp.  It returns 0. | ||||
| #  | ||||
| # Longjmp restores the environment saved by | ||||
| # the last call of setjmp. It then causes  | ||||
| # execution to continue as if the call of setjmp | ||||
| # had just returned 1. | ||||
| #  | ||||
| # The caller of setjmp must not itself have | ||||
| # returned in the interim.  All accessible data | ||||
| # have values as of the time longjmp was called. | ||||
| # | ||||
| #    [Description, but not code, borrowed from Plan 9.] | ||||
| 
 | ||||
| .globl setjmp
 | ||||
| setjmp: | ||||
|   movl 4(%esp), %eax | ||||
|  | @ -9,10 +26,10 @@ setjmp: | |||
|   movl %edi, 16(%eax) | ||||
|   movl %esp, 20(%eax) | ||||
|   movl %ebp, 24(%eax) | ||||
|   pushl 0(%esp)   /* %eip */ | ||||
|   pushl 0(%esp)   # %eip | ||||
|   popl 28(%eax) | ||||
| 
 | ||||
|   movl $0, %eax   /* return value */ | ||||
|   movl $0, %eax   # return value | ||||
|   ret | ||||
| 
 | ||||
| .globl longjmp
 | ||||
|  | @ -27,8 +44,8 @@ longjmp: | |||
|   movl 20(%eax), %esp | ||||
|   movl 24(%eax), %ebp | ||||
| 
 | ||||
|   addl $4, %esp   /* pop %eip into thin air */ | ||||
|   pushl 28(%eax)  /* push new %eip */ | ||||
|   addl $4, %esp   # pop and discard %eip | ||||
|   pushl 28(%eax)  # push new %eip | ||||
| 
 | ||||
|   movl $1, %eax   /* return value (appears to come from setjmp!) */ | ||||
|   movl $1, %eax   # return value (appears to come from setjmp!) | ||||
|   ret | ||||
|  |  | |||
							
								
								
									
										16
									
								
								spinlock.c
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								spinlock.c
									
										
									
									
									
								
							|  | @ -1,3 +1,5 @@ | |||
| // Mutual exclusion spin locks.
 | ||||
| 
 | ||||
| #include "types.h" | ||||
| #include "defs.h" | ||||
| #include "x86.h" | ||||
|  | @ -16,6 +18,7 @@ initlock(struct spinlock *lock, char *name) | |||
|   lock->cpu = 0xffffffff; | ||||
| } | ||||
| 
 | ||||
| // Record the current call stack in pcs[] by following the %ebp chain.
 | ||||
| void | ||||
| getcallerpcs(void *v, uint pcs[]) | ||||
| { | ||||
|  | @ -31,6 +34,10 @@ getcallerpcs(void *v, uint pcs[]) | |||
|     pcs[i] = 0; | ||||
| } | ||||
| 
 | ||||
| // Acquire the lock.
 | ||||
| // Loops (spins) until the lock is acquired.
 | ||||
| // (Because contention is handled by spinning, must not
 | ||||
| // go to sleep holding any locks.)
 | ||||
| void | ||||
| acquire(struct spinlock *lock) | ||||
| { | ||||
|  | @ -44,10 +51,16 @@ acquire(struct spinlock *lock) | |||
|   while(cmpxchg(0, 1, &lock->locked) == 1) | ||||
|     ; | ||||
|   cpuid(0, 0, 0, 0, 0);  // memory barrier
 | ||||
|   getcallerpcs(&lock, lock->pcs); | ||||
|    | ||||
|   // Record info about lock acquisition for debugging.
 | ||||
|   // The +10 is only so that we can tell the difference
 | ||||
|   // between forgetting to initialize lock->cpu
 | ||||
|   // and holding a lock on cpu 0.
 | ||||
|   lock->cpu = cpu() + 10; | ||||
|   getcallerpcs(&lock, lock->pcs); | ||||
| } | ||||
| 
 | ||||
| // Release the lock.
 | ||||
| void | ||||
| release(struct spinlock *lock) | ||||
| { | ||||
|  | @ -63,6 +76,7 @@ release(struct spinlock *lock) | |||
|     sti(); | ||||
| } | ||||
| 
 | ||||
| // Check whether this cpu is holding the lock.
 | ||||
| int | ||||
| holding(struct spinlock *lock) | ||||
| { | ||||
|  |  | |||
							
								
								
									
										12
									
								
								spinlock.h
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								spinlock.h
									
										
									
									
									
								
							|  | @ -1,6 +1,10 @@ | |||
| // Mutual exclusion lock.
 | ||||
| struct spinlock { | ||||
|   char *name; | ||||
|   uint locked; | ||||
|   int cpu; | ||||
|   uint pcs[10]; | ||||
|   uint locked;   // Is the lock held?
 | ||||
|    | ||||
|   // For debugging:
 | ||||
|   char *name;    // Name of lock.
 | ||||
|   int  cpu;      // The number of the cpu holding the lock.
 | ||||
|   uint pcs[10];  // The call stack (an array of program counters)
 | ||||
|                  // that locked the lock.
 | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										10
									
								
								stat.h
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								stat.h
									
										
									
									
									
								
							|  | @ -1,7 +1,7 @@ | |||
| struct stat { | ||||
|   int dev; | ||||
|   uint ino; | ||||
|   short type; | ||||
|   short nlink; | ||||
|   uint size; | ||||
|   int dev;     // Device number
 | ||||
|   uint ino;    // Inode number on device
 | ||||
|   short type;  // Type of file
 | ||||
|   short nlink; // Number of links to file
 | ||||
|   uint size;   // Size of file in bytes
 | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										14
									
								
								trap.c
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								trap.c
									
										
									
									
									
								
							|  | @ -7,11 +7,11 @@ | |||
| #include "traps.h" | ||||
| #include "syscall.h" | ||||
| 
 | ||||
| // Interrupt descriptor table (shared by all CPUs).
 | ||||
| struct gatedesc idt[256]; | ||||
| 
 | ||||
| extern uint vectors[];  // in vectors.S: array of 256 entry pointers
 | ||||
| 
 | ||||
| extern void trapenter(void); | ||||
| extern void trapenter1(void); | ||||
| 
 | ||||
| void | ||||
| tvinit(void) | ||||
|  | @ -65,30 +65,34 @@ trap(struct trapframe *tf) | |||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if(v == (IRQ_OFFSET + IRQ_IDE)){ | ||||
|   if(v == IRQ_OFFSET + IRQ_IDE){ | ||||
|     ide_intr(); | ||||
|     cli(); // prevent a waiting interrupt from overflowing stack
 | ||||
|     lapic_eoi(); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if(v == (IRQ_OFFSET + IRQ_KBD)){ | ||||
|   if(v == IRQ_OFFSET + IRQ_KBD){ | ||||
|     kbd_intr(); | ||||
|     cli(); // prevent a waiting interrupt from overflowing stack
 | ||||
|     lapic_eoi(); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if(v == (IRQ_OFFSET + IRQ_SPURIOUS)){ | ||||
|   if(v == IRQ_OFFSET + IRQ_SPURIOUS){ | ||||
|     cprintf("spurious interrupt from cpu %d eip %x\n", cpu(), tf->eip); | ||||
|     return;  // no eoi for this one.
 | ||||
|   } | ||||
| 
 | ||||
|   if(curproc[cpu()]) { | ||||
|     // assume process caused unexpected trap,
 | ||||
|     // for example by dividing by zero or dereferencing a bad pointer
 | ||||
|     cprintf("pid %d: unhandled trap %d on cpu %d eip %x -- kill proc\n", | ||||
|             curproc[cpu()]->pid, v, cpu(), tf->eip); | ||||
|     proc_exit(); | ||||
|   } | ||||
|    | ||||
|   // otherwise it's our mistake
 | ||||
|   cprintf("unexpected trap %d from cpu %d eip %x\n", v, cpu(), tf->eip); | ||||
|   panic("trap"); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										4
									
								
								traps.h
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								traps.h
									
										
									
									
									
								
							|  | @ -1,4 +1,6 @@ | |||
| // system defined:
 | ||||
| // x86 trap and interrupt constants.
 | ||||
| 
 | ||||
| // Processor-defined:
 | ||||
| #define T_DIVIDE         0      // divide error
 | ||||
| #define T_DEBUG          1      // debug exception
 | ||||
| #define T_NMI            2      // non-maskable interrupt
 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								x86.h
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								x86.h
									
										
									
									
									
								
							|  | @ -1,3 +1,6 @@ | |||
| // Special assembly routines to access x86-specific
 | ||||
| // hardware instructions.
 | ||||
| 
 | ||||
| static __inline uchar | ||||
| inb(int port) | ||||
| { | ||||
|  | @ -124,6 +127,7 @@ sti(void) | |||
|   __asm__ volatile("sti"); | ||||
| } | ||||
| 
 | ||||
| // Layout of the trap frame on the stack upon entry to trap.
 | ||||
| struct trapframe { | ||||
|   // registers as pushed by pusha
 | ||||
|   uint edi; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 rsc
						rsc