diff options
author | Frans Kaashoek <[email protected]> | 2017-02-01 18:04:13 -0500 |
---|---|---|
committer | Frans Kaashoek <[email protected]> | 2017-02-01 18:04:13 -0500 |
commit | ed396c068b881877330f7d40bfce02db9b1199b3 (patch) | |
tree | 69103a78128b46d6bae179b0440cca0a9c7f0b0c | |
parent | fbb4c0944422f860484142010bb9f366f3e87bf8 (diff) | |
download | xv6-labs-ed396c068b881877330f7d40bfce02db9b1199b3.tar.gz xv6-labs-ed396c068b881877330f7d40bfce02db9b1199b3.tar.bz2 xv6-labs-ed396c068b881877330f7d40bfce02db9b1199b3.zip |
Eliminate code for gs trick to track per-cpu state. We rely on lapiccpunum()
to find a per-cpu id with which we locate a cpu's cpu struct.
-rw-r--r-- | defs.h | 1 | ||||
-rw-r--r-- | lapic.c | 14 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | mmu.h | 9 | ||||
-rw-r--r-- | proc.c | 34 | ||||
-rw-r--r-- | proc.h | 30 | ||||
-rw-r--r-- | trapasm.S | 3 | ||||
-rw-r--r-- | vm.c | 7 |
8 files changed, 33 insertions, 67 deletions
@@ -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); @@ -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; @@ -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 @@ -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__ @@ -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. @@ -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: @@ -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 @@ -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 |