diff --git a/defs.h b/defs.h index 5e049ae..c4870d0 100644 --- a/defs.h +++ b/defs.h @@ -108,6 +108,7 @@ void exit(void); int fork(void); int growproc(int); int kill(int); +struct cpu* mycpu(void); struct proc* myproc(); void pinit(void); void procdump(void); diff --git a/lapic.c b/lapic.c index 9039665..9a12f17 100644 --- a/lapic.c +++ b/lapic.c @@ -98,22 +98,12 @@ lapicinit(void) lapicw(TPR, 0); } +// Should be called with interrupts disabled: the calling thread shouldn't be +// rescheduled between reading lapic[ID] and checking against cpu array. int lapiccpunum(void) { int apicid, i; - - // Cannot call cpunum when interrupts are enabled: - // result not guaranteed to last long enough to be used! - // Would prefer to panic but even printing is chancy here: - // almost everything, including cprintf and panic, calls cpu, - // often indirectly through acquire and release. - if(readeflags()&FL_IF){ - static int n; - if(n++ == 0) - cprintf("cpunum called from %x with interrupts enabled\n", - __builtin_return_address(0)); - } if (!lapic) return 0; diff --git a/main.c b/main.c index d7e59cf..e5b7d64 100644 --- a/main.c +++ b/main.c @@ -53,7 +53,7 @@ mpenter(void) static void mpmain(void) { - cprintf("cpu%d: starting %d\n", cpuid(), lapiccpunum()); + cprintf("cpu%d: starting %d\n", cpuid(), cpuid()); idtinit(); // load idt register xchg(&(mycpu()->started), 1); // tell startothers() we're up scheduler(); // start running processes diff --git a/mmu.h b/mmu.h index e732ccd..a1afa9f 100644 --- a/mmu.h +++ b/mmu.h @@ -42,13 +42,12 @@ // various segment selectors. #define SEG_KCODE 1 // kernel code #define SEG_KDATA 2 // kernel data+stack -#define SEG_KCPU 3 // kernel per-cpu data -#define SEG_UCODE 4 // user code -#define SEG_UDATA 5 // user data+stack -#define SEG_TSS 6 // this process's task state +#define SEG_UCODE 3 // user code +#define SEG_UDATA 4 // user data+stack +#define SEG_TSS 5 // this process's task state // cpu->gdt[NSEGS] holds the above segments. -#define NSEGS 7 +#define NSEGS 6 //PAGEBREAK! #ifndef __ASSEMBLER__ diff --git a/proc.c b/proc.c index 4e8f461..6445725 100644 --- a/proc.c +++ b/proc.c @@ -26,12 +26,29 @@ pinit(void) initlock(&ptable.lock, "ptable"); } -// XXX get rid off? +// Must be called with interrupts disabled int cpuid() { return mycpu()-cpus; } +// Must be called with interrupts disabled +struct cpu* +mycpu(void) +{ + // Would prefer to panic but even printing is chancy here: almost everything, + // including cprintf and panic, calls mycpu(), often indirectly through + // acquire and release. + if(readeflags()&FL_IF){ + static int n; + if(n++ == 0) + cprintf("mycpu called from %x with interrupts enabled\n", + __builtin_return_address(0)); + } + + return &cpus[lapiccpunum()]; +} + // Disable interrupts so that we are not rescheduled // while reading proc from the cpu structure struct proc* @@ -304,7 +321,8 @@ scheduler(void) { struct proc *p; struct cpu *c = mycpu(); - + c->proc = 0; + for(;;){ // Enable interrupts on this processor. sti(); @@ -321,15 +339,13 @@ scheduler(void) c->proc = p; switchuvm(p); p->state = RUNNING; - p->cpu = c; - // cprintf("%d: switch to %d\n", c-cpus, p->pid); - swtch(&(p->cpu->scheduler), p->context); + + swtch(&(c->scheduler), p->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. c->proc = 0; - p->cpu = 0; } release(&ptable.lock); @@ -358,9 +374,7 @@ sched(void) if(readeflags()&FL_IF) panic("sched interruptible"); intena = mycpu()->intena; - // cprintf("%d: before swtch %d %x\n", p->cpu-cpus, p->pid, * (int *) 0x1d); - swtch(&p->context, p->cpu->scheduler); - // cprintf("%d/%d: after swtch %d %x\n", cpuid(), p->cpu-cpus, p->pid, * (int *) 0x1d); + swtch(&p->context, mycpu()->scheduler); mycpu()->intena = intena; } @@ -422,8 +436,6 @@ sleep(void *chan, struct spinlock *lk) p->chan = chan; p->state = SLEEPING; - // cprintf("sleep %d\n", p->pid); - sched(); // Tidy up. diff --git a/proc.h b/proc.h index 7047d54..1647114 100644 --- a/proc.h +++ b/proc.h @@ -7,39 +7,12 @@ struct cpu { volatile uint started; // Has the CPU started? int ncli; // Depth of pushcli nesting. int intena; // Were interrupts enabled before pushcli? - // Per-CPU variables, holding pointers to the current cpu and to the current - // process (see cpu() and proc() in proc.c) - struct cpu *cpu; // On cpu 0, cpu = &cpus[0]; on cpu 1, cpu=&cpus[1], etc. - struct proc *proc; // The currently-running process on this cpu + struct proc *proc; // The process running on this cpu or null }; extern struct cpu cpus[NCPU]; extern int ncpu; -// The asm suffix tells gcc to use "%gs:0" to refer to cpu -// and "%gs:4" to refer to proc. seginit sets up the -// %gs segment register so that %gs refers to the memory -// holding those two variables in the local cpu's struct cpu. -// This is similar to how thread-local variables are implemented -// in thread libraries such as Linux pthreads. - -static inline struct cpu* -mycpu(void) { - struct cpu *cpu; - asm("movl %%gs:0, %0" : "=r"(cpu)); - return cpu; -} - -#if 0 -static inline struct proc* -myproc(void) { - struct proc *proc; - asm("movl %%gs:4, %0" : "=r"(proc)); - return proc; -} -#endif - - //PAGEBREAK: 17 // Saved registers for kernel context switches. // Don't need to save all the segment registers (%cs, etc), @@ -76,7 +49,6 @@ struct proc { struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) - struct cpu *cpu; // If running, which cpu. }; // Process memory is laid out contiguously, low addresses first: diff --git a/trapasm.S b/trapasm.S index 787727f..2271d27 100644 --- a/trapasm.S +++ b/trapasm.S @@ -14,9 +14,6 @@ alltraps: movw $(SEG_KDATA<<3), %ax movw %ax, %ds movw %ax, %es - movw $(SEG_KCPU<<3), %ax - movw %ax, %fs - movw %ax, %gs # Call trap(tf), where tf=%esp pushl %esp diff --git a/vm.c b/vm.c index d1640e8..9ac7401 100644 --- a/vm.c +++ b/vm.c @@ -21,17 +21,12 @@ seginit(void) // Cannot share a CODE descriptor for both kernel and user // because it would have to have DPL_USR, but the CPU forbids // an interrupt from CPL=0 to DPL=3. - c = &cpus[lapiccpunum()]; + c = &cpus[cpuid()]; c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0); c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, DPL_USER); c->gdt[SEG_UDATA] = SEG(STA_W, 0, 0xffffffff, DPL_USER); - c->cpu = c; - c->proc = 0; - // Map cpu and proc -- these are private per cpu. - c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 4, 0); lgdt(c->gdt, sizeof(c->gdt)); - loadgs(SEG_KCPU << 3); } // Return the address of the PTE in page table pgdir