2013-02-02 17 views
5

Próbuję zbudować prosty bootloader x86 Linux w NASMie.bootloader Linux x86

Linux bzImage jest przechowywany na partycji dysku sda1 począwszy od pierwszego sektora.

Odczytuję kod trybu rzeczywistego z pliku bzImage (15 sektorów) do pamięci, począwszy od 0x7E00. Jednak po wskoczeniu do kodu po prostu się zawiesza, nic się nie dzieje.

Utworzono kod dla głównego rekordu rozruchowego na sda. Prawdopodobnie najlepiej, jeśli po prostu dołączę całość. Chciałbym wiedzieć, dlaczego po prostu zawiesza się po instrukcji dalekiego skoku.

[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

Czy studiowałeś implementacje GRUB i LILO? –

+0

Przyjrzałem się implementacji LILO i wygląda na to, że w ten sam sposób wskakują do kodu Linuksa. Trudno jest jednak odczytać ich kod. – Druesukker

+0

Czy użyłeś debuggera, aby przejrzeć kod i zobaczyć przyczynę zawieszenia? – Jester

Odpowiedz

1

Zakładając, że kod jest boot loader (a zatem nie jest MBR):

  • Nigdy wyłączyć przerwania chyba trzeba. BIOS potrzebuje ich do poprawnego działania i w razie potrzeby umożliwi im korzystanie z niektórych funkcji BIOS-u (np. Czekanie na funkcje IRQ wewnątrz sektora "przenoszone sektory"). Ponieważ twój kod ładuje i przekazuje kontrolę do bardziej rzeczywistego kodu trybu (np. Bez przełączania do trybu chronionego lub cokolwiek jest zaangażowane), nie masz powodu, aby wyłączać przerwań w dowolnym miejscu w całym programie ładującym.
  • W przypadku adresowania w trybie rzeczywistym zwykle łatwiej jest używać 0x0000: 0x7C00 zamiast 0x07C0: 0x0000. Wygląda na to, że próbujesz wymieszać oba (na przykład ustaw rejestry segmentów dla pierwszego, ale zdefiniuj BOOTSEG i HDRSEG dla drugiego).
  • Tabela partycji zawiera "partycje rozszerzone", a nie "partycje podstawowe", dlatego tablica partycji jest niepoprawna (i prawdopodobnie powinna być pusta/pusta).
  • Program ładujący nie powinien przyjmować określonego/zakodowanego na sztywno "początkowego LBA" ("początkowa LBA" dla partycji zależy od tego, jak użytkownik końcowy czuł się jak partycjonowanie ich dysku, gdy system operacyjny jest zainstalowany). Musisz określić "początkową LBA" partycji z głównej tablicy partycji MBR, co zwykle ma miejsce, gdy MBR pozostawi DS: SI wskazującą na wpis tablicy partycji na partycji.
  • Nie należy zakładać, że uruchamia się system z "Urządzenia BIOS 0x80". MBR powinien zostawić DL ustawiony na prawidłowy numer urządzenia i nie powinno być żadnego powodu, dla którego twój kod nie powinien działać, jeśli (np.) System operacyjny jest zainstalowany na drugim dysku twardym lub czymś innym.
  • Twój zakodowany "początek LBA do odczytu" (w DAP) jest nieprawidłowy. Z przyczyn historycznych jest prawdopodobnie 63 sektory na ścieżkę, a twoja partycja zaczyna się na 64 sektorze. Oznacza to, że sektor LBA 0x3F jest pierwszym sektorem w partycji (który jest programem ładującym rozruch) i nie jest pierwszym sektorem jądra.Zakładam, że pierwszym sektorem jądra może być sektor LBA 0x40 (drugi sektor partycji).
  • "Liczba sektorów" również nie powinna być zakodowana na stałe. Chciałbyś wczytać początek jądra i zbadać go oraz określić, ile sektorów załadować, skąd.
  • Zwykle 512 bajtów (właściwie więcej niż 446 bajtów) jest zdecydowanie za mało dla porządnego programu rozruchowego. Pierwsze 512 bajtów programu ładującego rozruchu powinno załadować resztę programu ładującego (przy każdym pozostałym bajcie zapasowym użytym do poprawy obsługi błędów - np. puts("Read error while trying to load boot loader"), a nie tylko putc('B')). Cała reszta (ładowanie fragmentów jądra, konfigurowanie trybu wideo, ustawianie poprawnych wartości w polach "nagłówek trybu rzeczywistego" itd.) Powinna znajdować się w dodatkowych sektorach i nie znajdować się w pierwszym sektorze.

Należy zauważyć, że sposób uruchamiania komputera został starannie zaprojektowany w taki sposób, że każdy MBR może łączyć dowolny system operacyjny na dowolnej partycji dowolnego dysku; a MBR może być częścią czegoś większego (na przykład menedżera rozruchu), który pozwala na zainstalowanie wielu systemów operacyjnych (na przykład, gdy użytkownik może użyć ładnego menu lub czegoś, aby wybrać partycję, do której powinien załadować się kod MBR). Ten projekt umożliwia użytkownikowi zastąpienie MBR (lub menadżera rozruchu) cokolwiek innego w dowolnym momencie bez wpływu na żaden zainstalowany system operacyjny (lub powodujący konieczność naprawy wszystkich zainstalowanych systemów operacyjnych). Dla prostego przykładu, użytkownik powinien mieć 12 różnych partycji, które zawierają twój boot loader i oddzielną/niezależną wersję Linuksa, a następnie zainstalować dowolny menedżer rozruchowy (np. GRUB, Plop, GAG, MasterBooter, itp.), Że chcę w każdej chwili.

Przyczyna, dla której Twój kod się zawiesza, nie jest bardzo ważna, ponieważ mimo wszystko cały kod musi zostać przepisany. Jeśli jesteś ciekawy, zdecydowanie poleciłbym uruchomić go w emulatorze z debuggerem (np. Bochs), abyś mógł dokładnie sprawdzić, co się stało (np. Zrzuć pamięć w 0x00007E00, aby zobaczyć, co zawiera, jednoetapowy JMP do zobacz, co jest wykonywane, itp.).

1

Komentarz nie pasuje do kodu!

xor bx, bx ; Will also set ss = dx

Wątpię, czy to jest twój problem ...

Zastrzeżenie: Nie zrobiłem tego! Jestem "kurczakiem" i zawsze robiłem moje buty z dyskietki.

To, czego "oczekuję" w MBR polega na tym, aby odsunąć się z drogi, a następnie ponownie załadować pierwszy sektor na aktywnej partycji do 7C00h, a następnie tam przeskoczyć. Ten "prawdziwy bootloader" ładuje resztę. Nie jestem zaznajomiony z układem pliku bzImage - może będzie działał załadowany w 7E00h ...

Myślę, że jestem w mojej głowie. Wezmę mi płaszcz ...

+0

oprócz tego, że nie pasuje do komentarza, czy 'ax' i' bx' to nie KERNELSEG, a nie zero? –

+0

Myślę, że problemem było wyczyszczenie rejestrów segmentów na początku. Innym problemem nie było prawidłowe ustawienie rejestrów segmentów przed skokiem. Powinny one = KERNHDR oprócz cs, które powinno = KERNSEG. Dziękuję za odpowiedź, która działa zgodnie z oczekiwaniami. – Druesukker

Powiązane problemy