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:
parent
124fe7e457
commit
faad047ab2
8 changed files with 70 additions and 66 deletions
11
bootasm.S
11
bootasm.S
|
@ -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
|
||||||
|
|
75
bootother.S
75
bootother.S
|
@ -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
2
defs.h
|
@ -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
24
main.c
|
@ -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
6
proc.c
|
@ -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
14
proc.h
|
@ -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
|
||||||
|
|
|
@ -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
2
vm.c
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue