分类: LINUX
2010-10-29 13:26:00
1. 复位硬盘系统:BIOS的int 13中断,分两步完成;
a. 获取磁盘机的类型: AH=15H\DL=0x81;
b. 重置磁盘机系统(复位): AH= 00H\DL = 80;
2. 检查setup.S代码的末尾签名0xAA55和0x5A5A;
0xAA55和0x5A5A是用来确保正确引导setup.s的两个标志!检查setup代码结尾处的标志是否为AA55或5A5A,! 假如是,则跳到good_sig1处;否则,跳到bad_sig处,查找setup.s的剩余部分代码, 并且将其移动到内存中0x1000处。
3. 检查内核是不是大内核,是的话,检查是不是new loader装入,如不是就系统进入死循环。否则,new loader装入;
4. 下面是获取系统的扩展内存情况:
BIOS INT 15中断: AX = E820 获取内存映射,存于E820MAP数组中,位于0x90000:0x2d0-0x600;
AX = E801 获取扩展内存的大小,存于0x90000:2处;
5. 设置键盘的重复速率为最大:(持续按住按键时,若超过设定时间,键盘会自动以一定速率重复该字符)
BIOS INT 16中断: AX = 0X0305即可;
6. 调用video.S设置视频参数,有关显卡编程的,这一块没有怎么看;
7. 把rom bios中硬盘0(第一个硬盘,[4 * 0x41]处)硬盘1(第二个硬盘,[ 4 * 0x46]处)的参数表,分别拷到0x90000:0080H和0x90000:0090H处,大小都是16 bytes。
8. 判断第二块硬盘是否存在,不存在第二个表就清0。
9. 检测微通道总线MAC,检测鼠标器,检测APM BIOS,只要调用相应的BIOS中断就可以了;
10. 下面就要准备进入保护模式了:下面代码执行后地址就编程32位的了
cmpw $0, %cs:realmode_swtch
jz rmodeswtch_normal
lcall %cs:realmode_swtch
jmp rmodeswtch_end
rmodeswtch_normal:
pushw %cs
call default_switch //关中断,包括可屏蔽的和不可屏蔽的中断
11. 测试下loadflags是否为LOADED_HIGH,也就是判断是否为big-kernel,不是就移到0x1000处,是的话就原地不动,
12. 加载IDT,GDT的位置到IDTRY , GDTR:
gdt:
.word 0, 0, 0, 0 # dummy
.word 0, 0, 0, 0 # unused
.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
.word 0 # base address = 0
.word 0x9A00 # code read/exec
.word 0x00CF # granularity = 4096, 386
# (+5th nibble of limit)
.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
.word 0 # base address = 0
.word 0x9200 # data read/write
.word 0x00CF # granularity = 4096, 386
# (+5th nibble of limit)
idt_48:
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
gdt_48:
.word 0x8000 # gdt limit=2048,
# 256 GDT entries
.word 0, 0 # gdt base (filled in later)
lidt idt_48 # load idt with 0,0
xorl %eax, %eax # Compute gdt_base
movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
shll $4, %eax
addl $gdt, %eax
movl %eax, (gdt_48+2)
lgdt gdt_48
这个GDT和head.S中的GDT区别只是物理位置的不一样,setip.S中的早0x90200之后的一段空间,而head.S中的放在1M之后的地方。
这里的IDT都是空的,因为我们关中断了,它暂时用不到。
13. 开启A20地址线:
call empty_8042 //测试8042键盘键盘控制器状态寄存器,只输入缓冲器为空时才能够向里面写数据
movb $0xD1, %al # command write,表示要写数据到8042的P2端口,P2端口就用来选通A20信号,
outb %al, $0x64
call empty_8042
movb $0xDF, %al # 选通A20地址线
outb % al, $0x60
call empty_8042 //再测试输入缓冲器,若为空,表示已经选通。
由于键盘控制器速度比较慢,还有另一种方法选通A20,直接使用I/O 端口0x92, 前提是此端口没有被其他设备使用。
inb $0x92, %al #
orb $02, %al # "fast A20" version
outb %al, $0x92 # some chips have only this
14. 初始化8259控制器:这里只是屏蔽主从片所有的中断请求,其余的初始化在init_IRQ()函数中完成的。
15. 下面正式进入保护模式:将CR0第一位置1,即PE置位。
16. 接下来就跳到head.S中去继续初始化了:
.byte 0x66, 0xea # prefix + jmpi-opcode
code32: .long 0x1000 # will be set to 0x100000
# for big kernels
.word __KERNEL_CS
这里0x66是操作码前缀的意思,使用后可以使得后面的指针变为48位(16位的选择子,32位的偏移)。
0xea是jumpi的操作码, code32就是要跳转的目的地址
本博文转载于:FinL的博客