Moved WS_EX_CLIENTEDGE to the correct location.
[reactos.git] / freeldr / freeldr / arch / i386 / diskint13.S
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 .text
21 .code16
22
23 #define ASM
24 #include <arch.h>
25
26
27 /*
28 * BOOL BiosInt13Read(ULONG Drive, ULONG Head, ULONG Track, ULONG Sector, ULONG SectorCount, PVOID Buffer);
29 */
30 _biosdisk_drive:
31 .long 0
32 _biosdisk_head:
33 .long 0
34 _biosdisk_track:
35 .long 0
36 _biosdisk_sector:
37 .long 0
38 _biosdisk_nsects:
39 .long 0
40 _biosdisk_buffer:
41 .long 0
42 _biosdisk_retval:
43 .long 0
44 _biosdisk_retrycount:
45 .byte 0
46 _biosdisk_error_code:
47 .byte 0
48 EXTERN(_BiosInt13Read)
49 .code32
50
51 pushal
52
53 /* Get parameters */
54 movl 0x24(%esp),%eax
55 movl %eax,_biosdisk_drive
56 movl 0x28(%esp),%eax
57 movl %eax,_biosdisk_head
58 movl 0x2c(%esp),%eax
59 movl %eax,_biosdisk_track
60 movl 0x30(%esp),%eax
61 movl %eax,_biosdisk_sector
62 movl 0x34(%esp),%eax
63 movl %eax,_biosdisk_nsects
64 movl 0x38(%esp),%eax
65 movl %eax,_biosdisk_buffer
66
67 call switch_to_real
68
69 .code16
70 pushw %es // Save this just in case
71 movb $3,_biosdisk_retrycount // Set the retry count to 3
72
73 _biosdisk_read:
74 movl _biosdisk_buffer,%eax // Get buffer address in eax
75 shrl $4,%eax // Make linear address into segment
76 movw %ax,%es // Load ES with segment
77 movl _biosdisk_buffer,%ebx // and BX with offset
78 andl $0x0f,%ebx // so that data gets loaded to [ES:BX]
79 movb _biosdisk_sector,%cl // Get the sector in CL
80 movw _biosdisk_track,%ax // Cylinder in AX
81 movb %al,%ch // Now put it in CH
82 rorb $1,%ah // Low 8 bits of cylinder in CH, high 2 bits
83 rorb $1,%ah // in CL shifted to bits 6 & 7
84 andb $0xc0,%ah // Clear out low six bits
85 orb %ah,%cl // Or with sector number
86 movb _biosdisk_head,%dh // Get the head
87 movb _biosdisk_drive,%dl // Get the drive
88 movb $2,%ah // BIOS int 0x13, function 2 - Read Disk Sectors
89 movb _biosdisk_nsects,%al // Number of sectors to read
90 int $0x13 // Read a sector
91
92 // I have recently learned that not all bioses return
93 // the sector read count in the AL register (at least mine doesn't)
94 // even if the sectors were read correctly. So instead
95 // of checking the sector read count we will rely solely
96 // on the carry flag being set on error
97
98 //jmp _biosdisk_done
99 //cmpb _biosdisk_nsects,%al // See how many sectors we actually read
100 //jne _biosdisk_error // Jump if no error
101
102 movb $1,%al // Set the return value to be one (will be set to zero later if needed)
103 jc _biosdisk_error // Jump if error (CF = 1 on error)
104 jmp _biosdisk_done
105
106
107 _biosdisk_error:
108 movb %ah,_biosdisk_error_code// Save the error code
109
110 cmpb $0x11,%ah // Check and see if it was a corrected ECC error
111 je _biosdisk_done // If so then the data is still good, if not fail
112
113 movb _biosdisk_retrycount,%al// Get the current retry count
114 decb %al // Decrement it
115 movb %al,_biosdisk_retrycount// Save it
116 cmpb $0,%al // Is it zero?
117 jz _biosdisk_zero // Yes, return zero
118
119 movb $0,%ah // BIOS int 0x13, function 0 - Reset Disk System
120 movb _biosdisk_drive,%dl // Get the drive
121 int $0x13 // Reset the disk system
122 jmp _biosdisk_read // Try reading again
123
124 _biosdisk_zero:
125 movb $0,%al // We will return zero
126
127 _biosdisk_done:
128 movzbl %al,%eax // Put the number of sectors read into EAX
129 movl %eax,_biosdisk_retval // Save it as the return value
130
131 popw %es // Restore ES
132 call switch_to_prot
133
134 .code32
135
136 popal
137
138 movl _biosdisk_retval,%eax // Get return value
139 //movl $1,%eax
140
141 ret
142
143 /*
144 * BOOL BiosInt13ReadExtended(ULONG Drive, ULONG Sector, ULONG SectorCount, PVOID Buffer);
145 */
146 _disk_address_packet:
147 _packet_size:
148 .byte 0x10
149 _packet_reserved:
150 .byte 0
151 _packet_sector_count:
152 .word 0
153 _packet_transfer_buffer_offset:
154 .word 0
155 _packet_transfer_buffer_segment:
156 .word 0
157 _packet_lba_sector_number:
158 .quad 0
159 _packet_64bit_flat_address:
160 .quad 0
161 _int13_extended_drive:
162 .long 0
163 _int13_extended_sector_count:
164 .long 0
165 _int13_extended_retval:
166 .long 0
167 _int13_extended_retrycount:
168 .byte 0
169 EXTERN(_BiosInt13ReadExtended)
170 .code32
171
172 pushal
173
174 /* Get parameters */
175 movl 0x24(%esp),%eax
176 movl %eax,_int13_extended_drive
177 movl 0x28(%esp),%eax
178 movl %eax,_packet_lba_sector_number
179 movl 0x2c(%esp),%eax
180 movw %ax,_packet_sector_count
181 movl %eax,_int13_extended_sector_count
182 movl 0x30(%esp),%eax // Get buffer address in eax
183 shrl $4,%eax // Make linear address into segment
184 movw %ax,_packet_transfer_buffer_segment // Save segment
185 movl 0x34(%esp),%eax // Get buffer address in eax
186 andl $0x0f,%eax // Make linear address into offset
187 movw %ax,_packet_transfer_buffer_offset // Save offset
188
189 call switch_to_real
190
191 .code16
192 pushw %es // Save this just in case
193 movb $3,_int13_extended_retrycount // Set the retry count to 3
194
195 _int13_extended_read:
196 movb _int13_extended_drive,%dl // Get the drive
197 movb $0x42,%ah // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
198 movw $_disk_address_packet,%si // DS:SI -> disk address packet
199 int $0x13 // Read sectors
200
201 jc _int13_extended_error // Jump if error (CF = 1 on error)
202
203 movl _int13_extended_sector_count,%eax // Get the sector count in eax
204 cmpw _packet_sector_count,%ax // See how many sectors we actually read (returned in disk address packet sector count)
205 jne _int13_extended_error // Jump if not equal
206
207 jmp _int13_extended_done
208
209
210 _int13_extended_error:
211 movb %ah,_biosdisk_error_code // Save the error code
212
213 cmpb $0x11,%ah // Check and see if it was a corrected ECC error
214 je _int13_extended_done // If so then the data is still good, if not fail
215
216 movb _int13_extended_retrycount,%al // Get the current retry count
217 decb %al // Decrement it
218 movb %al,_int13_extended_retrycount // Save it
219 cmpb $0,%al // Is it zero?
220 jz _int13_extended_zero // Yes, return zero
221
222 movb $0,%ah // BIOS int 0x13, function 0 - Reset Disk System
223 movb _int13_extended_drive,%dl // Get the drive
224 int $0x13 // Reset the disk system
225 jmp _int13_extended_read // Try reading again
226
227 _int13_extended_zero:
228 movb $0,%al // We will return zero
229
230 _int13_extended_done:
231 movzbl %al,%eax // Put the number of sectors read into EAX
232 movl %eax,_int13_extended_retval // Save it as the return value
233
234 popw %es // Restore ES
235 call switch_to_prot
236
237 .code32
238
239 popal
240
241 movl _int13_extended_retval,%eax // Get return value
242
243 ret
244
245 /*
246 * BOOL BiosInt13ExtensionsSupported(ULONG Drive);
247 */
248 _int13_extension_check_drive:
249 .long 0
250 _int13_extension_check_retval:
251 .long 0
252 EXTERN(_BiosInt13ExtensionsSupported)
253 .code32
254
255 pushal
256
257 /* Get parameters */
258 movl 0x24(%esp),%eax
259 movl %eax,_int13_extension_check_drive
260
261 call switch_to_real
262
263 .code16
264 // Now make sure this computer supports extended reads
265 movb $0x41,%ah // AH = 41h
266 movw $0x55aa,%bx // BX = 55AAh
267 movb _int13_extension_check_drive,%dl // DL = drive (80h-FFh)
268 int $0x13 // IBM/MS INT 13 Extensions - INSTALLATION CHECK
269 jc _int13_extension_check_error // CF set on error (extensions not supported)
270 cmpw $0xaa55,%bx // BX = AA55h if installed
271 jne _int13_extension_check_error
272 testb $1,%cl // CX = API subset support bitmap
273 jz _int13_extension_check_error // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
274
275 // If we get here then we passed all the int13 extension tests
276 movl $1,_int13_extension_check_retval // Set return value to TRUE
277 jmp _int13_extension_check_done
278
279 _int13_extension_check_error:
280
281 movl $0,_int13_extension_check_retval // The tests failed so return FALSE
282
283 _int13_extension_check_done:
284
285 call switch_to_prot
286
287 .code32
288
289 popal
290
291 movl _int13_extension_check_retval,%eax // Get return value
292
293 ret
294
295 /*
296 * ULONG BiosInt13GetLastErrorCode(VOID);
297 */
298 EXTERN(_BiosInt13GetLastErrorCode)
299 .code32
300
301 movzbl _biosdisk_error_code,%eax // Get return value
302
303 ret
304
305
306 /*
307 * void StopFloppyMotor(void);
308 *
309 * Stops the floppy drive from spinning, so that other software is
310 * jumped to with a known state.
311 */
312 EXTERN(_StopFloppyMotor)
313 .code32
314
315 pushal
316
317 call switch_to_real
318
319 .code16
320
321 movw $0x3F2, %dx
322 xorb %al, %al
323 outb %al, %dx
324
325 call switch_to_prot
326
327 .code32
328
329 popal
330
331 ret
332
333 /*
334 * int get_heads(int drive);
335 */
336 EXTERN(_get_heads)
337 .code32
338
339 pushal
340 push %es
341
342 /* Get drive */
343 movl 0x28(%esp),%eax
344 movl %eax,_biosdisk_drive
345
346 call switch_to_real
347
348 .code16
349
350 movb $0x08,%ah
351 movb _biosdisk_drive,%dl
352 int $0x13
353 jc _get_heads_error
354
355 movzbl %dh,%edx
356 incl %edx
357 movl %edx,_biosdisk_retval
358 jmp _get_heads_done
359
360 _get_heads_error:
361 movl $0xff,_biosdisk_retval
362
363 _get_heads_done:
364
365 call switch_to_prot
366
367 .code32
368
369 pop %es
370 popal
371
372 movl _biosdisk_retval,%eax // Get return value
373
374 ret
375
376 /*
377 * int get_cylinders(int drive);
378 */
379 EXTERN(_get_cylinders)
380 .code32
381
382 pushal
383 push %es
384
385 /* Get drive */
386 movl 0x28(%esp),%eax
387 movl %eax,_biosdisk_drive
388
389 call switch_to_real
390
391 .code16
392
393 movb $0x08,%ah
394 movb _biosdisk_drive,%dl
395 int $0x13
396 jc _get_cylinders_error
397
398 xorl %edx,%edx
399 andb $0xc0,%cl
400 shrb $0x06,%cl
401 movb %cl,%dh
402 movb %ch,%dl
403 incl %edx
404 movl %edx,_biosdisk_retval
405 jmp _get_cylinders_done
406
407 _get_cylinders_error:
408 movl $0xff,_biosdisk_retval
409
410 _get_cylinders_done:
411
412 call switch_to_prot
413
414 .code32
415
416 pop %es
417 popal
418
419 movl _biosdisk_retval,%eax // Get return value
420
421 ret
422
423 /*
424 * int get_sectors(int drive);
425 */
426 EXTERN(_get_sectors)
427 .code32
428
429 pushal
430 push %es
431
432 /* Get drive */
433 movl 0x28(%esp),%eax
434 movl %eax,_biosdisk_drive
435
436 call switch_to_real
437
438 .code16
439
440 movb $0x08,%ah
441 movb _biosdisk_drive,%dl
442 int $0x13
443 jc _get_sectors_error
444
445 andb $0x3f,%cl
446 movzbl %cl,%ecx
447 movl %ecx,_biosdisk_retval
448 jmp _get_sectors_done
449
450 _get_sectors_error:
451 movl $0xff,_biosdisk_retval
452
453 _get_sectors_done:
454
455 call switch_to_prot
456
457 .code32
458
459 pop %es
460 popal
461
462 movl _biosdisk_retval,%eax // Get return value
463
464 ret
465
466
467 /*
468 * BOOL BiosInt13GetDriveParameters(ULONG Drive, PGEOMETRY Geometry);
469 */
470 _bios_int13_cylinders:
471 .long 0
472 _bios_int13_heads:
473 .long 0
474 _bios_int13_sectors:
475 .long 0
476 _bios_int13_bytes_per_sector:
477 .long 0
478 _bios_int13_drive_parameters_struct_address:
479 .long 0
480 EXTERN(_BiosInt13GetDriveParameters)
481 .code32
482
483 pushal
484 push %es
485
486 /* Get drive */
487 movl 0x28(%esp),%eax
488 movl %eax,_biosdisk_drive
489 movl 0x2c(%esp),%eax
490 movl %eax,_bios_int13_drive_parameters_struct_address
491
492 call switch_to_real
493
494 .code16
495
496 movb $0x08,%ah
497 movb _biosdisk_drive,%dl
498 int $0x13
499 jc _BiosInt13GetDriveParameters_Error
500
501 // Get the heads
502 movzbl %dh,%eax
503 incl %eax
504 movl %eax,_bios_int13_heads
505
506 // Get the sectors
507 movw %cx,%dx
508 andb $0x3f,%dl
509 movzbl %dl,%edx
510 movl %edx,_bios_int13_sectors
511
512 // Get the cylinders
513 xorl %edx,%edx
514 andb $0xc0,%cl
515 shrb $0x06,%cl
516 movb %cl,%dh
517 movb %ch,%dl
518 incl %edx
519 movl %edx,_bios_int13_cylinders
520
521 // Get the bytes per sector
522 movl $512,_bios_int13_bytes_per_sector // Just assume 512 bytes per sector
523 movl $0x01,_biosdisk_retval
524 jmp _BiosInt13GetDriveParameters_Done
525
526 _BiosInt13GetDriveParameters_Error:
527 movl $0x00,_biosdisk_retval
528
529 _BiosInt13GetDriveParameters_Done:
530
531 call switch_to_prot
532
533 .code32
534
535 // Copy drive parameters to structure
536 movl $_bios_int13_cylinders,%esi
537 movl _bios_int13_drive_parameters_struct_address,%edi
538 movl $0x04,%ecx
539 cld
540 rep movsl
541
542 pop %es
543 popal
544
545 movl _biosdisk_retval,%eax // Get return value
546
547 ret
548
549