add some comments
find out the hard way why user and kernel must have separate segment descriptors
This commit is contained in:
		
							parent
							
								
									c99599784e
								
							
						
					
					
						commit
						1afc9d3fca
					
				
					 6 changed files with 30 additions and 19 deletions
				
			
		
							
								
								
									
										2
									
								
								asm.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								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)),         \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								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)
 | 
			
		||||
      ;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								proc.h
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue