2017-05-29 99 views
1

OS時,我有以下bootloader代碼似乎運行在硬盤上完美的罰款:一般性保護錯誤上運行ISO

[bits 16] 
[org 0x7c00] 

bootld_start: 
    KERNEL_OFFSET equ 0x2000 

    xor ax, ax  ; Explicitly set ES = DS = 0 
    mov ds, ax 
    mov es, ax 
    mov bx, 0x8C00 ; Set SS:SP to 0x8C00:0x0000 . The stack will exist 
        ;  between 0x8C00:0x0000 and 0x8C00:0xFFFF 
    mov ss, bx 
    mov sp, ax 

    mov [BOOT_DRIVE], dl 

    mov bx, boot_msg 
    call print_string 

    mov dl, [BOOT_DRIVE] 
    call disk_load 

    jmp pm_setup 

    jmp $ 

BOOT_DRIVE: 
    db 0 

disk_load: 
    mov si, dap 
    mov ah, 0x42 

    int 0x13 

    ;cmp al, 4 
    ;jne disk_error_132 

    ret 

dap: 
    db 0x10    ; Size of DAP 
    db 0 
    ; You can only read 46 sectors into memory between 0x2000 and 
    ; 0x7C00. Don't read anymore or we overwrite the bootloader we are 
    ; executing from. (0x7c00-0x2000)/512 = 46 
    dw 46    ; Number of sectors to read 
    dw KERNEL_OFFSET ; Offset 
    dw 0    ; Segment 
    dd 1 
    dd 0 

disk_error_132: 
    mov bx, disk_error_132_msg 
    call print_string 

    jmp $ 

disk_error_132_msg: 
    db 'Error! Error! Something is VERY wrong! (0x132)', 0 

gdt_start: 

gdt_null: 
    dd 0x0 
    dd 0x0 

gdt_code: 
    dw 0xffff 
    dw 0x0 
    db 0x0 
    db 10011010b 
    db 11001111b 
    db 0x0 

gdt_data: 
    dw 0xffff 
    dw 0x0 
    db 0x0 
    db 10010010b 
    db 11001111b 
    db 0x0 

gdt_end: 

gdt_descriptor: 
    dw gdt_end - gdt_start 
    dd gdt_start 

CODE_SEG equ gdt_code - gdt_start 
DATA_SEG equ gdt_data - gdt_start 

boot_msg: 
    db 'OS is booting files... ', 0 

done_msg: 
    db 'Done! ', 0 

%include "boot/print_string.asm" 

pm_setup: 
    mov bx, done_msg 
    call print_string 

    mov ax, 0 
    mov ss, ax 
    mov sp, 0xFFFC 

    mov ax, 0 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 

    cli 
    lgdt[gdt_descriptor] 
    mov eax, cr0 
    or eax, 0x1 
    mov cr0, eax 
    jmp CODE_SEG:b32 

    [bits 32] 

    VIDEO_MEMORY equ 0xb8000 
    WHITE_ON_BLACK equ 0x0f 

    print32: 
     pusha 
     mov edx, VIDEO_MEMORY 
    .loop: 
     mov al, [ebx] 
     mov ah, WHITE_ON_BLACK 
     cmp al, 0 
     je .done 
     mov [edx], ax 
     add ebx, 1 
     add edx, 2 
     jmp .loop 
    .done: 
     popa 
     ret 

    b32: 
     mov ax, DATA_SEG 
     mov ds, ax 
     mov es, ax 
     mov fs, ax 
     mov gs, ax 
     mov ss, ax 

     ; Place stack below EBDA in lower memory 
     mov ebp, 0x9c000 
     mov esp, ebp 

     mov ebx, pmode_msg 
     call print32 

     call KERNEL_OFFSET 

     jmp $ 

    pmode_msg: 
     db 'Protected mode enabled!', 0 

kernel: 
    mov ebx, pmode_msg 
    call print32 
    jmp $ 

pmode_tst: 
    db 'Testing...' 

times 510-($-$$) db 0 
db 0x55 
db 0xAA 

的問題是,當我將其轉換爲使用這些命令的ISO:

mkdir iso 
mkdir iso/boot 
cp image.flp iso/boot/boot 
xorriso -as mkisofs -R -J -c boot/bootcat \ 
        -b boot/boot -no-emul-boot -boot-load-size 4 \ 
        -o image.iso iso 

...它失敗並出現三重故障。當我與qemu-system-i386 -boot d -cdrom os-image.iso -m 512 -d int -no-reboot -no-shutdown運行它,它輸出(不含無用SMM例外):

check_exception old: 0xffffffff new 0xd 
     0: v=0d e=0000 i=0 cpl=0 IP=0008:0000000000006616 
pc=0000000000006616 
SP=0010:000000000009bff8 env->regs[R_EAX]=0000000000000000 
EAX=00000000 EBX=00007d72 ECX=00000000 EDX=000000e0 
ESI=00007cb0 EDI=00000010 EBP=0009c000 ESP=0009bff8 
EIP=00006616 EFL=00000083 [--S---C] CPL=0 II=0 A20=1 SMM=0 HLT=0 
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-] 
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT 
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy 
GDT=     00007c73 00000018 
IDT=     00000000 000003ff 
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000 
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000   DR3=0000000000000000  
DR6=00000000ffff0ff0 DR7=0000000000000400 
CCS=000000e0 CCD=000001b3 CCO=ADDB     
EFER=0000000000000000 
check_exception old: 0xd new 0xd 
     1: v=08 e=0000 i=0 cpl=0 IP=0008:0000000000006616  pc=0000000000006616 SP=0010:000000000009bff8 env-  >regs[R_EAX]=0000000000000000 
EAX=00000000 EBX=00007d72 ECX=00000000 EDX=000000e0 
ESI=00007cb0 EDI=00000010 EBP=0009c000 ESP=0009bff8 
EIP=00006616 EFL=00000083 [--S---C] CPL=0 II=0 A20=1 SMM=0 HLT=0 
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-] 
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA] 
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT 
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy 
GDT=     00007c73 00000018 
IDT=     00000000 000003ff 
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000 
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000  DR3=0000000000000000  
DR6=00000000ffff0ff0 DR7=0000000000000400 
CCS=000000e0 CCD=000001b3 CCO=ADDB     
EFER=0000000000000000 
check_exception old: 0x8 new 0xd 

這意味着我得到了一個0X0D(一般性保護錯誤),然後0x08的(雙重故障),則三重故障。這是爲什麼發生?

編輯:我已經改變了命令:

xorriso -as mkisofs -R -J -c boot/bootcat -b boot/boot.flp -o nmos.iso nmos.flp 

但現在我收到以下錯誤:

xorriso : FAILURE : Cannot find in ISO image: -boot_image ... bin_path='/boot/boot.flp' 
xorriso : NOTE : -return_with SORRY 32 triggered by problem severity FAILURE 

有誰知道這是什麼意思?

編輯2:

我已經改變了代碼中使用啊= 0×02像這樣寫着:

mov bx, KERNEL_OFFSET 
mov ah, 0x02 
mov al, 46 
mov ch, 0x00 
mov dh, 0x00 
mov cl, 0x02 
mov dl, [BOOT_DRIVE] 

int 0x13 

,但它仍然是三重斷裂。爲什麼?

+0

I'我不是ISO的專家,但看起來你正在使用xorriso來創建一個ISO,但已經關閉了軟盤模擬。由於ISO不是模擬軟盤,所以您的DAP讀取可能會執行2048字節的扇區讀取,而讀取扇區1是相對於CD的開始。可能你並沒有將你的內核讀入內存,當你跳到KERNEL_OFFSET(0x2000)時,你正在執行內存,直到它在EIP 0x6616發生故障。我懷疑你的內核只是沒有被正確讀取。 –

+0

'xorriso -as mkisofs -R -J -c boot/bootcat -b boot/boot.flp -o nmos.iso nmos.flp'應該是'xorriso -as mkisofs -R -J -c boot/bootcat -b boot /boot.flp -o nmos.iso'。允許軟盤模擬的ISO生成是'nmos.iso'。你可能會發現這個**可能不適用於BOCHS,QEMU和一些真正的硬件,因爲int 13h/ah = 42h可能甚至不能用作模擬軟盤的CD-ROM。 –

+0

查看我之前評論的最後一句。 –

回答

0

問題中的所有三重故障的主要原因,真正歸因於你的內核沒有被正確加載到0x0000:0x2000的內存中。當您使用JMP將控制轉移到此位置時,最終運行內存區域中發生的情況,並執行CPU直到它遇到導致故障的指令。


引導光盤是具有多種不同的模式的奇獸,並且有引導這樣的CD,但他們也可能有自己的怪癖很多的BIOS。當您使用-no-emul-bootXORRISO您正在請求磁盤既不被視爲軟盤也不被視爲硬盤。你可以刪除-no-emul-boot -boot-load-size 4,它應該生成一個被視爲軟盤的ISO。問題在於許多真正的BIOS,仿真器(BOCH和QEMU)和虛擬機在使用軟盤模擬引導CD時不支持Int 13h/AH=42h擴展磁盤讀取。您可能會被迫通過Int 13h/AH=02h使用常規磁盤讀取。

如果您使用-no-emul-boot -boot-load-size 4,則應該可以通過Int 13h/AH = 42h使用擴展磁盤讀取,但它需要對引導加載程序進行一些更改。當使用-no-emul-boot -boot-load-size 4時,CDROM的扇區大小爲2048字節,而不是512.這需要對引導加載程序和內核進行一些修改。 -boot-load-size 4將信息寫入ISO,通知BIOS從ISO內的磁盤映像的起始處讀取4 512字節的塊。不再需要0xaa55引導簽名。

如果您使用-no-emul-boot還有一個需要處理的障礙。在CD-ROM上,LBA 0不是放置在最終ISO中的磁盤映像的位置。問題是,如何獲得磁盤鏡像在ISO中的LBA?您可以使用XORRISO將此信息寫入您創建的引導加載程序的特殊部分,然後使用-boot-info-table啓用此功能。

在引導加載程序開始時創建特殊部分相對比較容易。在El Torito Specification Supplement他們提到這一點:

EL TORITO BOOT INFORMATION TABLE 
... 
     The format of this table is as follows; all integers are in sec- 
     tion 7.3.1 ("little endian") format. 

     Offset Name   Size  Meaning 
      8  bi_pvd   4 bytes LBA of primary volume descriptor 
     12  bi_file  4 bytes LBA of boot file 
     16  bi_length  4 bytes Boot file length in bytes 
     20  bi_csum  4 bytes 32-bit checksum 
     24  bi_reserved 40 bytes Reserved 

     The 32-bit checksum is the sum of all the 32-bit words in the 
     boot file starting at byte offset 64. All linear block addresses 
     (LBAs) are given in CD sectors (normally 2048 bytes). 

這是在談論56個字節,我們創建拿着我們的bootloader虛擬磁盤的偏移量爲8。如果我們修改你的引導代碼的頂部看起來像這樣,我們有效地創建一個空的引導信息表:

start: 
    jmp bootld_start 
    times 8-($-$$) db 0   ; Pad out first 8 bytes 

    ; Boot info table 
    bi_pvd dd 0 
    bi_file dd 0 
    bi_kength dd 0 
    bi_csum dd 0 
    bi_reserved times 40 db 0 ; 40 bytes reserved 

當使用XORRISO-boot-info-table一旦ISO生成此表將被填充。 bi_file是我們需要的重要信息,因爲它是我們的磁盤鏡像放置在ISO內部的LBA。我們可以使用它來填充擴展磁盤讀取使用的磁盤訪問包,以便從ISO的正確位置讀取。

爲了使DAP有點更具可讀性,並考慮到我已經修改它看起來像2048字節扇區:

dap: 
dap_size: db 0x10    ; Size of DAP 
dap_zero  db 0 
    ; You can only read 11 2048 byte sectors into memory between 0x2000 and 
    ; 0x7C00. Don't read anymore or we overwrite the bootloader we are 
    ; executing from. (0x7c00-0x2000)/2048 = 11 (rounded down) 
dap_numsec: dw 11     ; Number of sectors to read 
dap_offset: dw KERNEL_OFFSET  ; Offset 
dap_segment: dw 0     ; Segment 
dap_lba_low: dd 0 
dap_lba_high:dd 0 

一個問題是,放入啓動信息表中的LBA是從磁盤映像的啓動(使用我們的引導程序的扇區)。我們需要將該LBA增加1,並將其放入DAP中,以便我們在內核啓動時使用LBA。使用32位指令,我們可以從引導信息表讀取32位值,加1並保存到DAP中。如果使用嚴格的16位指令,則向32位值添加一個更復雜。由於我們將進入386保護模式,因此我們可以假設在實模式下支持32位操作數的指令。代碼更新與內核的LBA的DAP可能看起來像:

mov ebx, [bi_file]  ; Get LBA of our disk image in ISO 
    inc ebx     ; Add sector to get LBA for start of kernel 
    mov [dap_lba_low], ebx ; Update DAP with LBA of kernel in the ISO 

其他唯一的問題是引導程序部門需要對其進行填充到2048(一個CD-ROM部門的規模),而超過512,我們可以刪除啓動簽名。變化:

times 510-($-$$) db 0 
db 0x55 
db 0xAA 

要:

times 2048-($-$$) db 0 

修改後的Bootloader代碼可能看起來像:

[bits 16] 
[org 0x7c00] 

KERNEL_OFFSET equ 0x2000 

start: 
    jmp bootld_start 
    times 8-($-$$) db 0   ; Pad out first 8 bytes 

    ;  Boot info table 
    bi_pvd dd 0 
    bi_file dd 0 
    bi_kength dd 0 
    bi_csum dd 0 
    bi_reserved times 40 db 0 ; 40 bytes reserved 

bootld_start: 

     xor ax, ax  ; Explicitly set ES = DS = 0 
     mov ds, ax 
     mov es, ax 
     mov bx, 0x8C00 ; Set SS:SP to 0x8C00:0x0000 . The stack will exist 
         ;  between 0x8C00:0x0000 and 0x8C00:0xFFFF 
     mov ss, bx 
     mov sp, ax 

     mov ebx, [bi_file]  ; Get LBA of our disk image in ISO 
     inc ebx     ; Add sector to get LBA for start of kernel 
     mov [dap_lba_low], ebx ; Update DAP with LBA of kernel in the ISO 

     mov [BOOT_DRIVE], dl  
     mov bx, boot_msg 
     call print_string 

     mov dl, [BOOT_DRIVE] 
     call disk_load 

     jmp pm_setup 

     jmp $ 

BOOT_DRIVE: 
     db 0 

disk_load: 
     mov si, dap 
     mov ah, 0x42 

     int 0x13 

     ;cmp al, 4 
     ;jne disk_error_132 

     ret 

dap: 
dap_size: db 0x10    ; Size of DAP 
dap_zero  db 0 
    ; You can only read 11 2048 byte sectors into memory between 0x2000 and 
    ; 0x7C00. Don't read anymore or we overwrite the bootloader we are 
    ; executing from. (0x7c00-0x2000)/2048 = 11 (rounded down) 
dap_numsec: dw 11     ; Number of sectors to read 
dap_offset: dw KERNEL_OFFSET  ; Offset 
dap_segment: dw 0     ; Segment 
dap_lba_low: dd 0 
dap_lba_high:dd 0 

disk_error_132: 
     mov bx, disk_error_132_msg 
     call print_string 

     jmp $ 

disk_error_132_msg: 
     db 'Error! Error! Something is VERY wrong! (0x132)', 0 

gdt_start: 

gdt_null: 
    dd 0x0 
    dd 0x0 

gdt_code: 
    dw 0xffff 
    dw 0x0 
    db 0x0 
    db 10011010b 
    db 11001111b 
    db 0x0 

gdt_data: 
    dw 0xffff 
    dw 0x0 
    db 0x0 
    db 10010010b 
    db 11001111b 
    db 0x0 

gdt_end: 

gdt_descriptor: 
    dw gdt_end - gdt_start 
    dd gdt_start 

CODE_SEG equ gdt_code - gdt_start 
DATA_SEG equ gdt_data - gdt_start 

boot_msg: 
     db 'OS is booting files... ', 0 

done_msg: 
     db 'Done! ', 0 

%include "boot/print_string.asm" 

pm_setup: 
     mov bx, done_msg 
     call print_string 

    mov ax, 0 
    mov ss, ax 
    mov sp, 0xFFFC 

    mov ax, 0 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 

    cli 
    lgdt[gdt_descriptor] 
    mov eax, cr0 
    or eax, 0x1 
    mov cr0, eax 
    jmp CODE_SEG:b32 

     [bits 32] 

     VIDEO_MEMORY equ 0xb8000 
     WHITE_ON_BLACK equ 0x0f 

     print32: 
      pusha 
      mov edx, VIDEO_MEMORY 
     .loop: 
      mov al, [ebx] 
      mov ah, WHITE_ON_BLACK 
      cmp al, 0 
      je .done 
      mov [edx], ax 
      add ebx, 1 
      add edx, 2 
      jmp .loop 
     .done: 
      popa 
      ret 

     b32: 
      mov ax, DATA_SEG 
      mov ds, ax 
      mov es, ax 
      mov fs, ax 
      mov gs, ax 
      mov ss, ax 

     ; Place stack below EBDA in lower memory 
      mov ebp, 0x9c000 
      mov esp, ebp 

      mov ebx, pmode_msg 
      call print32 

       call KERNEL_OFFSET 

      jmp $ 

     pmode_msg: 
       db 'Protected mode enabled!', 0 

kernel: 
     mov ebx, pmode_msg 
     call print32 
     jmp $ 

pmode_tst: 
     db 'Testing...' 

times 2048-($-$$) db 0 

然後,您可以修改原來的XORRISO命令是:

xorriso -as mkisofs -R -J -c boot/bootcat \ 
        -b boot/boot -no-emul-boot -boot-load-size 4 \ 
        -boot-info-table -o image.iso iso 
1

我是xorriso的開發者。如果image.flp是帶有MBR的軟盤映像 ,可能是分區表和文件系統,則Michael的提示 會朝着正確的方向前進。 El Torito指定了模擬 ,它允許引導映像文件在BIOS中顯示爲軟盤或硬盤。

選項-no-emul-boot -boot-load-size 4會導致BIOS加載 文件image.flp的第一個2048字節並將它們作爲x86程序執行。 顯然,軟盤映像不適合作爲普通程序。

根據mkisofs的傳統軟盤模擬是 選項-b的默認值。因此,您只需從xorriso命令行中刪除選項-no-emul-boot 即可將El Torito啓動映像 設置爲軟盤。 (-boot-load-size 4也已過時)。 軟盤映像必須具有512 字節的2400或2880或5760扇區,否則它將被xorriso拒絕。

其他大小的圖像可能會模擬爲硬盤,其中MBR分區表中的第一個 (且僅限)分區條目指示磁盤的大小爲 。 xorriso -as mkisofs選項-hard-disk-boot選擇此仿真。

+0

關於引導映像內容 和BIOS問題的唯一知識是: http:// git.zytor.com/syslinux/syslinux.git/tree/core/isolinux.asm 是一個經過測試的-no-emul-boot引導程序示例。 我唯一的軟盤模擬ISO示例是名爲MooseDT-SD1A-2D-8-16-32MB.iso的Seagate固件升級程序 。 –

+0

El Torito,4.1「INT 13 Function 08」給出了仿真的十六進制軟盤幾何結構。 軌道x頭x扇區:1.44 Meg = 0x50 x 2 x 0x12, 2.88 Meg = 0x50 x 2 x 0x24,1.2 Meg = 0x50 x 2 x 0x0F。 –