2016-03-16 30 views
5

Sto imparando la lingua dell'assembly. Ho scritto un semplice bootloader. Dopo averlo testato, non ha funzionato. Qui è il mio codice:Abilita il boot loader per caricare il secondo settore di un USB

[bits 16] 
[org 0x7c00] 

jmp start 

data: 
wolf_wel_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0 
wolf_kernel_load db 'Loading kernel....',0x0D,0x0A,0 
wolf_error_msg db 'Kernel.bin not found!',0x0D,0x0A,0 
wolf_error_msg1 db 'Press any key to restart..',0 

start: 
     mov si, wolf_wel_msg 
    call wolf_print 

    mov si, wolf_kernel_load 
    call wolf_print 

    pushf 
    stc 

    mov ah,00 
    mov dl,00 
    int 13h 

    read_sector: 
      mov ax, 0x0 
     mov es, ax 
     xor bx, bx 
      mov ah, 02 
     mov al, 01 
     mov ch, 01 
     mov cl, 02 
     mov dh, 00 
     mov dl, 00 
     int 13h 

    jc wolf_error 
    popf 
    jmp 0x0:0x1000 
    cli 
    hlt 

    wolf_error: 
      mov si, wolf_error_msg 
     call wolf_print 
     mov si, wolf_error_msg1 
     call wolf_print 
      mov ah,00 
     int 16h 
     xor ax,ax 
     int 19h 

    wolf_print: 
      lodsb 
     or al,al 
     jz exit 
     mov ah,0x0e 
     int 10h 
     jmp wolf_print 
     exit: 
      ret 

times 510-($-$$) db 0 
dw 0xAA55 

Questo codice viene inserito nel primo settore del USB utilizzando questo comando:

dd if=f:\boot.bin of=\\.\d: bs=512 count=1 

Un semplice programma viene caricato nel secondo settore di utilizzo di questo comando USB:

dd if=f:\hello.bin of=\\.\d: bs=512 seek=1 count=1 

Questo è il codice per il programma caricato nel secondo settore:

[bits 16] 
[org 0x1000] 

jmp start 
data: 
    msg db 'Hello',0 
start: 
    mov si, msg 
    jmp print 

    cli 
    hlt 
    print: 
     lodsb 
     or al, al 
     jz exit 
     mov ah,0x0e 
     int 10h 
     jmp print 
    exit: 
     ret 

Perché il mio boot loader non funziona? Ho fatto qualcosa di sbagliato? Eventuali suggerimenti?

+0

Che cosa hai già provato? Cosa esattamente "non funziona"? Hai qualche risultato? – Yexo

+0

No, ricevo l'output dicendo "kernel.bin non trovato". Significa che carry è impostato (non riuscito). –

+0

"ciao.bin" non caricato dal secondo settore. –

risposta

10

Il codice presuppone che DS sia impostato su 0. Non è possibile presumere che. La prima parte del codice deve impostare esplicitamente DS su 0 se si utilizza org 0x7c00.

Si dovrebbe seriamente considerare di definire il proprio stack impostando SS: SP. Non sai dove si trova l'esistente o se è abbastanza grande da gestire quello che intendi fare.

Appena prima che venga richiamato il bootloader, il BIOS imposta lo DL con il numero del dispositivo di avvio. Non impostare DL a 0 nel codice quando si effettuano richieste di unità dall'unità di avvio. Dovresti utilizzare il valore che esisteva in DL quando è stato chiamato il tuo bootloader.

si dovrebbe usare il CLD istruzioni per cancellare il flag di direzione dal momento che si sta utilizzando il LODSB istruzioni aspettandosi di essere in movimento in avanti in memoria. Non è garantito che il flag di direzione sia impostato correttamente, pertanto è necessario impostarlo esplicitamente nella direzione desiderata con CLD (inoltro) o STD (indietro).

Ho più informazioni sui problemi di cui sopra nella mia risposta StackOverflow con General Bootloader Tips.

Poiché non si utilizza uno BPB, si consiglia vivamente di rimuovere lo jmp start come prima istruzione del proprio bootloader. Spostare invece i dati dopo il codice ma prima della firma del settore di avvio (0xAA55). La ragione di ciò è che alcuni BIOS tenteranno di trovare un BPB basato su un'istruzione JMP che appare come prima istruzione del bootloader e, se trovato, sovrascrive parti del bootloader in memoria causando un comportamento potenzialmente indefinito.

vostro bootloader usa questa istruzione per iniziare la seconda fase caricato dal secondo settore:

jmp 0x0:0x1000 

Il problema è che quando si legge il settore creazione ES: BX in questo modo:

read_sector: 
    mov ax, 0x0 
    mov es, ax 
    xor bx, bx 

Questo imposta ES: BX a 0x0000: 0x0000 che chiaramente non è dove il vostro JMP si aspetta che il codice sia. È necessario impostare ES: BX nella posizione di memoria che si desidera INT 13/AH=02h per leggere i settori del disco in.

INT 13h/AH = 02h richiede che il numero di Cilindro/Testina/Settore sia impostato correttamente. I settori iniziano la numerazione a 1, ma Cilindri e teste sono a base zero. Il secondo settore del disco è a cilindro 0, testina 0, settore 2. Il codice imposta Cilindro a 1 invece di 0. Questo codice è sbagliato in quanto si dovrebbe davvero essere impostando a 0:

mov ch, 01 

Nella tua nella seconda fase è stato creato print come funzione poiché termina con un'istruzione RET. jmp print deve essere modificato in call print.

Con tutti i cambiamenti sopra raccomandate, tra cui quelli di miei consigli generali bootloader il codice potrebbe essere modificato per essere:

boot.asm

[bits 16] 
[org 0x7c00] 

        ; Use the boot drive number passed to us by BIOS in register DL 
start: 
    xor ax,ax  ; We want a segment of 0 for DS for this question 
    mov ds,ax  ;  Set AX to appropriate segment value for your situation 
    mov es,ax  ; In this case we'll default to ES=DS 
    mov bx,0x8000 ; Stack segment can be any usable memory 

    mov ss,bx  ; This places it with the top of the stack @ 0x80000. 
    mov sp,ax  ; Set SP=0 so the bottom of stack will be @ 0x8FFFF 

    cld   ; Set the direction flag to be positive direction 

    mov si, wolf_wel_msg 
    call wolf_print 

    mov si, wolf_kernel_load 
    call wolf_print 

    pushf 
    stc 

    mov ah,00 
    int 13h 

    read_sector: 
     mov ax, 0x0 
     mov es, ax  ; ES = 0 
     mov bx, 0x1000 ; BX = 0x1000. ES:BX=0x0:0x1000 
         ; ES:BX = starting address to read sector(s) into 
     mov ah, 02  ; Int 13h/AH=2 = Read Sectors From Drive 
     mov al, 01  ; Sectors to read = 1 
     mov ch, 00  ; CH=Cylinder. Second sector of disk 
         ; is at Cylinder 0 not 1 
     mov cl, 02  ; Sector to read = 2 
     mov dh, 00  ; Head to read = 0 
         ; DL hasn't been destroyed by our bootloader code and still 
         ;  contains boot drive # passed to our bootloader by the BIOS 
     int 13h 

    jc wolf_error 
    popf 
    jmp 0x0:0x1000 
    cli 
    hlt 

    wolf_error: 
     mov si, wolf_error_msg 
     call wolf_print 
     mov si, wolf_error_msg1 
     call wolf_print 
     mov ah,00 
     int 16h 
     xor ax,ax 
     int 19h 

    wolf_print: 
     lodsb 
     or al,al 
     jz exit 
     mov ah,0x0e 
     int 10h 
     jmp wolf_print 
     exit: 
     ret 

; Moved the data before the boot signature but after the code 
wolf_wel_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0 
wolf_kernel_load db 'Loading kernel....',0x0D,0x0A,0 
wolf_error_msg db 'Kernel.bin not found!',0x0D,0x0A,0 
wolf_error_msg1 db 'Press any key to restart..',0 

times 510-($-$$) db 0 
dw 0xAA55 

hello.asm

[org 0x1000] 

jmp start 
data: 
    msg db 'Hello',0 
start: 
    mov si, msg 
    call print  ; print is a function, use CALL instead of JMP 

    cli 
    hlt 
    print: 
     lodsb 
     or al, al 
     jz exit 
     mov ah,0x0e 
     int 10h 
     jmp print 
    exit: 
     ret 

Poiché sembra che si stia utilizzando Windows in base alle informazioni fornite nel comando DD, è possibile che si stia verificando un altro problema. Non so quale DD si usi ma of=\\.\d: non scrive all'inizio del disco (unità USB), scriverà sulla partizione in cui D: risiede, non l'inizio del disco stesso.

Si consiglia di utilizzare l'ultimo DD da Chrysocome. Ad oggi l'ultimo è 0.6beta3. Raccomando questa versione perché consente di accedere correttamente al disco (o chiavetta USB) rispetto all'inizio del disco, non in relazione all'inizio di una particolare partizione. Ciò potrebbe causare seri problemi nel tentativo di memorizzare correttamente il 1 ° e il 2 ° settore. Con l'ultima versione userei questi comandi con privilegi di amministratore scrivere sul drive USB:

dd if=f:\boot.bin od=d: bs=512 count=1 
dd if=f:\hello.bin od=d: bs=512 seek=1 count=1 

Questo presuppone che il USB unità è sull'unità D: come suggerito nella sua interrogazione. ATTENZIONE: il mancato utilizzo dell'unità corretta potrebbe causare la perdita e la corruzione di dati su un altro dispositivo !!

Se questi comandi funzionano correttamente l'output dovrebbe essere simile:

dd if=boot.bin od=d: bs=512 count=1 
rawwrite dd for windows version 0.6beta3. 
Written by John Newbigin <[email protected]> 
This program is covered by terms of the GPL Version 2. 

Device d: is a link to \\?\Device\HarddiskVolume5 \\?\Device\HarddiskVolume5 is a partition on \Device\Harddisk1 
512 100% 
1+0 records in 
1+0 records out 

dd if=hello.bin od=d: bs=512 seek=1 count=1 
rawwrite dd for windows version 0.6beta3. 
Written by John Newbigin <[email protected]> 
This program is covered by terms of the GPL Version 2. 

Device d: is a link to \\?\Device\HarddiskVolume5 \\?\Device\HarddiskVolume5 is a partition on \Device\Harddisk1 
28 5% 
0+1 records in 
0+1 records out 

Una volta che avete rilasciato questi comandi, Windows può rilevare automaticamente che l'unità non è più formattato correttamente. Non consentire a Windows di formattare l'unità. Se gli permetti di formattare il disco, lo ripartirà e lo formatterà. In tal modo distruggerà il settore di avvio che hai scritto. Quando richiesto, è sufficiente annullare la finestra di dialogo in formato .

Ricordarsi di smontare/espellere correttamente l'unità USB prima di rimuoverla dal sistema. La mancata corretta installazione potrebbe far sì che i dati non vengano scritti correttamente/completamente nell'unità.

Se si desidera creare un'immagine del disco per Bochs, QEMU, DOSBox ecc si potrebbe creare un floppy 720k con questi comandi al prompt dei comandi:

dd if=/dev/zero of=disk.img bs=1024 count=720  
dd if=f:\boot.bin of=disk.img bs=512 count=1 conv=notrunc 
dd if=f:\hello.bin of=disk.img bs=512 seek=1 count=1 conv=notrunc 

L'immagine del file disk.img dovrebbe essere utilizzabile da Bochs, QEMU , DOSbox, ecc. O scritti su un dischetto da 720k per l'uso su un computer reale.

/dev/zero si presenta come un tipico dispositivo Unix/Linux. Il comando DD per Windows che ho suggerito di utilizzare comprende /dev/zero come un dispositivo di input speciale che genera solo zeri. Windows non ha il dispositivo /dev/zero, ma DD lo vede come un dispositivo interno speciale e lo simula.


Quando viene eseguito con Bochs 2.6.8 su MS Windows questo è quello che ho visto:

enter image description here

Sul mio Lenovo L520 Laptop (non-EFI BIOS) con un'USB Stick 16GB questo è quello che ho visto:

enter image description here