一、可以通过int 0x13例程或者通过0x1F0~0x1F7这8个端口操作硬盘
1、0x13例程主要就是设置对参数,其他跟操作软盘一样,dl=0x80即可。
2、通过0x1F0~0x1F7这8个端口操作硬盘稍微复杂一点。
二、bochs配置文件需要稍加修改,其实也不用手工来做。如下:
1、运行bochs,选3.Edito ptions -->12.Disk &Boot options-->3.ATA channel 0(出现选项,直接回车确认即可,选完最后一项会自动退到上级菜单)-->7.First HD/CD on channel 1(输入disk,输入文件名,我不想麻烦,直接选软盘的映像a.img,选flat模式。cylinders输入80,heads输入2,sectors per track输入18,sector size输入512,可以看出以上参数都是按照a.img的参数设置的。其他参数都选默认值就行)-->返回到主菜单选4.保存。文件名用diskboot了,这个随心意。
2、打开diskboot文件看一下参数是否正确,把boot:后面改为disk。
3、修改magic_break,display_library后面的选项。其他不用动,如下:
display_library: x, options="gui_debug"
boot: disk
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="a.img", mode=flat, cylinders=80, heads=2, spt=18, sect_size=512, model="Generic 1234", biosdetect=auto, translation=auto
magic_break: enabled=1
三、Makefile 增加一行
bootFromDisk:
bochs -q -f diskboot
四、修改boot.asm把读软盘改为读硬盘。
1、用int 0x13方式
read_setup:
mov dh, 0 ; driver head
mov dl, 0x80 ; driver number
mov ch, 0 ; cycle number
mov cl, 2 ; start sector
mov bx, SETUP_LOAD_ADDR ; store to memory address
mov ah, 2 ; function number for read disk
mov al, 1 ; read 1 sector
int 0x13 ; handle disk driver bios routine
pushf ; flags register push stack
pop si
and si, 0x0001 ; CF set to 1 when operate disk error
cmp si ,0
jz .done
jmp read_setup
.done:
ret
同操作软盘这里就只是把dl的值改为了0x80。
运行了一下,成功。在没有改dl的值之前也运行了一次,也成功了。感觉int 0x13不挑食。也不知道是不是因为模拟环境的原因。
2、用操作硬盘控制器端口方式读硬盘:
有8个端口需要操作:
0x1F0--读写的数据都放这里面,共16bit。
0x1F1--读出错时放错误码,写数据的时候放功能码,8bit。
0x1F2--读写多少个扇区,8bit。
0x1F3--LBA地址的0~7位
0x1F4--LBA地址的8~15位
0x1F5--LBA地址的16~23位
0x1F6:每一位取值的意义
________________________________
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
-----------------------------------------------------
| 1 | LBA | 1 | DRV | Head number |
-----------------------------------------------------
LBA位:1-LBA地址模式;0-CSH地址模式
DRV位:1-从盘模式;0-主盘模式
Head number:CHS模式下传递磁头号(0~15);LBA模式下传递lba地址24~28位。
0x1F7:status register (read only)
用作状态寄存器时是一个只读寄存器。IDE控制器使用它来返回一些信息,这些信息取决于正在执行的命令。每一位意义如下:
_________________________________________
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---------------------------------------------------------------------
| BSY | RDY | WFT | SKC | DRQ | COR | IDX | ERR |
---------------------------------------------------------------------
BSY: 值为1时,表示硬盘控制器正在执行一个命令。除了digital output寄存器外的寄存器都不能被访问。
RDY:值为1时,表示硬盘控制器已经准备好执行命令,并且驱动器正在以正确的速度旋转。
WFT: 值为1时,表示硬盘控制器检测到一个写入故障。
SKC: 值为1时,表示读写头已经就位(寻道结束)。
DRQ: 值为1时,表示可以访问数据寄存器。写数据时,表示硬盘控制器等待数据;读数据时,表示硬盘控制器正发送数据。
COR: 值为1时,表示控制器必须通过使用ECC字节来纠正数据(Error Correction Code,纠错码:系数末尾的额外字节,用于验证其完整性,有时还用于纠正错误)。
IDX: 值为1时,表示控制器重新标记了索引标记(不是硬盘上的孔)。
ERR: 值为1时,表示发生了错误。错误代码已放入0x1F1中
0x1F7:command register (write only)
用作命令寄存器时,是一个只写寄存器。它接受对IDE控制器的命令。请注意,大多数命令都意味着一些值已放置在sector、cylinder等寄存器中。总是最后发送命令(将命令传送到0x1F7)。相关命令:
1X:重新校准磁盘。所有(10~1F)的命令都将导致重新校准磁盘。此命令没有参数,只需将命令代码写入命令寄存器,然后等待就绪状态再次变为活动状态。
20:读扇区,失败将重试。21:读扇区,失败不重试。22:需通过ECC校验。23:失败重试并且要通过ECC校验。这个命令在LBA模式下有效。当命令完成(DRQ激活)时,您可以从数据寄存器中读取256个字(16位)。
30:写扇区,失败将重试。31:写扇区,失败不重试。22:需通过ECC校验。23:失败重试并且要通过ECC校验。
其他命令不再列出,可参考:https://www.unige.ch/medecine/nouspikel/ti99/ide.htm,register那一部分。
由上面的资料可以写程序了:
readHD:
;---- prepart register ----
mov al, 1 ; -- sector count for read
mov dx, 0x1f2
out dx, al
inc dx ; 0x1f3 -- start address for read
mov al, 2
out dx, al
inc dx ; 0x1f4
mov al, 0
out dx, al
inc dx ; 0x1f5
out dx, al
inc dx ; 0x1f6
mov al, 0xe0 ; | 1 | lba | 1 | drv | lba highest four bit address |
; | 1 1 1 0 0000 -- set lba mode(0xE0) |
;---- wait RDY signal ----
inc dx ; 0x1f7
.waitRDY:
nop
in al, dx
test al, 0x40 ; | BSY | RDY | WFT | SKC | DRQ | COR | IDX | ERR |
; | - 1 - - - - - - |0x40
jz .waitRDY
;---- load read HD command ----
mov al, 0x20
out dx, al
;---- wait DRQ signal ----
.waitDRQ:
nop
mov dx, 0x1f7
in al, dx
test al, 0x08 ; | BSY | RDY | WFT | SKC | DRQ | COR | IDX | ERR |
; | - - - - 1 - - - |0x08
jz .waitDRQ
;---- read data and write to memory ----
mov cx, 256
mov di, SETUP_LOAD_ADDR
mov dx, 0x1f0
.readDT:
in ax, dx
mov word[di], ax
inc di
inc di
loop .readDT
ret