diff --git a/main.c b/main.c
index b489231..275aa80 100644
--- a/main.c
+++ b/main.c
@@ -12,19 +12,13 @@ static void mpmain(void) __attribute__((noreturn));
 int
 main(void)
 {
-  int bcpu, i;
   extern char edata[], end[];
 
   // clear BSS
   memset(edata, 0, end - edata);
 
-  // pushcli() every processor during bootstrap.
-  for(i=0; i<NCPU; i++)
-    cpus[i].ncli = 1;  // no interrupts during bootstrap
-
   mp_init(); // collect info about this machine
-  bcpu = mp_bcpu();
-  lapic_init(bcpu);
+  lapic_init(mp_bcpu());
   cprintf("\ncpu%d: starting xv6\n\n", cpu());
 
   pinit();         // process table
@@ -38,19 +32,15 @@ main(void)
   console_init();  // I/O devices & their interrupts
   ide_init();      // disk
   if(!ismp)
-    timer_init(); // uniprocessor timer
+    timer_init();  // uniprocessor timer
   userinit();      // first user process
+  bootothers();    // start other processors
 
-  // Allocate scheduler stacks and boot the other CPUs.
-  for(i=0; i<ncpu; i++)
-    cpus[i].stack = kalloc(KSTACKSIZE);
-  bootothers();
-
-  // Switch to our scheduler stack and continue with mpmain.
-  asm volatile("movl %0, %%esp" : : "r" (cpus[bcpu].stack+KSTACKSIZE));
+  // Finish setting up this processor in mpmain.
   mpmain();
 }
 
+// Bootstrap processor gets here after setting up the hardware.
 // Additional processors start here.
 static void
 mpmain(void)
@@ -62,7 +52,6 @@ mpmain(void)
   setupsegs(0);
   cpuid(0, 0, 0, 0, 0);  // memory barrier
   cpus[cpu()].booted = 1;
-  popcli();
 
   scheduler();
 }
@@ -73,6 +62,7 @@ bootothers(void)
   extern uchar _binary_bootother_start[], _binary_bootother_size[];
   uchar *code;
   struct cpu *c;
+  char *stack;
 
   // Write bootstrap code to unused memory at 0x7000.
   code = (uchar*)0x7000;
@@ -83,7 +73,8 @@ bootothers(void)
       continue;
 
     // Fill in %esp, %eip and start code on cpu.
-    *(void**)(code-4) = c->stack + KSTACKSIZE;
+    stack = kalloc(KSTACKSIZE);
+    *(void**)(code-4) = stack + KSTACKSIZE;
     *(void**)(code-8) = mpmain;
     lapic_startap(c->apicid, (uint)code);
 
diff --git a/proc.c b/proc.c
index b009892..808a15e 100644
--- a/proc.c
+++ b/proc.c
@@ -179,7 +179,6 @@ userinit(void)
 }
 
 // Return currently running process.
-// XXX comment better
 struct proc*
 curproc(void)
 {
@@ -206,11 +205,13 @@ scheduler(void)
   struct cpu *c;
   int i;
 
+  c = &cpus[cpu()];
   for(;;){
+    // Enable interrupts on this processor.
+    sti();
+
     // 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)
@@ -229,8 +230,8 @@ scheduler(void)
       c->curproc = 0;
       setupsegs(0);
     }
-
     release(&proc_table_lock);
+
   }
 }
 
diff --git a/proc.h b/proc.h
index 36913c4..fa60452 100644
--- a/proc.h
+++ b/proc.h
@@ -56,9 +56,9 @@ struct cpu {
   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 *stack;
   volatile int booted;        // Has the CPU started?
-  int ncli;                 // Depth of pushcli nesting.
+  int ncli;                   // Depth of pushcli nesting.
+  int intena;                 // Were interrupts enabled before pushcli? 
 };
 
 extern struct cpu cpus[NCPU];
diff --git a/spinlock.c b/spinlock.c
index bf02292..a1aa37d 100644
--- a/spinlock.c
+++ b/spinlock.c
@@ -88,15 +88,19 @@ holding(struct spinlock *lock)
 }
 
 
-
-// XXX!
-// Better names?  Better functions?  
+// Pushcli/popcli are like cli/sti except that they are matched:
+// it takes two popcli to undo two pushcli.  Also, if interrupts
+// are off, then pushcli, popcli leaves them off.
 
 void
 pushcli(void)
 {
+  int eflags;
+  
+  eflags = read_eflags();
   cli();
-  cpus[cpu()].ncli++;
+  if(cpus[cpu()].ncli++ == 0)
+    cpus[cpu()].intena = eflags & FL_IF;
 }
 
 void
@@ -106,7 +110,7 @@ popcli(void)
     panic("popcli - interruptible");
   if(--cpus[cpu()].ncli < 0)
     panic("popcli");
-  if(cpus[cpu()].ncli == 0)
+  if(cpus[cpu()].ncli == 0 && cpus[cpu()].intena)
     sti();
 }
 
diff --git a/trap.c b/trap.c
index 0acc94b..e38cd00 100644
--- a/trap.c
+++ b/trap.c
@@ -44,9 +44,6 @@ trap(struct trapframe *tf)
     return;
   }
 
-  // No interrupts during interrupt handling.
-  pushcli();
-
   switch(tf->trapno){
   case IRQ_OFFSET + IRQ_TIMER:
     if(cpu() == 0){
@@ -84,8 +81,6 @@ trap(struct trapframe *tf)
     cp->killed = 1;
   }
 
-  popcli();
-
   // 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 
   // until it gets to the regular system call return.)