汇编读取硬盘

目标:把指定数据从硬盘里读取出来,保存到指定内存,把这些数据输出到屏幕

端口本质是寄存器的代号,读写只能用in/out指令,如显卡,硬盘都有自己的寄存器,CPU读写不同的端口,实质上是在读写不同的寄存器。

计算机的主硬盘分配了8个端口,0x1f0~0x1f7

读写硬盘

CHS(Cylinders Heads Sectors),需要把磁头、柱面和扇区信息都传递下去。现在已经不用了

LBA(Logical Block Addressing),逻辑块寻址。

in-读出指令

in dest目的(al/ax) source源(dx/imm8)

源可以是8位立即数或者dx寄存器,使用8位立即数只能访问0~255端口,存在局限性。而使用dx寄存器则可以访问0~65535端口

out-写入指令

out dest目的(dx/imm8) source源(al/ax)

LBA28

用28位来标记硬盘的逻辑扇区号,总共2^28个扇区,每个扇区512字节。也就是说可以寻编128GB的硬盘

  • 要读取硬盘的第一步,是告诉硬盘要读取几个扇区,这个数值要写到0x1f2端口,这个是8位端口;
  • 第二步是告诉硬盘要从哪个扇区开始读,LBA28模式下,需要写入28位的逻辑扇区号,由于端口是8位的,所以要分成4份,分别写入0x1f30x1f6这四个端口。同时,0x1f6这个端口只写入了逻辑扇区号的2724位,剩下的几位还要标识硬盘号以及读写模式,第4位是选择硬盘号,第6位是选择读写模式;
  • 第三步是往0x1f7写入0x20,表示你要读取的硬盘;如果写入0x30,就是要写硬盘

Screenshot_20220111_213442.png

这时候需要查看硬盘的状态是否准备就绪,同样也是通过0x1f7端口来查询,读入状态字节后。我们只关心第3位和第7位,所以用and来把其他位置0,而cmp则可以判断硬盘是否有空并且已经准备好了

Screenshot_20220111_213740.png

  • 第四步就是读取硬盘。需要通过0x1f0端口。这是个16位的端口,一次可以读2个字节或者1个字。我们就循环读取0x1f0,把得到的数据保存到目标内存就可以了

Screenshot_20220111_213934.png

Code

data.asm

1
2
Data db 'Hi, I come from hard disk drive!'
db 0x00

readhdd.asm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
HDDPORT equ 0x1f0
NUL equ 0x00
SETCHAR equ 0x07
VIDEOMEM equ 0xb800
STRINGLEN equ 0xffff
section code align=16 vstart=0x7c00

mov si, [READSTART]
mov cx, [READSTART+0x02]
mov al, [SECTORNUM]
push ax

mov ax, [DESTMEN]
mov dx, [DESTMEN+0x02]
mov bx, 16
div bx

mov ds, ax
xor di, di
pop ax

call ReadHDD
xor si, si
call PrintString
jmp End

ReadHDD:
push ax
push bx
push cx
push dx

mov dx, HDDPORT+2
out dx, al

mov dx, HDDPORT+3
mov ax, si
out dx, al

mov dx, HDDPORT+4
mov al, ah
out dx, al

mov dx, HDDPORT+5
mov ax, cx
out dx, al

mov dx, HDDPORT+6
mov al, ah
mov ah, 0xe0
or al, ah
out dx, al

mov dx, HDDPORT+7
mov al, 0x20
out dx, al

.waits:
in al, dx
and al, 0x88
cmp al, 0x08
jnz .waits

mov dx, HDDPORT
mov cx, 256

.readword:
in ax, dx
mov [ds:di], ax
add di, 2
or ah, 0x00
jnz .readword

.return:
pop dx
pop cx
pop bx
pop ax

ret

PrintString:
.setup:
push ax
push bx
push cx
push dx
mov ax, VIDEOMEM
mov es, ax
xor di, di

mov bh, SETCHAR
mov cx, STRINGLEN

.printchar:
mov bl, [ds:si]
inc si
mov [es:di], bl
inc di
mov [es:di], bh
inc di
or bl, NUL
jz .return
loop .printchar
.return:
mov bx, di
pop dx
pop cx
pop bx
pop ax
ret

READSTART dd 10
SECTORNUM db 1
DESTMEN dd 0x10000

End: jmp End
times 510-($-$$) db 0
db 0x55, 0xaa

Screenshot_20220111_223359.png