问题
记录下自己学习自制操作系统时写MBR遇到的文件读取问题及解决方案。
简单来说就是LBA和CHS地址读取方式没分清。
环境
现象
照着文档或教程写的代码,扇区号啥的也没错,但文件无法读取。
经调试器检查,存储器状态接口与读入接口皆为0x0。
代码示例
这是LBA读文件的代码。
修改自从零开发操作系统- load_section:
- ; eax Section to read from
- ; bx Memory address to write to
- ; cx Number of sections to read
- ; backup eax & cx
- mov esi, eax
- mov di, cx
- ; write arguments
- ; Number of sections
- mov dx, 0x1f2
- mov al, cl
- out dx, al
- mov eax, esi
- ; Section (LBA) addr
- ; 7~0
- mov dx, 0x1f3
- out dx, al
- ; 15~8
- mov cl, 8
- shr eax, cl
- mov dx, 0x1f4
- out dx, al
- ; 23~16
- shr eax, cl
- mov dx, 0x1f5
- out dx, al
- ; 27~24
- shr eax, cl
- and al, 0x0f
- ; 7~4==1110 => LBA mode
- or al, 0xe0
- mov dx, 0x1f6
- out dx, al
- ; write command
- mov dx, 0x1f7
- mov al, 0x20
- out dx, al
- ; wait until disk ready
- .wait_disk:
- nop
- in al, dx
- ; 4th digit==1 => ready
- ; 7th digit==1 => busy
- ; if (not (4th==1 and 7th!=1)) then wait
- and al, 0x88
- cmp al, 0x08
- jnz .wait_disk
- ; calc read times
- ; di = cx = sections to read
- mov ax, di
- ; 1 word (2 bytes) per time per section, one section 512 bytes
- ; total 256 times per section
- mov dx, 256
- ; sections to read * time to read per section
- ; mul dx => prod=dx*ax, dx=prod.high16, ax=prod.low16
- mul dx
- ; high16 ignored, cx=low16 for loop times
- mov cx, ax
- mov dx, 0x1f0
- .read_loop:
- in ax, dx
- mov [bx], ax
- add bx, 2
- loop .read_loop
- ret
复制代码 这是CHS读文件的代码。
修改自《自己动手写操作系统》- BPB_SecPerTrk equ 18
- BS_DrvNum equ 0
- ReadSector:
- ; ax Section to read from
- ; cl Number of sectors to read
- ; bx Destination
- ; 1.44MB = 2 * 80 * 18 * 512
- ; (One head for each side)
- ; (Side * TracksPerSide * SectorsPerTrack * BytesPerSector)
- ; SecToRead / SecPerTrk -> [q]uotient, [r]emainder
- ; CyldNum = Q >> 1, HeadNum = Q & 1, StartSec = R + 1
- push bp
- mov bp, sp
- sub esp, 2
- mov byte [bp-2], cl
- push bx
- mov bl, BPB_SecPerTrk
- div bl
- inc ah
- mov cl, ah
- shr al, 1
- mov ch, al
- and dh, 1
- pop bx
- mov dl, BS_DrvNum
- .GoOnReading:
- ; int 0x13, ah=2 for reading to buffer
- ; al number of sectors to read
- ; ch cylinder number
- ; cl first section number
- ; dh header number
- ; dl drive number (0 for drive A)
- ; es:bx buffer
- mov ah, 2
- mov al, byte [bp-2]
- int 0x13
- jc .GoOnReading
- add esp, 2
- pop bp
- ret
复制代码 问题原因
我的问题出在代码与存储设备格式不匹配。
简称全称中文适用设备读取方式(不多赘述,具体请查找文档教程)LBALogical Block Addressing逻辑块 寻址多用于硬盘通过向设备写入地址与命令,并检查硬盘可用性,即可读取CHSCylinder Head Sector柱面-读头-扇区 寻址多用于软盘通过柱面、读头、扇区的三维坐标,调用系统中断,即可读取通过bochsrc中的floppya、floppyb指定软盘,ata[0-3][-master/-slave]指定硬盘。boot参数指定启动设备。
例:- # 软盘
- floppya: 1_44="img/floppy.img", status=inserted
- boot: floppy
复制代码- # 硬盘
- ata0-master: path="img/hd.img", type=disk, mode=flat
- boot: disk
复制代码 解决方案
LBA寻址一般给硬盘使用,CHS一般给软盘使用。
根据存储设备选择读取方式。
实验验证
点击展开工具
- bochs 虚拟机
- nasm 汇编
- bximage 虚拟盘制作,bochs自带
- dd 虚拟盘写入,大多类unix(linux和mac)自带
系统建议使用Linux或Mac,对于Windows用户bochsrc.bxrc与一些命令可能需更改,本文不多赘述。
代码
模拟mbr将操作系统载入内存并执行的过程
os.asm- %include "boot.inc"
- section MBR vstart=OS_BASE_ADDR
- mov ax, 0xb800
- mov gs, ax
- ; print msg
- mov byte [gs:0x00], 'O'
- mov byte [gs:0x01], 0x02
- mov byte [gs:0x02], 'S'
- mov byte [gs:0x03], 0x02
- jmp $
复制代码 载入后会打印绿色OS字样。
mbr_lba.asm- %include "boot.inc"StackBase equ 0x7c00; load loader.asm into memorysection MBR vstart=StackBase ; init mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, StackBase ; video mov ax, 0xb800 mov gs, ax ; display clear mov ax, 0x0600 mov bx, 0x0700 mov cx, 0x0000 ; dl=80, dh=25 mov dx, 0x184f int 0x10 ; print msg mov byte [gs:0x00], 'M' mov byte [gs:0x01], 0x04 mov byte [gs:0x02], 'B' mov byte [gs:0x03], 0x04 mov byte [gs:0x04], 'R' mov byte [gs:0x05], 0x04 mov byte [gs:0x06], ' ' mov byte [gs:0x07], 0x04 ; load loader mov eax, OS_START_SEC mov bx, OS_BASE_ADDR mov cx, 1 call load_section jmp OS_BASE_ADDRload_section:
- ; eax Section to read from
- ; bx Memory address to write to
- ; cx Number of sections to read
- ; backup eax & cx
- mov esi, eax
- mov di, cx
- ; write arguments
- ; Number of sections
- mov dx, 0x1f2
- mov al, cl
- out dx, al
- mov eax, esi
- ; Section (LBA) addr
- ; 7~0
- mov dx, 0x1f3
- out dx, al
- ; 15~8
- mov cl, 8
- shr eax, cl
- mov dx, 0x1f4
- out dx, al
- ; 23~16
- shr eax, cl
- mov dx, 0x1f5
- out dx, al
- ; 27~24
- shr eax, cl
- and al, 0x0f
- ; 7~4==1110 => LBA mode
- or al, 0xe0
- mov dx, 0x1f6
- out dx, al
- ; write command
- mov dx, 0x1f7
- mov al, 0x20
- out dx, al
- ; wait until disk ready
- .wait_disk:
- nop
- in al, dx
- ; 4th digit==1 => ready
- ; 7th digit==1 => busy
- ; if (not (4th==1 and 7th!=1)) then wait
- and al, 0x88
- cmp al, 0x08
- jnz .wait_disk
- ; calc read times
- ; di = cx = sections to read
- mov ax, di
- ; 1 word (2 bytes) per time per section, one section 512 bytes
- ; total 256 times per section
- mov dx, 256
- ; sections to read * time to read per section
- ; mul dx => prod=dx*ax, dx=prod.high16, ax=prod.low16
- mul dx
- ; high16 ignored, cx=low16 for loop times
- mov cx, ax
- mov dx, 0x1f0
- .read_loop:
- in ax, dx
- mov [bx], ax
- add bx, 2
- loop .read_loop
- rettimes 510 - ($ - $$) db 0x0dw 0xaa55
复制代码 mbr_chs.asm- %include "boot.inc"
- StackBase equ 0x7c00
- ; load os.asm into memory
- section MBR vstart=StackBase
- ; init
- mov ax, cs
- mov ds, ax
- mov es, ax
- mov ss, ax
- ; video
- mov ax, 0xb800
- mov gs, ax
- ; display clear
- mov ax, 0x0600
- mov bx, 0x0700
- mov cx, 0x0000
- ; dl=80, dh=25
- mov dx, 0x184f
- int 0x10
- ; print msg
- mov byte [gs:0x00], 'M'
- mov byte [gs:0x01], 0x04
- mov byte [gs:0x02], 'B'
- mov byte [gs:0x03], 0x04
- mov byte [gs:0x04], 'R'
- mov byte [gs:0x05], 0x04
- ; load os
- mov eax, OS_START_SEC
- mov bx, OS_BASE_ADDR
- mov cx, OS_SEC_CNT
- call ReadSector
- jmp OS_BASE_ADDR
- ReadSector:
- ; ax Section to read from
- ; cl Number of sectors to read
- ; bx Destination
- ; 1.44MB = 2 * 80 * 18 * 512
- ; (One head for each side)
- ; (Side * TracksPerSide * SectorsPerTrack * BytesPerSector)
- ; SecToRead / SecPerTrk -> [q]uotient, [r]emainder
- ; CyldNum = Q >> 1, HeadNum = Q & 1, StartSec = R + 1
- push bp
- mov bp, sp
- sub esp, 2
- mov byte [bp-2], cl
- push bx
- mov bl, BPB_SecPerTrk
- div bl
- inc ah
- mov cl, ah
- shr al, 1
- mov ch, al
- and dh, 1
- pop bx
- mov dl, BS_DrvNum
- .GoOnReading:
- ; int 0x13, ah=2 for reading to buffer
- ; al number of sectors to read
- ; ch cylinder number
- ; cl first section number
- ; dh header number
- ; dl drive number (0 for drive A)
- ; es:bx buffer
- mov ah, 2
- mov al, byte [bp-2]
- int 0x13
- jc .GoOnReading
- add esp, 2
- pop bp
- ret
- times 510 - ($ - $$) db 0x0
- dw 0xaa55
复制代码 这两个文件前面先清屏输出红色的MBR文字,后读入os。若os.asm载入成功,则前两个字符应被绿色OS字覆盖。
创建include目录(文件夹),并写入
include/boot.inc- OS_BASE_ADDR equ 0x900 ; os将被载入的内存地址
- OS_START_SEC equ 2 ; os被存储的起始扇区
- OS_SEC_CNT equ 1 ; os存储占用扇区数
- BPB_SecPerTrk equ 18 ; 存储设备单磁道扇区数
- BS_DrvNum equ 0 ; 存储设备号
复制代码 存储一些mbr和os共用公用的数据,方便修改。后两行仅mbr_chs.asm使用。
bochsrc_floppy.bxrc- romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
- vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest.bin
- keyboard: keymap=/usr/local/share/bochs/keymaps/sdl2-pc-us.map
- floppya: 1_44="os_chs.img", status=inserted
- boot: floppy
- log: /dev/null
- mouse: enabled=0
- megs: 32
- display_library: sdl2
复制代码 bochsrc_disk.bxrc- romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
- vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest.bin
- keyboard: keymap=/usr/local/share/bochs/keymaps/sdl2-pc-us.map
- ata0-master: type=disk, path="os_lba.img", mode=flat
- boot: disk
- log: /dev/null
- mouse: enabled=0
- megs: 32
- display_library: sdl2
复制代码 bochs的启动配置文件。
准备
制作软盘chs版本。- nasm -I include/ -f bin mbr_chs.asm -o mbr_chs.bin
- nasm -I include/ -f bin os.asm -o os.bin
- bximage -func=create -fd=1.44M -q os_chs.img
- dd if=mbr_chs.bin of=os_chs.img bs=512 count=1 conv=notrunc
- dd if=os.bin of=os_chs.img bs=512 count=1 conv=notrunc seek=2
复制代码 制作硬盘lba版本。- nasm -I include/ -f bin mbr_lba.asm -o mbr_lba.bin
- nasm -I include/ -f bin os.asm -o os.bin
- bximage -func=create -hd=10M -q os_lba.img
- dd if=mbr_lba.bin of=os_lba.img bs=512 count=1 conv=notrunc
- dd if=os.bin of=os_lba.img bs=512 count=1 conv=notrunc seek=2
复制代码 实验
先试试软盘- bochs -f bochsrc_floppy.bxrc
复制代码 然后硬盘- bochs -f bochsrc_disk.bxrc
复制代码 现象
不出意外的话,两次都应该出现OSR字样,原因在代码区有解释。
有兴趣可以将不同的mbr与不同的虚拟存储设备相结合。读取方式不匹配预期现象为显示MBR字样,说明OS加载失败。
有错误望指正。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |