操作系统开发:文件读取寻址问题、解决方案及实验
问题记录下自己学习自制操作系统时写MBR遇到的文件读取问题及解决方案。
简单来说就是LBA和CHS地址读取方式没分清。
环境
[*]bochs 虚拟机
[*]nasm 汇编
现象
照着文档或教程写的代码,扇区号啥的也没错,但文件无法读取。
经调试器检查,存储器状态接口与读入接口皆为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 , 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 -> uotient, emainder
; CyldNum = Q >> 1, HeadNum = Q & 1, StartSec = R + 1
push bp
mov bp, sp
sub esp, 2
mov byte , 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
int 0x13
jc .GoOnReading
add esp, 2
pop bp
ret问题原因
我的问题出在代码与存储设备格式不匹配。
简称全称中文适用设备读取方式(不多赘述,具体请查找文档教程)LBALogical Block Addressing逻辑块 寻址多用于硬盘通过向设备写入地址与命令,并检查硬盘可用性,即可读取CHSCylinder Head Sector柱面-读头-扇区 寻址多用于软盘通过柱面、读头、扇区的三维坐标,调用系统中断,即可读取通过bochsrc中的floppya、floppyb指定软盘,ata[-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 , 'O'
mov byte , 0x02
mov byte , 'S'
mov byte , 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 , 'M' mov byte , 0x04 mov byte , 'B' mov byte , 0x04 mov byte , 'R' mov byte , 0x04 mov byte , ' ' mov byte , 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 , ax
add bx, 2
loop .read_loop
rettimes 510 - ($ - $$) db 0x0dw 0xaa55mbr_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 , 'M'
mov byte , 0x04
mov byte , 'B'
mov byte , 0x04
mov byte , 'R'
mov byte , 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 -> uotient, emainder
; CyldNum = Q >> 1, HeadNum = Q & 1, StartSec = R + 1
push bp
mov bp, sp
sub esp, 2
mov byte , 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
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: sdl2bochsrc_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: sdl2bochs的启动配置文件。
准备
制作软盘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加载失败。
有错误望指正。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]