本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接,严禁用于任何商业用途。 作者:fireaxe_hq@hotmail.com
博客:fireaxe.blog.chinaunix.net
1 Boot加载 1.1 为何要有boot
电脑启动后,cpu会把软盘的第一个扇区(512字节),也就是所说的引导扇区,读入内存的0x7c00处执行。512实在是太小了,一个最简单的实模式转入保护模式的代码就会耗尽这512字节。如果在实模式中加载内核,则会把内核限制在1M以内(实际还要小些)。
由于这些缺点,需要首先用引导扇区加载一个boot程序,这个boot程序最大可以有几百K大小,虽然也不是很大,但对于之前的512字节来说,则已经是大的让人惊喜了。
在boot中,我们可以完成加载kernel的所有准备工作了。
1.2 加载boot到内存
此处是引导程序。该程序会读入一个扇区到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的开始处 |
1.3 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 $ |
本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接,严禁用于任何商业用途。 作者:fireaxe_hq@hotmail.com
博客:fireaxe.blog.chinaunix.net |