3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
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.
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.
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.
31 /* Setup segment registers */
48 /* Store the boot drive */
59 /* We should never get here */
65 * Switches the processor to protected mode
68 EXTERN(switch_to_prot)
72 cli /* None of these */
74 /* Get the return address off the stack */
77 /* Save 16-bit stack pointer */
83 /* Enable Protected Mode */
88 /* Clear prefetch queue & correct CS */
89 ljmp $PMODE_CS, $inpmode
95 /* Setup segment selectors */
104 /* Put the return address back onto the stack */
107 /* Now return in p-mode! */
111 * Switches the processor back to real mode
114 EXTERN(switch_to_real)
118 /* Get the return address off the stack */
121 /* Save 32-bit stack pointer */
124 /* jmp to 16-bit segment to set the limit correctly */
125 ljmp $RMODE_CS, $switch_to_real16
130 /* Restore segment registers to correct limit */
138 /* Disable Protected Mode */
140 andl $CR0_PE_CLR,%eax
143 /* Clear prefetch queue & correct CS */
155 /* Put the return address back onto the stack */
158 sti /* These are ok now */
160 /* Now return in r-mode! */
165 * void putchar(int ch);
174 /* Get character to display */
177 /* If we are displaying a CR '\n' then do a LF also */
187 /* If we are displaying a TAB '\t' then display 8 spaces ' ' */
191 /* Display the 8 spaces ' ' */
212 /* Display the character via BIOS int 0x10 function 0x0e */
240 /* Int 0x10, AH = 0x0F - Get Current Video Mode */
244 /* Int 0x10, AH = 0x00 - Set Current Video Mode, also clears the screen */
269 /* Int 0x16, AH = 0x01 - Get Keyboard Status */
272 jz kbhit_1 // ZF=0 if no key is available
274 /* Return value is non-zero if a key is available */
279 /* Return value is zero if no key is available */
288 /* Get return value from ebx */
310 /* Check and see if we have an extended scancode to return */
311 movb extended_scancode,%al
312 movb $0,extended_scancode
317 /* Int 0x16, AH = 0x00 - Wait for keypress */
321 /* If al is zero then it is an extended key */
325 /* Save the scan code to be returned on the next call to getch() */
326 movb %ah,extended_scancode
329 /* Store character in ebx */
337 /* Get return value from ebx */
345 * void gotoxy(int x, int y);
355 /* Get cursor positions */
363 /* Update the cursor position */
379 * BOOL BiosInt13Read(ULONG Drive, ULONG Head, ULONG Track, ULONG Sector, ULONG SectorCount, PVOID Buffer);
395 _biosdisk_retrycount:
397 EXTERN(_BiosInt13Read)
409 movl %eax,_biosdisk_drive
411 movl %eax,_biosdisk_head
413 movl %eax,_biosdisk_track
415 movl %eax,_biosdisk_sector
417 movl %eax,_biosdisk_nsects
419 movl %eax,_biosdisk_buffer
424 pushw %es // Save this just in case
425 movb $3,_biosdisk_retrycount // Set the retry count to 3
428 movl _biosdisk_buffer,%eax // Get buffer address in eax
429 shrl $4,%eax // Make linear address into segment
430 movw %ax,%es // Load ES with segment
431 movl _biosdisk_buffer,%ebx // and BX with offset
432 andl $0x0f,%ebx // so that data gets loaded to [ES:BX]
433 movb _biosdisk_sector,%cl // Get the sector in CL
434 movw _biosdisk_track,%ax // Cylinder in AX
435 movb %al,%ch // Now put it in CH
436 rorb $1,%ah // Low 8 bits of cylinder in CH, high 2 bits
437 rorb $1,%ah // in CL shifted to bits 6 & 7
438 andb $0xc0,%ah // Clear out low six bits
439 orb %ah,%cl // Or with sector number
440 movb _biosdisk_head,%dh // Get the head
441 movb _biosdisk_drive,%dl // Get the drive
442 movb $2,%ah // BIOS int 0x13, function 2 - Read Disk Sectors
443 movb _biosdisk_nsects,%al // Number of sectors to read
444 int $0x13 // Read a sector
446 // I have recently learned that not all bioses return
447 // the sector read count in the AL register (at least mine doesn't)
448 // even if the sectors were read correctly. So instead
449 // of checking the sector read count we will rely solely
450 // on the carry flag being set on error
453 //cmpb _biosdisk_nsects,%al // See how many sectors we actually read
454 //jne _biosdisk_error // Jump if no error
456 movb $1,%al // Set the return value to be one (will be set to zero later if needed)
457 jc _biosdisk_error // Jump if error (CF = 1 on error)
462 cmpb $0x11,%ah // Check and see if it was a corrected ECC error
463 je _biosdisk_done // If so then the data is still good, if not fail
465 movb _biosdisk_retrycount,%al// Get the current retry count
466 decb %al // Decrement it
467 movb %al,_biosdisk_retrycount// Save it
468 cmpb $0,%al // Is it zero?
469 jz _biosdisk_zero // Yes, return zero
471 movb $0,%ah // BIOS int 0x13, function 0 - Reset Disk System
472 movb _biosdisk_drive,%dl // Get the drive
473 int $0x13 // Reset the disk system
474 jmp _biosdisk_read // Try reading again
477 movb $0,%al // We will return zero
480 movzbl %al,%eax // Put the number of sectors read into EAX
481 movl %eax,_biosdisk_retval // Save it as the return value
483 popw %es // Restore ES
488 movl _biosdisk_retval,%eax // Get return value
500 * BOOL BiosInt13ReadExtended(ULONG Drive, ULONG Sector, ULONG SectorCount, PVOID Buffer);
502 _disk_address_packet:
507 _packet_sector_count:
509 _packet_transfer_buffer_segment:
511 _packet_transfer_buffer_offset:
513 _packet_lba_sector_number:
515 _packet_64bit_flat_address:
517 _int13_extended_drive:
519 _int13_extended_sector_count:
521 _int13_extended_retval:
523 _int13_extended_retrycount:
525 EXTERN(_BiosInt13ReadExtended)
537 movl %eax,_int13_extended_drive
539 movl %eax,_packet_lba_sector_number
541 movw %ax,_packet_sector_count
542 movl %eax,_int13_extended_sector_count
543 movl 0x28(%esp),%eax // Get buffer address in eax
544 shrl $4,%eax // Make linear address into segment
545 movw %ax,_packet_transfer_buffer_segment // Save segment
546 movl 0x28(%esp),%eax // Get buffer address in eax
547 andl $0x0f,%eax // Make linear address into offset
548 movw %ax,_packet_transfer_buffer_offset // Save offset
553 pushw %es // Save this just in case
554 movb $3,_int13_extended_retrycount // Set the retry count to 3
556 _int13_extended_read:
557 movb _int13_extended_drive,%dl // Get the drive
558 movb $42,%ah // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
559 movw $_disk_address_packet,%si // DS:SI -> disk address packet
560 int $0x13 // Read sectors
562 movb $1,%al // Set the return value to be one (will be set to zero later if needed)
563 jc _int13_extended_error // Jump if error (CF = 1 on error)
565 movl _int13_extended_sector_count,%eax // Get the sector count in eax
566 cmpw _packet_sector_count,%ax // See how many sectors we actually read (returned in disk address packet sector count)
567 jne _int13_extended_error // Jump if not equal
569 jmp _int13_extended_done
572 _int13_extended_error:
573 cmpb $0x11,%ah // Check and see if it was a corrected ECC error
574 je _int13_extended_done // If so then the data is still good, if not fail
576 movb _int13_extended_retrycount,%al // Get the current retry count
577 decb %al // Decrement it
578 movb %al,_int13_extended_retrycount // Save it
579 cmpb $0,%al // Is it zero?
580 jz _int13_extended_zero // Yes, return zero
582 movb $0,%ah // BIOS int 0x13, function 0 - Reset Disk System
583 movb _int13_extended_drive,%dl // Get the drive
584 int $0x13 // Reset the disk system
585 jmp _int13_extended_read // Try reading again
587 _int13_extended_zero:
588 movb $0,%al // We will return zero
590 _int13_extended_done:
591 movzbl %al,%eax // Put the number of sectors read into EAX
592 movl %eax,_int13_extended_retval // Save it as the return value
594 popw %es // Restore ES
599 movl _int13_extended_retval,%eax // Get return value
611 * BOOL BiosInt13ExtensionsSupported(ULONG Drive);
613 _int13_extension_check_drive:
615 _int13_extension_check_retval:
617 EXTERN(_BiosInt13ExtensionsSupported)
629 movl %eax,_int13_extension_check_drive
634 // Now make sure this computer supports extended reads
635 movb $0x41,%ah // AH = 41h
636 movw $0x55aa,%bx // BX = 55AAh
637 movb _int13_extension_check_drive,%dl // DL = drive (80h-FFh)
638 int $0x13 // IBM/MS INT 13 Extensions - INSTALLATION CHECK
639 jc _int13_extension_check_error // CF set on error (extensions not supported)
640 cmpw $0x55aa,%bx // BX = AA55h if installed
641 jne _int13_extension_check_error
642 testb $1,%cl // CX = API subset support bitmap
643 jz _int13_extension_check_error // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
645 // If we get here then we passed all the int13 extension tests
646 movl $1,_int13_extension_check_retval // Set return value to TRUE
647 jmp _int13_extension_check_done
649 _int13_extension_check_error:
651 movl $0,_int13_extension_check_retval // The tests failed so return FALSE
653 _int13_extension_check_done:
659 movl _int13_extension_check_retval,%eax // Get return value
688 /* Convert from BCD to normal */
718 /* Save return value */
725 /* Restore return value */
753 /* Convert from BCD to normal */
764 /* Save return value */
771 /* Restore return value */
781 * int getmonth(void);
799 /* Convert from BCD to normal */
810 /* Save return value */
817 /* Restore return value */
845 /* Convert from BCD to normal */
856 /* Save return value */
863 /* Restore return value */
873 * int getminute(void);
891 /* Convert from BCD to normal */
902 /* Save return value */
909 /* Restore return value */
919 * int getsecond(void);
937 /* Convert from BCD to normal */
948 /* Save return value */
955 /* Restore return value */
965 * void hidecursor(void);
979 /* Hide the cursor */
995 * void showcursor(void);
1009 /* Show the cursor */
1040 /* Get the cursor position */
1045 /* Save return value */
1052 /* Restore return value */
1076 /* Get the cursor position */
1081 /* Save return value */
1088 /* Restore return value */
1098 * void stop_floppy(void);
1100 * Stops the floppy drive from spinning, so that other software is
1101 * jumped to with a known state.
1103 EXTERN(_stop_floppy)
1126 * int get_heads(int drive);
1138 movl 0x18(%esp),%eax
1139 movl %eax,_biosdisk_drive
1146 movb _biosdisk_drive,%dl
1152 movl %edx,_biosdisk_retval
1156 movl $0xff,_biosdisk_retval
1164 movl _biosdisk_retval,%eax // Get return value
1175 * int get_cylinders(int drive);
1177 EXTERN(_get_cylinders)
1187 movl 0x18(%esp),%eax
1188 movl %eax,_biosdisk_drive
1195 movb _biosdisk_drive,%dl
1197 jc _get_cylinders_error
1205 movl %edx,_biosdisk_retval
1206 jmp _get_cylinders_done
1208 _get_cylinders_error:
1209 movl $0xff,_biosdisk_retval
1211 _get_cylinders_done:
1217 movl _biosdisk_retval,%eax // Get return value
1228 * int get_sectors(int drive);
1230 EXTERN(_get_sectors)
1240 movl 0x18(%esp),%eax
1241 movl %eax,_biosdisk_drive
1248 movb _biosdisk_drive,%dl
1250 jc _get_sectors_error
1254 movl %ecx,_biosdisk_retval
1255 jmp _get_sectors_done
1258 movl $0xff,_biosdisk_retval
1266 movl _biosdisk_retval,%eax // Get return value
1278 * Needed for enabling the a20 address line
1282 .word 0x00eb,0x00eb // jmp $+2, jmp $+2
1289 * Enable the A20 address line (to allow access to over 1mb)
1297 movb $0xD1,%al // command write
1300 mov $0xDF,%al // A20 on
1311 /* 16-bit stack pointer */
1315 /* 32-bit stack pointer */
1319 /* 16-bit return address */
1323 /* 32-bit return address */
1328 .p2align 2 /* force 4-byte alignment */
1330 /* NULL Descriptor */
1336 /* 32-bit flat CS */
1342 /* 32-bit flat DS */
1348 /* 16-bit real mode CS */
1354 /* 16-bit real mode DS */
1360 /* GDT table pointer */
1362 .word 0x27 /* Limit */
1363 .long gdt /* Base Address */