diff options
| -rw-r--r-- | defs.h | 3 | ||||
| -rwxr-xr-x | dot-bochsrc | 2 | ||||
| -rw-r--r-- | lapic.c | 22 | ||||
| -rw-r--r-- | main.c | 15 | ||||
| -rw-r--r-- | proc.c | 31 | ||||
| -rw-r--r-- | proc.h | 14 | ||||
| -rw-r--r-- | spinlock.c | 31 | ||||
| -rw-r--r-- | sysproc.c | 1 | ||||
| -rw-r--r-- | trap.c | 12 | ||||
| -rw-r--r-- | x86.h | 9 | 
10 files changed, 107 insertions, 33 deletions
@@ -92,6 +92,7 @@ int             pipewrite(struct pipe*, char*, int);  // proc.c  struct proc*    copyproc(struct proc*); +struct proc*    curproc();  void            exit(void);  int             growproc(int);  int             kill(int); @@ -114,6 +115,8 @@ void            getcallerpcs(void*, uint*);  int             holding(struct spinlock*);  void            initlock(struct spinlock*, char*);  void            release(struct spinlock*); +void            splhi(); +void            spllo();  // string.c  int             memcmp(const void*, const void*, uint); diff --git a/dot-bochsrc b/dot-bochsrc index 8c609bd..ddd5d93 100755 --- a/dot-bochsrc +++ b/dot-bochsrc @@ -107,7 +107,7 @@ romimage: file=$BXSHARE/BIOS-bochs-latest  #  650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66  2 to  2.5 Mips  #  400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3   1 to  1.8 Mips  #======================================================================= -cpu: count=2, ips=10000000, quantum=1 +cpu: count=2, ips=10000000, quantum=1, reset_on_triple_fault=0  #=======================================================================  # MEGS @@ -2,7 +2,10 @@  // See Chapter 8 & Appendix C of Intel processor manual volume 3.  #include "types.h" +#include "defs.h"  #include "traps.h" +#include "mmu.h" +#include "x86.h"  // Local APIC registers, divided by 4 for use as uint[] indices.  #define ID      (0x0020/4)   // ID @@ -84,6 +87,25 @@ lapic_init(int c)  int  cpu(void)  { +  // Cannot call cpu when interrupts are enabled: +  // result not guaranteed to last long enough to be used! +  // Would prefer to panic but even printing is chancy here: +  // everything, including cprintf, calls cpu, at least indirectly +  // through acquire and release. +  if(read_eflags()&FL_IF){ +    static int n; +    int i; +    uint pcs[10]; + +    if(n++%999 == 0){ +      getcallerpcs((uint*)read_ebp() + 2, pcs); +      cprintf("cpu called from %x with interrupts enabled: stk"); +      for(i=0; i<10 && pcs[i] && pcs[i] != -1; i++) +        cprintf(" %x", pcs[i]); +      cprintf("\n"); +    } +  } +    if(lapic)      return lapic[ID]>>24;    return 0; @@ -18,9 +18,9 @@ main(void)    // clear BSS    memset(edata, 0, end - edata); -  // Prevent release() from enabling interrupts. +  // splhi() every processor during bootstrap.    for(i=0; i<NCPU; i++) -    cpus[i].nlock = 1; +    cpus[i].nsplhi = 1;    mp_init(); // collect info about this machine    bcpu = mp_bcpu(); @@ -47,12 +47,14 @@ main(void)    bootothers();    // boot other CPUs    if(!ismp)      timer_init(); // uniprocessor timer +  cprintf("ismp %d\n", ismp); +  cprintf("userinit\n");    userinit();      // first user process    // enable interrupts on this processor. -  cpus[cpu()].nlock--; -  sti(); +  spllo(); +  cprintf("scheduler\n");    scheduler();  } @@ -66,10 +68,7 @@ mpmain(void)    setupsegs(0);    cpuid(0, 0, 0, 0, 0);  // memory barrier    cpus[cpu()].booted = 1; - -  // Enable interrupts on this processor. -  cpus[cpu()].nlock--; -  sti(); +  spllo();    scheduler();  } @@ -9,7 +9,6 @@  struct spinlock proc_table_lock;  struct proc proc[NPROC]; -struct proc *curproc[NCPU];  static struct proc *initproc;  int nextpid = 1; @@ -61,6 +60,7 @@ growproc(int n)    cp->mem = newmem;    kfree(oldmem, cp->sz);    cp->sz += n; +  setupsegs(cp);    return cp->sz - n;  } @@ -71,6 +71,7 @@ setupsegs(struct proc *p)  {    struct cpu *c; +  splhi();    c = &cpus[cpu()];    c->ts.ss0 = SEG_KDATA << 3;    if(p) @@ -93,6 +94,7 @@ setupsegs(struct proc *p)    lgdt(c->gdt, sizeof(c->gdt));    ltr(SEG_TSS << 3); +  spllo();  }  // Create a new process copying p as the parent. @@ -176,6 +178,19 @@ userinit(void)    initproc = p;  } +// Return currently running process. +// XXX comment better +struct proc* +curproc(void) +{ +  struct proc *p; + +  splhi(); +  p = cpus[cpu()].curproc; +  spllo(); +  return p; +} +  //PAGEBREAK: 42  // Per-CPU process scheduler.  // Each CPU calls scheduler() after setting itself up. @@ -188,12 +203,14 @@ void  scheduler(void)  {    struct proc *p; +  struct cpu *c;    int i;    for(;;){      // Loop over process table looking for process to run.      acquire(&proc_table_lock); - +     +    c = &cpus[cpu()];      for(i = 0; i < NPROC; i++){        p = &proc[i];        if(p->state != RUNNABLE) @@ -202,14 +219,14 @@ scheduler(void)        // Switch to chosen process.  It is the process's job        // to release proc_table_lock and then reacquire it        // before jumping back to us. -      cp = p; +      c->curproc = p;        setupsegs(p);        p->state = RUNNING; -      swtch(&cpus[cpu()].context, &p->context); +      swtch(&c->context, &p->context);        // Process is done running for now.        // It should have changed its p->state before coming back. -      cp = 0; +      c->curproc = 0;        setupsegs(0);      } @@ -222,11 +239,13 @@ scheduler(void)  void  sched(void)  { +  if(read_eflags()&FL_IF) +    panic("sched interruptible");    if(cp->state == RUNNING)      panic("sched running");    if(!holding(&proc_table_lock))      panic("sched proc_table_lock"); -  if(cpus[cpu()].nlock != 1) +  if(cpus[cpu()].nsplhi != 1)      panic("sched locks");    swtch(&cp->context, &cpus[cpu()].context); @@ -49,25 +49,23 @@ struct proc {  //   fixed-size stack  //   expandable heap -// Arrange that cp point to the struct proc that this -// CPU is currently running.  Such preprocessor  -// subterfuge can be confusing, but saves a lot of typing. -extern struct proc *curproc[NCPU];  // Current (running) process per CPU -#define cp (curproc[cpu()])  // Current process on this CPU - -  #define MPSTACK 512  // Per-CPU state  struct cpu {    uchar apicid;               // Local APIC ID +  struct proc *curproc;       // Process currently running.    struct context context;     // Switch 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 +  int nsplhi;                 // Depth of splhi nesting.  };  extern struct cpu cpus[NCPU];  extern int ncpu; + +// "cp" is a short alias for curproc(). +// It gets used enough to make this worthwhile. +#define cp curproc() @@ -25,13 +25,10 @@ initlock(struct spinlock *lock, char *name)  void  acquire(struct spinlock *lock)  { +  splhi();    if(holding(lock))      panic("acquire"); -  if(cpus[cpu()].nlock == 0) -    cli(); -  cpus[cpu()].nlock++; -    while(cmpxchg(0, 1, &lock->locked) == 1)      ; @@ -62,8 +59,7 @@ release(struct spinlock *lock)    cpuid(0, 0, 0, 0, 0);  // memory barrier (see Ch 7, IA-32 manual vol 3)    lock->locked = 0; -  if(--cpus[cpu()].nlock == 0) -    sti(); +  spllo();  }  // Record the current call stack in pcs[] by following the %ebp chain. @@ -91,3 +87,26 @@ holding(struct spinlock *lock)    return lock->locked && lock->cpu == cpu() + 10;  } + + +// XXX! +// Better names?  Better functions?   + +void +splhi(void) +{ +  cli(); +  cpus[cpu()].nsplhi++; +} + +void +spllo(void) +{ +  if(read_eflags()&FL_IF) +    panic("spllo - interruptible"); +  if(--cpus[cpu()].nsplhi < 0) +    panic("spllo"); +  if(cpus[cpu()].nsplhi == 0) +    sti(); +} + @@ -54,7 +54,6 @@ sys_sbrk(void)      return -1;    if((addr = growproc(n)) < 0)      return -1; -  setupsegs(cp);    return addr;  } @@ -44,8 +44,8 @@ trap(struct trapframe *tf)      return;    } -  // Make sure interrupts stay off during handler. -  cpus[cpu()].nlock++; +  // No interrupts during interrupt handling. +  splhi();    switch(tf->trapno){    case IRQ_OFFSET + IRQ_TIMER: @@ -84,7 +84,13 @@ trap(struct trapframe *tf)      cp->killed = 1;    } -  cpus[cpu()].nlock--; +  // Undo splhi but do not enable interrupts. +  // If you change this to spllo() you can get a  +  // triple fault by just typing too fast at the prompt. +  // An interrupt stops us right here, and when that +  // interrupt tries to return, somehow the segment +  // registers are all invalid. +  --cpus[cpu()].nsplhi;    // Force process exit if it has been killed and is in user space.    // (If it is still executing in the kernel, let it keep running  @@ -39,6 +39,15 @@ outsl(int port, const void *addr, int cnt)                     "cc");  } +static inline uint +read_ebp(void) +{ +  uint ebp; +   +  asm volatile("movl %%ebp, %0" : "=a" (ebp)); +  return ebp; +} +  struct segdesc;  static inline void  | 
