30天自制操作系统
背景
基本上,每个硬盘除了每扇(Sector)大小依旧是512字节外,柱面(Cylinder)数、磁头(Header)数都不一致。
用磁盘来取代原作者的软盘后,沿用原来的INT 0x13/AH=2h读磁盘的话会非常蹩脚并且非常不方便。参考Windows 7也是用INT 0x13/AH=0x42h读磁盘。用该方法读磁盘只需要关注到扇区即可,不需要关注到柱面跟磁头数,很直观。
调试
Bochs
这次采用了bochs2.6.9来支持。这虚拟机对编写操作系统的人来说非常有帮助!贴出本次用到的配置文件如下。对应目录则对应修改成本地的,这里不在另外赘述。
###############################################################
# Configuration file for Bochs
###############################################################
# how much memory the emulated machine will have
megs: 32
# 对应真实机器的BIOS和VGA BIOS
romimage: file="C:\Program Files (x86)\Bochs-2.6.9\BIOS-bochs-latest"
vgaromimage: file="C:\Program Files (x86)\Bochs-2.6.9\VGABIOS-lgpl-latest"
# 设置bochs使用的磁盘,软盘使用关键字floppya,硬盘使用disk
# 若有多个软盘,可写floppya,floppyb
#floppya: 1_44=a.img, status=inserted
# choose the boot disk.
# 默认是软盘,注释掉,改为disk
#boot: floppy
boot: disk
# where do we send log messages?
log: D:\Documents\bochs\bochsout.txt
# disable the mouse
mouse: enabled=0
# enable key mapping, using US layout as default.
keyboard: keymap="C:\Program Files (x86)\Bochs-2.6.9\keymaps\x11-pc-us.map"
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
#这一句是根据bximage生成的,后面会解释。
ata0-master: type=disk, path="D:\Documents\bochs\c.img", mode=flat, cylinders=20, heads=16, spt=63
magic_break: enabled=1
通过以下命令进行调试。bochsdbg.exe可以进行调试,但是bochs.exe则不行,需要注意。
bochsdbg -f "D:\Documents\bochs\bochs.disk"
magic_break开启后,虚拟机会把
XCHG BX, BX
当成断点停下来,方便调试。
错误
如果INT 0x13/AH=0x42h调用时用了错误的参数,除了CF位一定会置1外,还可能会
AH=42hAH=1h我在真机上试验到是AH莫名其妙还是42h,在bochs的虚拟机里则是1h。所以基本上不要真的把AH当成错误号来查询,你基本上是查不到什么有效信息的。只要LBA测试到是支持,那么INT 0x13/AH=0x42h肯定是支持的,如果还调用错误,那肯定是参数设置不对,需要仔细排查一下。
方案
是否支持
并非所有BIOS都支持INT 0x13/AH=0x42h,但是基本上目前绝大多数都支持。但是为了兼容性,还是最好判断一下。
MOV BX, 0x55AA
MOV AH, 0x41
INT 0x13
JC _10_stand_bios
CMP BX, 0xAA55
JNE _10_stand_bios
TEST CL, 1
JZ _10_stand_bios
可以通过以上方法简单判断到是否支持LBA。
如果不幸BIOS不支持,可以考虑回归之前的读取方式。不过我没做兼容。
修改点
由于我改写的ipl10.nas只支持nasm编译,所以在对应代码层级的Makefile文件里,需要做出一些变更。替换原来ipl10.bin为以下编译方式(自行设定好nasm的所在目录):
ipl10.bin : ipl10.nas Makefile
nasm ipl10.nas
ren ipl10 ipl10.bin
另外,由于没有采用原书代码里把最后读到的柱面数写入:
MOV [0x0ff0],CH
所以在asmhead.nas里相应的要自己填上大致读到的Sector数。由于不断深入开发,haribote.sys的大小必定越来越大,所以镜像生成后要多关注一下0x4200开始haribote.sys的内容到哪里结束。假设到0x6200结束,那么大致读上来的扇区数目就是:
0x6200 / 512
在asmhead.nas相应修改如下:
; 残り全部
MOV ESI,DSKCAC0+512 ; 転送元
MOV EDI,DSKCAC+512 ; 転送先
;MOV ECX,0
MOV ECX, 512 * 50 / 4 ; read by INT 0x13/AH = 42h
;MOV CL,BYTE [CYLS]
;IMUL ECX,512*18*2/4 ; シリンダ数からバイト数/4に変換
;SUB ECX,512/4 ; IPLの分だけ差し引く
CALL memcpy
由于没有做太多的测试,重新编译的时候可能还是需要手动把ipl10.bin删除,各位可以自己修改一下对应的命令。
LoadSectors: ; buffer = EBX, size = ECX, begin sector = EDI
PUSH EBP
MOV EBP, ESP
SUB ESP, 0x10 ; size of DAP
MOV AX, 0x4200 ; reads sectors into memory
MOV EDX, ECX
SAR ECX, 6 ; / 64
AND EDX, 0x8000003F ; % 64
MOV BYTE[ESP], 0x10 ; size of DAP
MOV BYTE[ESP + 1], 0 ; reserved for 0
MOV WORD[ESP + 2], 64 ; 64 sectors
MOV DWORD[ESP + 12], 0 ; always 0
MOV ESI, ESP ; DAP addr
PUSH EDX
MOV DL, 0x80 ; drive number
_8_loop:
PUSH ECX
MOV ECX, EBX
AND CX, 0xF
MOV WORD[EBP - 0x10 + 4], CX ; offset
MOV ECX, EBX
SHR ECX, 4
MOV WORD[EBP - 0x10 + 6], CX ; segment
POP ECX
MOV DWORD[EBP - 0x10 + 8], EDI ; begin sector
CMP ECX, 0
JLE _6_left
INT 0x13
JC _9_error
ADD EDI, 64 ; sector
ADD EBX, 512 * 64 ; bytes
DEC ECX
JMP _8_loop
_6_left:
POP EDX
CMP EDX, 0
JLE _7_leave
MOV WORD[ESP + 2], DX ; left sectors
MOV DL, 0x80
INT 0x13
JC _9_error
JMP _7_leave
_9_error:
MOV AL, 0
PUSH AX
MOV CX, 2
MOV SI, SP
CALL print_byte_str
;PUSH 0
;PUSH 'rr'
;PUSH 're' ; error
;MOV SI, SP
;CALL print_string
_7_leave:
MOV ESP, EBP
POP EBP
RET
下载
几乎把对应源码改了个遍,基本上找不到太多原来ipl10.nas的影子了。
里面LoadSectors是本篇的核心:ipl10.rar
网址:30天自制操作系统 https://www.yuejiaxmz.com/news/view/11930
相关内容
家庭自制水果软糖,大师配方,操作要点全解析个人财务管理系统的设计
基于javaweb个人财务管理系统
理财管理系统的设计与实现
个人记账管理系统的设计与实现
C++个人财务管理系统
急救知识大全及操作方法
基于微信小程序的个人账本的设计与实现/个人财务管理系统/基于java的财务管理系统
个人财务管理系统的设计与实现
ssm个人收支管理系统(开题+源码)