加载引导程序的第二阶段并启动它
最近我试图弄清楚引导程序如何工作。 我在nasm汇编程序中编写我的加载程序,并用bochs和软盘映像进行测试。加载引导程序的第二阶段并启动它
第1阶段和第2阶段的已编译二进制文件通过复制加入到一个图像中。 这张图片就像我想要的一样。 512Bytes stage1代码(包含magicnumber,它加载得很好)以及第二扇区中的512阶段2代码。
但我认为我的问题是将该部门加载到内存中并跳入内存中。我的代码有问题吗?
Stage1.asm
BITS 16
start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512)/16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 07C0h ;Set data segment to where we're loaded
mov ds, ax
mov si,s_version
call print_string
; ## Load stage2
mov si,s_loading
call print_string
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
;read 2nd sector
mov ah,02h
mov al,1 ;read 1
mov ch,0 ;on track 0
mov cl,2 ;2nd sector
mov dh,0 ;head 1
mov dl,0 ;from floppy a
mov bx,09C0h;destination segment
mov es,bx
mov bx,0 ;destination offset
int 13h ;<-- Fails right here
mov si,s_sector
call print_string
;print number of read sectors
add ax, 48
mov ah, 0Eh
int 10h
mov al, 21
mov ah, 0Eh
int 10h
;print the sector's magicnumber (debugging purposes)
mov al, [09C0h+511]
int 10h
xor ax,ax
int 16h
mov si,s_jumping
call print_string
call word 09C0h:0000h
; #### print a string from si
print_string:
push ax
push bx
mov ah, 0Eh
.repeat:
lodsb
cmp al, 0
je .exit
int 10h
jmp .repeat
.exit:
pop bx
pop ax
ret
; ****
; #### define strings
s_version db 'VeOS 0.0.0.1',10,13,0
s_loading db 'Loading Stage2...',10,13,0
s_sector db 'Loading sector...',10,13,0
s_jumping db 'Passing control to Stage2.',10,13,0
; ****
;fillup with zeros
times 510-($-$$) db 0
;boot signature
dw 0xAA55
stage2.asm
BITS 16
start:
mov ax, 09C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512)/16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 09C0h ;Set data segment to where we're loaded
mov ds, ax
mov ah, 0Eh
mov al, 21 ;"!"
int 10h
mov ah, 00h
int 16h
jmp $
times 511-($-$$) db 0
;Magicnumber for debugging
db 0x41
我彻底地用Google搜索,没有发现任何确切描述了如何在部门加载到RAM和跳进去。我的程序甚至没有发现第二部分的Magicnumber。
如果只是对地址进行一些错误估计,那会很好。
更新: 当前源代码,它有一个锁定的行被标记。我把所有4个主要寄存器设置为0,而不是纯粹的偏执狂。
Update2: 再次当前版本。在设置寄存器和发出int 13h之间没有任何东西完成。
更新:除了下面的内容,您还可以在加载时覆盖您的堆栈!
你堆位于07C0h + 288 : 4096
是08E0h:1000h = 09E0h:0000h
,而你阅读09C0h:0000
,和512个字节向前(结束于09E0h:0000h
)覆盖堆栈。要么移动你的堆栈,要么读到其他地方。请参阅memory map from osdev.org以获取灵感。
恐怕我不知道一个好的分步调试器。我只是在代码中放置了jmp $-2
指令,并使用QEMU内置调试器在适当的位置执行“信息寄存器”。我认为Bochs可能有类似的东西。
三(2.5)的东西我看(虽然有可能会更多):
;read 2nd sector
mov ah,02h
mov al,1 ;read 1
mov ch,0 ;on track 0
mov cl,1 ;2nd sector
mov dl,0 ;from floppy a
mov bx,09C0h ;destination
mov es,bx
int 13h
- 你要走
bx
为09c0h
,所以它会读09C0h:09C0h
而非09C0h:0000h
。 - 你说你正在阅读第二部分(
cl = 1
),但你正在阅读的第一部分!见Ralph Brown。 - 你没有设置
dh
(头)。在Bochs中这可能很好,但我无法回想起除了dl
being set to the drive number之外保证初始条件的最佳状态。
这里是我用于一个小测试内核的引导装载程序(部分来自osdev.org的各个部分,可能有我引入的错误,所以要小心),如果你想比较/复制。(我保留dl
原封不动,因为它包含引导驱动器,所以你不必硬编码它)。
bits 16
org 0x7c00
Start: jmp EntryPoint
PrintString16:
pusha
.PrintLoop:
lodsb
or al, al
jz .PrintDone
mov ah, 0xe
int 0x10
jmp .PrintLoop
.PrintDone:
popa
ret
EntryPoint:
xor ax, ax
mov ss, ax
mov ds, ax
mov sp, 0x7c00
.DiskReset:
mov ah, 0
int 0x13
jc .DiskReset
mov ax, 0x50 ; load to 0x500 linear address. It has unused space up to 0x7bff
mov es, ax
xor bx, bx
mov ax, 0x023B ; count = 0x3b = 59, the maximum (while still leaving soom room for the stack and the boot sector code we're currently running)
mov cx, 0x0002
xor dh, dh ; leave dl intact
int 0x13
jnc .ReadDone
mov si, ReadError
call PrintString16
jmp .DiskReset
.ReadDone:
;jmp 0x50:0x0 ;jump to stage 2 loaded at 0x500
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ax, 0x9000
mov ss, ax
mov sp, 0xffff
sti
mov si, HelloMsg
call PrintString16
; Disable interrupts until safely in protected mode
cli
; Install GDT
lgdt [toc]
; Enable A20
mov al, 0xdd
out 0x64, al
mov si, GoPMode
call PrintString16
; enable protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8:PmodeStart
bits 32
PmodeStart:
; setup stack and datasegments
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Setup stack at 0x90000
mov esp, 0x90000
; Jump to C-code
jmp 0x8:0x500
; Reboot if C-code returns
Reboot:
mov word [0x472], 0x1234
jmp 0x8:0xffff0
ReadError db 'Read error - retrying...', 13, 10, 0
HelloMsg db 'Loading...',0
GoPMode db 'Entering protected mode..',0
gdt_data:
dd 0 ; null descriptor
dd 0
; gdt code: ; code descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; gdt data: ; data descriptor
dw 0FFFFh ; limit low (Same as code)10:56 AM 7/8/2007
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
end_of_gdt:
toc:
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT)
dd gdt_data ; base of GDT
times 510 - ($-$$) db 0 ; pad to 512 bytees, will also warn if we exceed 512 bytes
dw 0xAA55 ; boot signature
正如你所说,我设置了bx = 0和cl = 2。现在bochs(或我的代码)在执行int 13h的时刻锁定。 Bochs对虚拟软盘的状态保持在“阅读”状态,没有任何反应。 但是,感谢您的帮助到目前为止。要看你的代码。 – vikenemesh
而'dh = 0',也只是为了清楚你将'es'设置为'09c0h'后将'bx'设置为零,对吧?因为这种行为听起来像是你刚刚重写了中断表。无论如何,随时更新您的问题与更新的源代码,我会看看。 – user786653
查看上面的更新源代码。 – vikenemesh