内容参考《linux0.01内核分析与操作系统设计》
当操作系统的引导程序远远不止512B,这时,就必须使用二次装载的方式。
举例:由BIOS从磁盘上装入引导扇区(0头0磁道1扇区)到内存地址07C0:0000(跟0000:7c00其实地址是一样的,发现没有),并跳转到该地址执行;再有从07C0:0000地址开始的引导扇区中的引导代码把存放在其他扇区中的程序装入内存,并跳转到该程序中执行。
下面的boot.asm是一个引导扇区程序,将使用BIOS的INT13h从磁盘读取2.3.4.5.6共5个扇区(当然我们这里其实只有第2扇区有内容)到1000:0000处,然后跳转到1000:0000处执行被装入的代码。
; boot.asm
; 从磁盘扇区装载另外一个程序,并且执行
[ORG 0]
jmp 07C0h:start ; 跳转到段07C0
start:
; 设置段寄存器
mov ax, cs
mov ds, ax
mov es, ax
reset: ; 重置软盘驱动器
mov ax, 0 ;
mov dl, 0 ; Drive=0 (=A)
int 13h ;
jc reset ; ERROR => reset again
read:
mov ax, 1000h ; ES:BX = 1000:0000
mov es, ax ;
mov bx, 0 ;
mov ah, 2 ; 读取磁盘数据到地址ES:BX
mov al, 5 ; 读取5个扇区
mov ch, 0 ; Cylinder=0
mov cl, 2 ; Sector=2
mov dh, 0 ; Head=0
mov dl, 0 ; Drive=0
int 13h ; Read!
jc read ; ERROR => Try again
jmp 1000h:0000 ; 跳转到被装载的程序处,开始执行
times 510-($-$$) db 0
dw 0AA55h
下面的是被引导程序加载的另一程序,存放在第2扇区,负责打印字符串:
; prog.ASM
; 被引导程序装载的程序
; 在屏幕上打印:Program Loaded Succeed! Hello, myos!
[ORG 0]
jmp start2 ; Goto segment 07C0
; 定义需要打印的字符串
msg db 'Program Loaded Succeed! Hello, myos!',$0
start2:
; 设置段寄存器
mov ax, cs
mov ds, ax
mov es, ax
mov si, msg ; 打印字符串
print:
lodsb ; AL=字符串存放在DS:SI
cmp al, 0 ; If AL=0 then hang
je hang
mov ah, 0Eh ; Print AL
mov bx, 7
int 10h
jmp print ; 打印下一个字符
hang: ; 挂起计算机!
jmp hang
times 510-($-$$) db 0
dw 0AA55h
编译:
nasm boot.asm -o boot.bin
nasm prog.asm -o prog.bin
然后把这两个二进制文件分别拷贝到软盘镜像文件boot.img上面,boot.bin放在前512字节,prog.bin随后,除了用Partcopy之外,最简单的是使用UltraEdit啦,如图用UltraEdit打开一个原先的磁盘文件boot.img,用boot.bin和prog.bin来覆盖,如图:
下面使用bochs来使用这个boot.img磁盘文件引导检验下我们的程序吧,bochs的调试工具bochsdbg。
我的run.bat文件:
cd "d:\Bochs-2.4.1\myboot"
..\bochsdbg -q -f bochsrc.bxrc
在内存0000:7c00处设个断点吧,等待BIOS执行POST完毕来加载我们的引导程序,如图
bochs听话的在0000:7c00处停下了,我们可以看到引导程序的第一条指令正是boot.asm里面的jmp 07c0h:start,现在的CPU段寄存器是多少,用命令sregs(bochs-2.04),如图:
我想看下在程序boot.asm跳转到被加载程序处之前的CPU段寄存器,先找到jmp 1000h:0000代码的内存位置(用u命令),然后在该处设置中断,再用命令sregs查看:
继续执行,在00007c2c处停下后,当前段寄存器:
代码段cs和数据段ds均为07c0
:
继续单步执行下2步(命令n):
我们已经进入了被引导程序加载prog.asm程序段,此时段寄存器
cs=0x1000,ds还是0x07c0,接下来程序又将设置段寄存器DS和ES啦,然后cs和ds将编程0x1000。
阅读(1765) | 评论(0) | 转发(0) |