assembly - 为什么这种使用 BIOS 磁盘服务读取扇区不起作用?
问题描述
我正在尝试使用 BIOS 磁盘服务读取扇区功能读取扇区,但无论我做什么,进位标志都已设置,AH 为 0x01,这意味着它认为存在无效参数。我已经验证了寄存器的内容与我的分区表相对应,我还将在下面粘贴。磁盘映像只是在 Arch Linux 上使用 fdisk 创建的普通映像,没有什么特别之处。我在 QEMU 中运行它,因此这是 SeaBIOS。
我什至查看了 SeaBIOS 代码,据我所知,它返回无效参数错误的唯一方法是计数 (AL) 等于 0 或大于或等于 128,如果扇区(即CL&0x3f) 为 0,或者如果柱面、磁头或扇区大于磁盘具有的每个数量。据我所知,这一切似乎都不是真的。这个 CHS 地址应该是十进制的 (0, 32, 33) [我将在最后粘贴一个 C 程序来验证] 这应该对应于绝对扇区 2048。最后一个扇区是 (0, 65, 1) 所以第一个扇区不应超出范围。是的,DL 是 0x80,第一个驱动器。
我正在运行 qemu 像这样:qemu -gdb tcp::26000 -S -hda disk.img
。
那么发生了什么?
.equ MBR_ADDRESS_RESIDENT, 0x0600 # Where the MBR will reside
.equ MBR_ADDRESS_ORIGINAL, 0x7c00 # Where the MBR was loaded
.equ MBR_OFFSET_PT, 0x01be # Offset of the MBR Partition Table
.equ MBR_OFFSET_SIGNATURE, 0x01fe # Offset of the MBR Signature
.equ MBR_SIZE, 0x0200 # Size of the MBR, 512B
.equ STACK_ADDRESS, 0x8000 # at the 32KB mark
.equ STACK_SIZE, 0x0200 # 512B
cli # Disable interrupts
xor ax, ax
mov ds, ax # DS := 0x0
mov es, ax # ES := 0x0
mov ss, ax # SS := 0x0
mov sp, STACK_ADDRESS # Use the 512B at 0x7e00-0x800 for the stack
mov bp, sp
push dx
# Relocate this MBR sector
mov si, MBR_ADDRESS_ORIGINAL # Where this sector is located
mov di, MBR_ADDRESS_RESIDENT # Where this sector will be relocated
mov cx, MBR_SIZE # The size of this sector, 512B
cld
rep movsb
sti
ljmp 0x0000, main # Initialize the code segment register
# --- [[SNIP CODE] ---
# SI does point to the partition table. Even hardcoding the values of DX and CX changes nothing.
mov dx, [si+0x00]
# DL Verified to equal 0x80
# DH Verified to equal 0x20
mov cx, [si+0x02]
# CL Verified to equal 0x21
# CH Verified to equal 0x00
mov bx, 0x7c00 # Address to load sector
mov al, 0x01 # Read one sector
mov ah, 0x02 # Read Sector Function
int 0x13 # BIOS Disk Service
jc error
jmp ok
这是我的分区表
$ dd if=disk.img of=disk.img.ptable bs=1 count=64 skip=446
64+0 records in
64+0 records out
64 bytes copied, 0.000883791 s, 72.4 kB/s
$ xxd disk.img.ptable
00000000: 8020 2100 0141 0100 0008 0000 0008 0000 . !..A..........
00000010: 0041 0200 830a 0802 0010 0000 0070 0000 .A...........p..
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
这是 fdisk 认为的样子:
$ fdisk -l disk.img
Disk disk.img: 16 MiB, 16777216 bytes, 32768 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xfdd440d0
Device Boot Start End Sectors Size Id Type
disk.img1 * 2048 4095 2048 1M 1 FAT12
disk.img2 4096 32767 28672 14M 83 Linux
根据寄存器的值验证 CHS 地址...
$ cat main.c
#include <stdint.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
uint8_t
DL = 0x80,
DH = 0x20, /* H */
CL = 0x21, /* Bits 7-6 are higher 2 bits of C,
Bits 5-0 are S */
CH = 0x00; /* Lower 8 bits of C */
uint16_t C, H, S;
C = CH | (((uint16_t)CL << 2) & 0x0300);
H = DH;
S = CL & 0x3f;
printf("C/H/S = %d, %d, %d\n", C, H, S);
return (0);
}
$ ./a.out
C/H/S = 0, 32, 33
以下是我如何创建磁盘映像
$ dd if=/dev/zero of=disk.img bs=1M count=16
$ dd conv=notrunc if=MBR.bin of=disk.img bs=512 count=1 seek=0
$ printf ",1M,01\n;" | sfdisk disk.img
$ sfdisk -A disk.img 1
解决方案
推荐阅读
- javascript - 在nuxt + ts + pm2上运行应用程序时如何指定端口?
- magento - magento 2.4.1 电子邮件中的空订单状态
- python - 即使使用“allow_unicode=True”,韩语中的 Slug 也无法在 Django 中工作
- sql-server - 子字符串中的 Mssql 子查询
- docker - 如何配置 docker 代理?
- javascript - 打开窗口,调用 window.print(),打印(静默)并关闭选项卡
- css - Github Pages 没有加载 Bootstrap 样式,尽管在本地运行它完全没问题(使用 gulp)
- python - 如何在考虑子矩阵列的情况下按多列对数据框进行排序
- django - 无法访问 django API
- ansible - Ansible 复制模块。“找不到来源”