2011-10-10 78 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