diff options
| -rw-r--r-- | elf.h | 6 | ||||
| -rw-r--r-- | fs.h | 53 | ||||
| -rw-r--r-- | kalloc.c | 4 | ||||
| -rw-r--r-- | mkdir.c | 1 | ||||
| -rw-r--r-- | proc.c | 5 | ||||
| -rw-r--r-- | proc.h | 76 | ||||
| -rw-r--r-- | setjmp.S | 27 | ||||
| -rw-r--r-- | spinlock.c | 16 | ||||
| -rw-r--r-- | spinlock.h | 12 | ||||
| -rw-r--r-- | stat.h | 10 | ||||
| -rw-r--r-- | trap.c | 14 | ||||
| -rw-r--r-- | traps.h | 4 | ||||
| -rw-r--r-- | x86.h | 4 | 
13 files changed, 151 insertions, 81 deletions
| @@ -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; @@ -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 + +// 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) -// 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 +// 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 @@ -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)  { @@ -2,6 +2,7 @@  #include "stat.h"  #include "user.h" +int  main(int argc, char *argv[])  {    int i; @@ -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: @@ -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]; @@ -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 @@ -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)  { @@ -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.  }; @@ -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  }; @@ -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");  } @@ -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 @@ -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; | 
