summaryrefslogtreecommitdiff
path: root/disk.asm
blob: 1843fcae027b65e281e10f39474eb211c9ebec70 (plain) (blame)
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.", ASCII_CR, 0
msg_disk_read: db "Sector read successful.", ASCII_CR, 0

error_msg_disk_reset: db "Drive reset failed!", ASCII_CR, 0
error_msg_disk_read: db "Drive read failed!", ASCII_CR, 0

disk_info_fmt: db 'HDD(%c): INT 13h Ext: %x (%x)', ASCII_CR, 0
error_msg_disk_status_fmt: db 'ERROR %x: Drive %x: %s', ASCII_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