一看二做三总结
分类: 嵌入式
2011-06-09 22:18:35
电脑启动后,cpu会把软盘的第一个扇区(512字节),也就是所说的引导扇区,读入内存的0x7c00处执行。512实在是太小了,一个最简单的实模式转入保护模式的代码就会耗尽这512字节。如果在实模式中加载内核,则会把内核限制在1M以内(实际还要小些)。
由于这些缺点,需要首先用引导扇区加载一个boot程序,这个boot程序最大可以有几百K大小,虽然也不是很大,但对于之前的512字节来说,则已经是大的让人惊喜了。
在boot中,我们可以完成加载kernel的所有准备工作了。
此处是引导程序。该程序会读入一个扇区到0x8000h开始的内存处,并移动bx到下一个扇区的开始处。
; ch 磁道 ; cl 扇区 ; dh 磁头 ; bx会被加512 ReadFloopy: push ax push cx push dx push es
mov ax, 0800h ; 加载到08000h,所以要把0800h移入段寄存器es mov es, ax mov ah, 02h ; 读操作 mov al, 01h ; read sector no. mov dl, 00h ; 0号软驱 int 13h add bx, 512 ; 每次把bx向后移一个扇区
pop es pop dx pop cx pop ax ret |
下面的程序会读入60个扇区的内容到0x8100处。注意最后的跳转指令,该指令会设置cs寄存器为0x800,设置ip寄存器为0x100,也就是boot程序的入口。
LABEL_BEGIN: mov ax, cs mov ds, ax mov ss, ax mov es, ax mov sp, BaseOfStack
call ResetFloopy ; reset floopy
; read sectors to memory mov ax, 1 mov bx, 0100h ; 程序开始的偏移量 .loop: push ax mov cl, 18 div cl mov cl, ah add cl, 1 mov ch, al shr ch, 1 mov dh, al and dh, 1 call ReadFloopy ; 读扇区 pop ax add ax, 1 cmp ax, 60 ; 读60个扇区 jnz .loop
jmp 0800h:0100h ; 跳入boot的开始处 |
由于boot中要做的事情比较多,所以现在的编译模式改为汇编与c程序的汇编,其makefile写法如下:
default:rt/hboot.bin objdump -d rt/hboot.elf > rt/dump.txt
rt/hboot.bin:rt/hboot.elf objcopy --gap-fill=0xff -O binary $< $@
rt/hboot.elf:rt/bootInit.o main.o ld -s -Ttext 0100 $^ -o $@
rt/%.o:%.c mkdir -p rt gcc -c -fno-builtin $< -o rt/$*.o
rt/%.o:%.s mkdir -p rt nasm -f elf $< -o rt/$*.o |
由于boot开始时还是在实模式下,所以要在汇编中标注[BITS 16]。global _Start_Boot用于说明这个是一个全局符号,这是为了让编译器能够找到。此处只是一个打印字符串的延时程序。
[BITS 16] global _Start_Boot _Start_Boot: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, 08100h
mov ax, BootMessage mov bp, ax mov cx, 15 mov ax, 01301h mov bx, 000ch mov dl, 0 int 10h
jmp $ |