自制操作系统(3)——引导分区升级版(硬盘IO方式)

频道:行业资讯 日期: 浏览:627

项目地址

经过一个学期的学习,勉强照着书本弄了一个辣鸡系统。不过跟作者的环境不同,仍然有一些需要自己改进的地方。比如引导分区的IO。

硬盘IO方式

使用硬盘IO的方式需要在bochs的配置文件中将输入文件改为硬盘类型,如下

boot: disk # no floppyb ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0-master: type=disk, path="./img/boot.img"

然后镜像会以硬盘方式挂载。之后可以使用in、out指令操控它的输入输出,并且方便之处在于,不需要进行CHS的转换,直接给出逻辑扇区号就可以了。

指令使用

使用方式参考

原文已经讲清楚了用法,这里展示我的源码

SecCnt equ 0x1f2 LBALow equ 0x1f3 LBAMID equ 0x1f4 LBAHIGH equ 0x1f5 DEVICE equ 0x1f6 COMMAND equ 0x1f7 DISKDATA equ 0x1f0 ; cx 扇区数 ; bx 逻辑号 ; di 写入位置 Read_Disk: ; 读取扇区数 mov al, cl mov dx, SecCnt out dx, al ; LBA 地址 ; 低地址 mov al, bl mov dx, LBALow out dx, al ; 中地址 shr ebx, 8 mov al, bl mov dx, LBAMID out dx, al ; 高地址 shr ebx, 8 mov al, bl mov dx, LBAHIGH out dx, al ; 高四位 shr ebx, 8 and bl, 0x0f or bl, 0xe0 mov al, bl mov dx, DEVICE out dx, al ; 设置 command,读取扇区 mov al, 0x20 mov dx, COMMAND out dx, al .check_disk: ; 检查磁盘状态 in al, dx and al,0x88 ;第4位为1表示硬盘准备好数据传输,第7位为1表示硬盘忙 cmp al,0x08 jne .check_disk ; mov ax, cx mov dx, 256 mul dx mov cx, ax mov bx, di mov dx, DISKDATA .read_data: in ax, dx mov [bx], ax add bx, 2 loop .read_data ret

总体逻辑还是比较简单,封装称一个函数形式后可以重复使用

读取FAT12文件格式

这部分为是想换成FAT16的,不过挂载拷贝文件后发现还是FAT12格式,只好将就了。

如果你知道怎么整成FAT16请务必告诉我

读取文件系统的思路是先读取目录,文件存在则将FAT表全部拷贝下来,因为FAT12的表项是1.5个字节,所以需要判断簇号的奇偶行来读取

; si 存放文件名地址 ; di 目标位置 TmpFile equ 0x500 BaseOfRootDir equ 19 SectorOfRoot equ 14 DataOffset equ 17 Search_File: mov [.DesIndex], di push si mov cx, 1 mov bx, BaseOfRootDir mov di, TmpFile call Read_Disk pop si mov cx, 0 mov dx, 0 .read_one_sector: ; 读取一个扇区,一个扇区16个表项,用 CX 计数 mov di, TmpFile cmp cx, 16 je .one_sector_finish mov ax, 32 mov bx, cx mul bx add di, ax inc cx mov bx, -1 .cmp_name: ; 比较文件名,长度为11 inc bx cmp bx, 11 jz .find_filename mov al, byte [si + bx] cmp al, byte [di + bx] jz .cmp_name jmp .read_one_sector .one_sector_finish: ; dx 记录已读目录项数 inc dx cmp dx, SectorOfRoot jz .search_fail push si push cx push dx mov bx, BaseOfRootDir add bx, dx mov di, TmpFile call Read_Disk pop dx pop cx pop si jmp .read_one_sector .find_filename: ; 查找成功后找寻起始簇号 push di mov si, .ReadSuccess call .print pop di add di, 0x1a mov ax, word [di] mov [.FATEntry], ax call .copy_file ret .copy_file: ; 先将 FAT 表放进 0x500 mov si, word [.FATEntry] push si mov cx, 9 mov bx, 1 mov di, TmpFile call Read_Disk pop si and si, 0xff mov bx, si .copy: push bx add bx, SectorOfRoot add bx, DataOffset push bx ; 读取一个扇区打印一个点 mov ah, 0x0e mov al, . int 10h pop bx mov cx, 1 mov di, [.DesIndex] call Read_Disk add word [.DesIndex], 0x200 pop cx mov ax, 3 mul cx mov bx, 2 div bx add ax, TmpFile mov di, ax mov bx, word [di] ; 判断奇偶性 cmp dx, 0 jz .next shr bx, 4 .next: ; 如果属于正常文件,则继续进行读取 and bx, 0x0fff cmp bx, 0xff8 jge .copy_finish jmp .copy .copy_finish: mov si, .CopyFinish call .print ret .search_fail: mov si, .ReadFail call .print ret .print: mov ah, 0x0e mov al, [si] cmp al, 0 jnz .continue ret .continue: inc si int 10h jmp .print .ReadFail db "Read Fail", 0 .ReadSuccess db "Read Success", 0 .CopyFinish db "CopyFinish", 0 .FATEntry dw 0 .DesIndex dw 0

这里使用了一些小技巧,把一些参数存在事先定义好的变量中,随时存取。两个文件加起来已经接近512字节了,原本函数还有其他输出,不过超过了512字节,所以取消了。

0 留言

评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。
验证码