From 1afc9d3fcaa7c5992659bb8b69f639b746dda2bc Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Thu, 5 Aug 2010 21:16:55 -0400 Subject: [PATCH] add some comments find out the hard way why user and kernel must have separate segment descriptors --- asm.h | 2 ++ bootasm.S | 6 ++++-- bootother.S | 6 ++++-- main.c | 22 ++++++++++++---------- proc.h | 4 ++-- vm.c | 9 ++++++--- 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/asm.h b/asm.h index 0c052db..68210d7 100644 --- a/asm.h +++ b/asm.h @@ -6,6 +6,8 @@ .word 0, 0; \ .byte 0, 0, 0, 0 +// The 0xC0 means the limit is in 4096-byte units +// and (for executable segments) 32-bit mode. #define SEG_ASM(type,base,lim) \ .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ diff --git a/bootasm.S b/bootasm.S index f6af255..56175ce 100644 --- a/bootasm.S +++ b/bootasm.S @@ -51,8 +51,10 @@ seta20.2: orl $CR0_PE, %eax movl %eax, %cr0 - # Jump to next instruction, but in 32-bit code segment. - # Switches processor into 32-bit mode. + # This ljmp is how you load the CS (Code Segment) register. + # SEG_ASM produces segment descriptors with the 32-bit mode + # flag set (the D flag), so addresses and word operands will + # default to 32 bits after this jump. ljmp $(SEG_KCODE<<3), $start32 .code32 # Assemble for 32-bit mode diff --git a/bootother.S b/bootother.S index 11d32f1..899669a 100644 --- a/bootother.S +++ b/bootother.S @@ -45,8 +45,10 @@ start: orl $CR0_PE, %eax movl %eax, %cr0 - # Jump to next instruction, but in 32-bit code segment. - # Switches processor into 32-bit mode. + # This ljmp is how you load the CS (Code Segment) register. + # SEG_ASM produces segment descriptors with the 32-bit mode + # flag set (the D flag), so addresses and word operands will + # default to 32 bits after this jump. ljmp $(SEG_KCODE<<3), $start32 .code32 # Assemble for 32-bit mode diff --git a/main.c b/main.c index 8be66e3..a6088cb 100644 --- a/main.c +++ b/main.c @@ -16,13 +16,13 @@ main(void) { mpinit(); // collect info about this machine lapicinit(mpbcpu()); - ksegment(); + ksegment(); // set up segments picinit(); // interrupt controller ioapicinit(); // another interrupt controller consoleinit(); // I/O devices & their interrupts uartinit(); // serial port - pminit(); // physical memory for kernel - jkstack(); // Jump to mainc on a properly-allocated stack + pminit(); // discover how much memory there is + jkstack(); // call mainc() on a properly-allocated stack } void @@ -41,7 +41,7 @@ void mainc(void) { cprintf("\ncpu%d: starting xv6\n\n", cpu->id); - kvmalloc(); // allocate the kernel page table + kvmalloc(); // initialze the kernel page table pinit(); // process table tvinit(); // trap vectors binit(); // buffer cache @@ -57,8 +57,9 @@ mainc(void) mpmain(); } -// Bootstrap processor gets here after setting up the hardware. -// Additional processors start here. +// Common CPU setup code. +// Bootstrap CPU comes here from mainc(). +// Other CPUs jump here from bootother.S. static void mpmain(void) { @@ -66,11 +67,11 @@ mpmain(void) ksegment(); lapicinit(cpunum()); } - vminit(); // Run with paging on each processor + vminit(); // turn on paging cprintf("cpu%d: starting\n", cpu->id); - idtinit(); + idtinit(); // load idt register xchg(&cpu->booted, 1); - scheduler(); + scheduler(); // start running processes } static void @@ -85,6 +86,7 @@ bootothers(void) // placed the start of bootother.S there. code = (uchar *) 0x7000; memmove(code, _binary_bootother_start, (uint)_binary_bootother_size); + for(c = cpus; c < cpus+ncpu; c++){ if(c == cpus+cpunum()) // We've started already. continue; @@ -95,7 +97,7 @@ bootothers(void) *(void**)(code-8) = mpmain; lapicstartap(c->id, (uint)code); - // Wait for cpu to get through bootstrap. + // Wait for cpu to finish mpmain() while(c->booted == 0) ; } diff --git a/proc.h b/proc.h index ebc42f1..5e5d031 100644 --- a/proc.h +++ b/proc.h @@ -3,8 +3,8 @@ #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 -#define SEG_UDATA 5 +#define SEG_UCODE 4 // user code +#define SEG_UDATA 5 // user data+stack #define SEG_TSS 6 // this process's task state #define NSEGS 7 diff --git a/vm.c b/vm.c index c94e9a3..9ea5e92 100644 --- a/vm.c +++ b/vm.c @@ -93,12 +93,15 @@ ksegment(void) { struct cpu *c; - // Map once virtual addresses to linear addresses using identity map + // Map virtual addresses to linear addresses using identity map. + // 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[cpunum()]; 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, 0x0, 0xffffffff, DPL_USER); - c->gdt[SEG_UDATA] = SEG(STA_W, 0x0, 0xffffffff, DPL_USER); + c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, DPL_USER); + c->gdt[SEG_UDATA] = SEG(STA_W, 0, 0xffffffff, DPL_USER); // map cpu, and curproc c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 8, 0);