2013-02-02 37 views
5

我想在nasm中構建一個簡單的x86 Linux引導程序。Linux x86引導程序

在Linux的bzImage存儲在從所述第一扇區開始的磁盤分區SDA1。

予讀取來自bzImage的(15個扇區)的實模式代碼到存儲器從0x7E00開始。 但是,當我跳進代碼時,它只是掛起,沒有任何反應。

我已經創建代碼,SDA上的主引導記錄。我可能是最好的,如果我只附加 整件事情。我想知道爲什麼它會在遠程跳轉指令後掛起。

[BITS 16] 

%define BOOTSEG 0x7C0 
%define BOOTADDR (BOOTSEG * 0x10) 

%define HDRSEG (BOOTSEG + 0x20) 
%define HDRADDR (HDRSEG * 0x10) 

%define KERNSEG (HDRSEG + 0x20) 

[ORG BOOTADDR] 
entry_section: 
    cli 
    jmp  start 
start: 
    ; Clear segments 
    xor  ax, ax 
    mov  ds, ax 
    mov  es, ax 
    mov  gs, ax 
    mov  fs, ax 
    mov  ss, ax 
    mov  sp, BOOTADDR ; Lots of room for it to grow down from here 

    ; Read all 15 sectors of realmode code in the kernel 
    mov  ah, 0x42 
    mov  si, dap 
    mov  dl, 0x80 
    int  0x13 
    jc bad 

    ; Test magic number of kernel header 
    mov  eax, dword [HDRADDR + 0x202] 
    cmp  eax, 'HdrS' 
    jne  bad 

    ; Test jump instruction is there 
    mov  al, byte [KERNSEG * 16] 
    cmp  al, 0xEB 
    jne  bad 

    xor  ax, ax  ; Kernel entry code will set ds = ax 
    xor  bx, bx  ; Will also set ss = dx 
    jmp  dword KERNSEG:0 

; Simple function to report an error and halt 
bad: 
    mov  al, "B" 
    call putc 
    jmp  halt 

; Param: char in al 
putc: 
    mov  ah, 0X0E  
    mov  bh, 0x0F 
    xor  bl, bl 
    int  0x10 
    ret 

halt: 
    hlt 
    jmp  halt 

; Begin data section 
dap:    ; Disk address packet 
    db 0x10   ; Size of dap in bytes 
    db 0    ; Unused 
    dw 15    ; Number of sectors to read 
    dw 0    ; Offset where to place data 
    dw HDRSEG   ; Segment where to place data 
    dd 0x3F   ; Low order of start addres in sectors 
    dd 0    ; High order of start address in sectors 

; End data section 

times 446-($-$$) db 0 ; Padding to make the MBR 512 bytes 

; Hardcoded partition entries 
part_boot: 
    dw 0x0180, 0x0001, 0xFE83, 0x3c3f, 0x003F, 0x0000, 0xF3BE, 0x000E 
part_sda2: 
    dw 0x0000, 0x3D01, 0xFE83, 0xFFFF, 0xF3FD, 0x000E, 0x5AF0, 0x01B3 
part_sda3: 
    dw 0xFE00, 0xFFFF, 0xFE83, 0xFFFF, 0x4EED, 0x01C2, 0xb113, 0x001D 
part_sda4: 
    dw 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 

dw 0xAA55 ; Magic number at relative address 510 
mbrend:  ; Relative address 512 
+0

你研究過GRUB和LILO的實現嗎? –

+0

我看了LILO的實現,看起來像他們以相同的方式跳入Linux代碼。儘管閱讀他們的代碼很難。 – Druesukker

+0

您是否使用調試器來遍歷代碼並查看掛起的原因? – Jester

回答

1

假設你的代碼是引導裝載程序(因此不是MBR):

  • 決不要停用的IRQ,除非你要。 BIOS需要它們正常工作,並且無論如何都會在某些BIOS功能中啓用它們(例如等待磁盤功能中的「扇區轉移」IRQ)。因爲你的代碼只是加載並傳遞控制給更多的實模式代碼(例如,沒有切換到保護模式或者涉及到任何東西),所以你沒有理由在整個引導加載器的任何地方禁用IRQ。
  • 對於實模式尋址,它通常更清晰/更易於使用0x0000:0x7C00,而不是0x07C0:0x0000。您似乎試圖混合兩者(例如爲前者設置段寄存器,但爲後者定義BOOTSEG和HDRSEG)。
  • 分區表包含「擴展分區」而不是「主分區」,因此分區表是錯誤的(應該可能爲空/空)。
  • 引導裝載程序不應該承擔任何特定/硬編碼「開始LBA」(以下簡稱「開始LBA」的分區取決於最終用戶如何感覺就像安裝操作系統的分區時,其磁盤)。您需要從MBR的主分區表中確定分區的「啓動LBA」,這通常是通過希望MBR使DS:SI指向分區的分區表條目來完成的。
  • 您不應該認爲您正在從「BIOS設備0x80」啓動。 MBR應該將DL設置爲正確的設備編號,並且如果(例如)操作系統安裝在第二個硬盤驅動器或其他設備上,應該沒有理由說明你的代碼不應該工作。
  • 您的硬編碼「啓動LBA讀取」(在DAP中)是錯誤的。由於歷史原因,每個軌道可能有63個扇區,並且您的分區從第64個扇區開始。這意味着LBA扇區0x3F是分區中的第一個扇區(這是您的引導加載程序),而不是內核的第一個扇區。我假設內核的第一個扇區可能是LBA扇區0x40(分區的第二個扇區)。
  • 「扇區數」也不應硬編碼。你需要加載內核的開始並檢查它,然後確定要從中加載多少個扇區。
  • 典型的512字節(實際上更像446字節)對於體面的引導加載程序來說太少了。引導加載程序的前512個字節應加載引導加載程序的其餘部分(剩餘的每個備用字節用於改進錯誤處理 - 例如puts("Read error while trying to load boot loader")而不僅僅是putc('B'))。其他所有內容(加載內核片段,設置視頻模式,在「實模式內核頭」字段中設置正確的值等)應該位於額外的扇區中,而不在第一個扇區中。

注意的方式在電腦開機都經過精心設計,使得任何MBR可以鏈式加載任何磁盤的任何分區的任何操作系統;並且MBR可以是允許安裝多個OS(例如,用戶可以使用漂亮的菜單或某物來選擇MBR的代碼應該鏈式加載哪個分區)的更大的事物(例如啓動管理器)的一部分。這種設計允許用戶隨時用其他任何東西替換MBR(或啓動管理器),而不影響任何已安裝的操作系統(或導致所有安裝的操作系統需要修復)。舉一個簡單的例子,一個用戶應該能夠擁有12個不同的分區,這些分區都包含你的啓動加載器和一個獨立/獨立版本的Linux,然後安裝任何啓動管理器(例如GRUB,Plop,GAG,MasterBooter等)隨時想要。

爲什麼你的代碼掛起,這不是很重要,因爲所有的代碼都需要重寫。如果您很好奇,我強烈建議使用調試器(例如Bochs)在仿真器中運行它,以便您可以準確檢查發生了什麼(例如,在0x00007E00轉儲內存以查看它包含的內容,單步執行JMP看看正在執行什麼等)。

1

評論與代碼不匹配!

xor bx, bx ; Will also set ss = dx

我嚴重懷疑,如果這是你的問題......

聲明:我沒有這樣做!我是「雞」,並且一直使用軟盤啓動我的bootin。

我「期望」在MBR看到的是它本身遷出的方式,然後加載上的活動分區的第一個扇區再次7C00h處,然後跳轉到那裏。這個「真正的引導程序」負載其餘的。我不熟悉的bzImage的佈局 - 也許它會在7E00h做工加載中...

我覺得我在我的頭上。我會把我的外套......

+0

除了不匹配評論,應該'ax'和'bx'不是KERNELSEG,而不是零? –

+0

我認爲問題是在開始時清除段寄存器。另一個問題是在跳轉之前沒有正確設置段寄存器。他們應該= KERNHDR,除了cs應該= KERNSEG。感謝答案,它現在按預期工作。 – Druesukker