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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
|
%ifndef _DISK_ASM
%define _DISK_ASM
%include "stdio.asm"
disk_info:
push bp
mov bp, sp
xor dx, dx
mov ah, 41h
mov bx, 55aah
mov dl, [bp + 4] ; drive number {80h..ffh}
int 13h
jc .return
shr ax, 8
push dx
push cx
push ax
push disk_info_fmt
call printf
add sp, 6
.return:
mov sp, bp
pop bp
ret
disk_last_status:
push bp
mov bp, sp
; DL = drive number
mov ah, 01h ; BIOS get status of last drive operation
int 13h ; BIOS disk service
; carry set on error
mov sp, bp
pop bp
ret
disk_convert_status:
push bp
mov bp, sp
pusha
cmp ah, 00h ; Avoid writing "success" message
je .return
xor cx, cx
mov cx, ax ; AL contains the sector count
and cx, 00ffh ; store in CX
shr ax, 8 ; shift error code into AL
; This block handles AL when not 00h..11h
; The extended error values have no real order
cmp al, 20h
je .status_20
cmp al, 40h
je .status_40
cmp al, 80h
je .status_80
cmp al, 0AAh
je .status_AA
cmp al, 0BBh
je .status_BB
cmp al, 0CCh
je .status_CC
cmp al, 0E0h
je .status_E0
cmp al, 0FFh
je .status_FF
jmp .convert ; No match, convert AL as-is
; Adjust error code so that it can be indexed
; easily by error_msg_disk_table
.status_20:
mov al, 12h
jmp .convert
.status_40:
mov al, 13h
jmp .convert
.status_80:
mov al, 14h
jmp .convert
.status_AA:
mov al, 15h
jmp .convert
.status_BB:
mov al, 16h
jmp .convert
.status_CC:
mov al, 17h
jmp .convert
.status_E0:
mov al, 18h
jmp .convert
.status_FF:
mov al, 19h
jmp .convert
.convert:
mov bx, ax ; Get array index
imul bx, bx, 2 ; Calculate index offset
; in human speak: idx * (idx * WORD)
lea si, [error_msg_disk_table] ; Load address of table into source index
add si, bx ; Add calculated index offset
and dx, 00ffh ; get drive number
push word [si] ; error message
push dx ; drive number
push ax ; error code
push error_msg_disk_status_fmt
call printf ; Print error message
add sp, 8 ; Clean up stack
.return:
popa
mov sp, bp
pop bp
ret
disk_lba_chs:
push bp
mov bp, sp
mov ax, word [bp - 2] ; LBA
mov sp, bp
pop bp
ret
disk_reset:
push bp
mov bp, sp
pusha
mov ah, 00h ; reset disk
mov dl, [bp + 4] ; disk number
int 13h ; BIOS disk service
jnc .success
.success:
popa
mov sp, bp
pop bp
ret
disk_read:
push bp
mov bp, sp
push di
mov di, 3 ; retry counter
.readloop:
push ax
push bx
push cx
push dx
; AL = Sectors to read
; ES:BX = Buffer address
; CH = Cylinder (10 bits [6 & 7 of CL are MSB])
; CL = Sector (5 lower bits)
; DH = Head
; DL = Drive
mov ah, 02h ; BIOS - read disk sectors
int 13h ; BIOS disk service
jnc .success
call disk_convert_status
push dx
call disk_reset
add sp, 2
pop dx
pop cx
pop bx
pop ax
dec di
jnz .readloop
.success:
pop di
mov sp, bp
pop bp
ret
; data
align 2
drive0: dw 0
msg_disk_reset: db "Drive reset successful.", CR, 0
msg_disk_read: db "Sector read successful.", CR, 0
error_msg_disk_reset: db "Drive reset failed!", CR, 0
error_msg_disk_read: db "Drive read failed!", CR, 0
disk_info_fmt: db 'HDD(%c): INT 13h Ext: %x (%x)', CR, 0
error_msg_disk_status_fmt: db 'ERROR %x: Drive %x: %s', CR, 0
error_msg_disk:
eds_success: db "Success", 0 ; 00h
eds_invalid_command: db "Invalid command", 0
eds_address_mark: db "Cannot find address mark", 0
eds_write_protected: db "Attempted write on write protected disk", 0
eds_sector_not_found: db "Sector not found.", 0
eds_reset_failed: db "Reset failed.", 0
eds_disk_change_line_active: db "Disk change line active", 0
eds_drive_parameter_activity_failed: db "Drive parameter activity failed", 0
eds_dma_overrun: db "DMA overrun", 0
eds_dma_boundary_64: db "DMA over 64kb boundary", 0
eds_bad_sector: db "Bad sector detected", 0
eds_bad_cylinder: db "Bad cylinder detected", 0
eds_media_type_not_found: db "Media type not found", 0
eds_invalid_number_of_sectors: db "Invalid number of sectors", 0
eds_control_data_address_mark: db "Control data address mark detected", 0
eds_dma_out_of_range: db "DMA out of range", 0
eds_crc_ecc_data_error: db "CRC/ECC data error", 0 ; 10h
eds_ecc_corrected_data_error: db "ECC corrected data error", 0 ; 11h
; Everything was normal until... this...
eds_controller_failure: db "Controller failure", 0 ; 20h
eds_seek_failure: db "Seek failure", 0 ; 40h
eds_timeout: db "Drive timed out (not ready?)", 0 ; 80h
eds_not_ready: db "Drive not ready", 0 ; AAh
eds_undefined_error: db "Undefined error", 0 ; BBh
eds_write_fault: db "Write fault", 0 ; CCh
eds_status_error: db "Status error", 0 ; E0h
eds_sense_operation_failed: db "Sense operation failed", 0 ; FFh
error_msg_disk_table: ; is an array of pointers for each error message
dw eds_success
dw eds_invalid_command
dw eds_address_mark
dw eds_write_protected
dw eds_sector_not_found
dw eds_reset_failed
dw eds_disk_change_line_active
dw eds_drive_parameter_activity_failed
dw eds_dma_overrun
dw eds_dma_boundary_64
dw eds_bad_sector
dw eds_bad_cylinder
dw eds_media_type_not_found
dw eds_invalid_number_of_sectors
dw eds_control_data_address_mark
dw eds_dma_out_of_range
dw eds_crc_ecc_data_error
dw eds_ecc_corrected_data_error
dw eds_controller_failure
dw eds_seek_failure
dw eds_timeout
dw eds_not_ready
dw eds_undefined_error
dw eds_write_fault
dw eds_status_error
dw eds_sense_operation_failed
dw 0000h ; END of error_msg_disk_table
%endif ; _DISK_ASM
|