- boot 用于在架点的时候把 head 中的内核代码加载到内存某个指定位置,在设置好 GDT 表等信息之后,把处理器设置成运行在保护模式下,然后跳转到 head 代码处运行
- 首先利用 ROM 的 BIOS 中断 int 0x13 把软盘中的 head 代码读入到内存 0x10000,然后再把这段代码移动到内存 0 开始,最后设置设置控制寄存器 CR0 中的开启保护运行模式标志,并跳转到内存 0 处开始执行 head 代码
- 为什么不直接移动到 0 呢,因为在这里存放 BIOS 的中断过程,移动到时候本身就要用到
- head 实现两个运行在 r3 的任务在始终控制下的相互切花运行,并且实现了在屏幕上显示字符的系统调用
PC 机在加电启动的时候,会把启动盘第一个扇区加载到物理内存 0x7c00 位置开始处,并把执行权转移到 0x7c00 处开始执行
这是 head 的空间布局(以段表为中心)
这是内存视图
BOOTSEG=0x07c0
SYSSEG=0x1000
SYSLEN=17
entry start
start:
jmpi go,#BOOTSEG
go: mov ax,cs
mov ds,ax
mov ss,ax
mov sp,#0x400
load_system:
mov dx,#0x0000
mov cx,#0x0002
mov ax,#SYSSEG
mov es,ax
xor bx,bx
mov ax,#0x200+SYSLEN
int 0x13 ! 利用BIOS中断从启动盘读取head代码 ES:BX 读入缓冲区位置 AH 读扇区功能号 AL 读的扇区数
jnc ok_load
die:jmp die
! move kernel code to 0x0
ok_load:
cli
mov ax,#SYSSEG
mov ds,ax
xor ax,ax
mov es,ax
mov cx,#0x1000
sub si,si
sub di,di
mov cx,#0x1000
rep
movw
mov ax,#BOOTSEG
mov ds,ax
lidt idt_48 ! load IDTR
lgdt gdt_48 ! load GDTR
mov ax,#0x0001
lmsw ax
jmpi 0,8
gdt:
.word 0,0,0,0
.word 0x07ff
.word 0x0000
.word 0x9a00
.word 0x00c0
.word 0x07ff
.word 0x0000
.word 0x9200
.word 0x00c0
idt_48:
.word 0
.word 0,0
gdt_48:
.word 0x7ff
.word 0x7c00+gdt,0
.org 510
.word 0xaa55
LATCH=11930
SCRN_SEL=0x18
TSS0_SEL=0x20
LDT0_SEL=0x28
TSS1_SEL=0x30
LDT1_SEL=0x38
.text
startup_32:
# load segment register
movl $0x10,%eax
mov %ax,%ds
lss init_stack,%esp # loads a far pointer (segment selector and offset)
# load idt & gdt
call setup_idt
call setup_gdt
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
lss init_stack,%esp
# set 8253 timer: int per 10ms
movb $0x36,%al
movl $0x43,%edx
outb %al,%dx
movl $LATCH,%eax
movl $0x40,%edx
outb %al,%dx
movb %ah,%al
outb %al,%dx
# set int (8) gate (128) in idt
movl $0x00080000,%eax # 高字节是内核代码段选择符
movw $timer_interrupt,%ax # 中断描述符
movw $0x8e00,%dx # 中断门类型 r0
movl $0x08,%ecx
lea idt(,%ecx,8),%esi
movl %eax,(%esi)
movl %edx,4(%esi)
movw $system_interrupt,%ax # 陷阱门描述符
movw $0xef00,%dx # 陷阱门类型 r3
movl $0x80,%ecx
lea idt(,%ecx,8),%esi
movl %eax,(%esi)
movl %edx,4(%esi)
# 在堆栈中人工建立中断返回时的场景
pushfl # push the entire 32-bit EFLAGS register onto the stack
andl $0xffffbfff,(%esp)
popfl
movl $TSS0_SEL,%eax
ltr %ax
movl $LDT0_SEL,%eax
lldt %ax
movl $0,current # ?
sti
pushl $0x17
pushl $init_stack
pushfl
pushl $0x0f
pushl $task0
iret
setup_gdt:
lgdt lgdt_opcode
ret
# 设置idt中所有 256 个中断门描述符都为同一个 ingore_int
setup_idt:
lea ignore_int,%edx
movl $0x00080000,%eax
movw %dx,%ax
movw $0x8e00,%dx
lea idt,%edi
mov $256,%ecx
rp_idt:
movl %eax,(%edi)
movl %edx,4(%edi)
addl $8,%edi
dec %ecx
jne rp_idt
lidt lidt_opcode
ret
write_char:
push %gs
pushl %ebx
mov $SCRN_SEL,%ebx
mov %bx,%gs
movl src_loc,%bx
shl $1,%ebx
movb %al,%gs:(%ebx)
shr $1,%ebx
incl %ebx
cmpl $2000,%ebx
jb 1f
movl $0,%ebx
1: movl %ebx,src_loc
popl %ebx
pop %gs
ret
# 注册三个中断处理程序
.align 2
ignore_int:
push %ds
pushl %eax
movl $0x10,%eax
mov %ax,%ds
movl $67,%eax
call write_char
popl %eax
pop %ds
iret
# 计时器中断处理函数
.align 2
timer_interrupt:
push %ds
pushl %eax
movl $0x10,%eax
mov %ax,%ds
movb $0x20,%al
outb %al,$0x20 # 开硬件中断
movl $1,%eax
cmpl %eax,current # 判断当前任务
je 1f
movl %eax,current
ljmp $TSS1_SEL,$0
jmp 2f
1: movl $0,current
ljmp $TSS0_SEL,$0
2: popl %eax
pop %ds
iret
.align 2
system_interrupt:
push %ds
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
movl $0x10,%edx
mov %dx,%ds
call write_char
popl %eax
popl %ebx
popl %ecx
popl %edx
pop %ds
iret
/* data */
current: .long 0
src_loc: .long 0
.align 2
lidt_opcode:.word 256*8-1
.long idt
lgdt_opcode:.word (end_gdt-gdt)-1
.long gdt
.align 3
idt: .fill 256,8,0
gdt: .quad 0x0000000000000000
.quad 0x00c09a00000007ff
.quad 0x00c09200000007ff
.quad 0x00c0920b80000002
.word 0x68,tss0,0xe900,0x0
.word 0x40,ldt0,0xe200,0x0
.word 0x68,tss1,0xe900,0x0
.word 0x40,ldt1,0xe200,0x0
end_gdt: .fill 128,4,0
init_stack: .long init_stack
.word 0x10
.align 3
ldt0: .quad 0x0000000000000000
.quad 0x00c0fa00000003ff
.quad 0x00c00f20000003ff
tss0: .long 0
.long krn_stk0,0x10
.long 0,0,0,0,0
.long 0,0,0,0,0
.long 0,0,0,0,0
.long 0,0,0,0,0,0
.long LDT0_SEL,0x08000000
# 内核栈
.fill 128,4,0
krn_stk0:
.align 3
ldt1: .quad 0x0000000000000000
.quad 0x00c0fa00000003ff
.quad 0x00c00f20000003ff
tss1: .long 0
.long krn_stk1,0x10
.long 0,0,0,0,0
.long task1,0x200
.long 0,0,0,0
.long usr_stk1,0,0,0
.long 0x17,0x07,0x17,0x17,0x17,0x17
.long LDT1_SEL,0x08000000
# 内核栈
.fill 128,4,0
krn_stk1:
task0:
movl $0x17,%eax
movw %ax,%ds
movl $65,%al # 'A'
int $0x80
movl $0xfff,%ecx
1: loop 1b
jmp task0
task1:
movl $66,%al # 'B'
int $0x80
movl $0xfff,%ecx
1: loop 1b
jmp task1
# 用户栈
.fill 128,4,0
usr_stk1: