2011-10-10 89 views
4

最近我试图弄清楚引导程序如何工作。 我在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之间没有任何东西完成。

回答

3

更新:除了下面的内容,您还可以在加载时覆盖您的堆栈!

你堆位于07C0h + 288 : 409608E0h: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 
  • 你要走bx09c0h,所以它会读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 
+0

正如你所说,我设置了bx = 0和cl = 2。现在bochs(或我的代码)在执行int 13h的时刻锁定。 Bochs对虚拟软盘的状态保持在“阅读”状态,没有任何反应。 但是,感谢您的帮助到目前为止。要看你的代码。 – vikenemesh

+0

而'dh = 0',也只是为了清楚你将'es'设置为'09c0h'后将'bx'设置为零,对吧?因为这种行为听起来像是你刚刚重写了中断表。无论如何,随时更新您的问题与更新的源代码,我会看看。 – user786653

+0

查看上面的更新源代码。 – vikenemesh