【问题标题】:Loading 2nd stage of bootloader and starting it [duplicate]加载引导加载程序的第二阶段并启动它[重复]
【发布时间】:2011-12-04 17:03:06
【问题描述】:

最近我试图了解引导加载程序的工作原理。 我正在用 nasm 汇编器编写加载程序,并使用 bochs 和软盘映像对其进行测试。

第 1 阶段和第 2 阶段的编译二进制文件通过复制合并到一个图像中。 这张图正是我想要的。 512Bytes stage1 代码(包括幻数,它加载得很好)和第二扇区中的 512 个 stage2 代码。

但我认为我的问题是将扇区加载到内存中并跳入其中。我的代码有问题吗?

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

我彻底搜索了一下,没有找到任何描述如何将扇区加载到 ram 中并跳转到其中的确切内容。我的程序甚至没有找到第二扇区的 Magicnumber。

如果只是地址上的一些错误计算,那就太好了。

更新: 当前源代码,它有锁定的行被标记。出于纯粹的偏执,我将所有 4 个主要寄存器都设置为 0。

更新2: 再次是当前版本。在设置寄存器和发出 int 13h 之间没有做任何事情。

【问题讨论】:

    标签: assembly nasm x86-16 bootloader osdev


    【解决方案1】:

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

    您的堆栈位于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 对虚拟软盘的状态保持在“阅读”状态,没有任何反应。但感谢您到目前为止的帮助。来看看你的代码。
    • dh = 0,也只是为了清楚您在将es 设置为09c0h 之后将bx 设置为零,对吗?因为这种行为听起来就像你只是覆盖了中断表。无论如何,请随时使用更新的源代码更新您的问题,我会看看。
    • 更新源代码见上文。
    • 好吧,您出于纯粹的偏执而将所有寄存器归零,但随后您继续调用print_string,然后再发出int 13h。这可能只是一个问题:)
    • 据我所知,print_string中使用的10h中断的0Eh函数不会修改寄存器。为了更加安全,我什至推开 ax-dx 并在 print_string 完成后弹出它们。在 int 13h 时仍处于“正在阅读”状态的锁定。
    猜你喜欢
    • 2016-03-22
    • 2013-05-05
    • 2019-08-24
    • 2019-07-08
    • 2016-02-14
    • 1970-01-01
    • 2020-10-21
    • 2017-06-07
    • 2016-07-02
    相关资源
    最近更新 更多