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
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)
setupsegs(0);
cpuid(0, 0, 0, 0, 0); // memory barrier
cpus[cpu()].booted = 1;
- popcli();
scheduler();
}
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;
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);
}
// Return currently running process.
-// XXX comment better
struct proc*
curproc(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)
c->curproc = 0;
setupsegs(0);
}
-
release(&proc_table_lock);
+
}
}
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];
}
-
-// 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
panic("popcli - interruptible");
if(--cpus[cpu()].ncli < 0)
panic("popcli");
- if(cpus[cpu()].ncli == 0)
+ if(cpus[cpu()].ncli == 0 && cpus[cpu()].intena)
sti();
}
return;
}
- // No interrupts during interrupt handling.
- pushcli();
-
switch(tf->trapno){
case IRQ_OFFSET + IRQ_TIMER:
if(cpu() == 0){
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.)