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.
This commit is contained in:
parent
fbb4c09444
commit
ed396c068b
1
defs.h
1
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);
|
||||
|
|
14
lapic.c
14
lapic.c
|
@ -98,23 +98,13 @@ 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;
|
||||
|
||||
|
|
2
main.c
2
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
|
||||
|
|
9
mmu.h
9
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__
|
||||
|
|
32
proc.c
32
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,6 +321,7 @@ scheduler(void)
|
|||
{
|
||||
struct proc *p;
|
||||
struct cpu *c = mycpu();
|
||||
c->proc = 0;
|
||||
|
||||
for(;;){
|
||||
// Enable interrupts on this processor.
|
||||
|
@ -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.
|
||||
|
|
30
proc.h
30
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:
|
||||
|
|
|
@ -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
|
||||
|
|
7
vm.c
7
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
|
||||
|
|
Loading…
Reference in a new issue