在《30天自制操作系统》中,作者使用软盘作为操作系统存储介质进行操作系统的编写讲解。但目前计算机设备都已基本放弃软盘支持,虽然依然可以在虚拟机上进行模拟练习,始终还是希望有一个可以真正能在物理设备上驱动安装的系统。
目前常用的移动介质基本都是U盘,所以我开始尝试用U盘开始学习。但在进行存储读写时,就出现了问题。因为U盘的存储结构和软盘是有区别的。而且,现在多数都使用FAT32格式,那么对于MBR中BPB(BIOS Parameter Block)的结构也存在差异。
目前对于磁盘的读写有2种方式,一种是CHS寻址模式,一种是LBA寻址模式。CHS方式更多的是基于最初的磁盘结构,就是柱面+磁头+扇区的读写方式。书中作者对软盘的读写就是采用的这种方式。LBA是一种基于逻辑地址块的寻址模式。这种模式隐藏了存储器底层的一些细节,比如对于柱面、磁头、扇区等的了解。因而也是一种更为通用的磁盘读写模式。虽然CHS和LBA的寻址基本单位都是扇区,但CHS需要3个参数同时确定一个扇区,而LBA将所有的扇区进行逻辑上的线性排列,从而能够进行线性查询。
BOIS中的INT13H函数支持这两种寻址模式。
在查找资料的过程中,我没有查找到利用INT13H函数用CHS模式对U盘进行读写的示例,因为我也是初学者,对于这方面的知识也不全面,所以,我也不确定在CHS模式是否可以。但LBA模式是一定可以的。
LBA模式在读写硬盘上虽然较为CHS模式简单,因为它是线性寻址的。但在INT13H函数中,需要提前设置一个地址数据结构,用于存储一些读取信息,比如读取的内存地址、扇区数、其实LBA块等。该数据结构的构成格式如下:
偏移(字节) | 大小(字节) | 说明 |
0 | 1 | 该数据结构的大小,通常为16字节 |
1 | 1 | 通常为0,意义不明 |
2 | 2 | 传输的扇区数(在某些BIOS中最大为127)。 |
4 | 4 | 内存地址(2字节的段地址:2字节的偏移地址)。 |
8 | 4 | 起始LBA块 |
12 | 4 | 用于对大容量存储设备的读取 |
该模式下的INT13H调用过程:
l 首先在磁盘地址数据结构体中设置正确的值。
l 设置DS:SI地址数据结构在内存中的地址
l 读出数据到内存:AH=0x42,写入内存数据到磁盘AH=0x43
l DL=驱动器编号
l 调用INT 0x13
在读取的过程中出现错误的话,进位标志(carry flag)会被置1。执行成功的话,AH置0。
实例:
entry:
mov ax,cs ;初始化寄存器
mov ds,ax
mov ds,ax
mov es,ax
mov ah,0x42
mov dl,0x80
mov si,packet
int 0x13
jc error
;将写入的内存地址后移512字节
;以下是将地址数据结构中的起始LBA后移1块继续写入下一个扇区
;将packet的内存偏移512字节
mov ax,[bufferoff]
mov bx,bufferoff
add ax,0x0200
mov [bx],ax
;将起始LBA加1,以读取下一个扇区
mov ax,[blockNum]
mov bx,blockNum
add ax,1
mov [bx],ax
cmp ax,5 ;连续读取4个扇区
je finish
jmp entry
;地址数据结构体
packet:
packet_size: db 10h ;packet大小,16个字节
reserved: db 0
count: dw 1 ;读1个扇区
bufferoff: dw 0x0820 ;读到内存0x0820处,偏移地址
bufferseg: dw 0 ;段地址
blockNum: dd 1 ;起始LBA块
dd 0
error:
finish:
对于以上程序,也可以在packet的count中一次性设置需要写入的扇区数。但为了测试连续写入,所以我每次只写入一个扇区。
详细的可参见:
http://wiki.osdev.org/ATA_in_x86_RealMode_(BIOS)
http://www.cnblogs.com/zeng2013/p/3637864.html