change some comments, maybe more informative

delete most comments from bootother.S (since copy of bootasm.S)
ksegment() -> seginit()
move more stuff from main() to mainc()
This commit is contained in:
Robert Morris 2010-09-13 15:34:44 -04:00
parent 124fe7e457
commit faad047ab2
8 changed files with 70 additions and 66 deletions

View file

@ -13,7 +13,7 @@
.code16 # Assemble for 16-bit mode .code16 # Assemble for 16-bit mode
.globl start .globl start
start: start:
cli # Disable interrupts cli # BIOS enabled interrupts ; disable
# Set up the important data segment registers (DS, ES, SS). # Set up the important data segment registers (DS, ES, SS).
xorw %ax,%ax # Segment number zero xorw %ax,%ax # Segment number zero
@ -45,7 +45,8 @@ seta20.2:
# Switch from real to protected mode, using a bootstrap GDT # Switch from real to protected mode, using a bootstrap GDT
# and segment translation that makes virtual addresses # and segment translation that makes virtual addresses
# identical to physical addresses, so that the # identical to physical addresses, so that the
# effective memory map does not change during the switch. # effective memory map does not change after subsequent
# loads of segment registers.
lgdt gdtdesc lgdt gdtdesc
movl %cr0, %eax movl %cr0, %eax
orl $CR0_PE, %eax orl $CR0_PE, %eax
@ -57,7 +58,11 @@ seta20.2:
# default to 32 bits after this jump. # default to 32 bits after this jump.
ljmp $(SEG_KCODE<<3), $start32 ljmp $(SEG_KCODE<<3), $start32
.code32 # Assemble for 32-bit mode # tell the assembler to generate 0x66 prefixes for 16-bit
# instructions like movw, and to generate 32-bit immediate
# addresses.
.code32
start32: start32:
# Set up the protected-mode data segment registers # Set up the protected-mode data segment registers
movw $(SEG_KDATA<<3), %ax # Our data segment selector movw $(SEG_KDATA<<3), %ax # Our data segment selector

View file

@ -9,80 +9,69 @@
# Because this code sets DS to zero, it must sit # Because this code sets DS to zero, it must sit
# at an address in the low 2^16 bytes. # at an address in the low 2^16 bytes.
# #
# Bootothers (in main.c) sends the STARTUPs, one at a time. # Bootothers (in main.c) sends the STARTUPs one at a time.
# It puts this code (start) at 0x7000. # It copies this code (start) at 0x7000.
# It puts the correct %esp in start-4, # It puts the address of a newly allocated per-core stack in start-4,
# and the place to jump to in start-8. # and the address of the place to jump to (mpmain) in start-8.
# #
# This code is identical to bootasm.S except: # This code is identical to bootasm.S except:
# - it does not need to enable A20 # - it does not need to enable A20
# - it uses the address at start-4 for the %esp # - it uses the address at start-4 for the %esp
# - it jumps to the address at start-8 instead of calling bootmain # - it jumps to the address at start-8 instead of calling bootmain
#define SEG_KCODE 1 // kernel code #define SEG_KCODE 1
#define SEG_KDATA 2 // kernel data+stack #define SEG_KDATA 2
#define CR0_PE 1 // protected mode enable bit #define CR0_PE 1
.code16 # Assemble for 16-bit mode .code16
.globl start .globl start
start: start:
cli # Disable interrupts cli
# Set up the important data segment registers (DS, ES, SS). xorw %ax,%ax
xorw %ax,%ax # Segment number zero movw %ax,%ds
movw %ax,%ds # -> Data Segment movw %ax,%es
movw %ax,%es # -> Extra Segment movw %ax,%ss
movw %ax,%ss # -> Stack Segment
//PAGEBREAK! //PAGEBREAK!
# Switch from real to protected mode, using a bootstrap GDT
# and segment translation that makes virtual addresses
# identical to physical addresses, so that the
# effective memory map does not change during the switch.
lgdt gdtdesc lgdt gdtdesc
movl %cr0, %eax movl %cr0, %eax
orl $CR0_PE, %eax orl $CR0_PE, %eax
movl %eax, %cr0 movl %eax, %cr0
# 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 ljmp $(SEG_KCODE<<3), $start32
.code32 # Assemble for 32-bit mode .code32
start32: start32:
# Set up the protected-mode data segment registers movw $(SEG_KDATA<<3), %ax
movw $(SEG_KDATA<<3), %ax # Our data segment selector movw %ax, %ds
movw %ax, %ds # -> DS: Data Segment movw %ax, %es
movw %ax, %es # -> ES: Extra Segment movw %ax, %ss
movw %ax, %ss # -> SS: Stack Segment movw $0, %ax
movw $0, %ax # Zero segments not ready for use movw %ax, %fs
movw %ax, %fs # -> FS movw %ax, %gs
movw %ax, %gs # -> GS
# Set up the stack pointer and call into C. # switch to the stack allocated by bootothers()
movl start-4, %esp movl start-4, %esp
# call mpmain()
call *(start-8) call *(start-8)
# If the call returns (it shouldn't), trigger a Bochs movw $0x8a00, %ax
# breakpoint if running under Bochs, then loop.
movw $0x8a00, %ax # 0x8a00 -> port 0x8a00
movw %ax, %dx movw %ax, %dx
outw %ax, %dx outw %ax, %dx
movw $0x8ae0, %ax # 0x8ae0 -> port 0x8a00 movw $0x8ae0, %ax
outw %ax, %dx outw %ax, %dx
spin: spin:
jmp spin jmp spin
# Bootstrap GDT .p2align 2
.p2align 2 # force 4 byte alignment
gdt: gdt:
SEG_NULLASM # null seg SEG_NULLASM
SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)
SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg SEG_ASM(STA_W, 0x0, 0xffffffff)
gdtdesc: gdtdesc:
.word (gdtdesc - gdt - 1) # sizeof(gdt) - 1 .word (gdtdesc - gdt - 1)
.long gdt # address gdt .long gdt

2
defs.h
View file

@ -152,7 +152,7 @@ void uartintr(void);
void uartputc(int); void uartputc(int);
// vm.c // vm.c
void ksegment(void); void seginit(void);
void kvmalloc(void); void kvmalloc(void);
void vmenable(void); void vmenable(void);
pde_t* setupkvm(void); pde_t* setupkvm(void);

24
main.c
View file

@ -11,16 +11,14 @@ void jkstack(void) __attribute__((noreturn));
void mainc(void); void mainc(void);
// Bootstrap processor starts running C code here. // Bootstrap processor starts running C code here.
// Allocate a real stack and switch to it, first
// doing some setup required for memory allocator to work.
int int
main(void) main(void)
{ {
mpinit(); // collect info about this machine mpinit(); // collect info about this machine
lapicinit(mpbcpu()); lapicinit(mpbcpu());
ksegment(); // set up segments seginit(); // set up segments
picinit(); // interrupt controller
ioapicinit(); // another interrupt controller
consoleinit(); // I/O devices & their interrupts
uartinit(); // serial port
kinit(); // initialize memory allocator kinit(); // initialize memory allocator
jkstack(); // call mainc() on a properly-allocated stack jkstack(); // call mainc() on a properly-allocated stack
} }
@ -37,10 +35,16 @@ jkstack(void)
panic("jkstack"); panic("jkstack");
} }
// Set up hardware and software.
// Runs only on the boostrap processor.
void void
mainc(void) mainc(void)
{ {
cprintf("\ncpu%d: starting xv6\n\n", cpu->id); cprintf("\ncpu%d: starting xv6\n\n", cpu->id);
picinit(); // interrupt controller
ioapicinit(); // another interrupt controller
consoleinit(); // I/O devices & their interrupts
uartinit(); // serial port
kvmalloc(); // initialize the kernel page table kvmalloc(); // initialize the kernel page table
pinit(); // process table pinit(); // process table
tvinit(); // trap vectors tvinit(); // trap vectors
@ -64,16 +68,17 @@ static void
mpmain(void) mpmain(void)
{ {
if(cpunum() != mpbcpu()) { if(cpunum() != mpbcpu()) {
ksegment(); seginit();
lapicinit(cpunum()); lapicinit(cpunum());
} }
vmenable(); // turn on paging vmenable(); // turn on paging
cprintf("cpu%d: starting\n", cpu->id); cprintf("cpu%d: starting\n", cpu->id);
idtinit(); // load idt register idtinit(); // load idt register
xchg(&cpu->booted, 1); xchg(&cpu->booted, 1); // tell bootothers() we're up
scheduler(); // start running processes scheduler(); // start running processes
} }
// Start the non-boot processors.
static void static void
bootothers(void) bootothers(void)
{ {
@ -91,10 +96,13 @@ bootothers(void)
if(c == cpus+cpunum()) // We've started already. if(c == cpus+cpunum()) // We've started already.
continue; continue;
// Fill in %esp, %eip and start code on cpu. // Tell bootother.S what stack to use and the address of mpmain;
// it expects to find these two addresses stored just before
// its first instruction.
stack = kalloc(); stack = kalloc();
*(void**)(code-4) = stack + KSTACKSIZE; *(void**)(code-4) = stack + KSTACKSIZE;
*(void**)(code-8) = mpmain; *(void**)(code-8) = mpmain;
lapicstartap(c->id, (uint)code); lapicstartap(c->id, (uint)code);
// Wait for cpu to finish mpmain() // Wait for cpu to finish mpmain()

6
proc.c
View file

@ -65,7 +65,8 @@ procdump(void)
//PAGEBREAK: 32 //PAGEBREAK: 32
// Look in the process table for an UNUSED proc. // Look in the process table for an UNUSED proc.
// If found, change state to EMBRYO and return it. // If found, change state to EMBRYO and initialize
// state required to run in the kernel.
// Otherwise return 0. // Otherwise return 0.
static struct proc* static struct proc*
allocproc(void) allocproc(void)
@ -97,7 +98,7 @@ found:
p->tf = (struct trapframe*)sp; p->tf = (struct trapframe*)sp;
// Set up new context to start executing at forkret, // Set up new context to start executing at forkret,
// which returns to trapret (see below). // which returns to trapret.
sp -= 4; sp -= 4;
*(uint*)sp = (uint)trapret; *(uint*)sp = (uint)trapret;
@ -105,6 +106,7 @@ found:
p->context = (struct context*)sp; p->context = (struct context*)sp;
memset(p->context, 0, sizeof *p->context); memset(p->context, 0, sizeof *p->context);
p->context->eip = (uint)forkret; p->context->eip = (uint)forkret;
return p; return p;
} }

14
proc.h
View file

@ -11,7 +11,7 @@
// Per-CPU state // Per-CPU state
struct cpu { struct cpu {
uchar id; // Local APIC ID; index into cpus[] below uchar id; // Local APIC ID; index into cpus[] below
struct context *scheduler; // Switch here to enter scheduler struct context *scheduler; // swtch() here to enter scheduler
struct taskstate ts; // Used by x86 to find stack for interrupt struct taskstate ts; // Used by x86 to find stack for interrupt
struct segdesc gdt[NSEGS]; // x86 global descriptor table struct segdesc gdt[NSEGS]; // x86 global descriptor table
volatile uint booted; // Has the CPU started? volatile uint booted; // Has the CPU started?
@ -20,7 +20,7 @@ struct cpu {
// Cpu-local storage variables; see below // Cpu-local storage variables; see below
struct cpu *cpu; struct cpu *cpu;
struct proc *proc; struct proc *proc; // The currently-running process.
}; };
extern struct cpu cpus[NCPU]; extern struct cpu cpus[NCPU];
@ -29,13 +29,13 @@ extern int ncpu;
// Per-CPU variables, holding pointers to the // Per-CPU variables, holding pointers to the
// current cpu and to the current process. // current cpu and to the current process.
// The asm suffix tells gcc to use "%gs:0" to refer to cpu // The asm suffix tells gcc to use "%gs:0" to refer to cpu
// and "%gs:4" to refer to proc. ksegment sets up the // and "%gs:4" to refer to proc. seginit sets up the
// %gs segment register so that %gs refers to the memory // %gs segment register so that %gs refers to the memory
// holding those two variables in the local cpu's struct cpu. // holding those two variables in the local cpu's struct cpu.
// This is similar to how thread-local variables are implemented // This is similar to how thread-local variables are implemented
// in thread libraries such as Linux pthreads. // in thread libraries such as Linux pthreads.
extern struct cpu *cpu asm("%gs:0"); // This cpu. extern struct cpu *cpu asm("%gs:0"); // &cpus[cpunum()]
extern struct proc *proc asm("%gs:4"); // Current proc on this cpu. extern struct proc *proc asm("%gs:4"); // cpus[cpunum()].proc
//PAGEBREAK: 17 //PAGEBREAK: 17
// Saved registers for kernel context switches. // Saved registers for kernel context switches.
@ -61,13 +61,13 @@ enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
// Per-process state // Per-process state
struct proc { struct proc {
uint sz; // Size of process memory (bytes) uint sz; // Size of process memory (bytes)
pde_t* pgdir; // Linear address of proc's pgdir pde_t* pgdir; // Page table
char *kstack; // Bottom of kernel stack for this process char *kstack; // Bottom of kernel stack for this process
enum procstate state; // Process state enum procstate state; // Process state
volatile int pid; // Process ID volatile int pid; // Process ID
struct proc *parent; // Parent process struct proc *parent; // Parent process
struct trapframe *tf; // Trap frame for current syscall struct trapframe *tf; // Trap frame for current syscall
struct context *context; // Switch here to run process struct context *context; // swtch() here to run process
void *chan; // If non-zero, sleeping on chan void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files struct file *ofile[NOFILE]; // Open files

View file

@ -23,7 +23,7 @@ initlock(struct spinlock *lk, char *name)
void void
acquire(struct spinlock *lk) acquire(struct spinlock *lk)
{ {
pushcli(); pushcli(); // disable interrupts to avoid deadlock.
if(holding(lk)) if(holding(lk))
panic("acquire"); panic("acquire");

2
vm.c
View file

@ -13,7 +13,7 @@ static pde_t *kpgdir; // for use in scheduler()
// Set up CPU's kernel segment descriptors. // Set up CPU's kernel segment descriptors.
// Run once at boot time on each CPU. // Run once at boot time on each CPU.
void void
ksegment(void) seginit(void)
{ {
struct cpu *c; struct cpu *c;