读盘加载操作系统内核时出现错误0x0C80

问题描述 投票:0回答:1

当我尝试使用 BIOS 从磁盘读取时,出现错误 0x0C80,这是我的代码:

disk_load:
    push dx
    mov ah, 0x42 ; BIOS extended read routine
    mov dl, 0x80 ; Drive number (0x80 for the first HDD)
    mov si, DAP  ; DS:SI -> Disk Address Packet
    int 0x13     ; BIOS Disk interrupt
    jc disk_error
    pop dx
    cmp dh, al
    jne disk_sectors_error
    jmp disk_success
    jmp disk_exit

DAP:
    db 0x10      ; Size of DAP
    db 0x00      ; Reserved
    dw 16         ; Number of sectors to read, equal to value in dh
    dw 0x1000    ; Offset to buffer
    dw 0x0000    ; Segment of buffer
    dq 1         ; Starting absolute block number (LBA)

disk_success:
    mov bx, SUCCESS_MSG
    jmp disk_exit

disk_error:
    mov bx, DISK_ERR_MSG
    call print_string
    mov dh, ah   ; AH contains the error code
    call print_hex
    jmp disk_loop

disk_sectors_error:
    mov bx, SECTORS_ERR_MSG
    call print_string

SUCCESS_MSG:
    db "Disk was successfully read ", 0

DISK_ERR_MSG:
    db "Disk read error! Error code: ", 0

SECTORS_ERR_MSG:
    db "Incorrect number of sectors read ", 0

disk_loop:
    jmp $

disk_exit:
    ret
[org 0x7c00]

KERNEL_OFFSET equ 0x1000   ; Смещение в памяти, из которого мы загрузим ядро

mov [BOOT_DRIVE], dl       ; BIOS stores our boot drive in DL, so it ’s
                           ; best to remember this for later. (Remember that
                           ; the BIOS sets us the boot drive in 'dl' on boot)
mov bp, 0x9000             ; Устанавливаем стек
mov sp, bp

call load_kernel          ; Загружаем ядро
call switch_to_pm         ; Переключаемся в Защищенный Режим
jmp $

%include "OS/boot/print_string.asm"         ; ф. печати строки
%include "OS/boot/print_hex.asm"            ; ф. печати 16-ричного числа
%include "OS/boot/disk_load.asm"            ; ф. чтения диска
%include "OS/boot/print_string_pm.asm"     ; ф. печати строки (32PM)
%include "OS/boot/switch.asm"              ; ф. переключения в 32PM
%include "OS/boot/gdt.asm"                 ; таблица GDT

[bits 16]

load_kernel:
    mov bx, KERNEL_OFFSET
    mov dh, 16
    mov dl, [BOOT_DRIVE]
    call disk_load
    ret

[bits 32]                   ; Сюда мы попадем после переключения в 32PM

BEGIN_PM:
    mov esp, 0x90000
    call KERNEL_OFFSET      ; Переходим в адрес, по которому загрузился код ядра
    jmp $

BOOT_DRIVE:      db 0

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

我需要读取前16个扇区并加载内核,然后进入32位保护模式并执行它

我从Github

获取了代码的基础

Console

我尝试在互联网上搜索,但找不到任何可以帮助我的东西:(

assembly kernel nasm qemu osdev
1个回答
0
投票

关于
disk_load

call print_string
mov dh, ah   ; AH contains the error code
call print_hex

您没有向我们展示“print_string.asm”或“print_hex.asm”的内容,因此我们无法检查 AH 是否在 print_string 调用中幸存下来或 print_hex 是否需要 DH 输入!

来自 IBM/MS INT 13 Extensions 的错误代码 0Ch 读取“不支持的轨道或无效媒体”。
它可能源于您使用硬编码的驱动器号,如

mov dl, 0x80 ; Drive number (0x80 for the first HDD)
中所示。你did传递给你的disk_load例程,BIOS给你的BOOT_DRIVE代码,那你为什么要覆盖它?
另外,如果您不打算使用 DH 中的扇区计数而只是信任磁盘地址数据包中已有的硬编码值,那么传递扇区计数有何意义? KERNEL_OFFSET 参数也是如此。正如 @Nassau 在评论中所写的那样,请确保您使用 qemu 创建的磁盘映像至少包含这 16 个扇区。

  cmp dh, al
  jne disk_sectors_error
  ...
disk_sectors_error:
  mov bx, SECTORS_ERR_MSG
  call print_string
SUCCESS_MSG:
  db "Disk was successfully read ", 0

“ExtendedRead”函数不会报告通过 AL 寄存器成功传输的块数!在 DAP 中查找此信息。
当发生可能的失败时,您打印一条合适的消息,但允许 CPU 开始执行文本消息!这些消息属于最终的

disk_exit:
ret
下面。这样,disk_sectors_error代码就可以正确地落入
disk_loop:
jmp $
代码中。

关于 IBM/MS INT 13 扩展

永远不要假设这些扩展可用!它们具有“安装检查”功能,可让您了解其功能。使用它:

mov  dl, [BOOT_DRIVE]
test dl, dl
jns  UseCHS     ; Not meant for drives [00h,7Fh]
mov  bx, 55AAh
mov  ah, 41h
int  13h        ; -> AX BX CX DH CF
jc   UseCHS     ; Extensions not supported
cmp  bx, 0AA55h
jne  UseCHS     ; Not installed
shr  cx, 1
jnc  UseCHS     ; Functions 42h, 43h, 44h, 47h, 48h not supported

如果扩展不可用,则使用合适的消息中止或退回到正常的 CHS (CylinderHeadSector) 功能。

引导加载程序

BIOS 将我们的启动驱动器存储在 DL 中,因此最好记住这一点以供以后使用。 (请记住,BIOS 在启动时将启动驱动器设置为“dl”)

您的评论是对的,但比这更深入。 DL 是唯一一个在引导加载程序开始时保证保存有意义的值的寄存器。您必须自己设置段寄存器和堆栈指针,并且不要相信 BIOS 会为您完成这些操作。

%include "OS/boot/print_string_pm.asm"
%include "OS/boot/switch.asm"

%include "OS/boot/gdt.asm"

切换到保护模式不是引导加载程序应该做的事情!它属于你的内核的设置代码。

%包括“OS/boot/print_string.asm”
%包括“OS / boot / print_hex.asm”

%include "OS/boot/disk_load.asm"

为什么有这么多包含文件?他们所做的小工作并不能证明单独的文件是合理的,更重要的是,他们引诱您犯这些错误。我指的是引导加载程序和
disk_load

之间以及 disk_loadprint_hex 之间的参数不匹配。 只需将其实际源文本插入引导加载程序源即可。
[org 0x7c00] KERNEL_OFFSET equ 0x1000 cld xor ax, ax mov ds, ax mov es, ax mov ss, ax mov sp, 0x9000 mov [BOOT_DRIVE], dl mov bx, KERNEL_OFFSET mov cx, 16 call disk_load jmp 0:KERNEL_OFFSET ; --------------------------------- ; IN (ax:bx,cx,dl) disk_load: mov si, DAP ; DS:SI -> Disk Address Packet mov [si+2], cx ; Count mov [si+4], bx ; Offset mov [si+6], ax ; Segment test dl, dl jns UseCHS ; Not meant for drives [00h,7Fh] mov bx, 55AAh mov ah, 41h ; BIOS.InstallationCheck int 13h ; -> AX BX CX DH CF jc UseCHS ; Extensions not supported cmp bx, 0AA55h jne UseCHS ; Not installed shr cx, 1 jnc UseCHS ; Functions 42h, 43h, 44h, 47h, 48h not supported mov ah, 0x42 ; BIOS.ExtendedRead int 0x13 ; -> AH CF jc disk_error cmp [si+2], cx je disk_success disk_sectors_error: mov si, SECTORS_ERR_MSG call print_string jmp $ disk_error: push ax ; AH contains the error code mov si, DISK_ERR_MSG call print_string pop ax call print_hex jmp $ UseCHS: ... disk_success: mov si, SUCCESS_MSG ; ---------------------------- ; IN (si) OUT (si) MOD (ax) print_string: lodsb mov ah, 0Eh .next: int 10h lodsb cmp al, 0 jne .next ret ; ---------------------------- ; IN (ax) print_hex: ... ret ; ---------------------------- DAP: db 16 ; Size of DAP db 0 ; Reserved dw 0 ; Number of sectors to read dw 0 ; Offset to buffer dw 0 ; Segment of buffer dq 1 ; Starting absolute block number (LBA) SUCCESS_MSG: db "Disk was successfully read ", 0 DISK_ERR_MSG: db "Disk read error! Error code: ", 0 SECTORS_ERR_MSG: db "Incorrect number of sectors read ", 0 BOOT_DRIVE: db 0 ; ---------------------------- times 510-($-$$) db 0 dw 0xAA55

© www.soinside.com 2019 - 2024. All rights reserved.