1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.163 2006/07/07 16:10:37 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex x86 emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
125 #define DEBUG_ROMBIOS 1
128 #define DEBUG_INT13_HD 0
129 #define DEBUG_INT13_CD 0
130 #define DEBUG_INT13_ET 0
131 #define DEBUG_INT13_FL 0
132 #define DEBUG_INT15 0
133 #define DEBUG_INT16 0
134 #define DEBUG_INT1A 0
135 #define DEBUG_INT74 0
139 #define BX_USE_PS2_MOUSE 1
140 #define BX_CALL_INT15_4F 1
141 #define BX_USE_EBDA 1
142 #define BX_SUPPORT_FLOPPY 1
143 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
144 //#define BX_PCIBIOS 1
149 #define BX_USE_ATADRV 1
150 //#define BX_ELTORITO_BOOT 1
152 #define BX_MAX_ATA_INTERFACES 4
153 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
155 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
156 #define BX_DEBUG_SERIAL 1 /* output to COM1 */
158 /* model byte 0xFC = AT */
159 #define SYS_MODEL_ID 0xFC
160 #define SYS_SUBMODEL_ID 0x00
161 #define BIOS_REVISION 1
162 #define BIOS_CONFIG_TABLE 0xe6f5
164 #ifndef BIOS_BUILD_DATE
165 # define BIOS_BUILD_DATE "06/23/99"
168 // 1K of base memory used for Extended Bios Data Area (EBDA)
169 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
170 #define EBDA_SEG 0x9FC0
171 #define EBDA_SIZE 1 // In KiB
172 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
174 // Define the application NAME
176 # define BX_APPNAME "Plex86"
178 # define BX_APPNAME "Bochs"
182 #if BX_USE_ATADRV && BX_CPU<3
183 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
185 #if BX_USE_ATADRV && !BX_USE_EBDA
186 # error ATA/ATAPI Driver can only be used if EBDA is available
188 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
189 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
191 #if BX_PCIBIOS && BX_CPU<3
192 # error PCI BIOS can only be used with 386+ cpu
194 #if BX_APM && BX_CPU<3
195 # error APM BIOS can only be used with 386+ cpu
198 #define PANIC_PORT 0x400
199 #define PANIC_PORT2 0x401
200 #define INFO_PORT 0x402
201 #define DEBUG_PORT 0x403
203 // define this if you want to make PCIBIOS working on a specific bridge only
204 // undef enables PCIBIOS when at least one PCI device is found
205 // i440FX is emulated by Bochs and QEMU
206 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
209 // #$20 is hex 20 = 32
210 // #0x20 is hex 20 = 32
217 // all hex literals should be prefixed with '0x'
218 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
219 // no mov SEG-REG, #value, must mov register into seg-reg
220 // grep -i "mov[ ]*.s" rombios.c
222 // This is for compiling with gcc2 and gcc3
223 #define ASM_START #asm
224 #define ASM_END #endasm
238 ;; the HALT macro is called with the line number of the HALT call.
239 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
240 ;; to print a BX_PANIC message. This will normally halt the simulation
241 ;; with a message such as "BIOS panic at rombios.c, line 4091".
242 ;; However, users can choose to make panics non-fatal and continue.
269 typedef unsigned char Bit8u;
270 typedef unsigned short Bit16u;
271 typedef unsigned short bx_bool;
272 typedef unsigned long Bit32u;
276 void memsetb(seg,offset,value,count);
277 void memcpyb(dseg,doffset,sseg,soffset,count);
278 void memcpyd(dseg,doffset,sseg,soffset,count);
280 // memset of count bytes
282 memsetb(seg,offset,value,count)
297 mov cx, 10[bp] ; count
300 mov ax, 4[bp] ; segment
302 mov ax, 6[bp] ; offset
304 mov al, 8[bp] ; value
320 // memcpy of count bytes
322 memcpyb(dseg,doffset,sseg,soffset,count)
340 mov cx, 12[bp] ; count
343 mov ax, 4[bp] ; dsegment
345 mov ax, 6[bp] ; doffset
347 mov ax, 8[bp] ; ssegment
349 mov ax, 10[bp] ; soffset
367 // memcpy of count dword
369 memcpyd(dseg,doffset,sseg,soffset,count)
387 mov cx, 12[bp] ; count
390 mov ax, 4[bp] ; dsegment
392 mov ax, 6[bp] ; doffset
394 mov ax, 8[bp] ; ssegment
396 mov ax, 10[bp] ; soffset
414 #endif //BX_USE_ATADRV
416 // read_dword and write_dword functions
417 static Bit32u read_dword();
418 static void write_dword();
421 read_dword(seg, offset)
431 mov ax, 4[bp] ; segment
433 mov bx, 6[bp] ; offset
438 ;; ax = return value (word)
439 ;; dx = return value (word)
448 write_dword(seg, offset, data)
460 mov ax, 4[bp] ; segment
462 mov bx, 6[bp] ; offset
463 mov ax, 8[bp] ; data word
464 mov [bx], ax ; write data word
467 mov ax, 10[bp] ; data word
468 mov [bx], ax ; write data word
477 // Bit32u (unsigned long) and long helper functions
506 cmp eax, dword ptr [di]
525 mul eax, dword ptr [di]
621 // for access to RAM area which is used by interrupt vectors
622 // and BIOS Data Area
625 unsigned char filler1[0x400];
626 unsigned char filler2[0x6c];
632 #define BiosData ((bios_data_t *) 0)
636 Bit16u heads; // # heads
637 Bit16u cylinders; // # cylinders
638 Bit16u spt; // # sectors / track
658 Bit8u iface; // ISA or PCI
659 Bit16u iobase1; // IO Base 1
660 Bit16u iobase2; // IO Base 2
665 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
666 Bit8u device; // Detected type of attached devices (hd/cd/none)
667 Bit8u removable; // Removable device flag
668 Bit8u lock; // Locks for removable devices
669 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
670 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
671 Bit16u blksize; // block size
673 Bit8u translation; // type of translation
674 chs_t lchs; // Logical CHS
675 chs_t pchs; // Physical CHS
677 Bit32u sectors; // Total sectors count
682 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
685 ata_device_t devices[BX_MAX_ATA_DEVICES];
687 // map between (bios hd id - 0x80) and ata channels
688 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
690 // map between (bios cd id - 0xE0) and ata channels
691 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
693 // Buffer for DPTE table
696 // Count of transferred sectors and bytes
703 // ElTorito Device Emulation data
707 Bit8u emulated_drive;
708 Bit8u controller_index;
711 Bit16u buffer_segment;
718 #endif // BX_ELTORITO_BOOT
720 // for access to EBDA area
721 // The EBDA structure should conform to
722 // http://www.frontiernet.net/~fys/rombios.htm document
723 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
725 unsigned char filler1[0x3D];
727 // FDPT - Can be splitted in data members if needed
728 unsigned char fdpt0[0x10];
729 unsigned char fdpt1[0x10];
731 unsigned char filler2[0xC4];
737 // El Torito Emulation data
739 #endif // BX_ELTORITO_BOOT
743 #define EbdaData ((ebda_data_t *) 0)
745 // for access to the int13ext structure
756 #define Int13Ext ((int13ext_t *) 0)
758 // Disk Physical Table definition
765 Bit32u sector_count1;
766 Bit32u sector_count2;
777 Bit8u device_path[8];
782 #define Int13DPT ((dpt_t *) 0)
784 #endif // BX_USE_ATADRV
789 Bit16u di, si, bp, sp;
790 Bit16u bx, dx, cx, ax;
794 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
802 Bit32u edi, esi, ebp, esp;
803 Bit32u ebx, edx, ecx, eax;
806 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
807 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
835 #define SetCF(x) x.u.r8.flagsl |= 0x01
836 #define SetZF(x) x.u.r8.flagsl |= 0x40
837 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
838 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
839 #define GetCF(x) (x.u.r8.flagsl & 0x01)
850 static Bit8u inb_cmos();
852 static void outb_cmos();
855 static void init_rtc();
856 static bx_bool rtc_updating();
858 static Bit8u read_byte();
859 static Bit16u read_word();
860 static void write_byte();
861 static void write_word();
862 static void bios_printf();
864 static Bit8u inhibit_mouse_int_and_events();
865 static void enable_mouse_int_and_events();
866 static Bit8u send_to_mouse_ctrl();
867 static Bit8u get_mouse_data();
868 static void set_kbd_command_byte();
870 static void int09_function();
871 static void int13_harddisk();
872 static void int13_cdrom();
873 static void int13_cdemu();
874 static void int13_eltorito();
875 static void int13_diskette_function();
876 static void int14_function();
877 static void int15_function();
878 static void int16_function();
879 static void int17_function();
880 static Bit32u int19_function();
881 static void int1a_function();
882 static void int70_function();
883 static void int74_function();
884 static Bit16u get_CS();
885 static Bit16u get_SS();
886 static unsigned int enqueue_key();
887 static unsigned int dequeue_key();
888 static void get_hd_geometry();
889 static void set_diskette_ret_status();
890 static void set_diskette_current_cyl();
891 static void determine_floppy_media();
892 static bx_bool floppy_drive_exists();
893 static bx_bool floppy_drive_recal();
894 static bx_bool floppy_media_known();
895 static bx_bool floppy_media_sense();
896 static bx_bool set_enable_a20();
897 static void debugger_on();
898 static void debugger_off();
899 static void keyboard_init();
900 static void keyboard_panic();
901 static void shutdown_status_panic();
902 static void nmi_handler_msg();
904 static void print_bios_banner();
905 static void print_boot_device();
906 static void print_boot_failure();
907 static void print_cdromboot_failure();
911 // ATA / ATAPI driver
916 Bit16u ata_cmd_non_data();
917 Bit16u ata_cmd_data_in();
918 Bit16u ata_cmd_data_out();
919 Bit16u ata_cmd_packet();
921 Bit16u atapi_get_sense();
922 Bit16u atapi_is_ready();
923 Bit16u atapi_is_cdrom();
925 #endif // BX_USE_ATADRV
930 Bit8u cdemu_isactive();
931 Bit8u cdemu_emulated_drive();
935 #endif // BX_ELTORITO_BOOT
937 static char bios_cvs_version_string[] = "$Revision: 1.163 $ $Date: 2006/07/07 16:10:37 $";
939 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
941 #define BIOS_PRINTF_HALT 1
942 #define BIOS_PRINTF_SCREEN 2
943 #define BIOS_PRINTF_INFO 4
944 #define BIOS_PRINTF_DEBUG 8
945 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
946 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
948 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
950 // Defines the output macros.
951 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
952 // per-device basis. Debug info are sent only in debug mode
954 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
956 # define BX_DEBUG(format, p...)
958 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
959 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
962 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
964 # define BX_DEBUG_ATA(a...)
967 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
969 # define BX_DEBUG_INT13_HD(a...)
972 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
974 # define BX_DEBUG_INT13_CD(a...)
977 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
979 # define BX_DEBUG_INT13_ET(a...)
982 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
984 # define BX_DEBUG_INT13_FL(a...)
987 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
989 # define BX_DEBUG_INT15(a...)
992 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
994 # define BX_DEBUG_INT16(a...)
997 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
999 # define BX_DEBUG_INT1A(a...)
1002 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1004 # define BX_DEBUG_INT74(a...)
1007 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1008 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1009 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1010 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1011 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1012 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1013 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1014 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1016 #define GET_AL() ( AX & 0x00ff )
1017 #define GET_BL() ( BX & 0x00ff )
1018 #define GET_CL() ( CX & 0x00ff )
1019 #define GET_DL() ( DX & 0x00ff )
1020 #define GET_AH() ( AX >> 8 )
1021 #define GET_BH() ( BX >> 8 )
1022 #define GET_CH() ( CX >> 8 )
1023 #define GET_DH() ( DX >> 8 )
1025 #define GET_ELDL() ( ELDX & 0x00ff )
1026 #define GET_ELDH() ( ELDX >> 8 )
1028 #define SET_CF() FLAGS |= 0x0001
1029 #define CLEAR_CF() FLAGS &= 0xfffe
1030 #define GET_CF() (FLAGS & 0x0001)
1032 #define SET_ZF() FLAGS |= 0x0040
1033 #define CLEAR_ZF() FLAGS &= 0xffbf
1034 #define GET_ZF() (FLAGS & 0x0040)
1036 #define UNSUPPORTED_FUNCTION 0x86
1039 #define MAX_SCAN_CODE 0x58
1047 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1048 { none, none, none, none, none },
1049 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1050 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1051 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1052 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1053 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1054 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1055 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1056 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1057 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1058 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1059 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1060 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1061 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1062 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1063 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1064 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1065 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1066 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1067 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1068 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1069 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1070 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1071 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1072 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1073 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1074 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1075 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1076 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1077 { none, none, none, none, none }, /* L Ctrl */
1078 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1079 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1080 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1081 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1082 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1083 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1084 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1085 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1086 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1087 { 0x273b, 0x273a, none, none, none }, /* ;: */
1088 { 0x2827, 0x2822, none, none, none }, /* '" */
1089 { 0x2960, 0x297e, none, none, none }, /* `~ */
1090 { none, none, none, none, none }, /* L shift */
1091 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1092 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1093 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1094 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1095 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1096 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1097 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1098 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1099 { 0x332c, 0x333c, none, none, none }, /* ,< */
1100 { 0x342e, 0x343e, none, none, none }, /* .> */
1101 { 0x352f, 0x353f, none, none, none }, /* /? */
1102 { none, none, none, none, none }, /* R Shift */
1103 { 0x372a, 0x372a, none, none, none }, /* * */
1104 { none, none, none, none, none }, /* L Alt */
1105 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1106 { none, none, none, none, none }, /* caps lock */
1107 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1108 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1109 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1110 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1111 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1112 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1113 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1114 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1115 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1116 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1117 { none, none, none, none, none }, /* Num Lock */
1118 { none, none, none, none, none }, /* Scroll Lock */
1119 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1120 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1121 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1122 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1123 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1124 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1125 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1126 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1127 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1128 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1129 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1130 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1131 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1132 { none, none, none, none, none },
1133 { none, none, none, none, none },
1134 { none, none, none, none, none },
1135 { 0x5700, 0x5700, none, none, none }, /* F11 */
1136 { 0x5800, 0x5800, none, none, none } /* F12 */
1220 outb_cmos(cmos_reg, val)
1228 mov al, 4[bp] ;; cmos_reg
1230 mov al, 6[bp] ;; val
1245 mov al, 4[bp] ;; cmos_reg
1256 outb_cmos(0x0a, 0x26);
1257 outb_cmos(0x0b, 0x02);
1265 // This function checks to see if the update-in-progress bit
1266 // is set in CMOS Status Register A. If not, it returns 0.
1267 // If it is set, it tries to wait until there is a transition
1268 // to 0, and will return 0 if such a transition occurs. A 1
1269 // is returned only after timing out. The maximum period
1270 // that this bit should be set is constrained to 244useconds.
1271 // The count I use below guarantees coverage or more than
1272 // this time, with any reasonable IPS setting.
1277 while (--count != 0) {
1278 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1281 return(1); // update-in-progress never transitioned to 0
1286 read_byte(seg, offset)
1296 mov ax, 4[bp] ; segment
1298 mov bx, 6[bp] ; offset
1300 ;; al = return value (byte)
1309 read_word(seg, offset)
1319 mov ax, 4[bp] ; segment
1321 mov bx, 6[bp] ; offset
1323 ;; ax = return value (word)
1332 write_byte(seg, offset, data)
1344 mov ax, 4[bp] ; segment
1346 mov bx, 6[bp] ; offset
1347 mov al, 8[bp] ; data byte
1348 mov [bx], al ; write data byte
1358 write_word(seg, offset, data)
1370 mov ax, 4[bp] ; segment
1372 mov bx, 6[bp] ; offset
1373 mov ax, 8[bp] ; data word
1374 mov [bx], ax ; write data word
1400 /* serial debug port*/
1401 #define BX_DEBUG_PORT 0x03f8
1404 #define UART_RBR 0x00
1405 #define UART_THR 0x00
1408 #define UART_IER 0x01
1409 #define UART_IIR 0x02
1410 #define UART_FCR 0x02
1411 #define UART_LCR 0x03
1412 #define UART_MCR 0x04
1413 #define UART_DLL 0x00
1414 #define UART_DLM 0x01
1417 #define UART_LSR 0x05
1418 #define UART_MSR 0x06
1419 #define UART_SCR 0x07
1421 int uart_can_tx_byte(base_port)
1424 return inb(base_port + UART_LSR) & 0x20;
1427 void uart_wait_to_tx_byte(base_port)
1430 while (!uart_can_tx_byte(base_port));
1433 void uart_wait_until_sent(base_port)
1436 while (!(inb(base_port + UART_LSR) & 0x40));
1439 void uart_tx_byte(base_port, data)
1443 uart_wait_to_tx_byte(base_port);
1444 outb(base_port + UART_THR, data);
1445 uart_wait_until_sent(base_port);
1474 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1475 uart_tx_byte(BX_DEBUG_PORT, c);
1477 #if BX_VIRTUAL_PORTS
1478 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1479 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1481 if (action & BIOS_PRINTF_SCREEN) {
1482 if (c == '\n') wrch('\r');
1488 put_int(action, val, width, neg)
1493 short nval = val / 10;
1495 put_int(action, nval, width - 1, neg);
1497 while (--width > 0) send(action, ' ');
1498 if (neg) send(action, '-');
1500 send(action, val - (nval * 10) + '0');
1504 put_uint(action, val, width, neg)
1510 unsigned short nval = val / 10;
1512 put_uint(action, nval, width - 1, neg);
1514 while (--width > 0) send(action, ' ');
1515 if (neg) send(action, '-');
1517 send(action, val - (nval * 10) + '0');
1521 put_luint(action, val, width, neg)
1527 unsigned long nval = val / 10;
1529 put_luint(action, nval, width - 1, neg);
1531 while (--width > 0) send(action, ' ');
1532 if (neg) send(action, '-');
1534 send(action, val - (nval * 10) + '0');
1537 //--------------------------------------------------------------------------
1539 // A compact variable argument printf function which prints its output via
1540 // an I/O port so that it can be logged by Bochs/Plex.
1541 // Currently, only %x is supported (or %02x, %04x, etc).
1543 // Supports %[format_width][format]
1544 // where format can be d,x,c,s
1545 //--------------------------------------------------------------------------
1547 bios_printf(action, s)
1551 Bit8u c, format_char;
1555 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width;
1563 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1564 #if BX_VIRTUAL_PORTS
1565 outb(PANIC_PORT2, 0x00);
1567 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1570 while (c = read_byte(get_CS(), s)) {
1575 else if (in_format) {
1576 if ( (c>='0') && (c<='9') ) {
1577 format_width = (format_width * 10) + (c - '0');
1580 arg_ptr++; // increment to next arg
1581 arg = read_word(arg_seg, arg_ptr);
1583 if (format_width == 0)
1585 for (i=format_width-1; i>=0; i--) {
1586 nibble = (arg >> (4 * i)) & 0x000f;
1587 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1590 else if (c == 'u') {
1591 put_uint(action, arg, format_width, 0);
1593 else if (c == 'l') {
1595 arg_ptr++; /* increment to next arg */
1596 hibyte = read_word(arg_seg, arg_ptr);
1597 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1599 else if (c == 'd') {
1601 put_int(action, -arg, format_width - 1, 1);
1603 put_int(action, arg, format_width, 0);
1605 else if (c == 's') {
1606 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1608 else if (c == 'c') {
1612 BX_PANIC("bios_printf: unknown format\n");
1622 if (action & BIOS_PRINTF_HALT) {
1623 // freeze in a busy loop.
1633 //--------------------------------------------------------------------------
1635 //--------------------------------------------------------------------------
1636 // this file is based on LinuxBIOS implementation of keyboard.c
1637 // could convert to #asm to gain space
1644 /* ------------------- Flush buffers ------------------------*/
1645 /* Wait until buffer is empty */
1647 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1649 /* flush incoming keys */
1653 if (inb(0x64) & 0x01) {
1659 // Due to timer issues, and if the IPS setting is > 15000000,
1660 // the incoming keys might not be flushed here. That will
1661 // cause a panic a few lines below. See sourceforge bug report :
1662 // [ 642031 ] FATAL: Keyboard RESET error:993
1664 /* ------------------- controller side ----------------------*/
1665 /* send cmd = 0xAA, self test 8042 */
1668 /* Wait until buffer is empty */
1670 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1671 if (max==0x0) keyboard_panic(00);
1675 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1676 if (max==0x0) keyboard_panic(01);
1678 /* read self-test result, 0x55 should be returned from 0x60 */
1679 if ((inb(0x60) != 0x55)){
1680 keyboard_panic(991);
1683 /* send cmd = 0xAB, keyboard interface test */
1686 /* Wait until buffer is empty */
1688 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1689 if (max==0x0) keyboard_panic(10);
1693 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1694 if (max==0x0) keyboard_panic(11);
1696 /* read keyboard interface test result, */
1697 /* 0x00 should be returned form 0x60 */
1698 if ((inb(0x60) != 0x00)) {
1699 keyboard_panic(992);
1702 /* Enable Keyboard clock */
1706 /* ------------------- keyboard side ------------------------*/
1707 /* reset kerboard and self test (keyboard side) */
1710 /* Wait until buffer is empty */
1712 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1713 if (max==0x0) keyboard_panic(20);
1717 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1718 if (max==0x0) keyboard_panic(21);
1720 /* keyboard should return ACK */
1721 if ((inb(0x60) != 0xfa)) {
1722 keyboard_panic(993);
1727 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1728 if (max==0x0) keyboard_panic(31);
1730 if ((inb(0x60) != 0xaa)) {
1731 keyboard_panic(994);
1734 /* Disable keyboard */
1737 /* Wait until buffer is empty */
1739 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1740 if (max==0x0) keyboard_panic(40);
1744 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1745 if (max==0x0) keyboard_panic(41);
1747 /* keyboard should return ACK */
1748 if ((inb(0x60) != 0xfa)) {
1749 keyboard_panic(995);
1752 /* Write Keyboard Mode */
1755 /* Wait until buffer is empty */
1757 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1758 if (max==0x0) keyboard_panic(50);
1760 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1763 /* Wait until buffer is empty */
1765 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1766 if (max==0x0) keyboard_panic(60);
1768 /* Enable keyboard */
1771 /* Wait until buffer is empty */
1773 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1774 if (max==0x0) keyboard_panic(70);
1778 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1779 if (max==0x0) keyboard_panic(70);
1781 /* keyboard should return ACK */
1782 if ((inb(0x60) != 0xfa)) {
1783 keyboard_panic(996);
1790 //--------------------------------------------------------------------------
1792 //--------------------------------------------------------------------------
1794 keyboard_panic(status)
1797 // If you're getting a 993 keyboard panic here,
1798 // please see the comment in keyboard_init
1800 BX_PANIC("Keyboard error:%u\n",status);
1803 //--------------------------------------------------------------------------
1804 // shutdown_status_panic
1805 // called when the shutdown statsu is not implemented, displays the status
1806 //--------------------------------------------------------------------------
1808 shutdown_status_panic(status)
1811 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1814 //--------------------------------------------------------------------------
1815 // print_bios_banner
1816 // displays a the bios version
1817 //--------------------------------------------------------------------------
1821 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1822 BIOS_BUILD_DATE, bios_cvs_version_string);
1827 #ifdef BX_ELTORITO_BOOT
1833 //--------------------------------------------------------------------------
1834 // print_boot_device
1835 // displays the boot device
1836 //--------------------------------------------------------------------------
1838 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1841 print_boot_device(cdboot, drive)
1842 Bit8u cdboot; Bit16u drive;
1846 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1847 // drive contains real/emulated boot drive
1849 if(cdboot)i=2; // CD-Rom
1850 else if((drive&0x0080)==0x00)i=0; // Floppy
1851 else if((drive&0x0080)==0x80)i=1; // Hard drive
1854 printf("Booting from %s...\n",drivetypes[i]);
1857 //--------------------------------------------------------------------------
1858 // print_boot_failure
1859 // displays the reason why boot failed
1860 //--------------------------------------------------------------------------
1862 print_boot_failure(cdboot, drive, reason, lastdrive)
1863 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1865 Bit16u drivenum = drive&0x7f;
1867 // cdboot: 1 if boot from cd, 0 otherwise
1868 // drive : drive number
1869 // reason: 0 signature check failed, 1 read error
1870 // lastdrive: 1 boot drive is the last one in boot sequence
1873 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1874 else if (drive & 0x80)
1875 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1877 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1881 BX_PANIC("Not a bootable disk\n");
1883 BX_PANIC("Could not read the boot disk\n");
1887 //--------------------------------------------------------------------------
1888 // print_cdromboot_failure
1889 // displays the reason why boot failed
1890 //--------------------------------------------------------------------------
1892 print_cdromboot_failure( code )
1895 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1903 BX_PANIC("NMI Handler called\n");
1909 BX_PANIC("INT18: BOOT FAILURE\n");
1916 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1918 BX_INFO("%s\n", bios_cvs_version_string);
1927 // Use PS2 System Control port A to set A20 enable
1929 // get current setting first
1932 // change A20 status
1934 outb(0x92, oldval | 0x02);
1936 outb(0x92, oldval & 0xfd);
1938 return((oldval & 0x02) != 0);
1955 // ---------------------------------------------------------------------------
1956 // Start of ATA/ATAPI Driver
1957 // ---------------------------------------------------------------------------
1959 // Global defines -- ATA register and register bits.
1960 // command block & control block regs
1961 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1962 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1963 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1964 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1965 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1966 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1967 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1968 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1969 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1970 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1971 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1972 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1973 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1975 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1976 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1977 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1978 #define ATA_CB_ER_MC 0x20 // ATA media change
1979 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1980 #define ATA_CB_ER_MCR 0x08 // ATA media change request
1981 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
1982 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
1983 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
1985 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
1986 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
1987 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
1988 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
1989 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
1991 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
1992 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
1993 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
1994 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
1995 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
1997 // bits 7-4 of the device/head (CB_DH) reg
1998 #define ATA_CB_DH_DEV0 0xa0 // select device 0
1999 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2001 // status reg (CB_STAT and CB_ASTAT) bits
2002 #define ATA_CB_STAT_BSY 0x80 // busy
2003 #define ATA_CB_STAT_RDY 0x40 // ready
2004 #define ATA_CB_STAT_DF 0x20 // device fault
2005 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2006 #define ATA_CB_STAT_SKC 0x10 // seek complete
2007 #define ATA_CB_STAT_SERV 0x10 // service
2008 #define ATA_CB_STAT_DRQ 0x08 // data request
2009 #define ATA_CB_STAT_CORR 0x04 // corrected
2010 #define ATA_CB_STAT_IDX 0x02 // index
2011 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2012 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2014 // device control reg (CB_DC) bits
2015 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2016 #define ATA_CB_DC_SRST 0x04 // soft reset
2017 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2019 // Most mandtory and optional ATA commands (from ATA-3),
2020 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2021 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2022 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2023 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2024 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2025 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2026 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2027 #define ATA_CMD_DEVICE_RESET 0x08
2028 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2029 #define ATA_CMD_FLUSH_CACHE 0xE7
2030 #define ATA_CMD_FORMAT_TRACK 0x50
2031 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2032 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2033 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2034 #define ATA_CMD_IDLE1 0xE3
2035 #define ATA_CMD_IDLE2 0x97
2036 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2037 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2038 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2039 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2040 #define ATA_CMD_NOP 0x00
2041 #define ATA_CMD_PACKET 0xA0
2042 #define ATA_CMD_READ_BUFFER 0xE4
2043 #define ATA_CMD_READ_DMA 0xC8
2044 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2045 #define ATA_CMD_READ_MULTIPLE 0xC4
2046 #define ATA_CMD_READ_SECTORS 0x20
2047 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2048 #define ATA_CMD_RECALIBRATE 0x10
2049 #define ATA_CMD_SEEK 0x70
2050 #define ATA_CMD_SET_FEATURES 0xEF
2051 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2052 #define ATA_CMD_SLEEP1 0xE6
2053 #define ATA_CMD_SLEEP2 0x99
2054 #define ATA_CMD_STANDBY1 0xE2
2055 #define ATA_CMD_STANDBY2 0x96
2056 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2057 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2058 #define ATA_CMD_WRITE_BUFFER 0xE8
2059 #define ATA_CMD_WRITE_DMA 0xCA
2060 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2061 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2062 #define ATA_CMD_WRITE_SECTORS 0x30
2063 #define ATA_CMD_WRITE_VERIFY 0x3C
2065 #define ATA_IFACE_NONE 0x00
2066 #define ATA_IFACE_ISA 0x00
2067 #define ATA_IFACE_PCI 0x01
2069 #define ATA_TYPE_NONE 0x00
2070 #define ATA_TYPE_UNKNOWN 0x01
2071 #define ATA_TYPE_ATA 0x02
2072 #define ATA_TYPE_ATAPI 0x03
2074 #define ATA_DEVICE_NONE 0x00
2075 #define ATA_DEVICE_HD 0xFF
2076 #define ATA_DEVICE_CDROM 0x05
2078 #define ATA_MODE_NONE 0x00
2079 #define ATA_MODE_PIO16 0x00
2080 #define ATA_MODE_PIO32 0x01
2081 #define ATA_MODE_ISADMA 0x02
2082 #define ATA_MODE_PCIDMA 0x03
2083 #define ATA_MODE_USEIRQ 0x10
2085 #define ATA_TRANSLATION_NONE 0
2086 #define ATA_TRANSLATION_LBA 1
2087 #define ATA_TRANSLATION_LARGE 2
2088 #define ATA_TRANSLATION_RECHS 3
2090 #define ATA_DATA_NO 0x00
2091 #define ATA_DATA_IN 0x01
2092 #define ATA_DATA_OUT 0x02
2094 // ---------------------------------------------------------------------------
2095 // ATA/ATAPI driver : initialization
2096 // ---------------------------------------------------------------------------
2099 Bit16u ebda_seg=read_word(0x0040,0x000E);
2100 Bit8u channel, device;
2102 // Channels info init.
2103 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2104 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2105 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2106 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2107 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2110 // Devices info init.
2111 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2112 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2113 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2114 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2115 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2116 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2117 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2118 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2119 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2120 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2121 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2122 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2123 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2124 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2126 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2129 // hdidmap and cdidmap init.
2130 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2131 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2132 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2135 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2136 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2139 // ---------------------------------------------------------------------------
2140 // ATA/ATAPI driver : device detection
2141 // ---------------------------------------------------------------------------
2145 Bit16u ebda_seg=read_word(0x0040,0x000E);
2146 Bit8u hdcount, cdcount, device, type;
2147 Bit8u buffer[0x0200];
2150 #if BX_MAX_ATA_INTERFACES > 0
2151 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2152 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2153 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2154 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2156 #if BX_MAX_ATA_INTERFACES > 1
2157 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2158 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2159 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2160 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2162 #if BX_MAX_ATA_INTERFACES > 2
2163 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2164 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2165 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2166 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2168 #if BX_MAX_ATA_INTERFACES > 3
2169 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2170 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2171 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2172 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2174 #if BX_MAX_ATA_INTERFACES > 4
2175 #error Please fill the ATA interface informations
2181 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2182 Bit16u iobase1, iobase2;
2183 Bit8u channel, slave, shift;
2184 Bit8u sc, sn, cl, ch, st;
2186 channel = device / 2;
2189 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2190 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2192 // Disable interrupts
2193 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2196 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2197 outb(iobase1+ATA_CB_SC, 0x55);
2198 outb(iobase1+ATA_CB_SN, 0xaa);
2199 outb(iobase1+ATA_CB_SC, 0xaa);
2200 outb(iobase1+ATA_CB_SN, 0x55);
2201 outb(iobase1+ATA_CB_SC, 0x55);
2202 outb(iobase1+ATA_CB_SN, 0xaa);
2204 // If we found something
2205 sc = inb(iobase1+ATA_CB_SC);
2206 sn = inb(iobase1+ATA_CB_SN);
2208 if ( (sc == 0x55) && (sn == 0xaa) ) {
2209 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2211 // reset the channel
2214 // check for ATA or ATAPI
2215 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2216 sc = inb(iobase1+ATA_CB_SC);
2217 sn = inb(iobase1+ATA_CB_SN);
2218 if ((sc==0x01) && (sn==0x01)) {
2219 cl = inb(iobase1+ATA_CB_CL);
2220 ch = inb(iobase1+ATA_CB_CH);
2221 st = inb(iobase1+ATA_CB_STAT);
2223 if ((cl==0x14) && (ch==0xeb)) {
2224 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2225 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2226 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2227 } else if ((cl==0xff) && (ch==0xff)) {
2228 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2233 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2235 // Now we send a IDENTIFY command to ATA device
2236 if(type == ATA_TYPE_ATA) {
2238 Bit16u cylinders, heads, spt, blksize;
2239 Bit8u translation, removable, mode;
2241 //Temporary values to do the transfer
2242 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2243 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2245 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2246 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2248 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2249 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2250 blksize = read_word(get_SS(),buffer+10);
2252 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2253 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2254 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2256 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2258 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2259 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2260 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2261 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2262 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2263 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2264 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2265 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2266 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2268 translation = inb_cmos(0x39 + channel/2);
2269 for (shift=device%4; shift>0; shift--) translation >>= 2;
2270 translation &= 0x03;
2272 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2274 switch (translation) {
2275 case ATA_TRANSLATION_NONE:
2278 case ATA_TRANSLATION_LBA:
2281 case ATA_TRANSLATION_LARGE:
2284 case ATA_TRANSLATION_RECHS:
2288 switch (translation) {
2289 case ATA_TRANSLATION_NONE:
2291 case ATA_TRANSLATION_LBA:
2294 heads = sectors / 1024;
2295 if (heads>128) heads = 255;
2296 else if (heads>64) heads = 128;
2297 else if (heads>32) heads = 64;
2298 else if (heads>16) heads = 32;
2300 cylinders = sectors / heads;
2302 case ATA_TRANSLATION_RECHS:
2303 // Take care not to overflow
2305 if(cylinders>61439) cylinders=61439;
2307 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2309 // then go through the large bitshift process
2310 case ATA_TRANSLATION_LARGE:
2311 while(cylinders > 1024) {
2315 // If we max out the head count
2316 if (heads > 127) break;
2320 // clip to 1024 cylinders in lchs
2321 if (cylinders > 1024) cylinders=1024;
2322 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2324 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2325 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2326 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2329 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2333 // Now we send a IDENTIFY command to ATAPI device
2334 if(type == ATA_TYPE_ATAPI) {
2336 Bit8u type, removable, mode;
2339 //Temporary values to do the transfer
2340 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2341 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2343 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2344 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2346 type = read_byte(get_SS(),buffer+1) & 0x1f;
2347 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2348 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2351 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2352 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2353 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2354 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2357 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2364 Bit8u c, i, version, model[41];
2368 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2370 case ATA_TYPE_ATAPI:
2371 // Read ATA/ATAPI version
2372 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2373 for(version=15;version>0;version--) {
2374 if((ataversion&(1<<version))!=0)
2380 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2381 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2385 write_byte(get_SS(),model+40,0x00);
2387 if(read_byte(get_SS(),model+i)==0x20)
2388 write_byte(get_SS(),model+i,0x00);
2396 printf("ata%d %s: ",channel,slave?" slave":"master");
2397 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2398 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2400 case ATA_TYPE_ATAPI:
2401 printf("ata%d %s: ",channel,slave?" slave":"master");
2402 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2403 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2404 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2406 printf(" ATAPI-%d Device\n",version);
2408 case ATA_TYPE_UNKNOWN:
2409 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2415 // Store the devices counts
2416 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2417 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2418 write_byte(0x40,0x75, hdcount);
2422 // FIXME : should use bios=cmos|auto|disable bits
2423 // FIXME : should know about translation bits
2424 // FIXME : move hard_drive_post here
2428 // ---------------------------------------------------------------------------
2429 // ATA/ATAPI driver : software reset
2430 // ---------------------------------------------------------------------------
2432 // 8.2.1 Software reset - Device 0
2434 void ata_reset(device)
2437 Bit16u ebda_seg=read_word(0x0040,0x000E);
2438 Bit16u iobase1, iobase2;
2439 Bit8u channel, slave, sn, sc;
2442 channel = device / 2;
2445 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2446 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2450 // 8.2.1 (a) -- set SRST in DC
2451 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2453 // 8.2.1 (b) -- wait for BSY
2456 Bit8u status = inb(iobase1+ATA_CB_STAT);
2457 if ((status & ATA_CB_STAT_BSY) != 0) break;
2460 // 8.2.1 (f) -- clear SRST
2461 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2463 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2465 // 8.2.1 (g) -- check for sc==sn==0x01
2467 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2468 sc = inb(iobase1+ATA_CB_SC);
2469 sn = inb(iobase1+ATA_CB_SN);
2471 if ( (sc==0x01) && (sn==0x01) ) {
2473 // 8.2.1 (h) -- wait for not BSY
2476 Bit8u status = inb(iobase1+ATA_CB_STAT);
2477 if ((status & ATA_CB_STAT_BSY) == 0) break;
2482 // 8.2.1 (i) -- wait for DRDY
2485 Bit8u status = inb(iobase1+ATA_CB_STAT);
2486 if ((status & ATA_CB_STAT_RDY) != 0) break;
2489 // Enable interrupts
2490 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2493 // ---------------------------------------------------------------------------
2494 // ATA/ATAPI driver : execute a non data command
2495 // ---------------------------------------------------------------------------
2497 Bit16u ata_cmd_non_data()
2500 // ---------------------------------------------------------------------------
2501 // ATA/ATAPI driver : execute a data-in command
2502 // ---------------------------------------------------------------------------
2507 // 3 : expected DRQ=1
2508 // 4 : no sectors left to read/verify
2509 // 5 : more sectors to read/verify
2510 // 6 : no sectors left to write
2511 // 7 : more sectors to write
2512 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2513 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2516 Bit16u ebda_seg=read_word(0x0040,0x000E);
2517 Bit16u iobase1, iobase2, blksize;
2518 Bit8u channel, slave;
2519 Bit8u status, current, mode;
2521 channel = device / 2;
2524 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2525 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2526 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2527 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2528 if (mode == ATA_MODE_PIO32) blksize>>=2;
2531 // sector will be 0 only on lba access. Convert to lba-chs
2533 sector = (Bit16u) (lba & 0x000000ffL);
2535 cylinder = (Bit16u) (lba & 0x0000ffffL);
2537 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2540 // Reset count of transferred data
2541 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2542 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2545 status = inb(iobase1 + ATA_CB_STAT);
2546 if (status & ATA_CB_STAT_BSY) return 1;
2548 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2549 outb(iobase1 + ATA_CB_FR, 0x00);
2550 outb(iobase1 + ATA_CB_SC, count);
2551 outb(iobase1 + ATA_CB_SN, sector);
2552 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2553 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2554 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2555 outb(iobase1 + ATA_CB_CMD, command);
2558 status = inb(iobase1 + ATA_CB_STAT);
2559 if ( !(status & ATA_CB_STAT_BSY) ) break;
2562 if (status & ATA_CB_STAT_ERR) {
2563 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2565 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2566 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2570 // FIXME : move seg/off translation here
2573 sti ;; enable higher priority interrupts
2581 mov di, _ata_cmd_data_in.offset + 2[bp]
2582 mov ax, _ata_cmd_data_in.segment + 2[bp]
2583 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2585 ;; adjust if there will be an overrun. 2K max sector size
2587 jbe ata_in_no_adjust
2590 sub di, #0x0800 ;; sub 2 kbytes from offset
2591 add ax, #0x0080 ;; add 2 Kbytes to segment
2594 mov es, ax ;; segment in es
2596 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2598 mov ah, _ata_cmd_data_in.mode + 2[bp]
2599 cmp ah, #ATA_MODE_PIO32
2604 insw ;; CX words transfered from port(DX) to ES:[DI]
2609 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2612 mov _ata_cmd_data_in.offset + 2[bp], di
2613 mov _ata_cmd_data_in.segment + 2[bp], es
2618 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2620 status = inb(iobase1 + ATA_CB_STAT);
2622 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2623 != ATA_CB_STAT_RDY ) {
2624 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2630 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2631 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2632 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2638 // Enable interrupts
2639 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2643 // ---------------------------------------------------------------------------
2644 // ATA/ATAPI driver : execute a data-out command
2645 // ---------------------------------------------------------------------------
2650 // 3 : expected DRQ=1
2651 // 4 : no sectors left to read/verify
2652 // 5 : more sectors to read/verify
2653 // 6 : no sectors left to write
2654 // 7 : more sectors to write
2655 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2656 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2659 Bit16u ebda_seg=read_word(0x0040,0x000E);
2660 Bit16u iobase1, iobase2, blksize;
2661 Bit8u channel, slave;
2662 Bit8u status, current, mode;
2664 channel = device / 2;
2667 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2668 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2669 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2670 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2671 if (mode == ATA_MODE_PIO32) blksize>>=2;
2674 // sector will be 0 only on lba access. Convert to lba-chs
2676 sector = (Bit16u) (lba & 0x000000ffL);
2678 cylinder = (Bit16u) (lba & 0x0000ffffL);
2680 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2683 // Reset count of transferred data
2684 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2685 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2688 status = inb(iobase1 + ATA_CB_STAT);
2689 if (status & ATA_CB_STAT_BSY) return 1;
2691 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2692 outb(iobase1 + ATA_CB_FR, 0x00);
2693 outb(iobase1 + ATA_CB_SC, count);
2694 outb(iobase1 + ATA_CB_SN, sector);
2695 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2696 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2697 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2698 outb(iobase1 + ATA_CB_CMD, command);
2701 status = inb(iobase1 + ATA_CB_STAT);
2702 if ( !(status & ATA_CB_STAT_BSY) ) break;
2705 if (status & ATA_CB_STAT_ERR) {
2706 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2708 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2709 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2713 // FIXME : move seg/off translation here
2716 sti ;; enable higher priority interrupts
2724 mov si, _ata_cmd_data_out.offset + 2[bp]
2725 mov ax, _ata_cmd_data_out.segment + 2[bp]
2726 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2728 ;; adjust if there will be an overrun. 2K max sector size
2730 jbe ata_out_no_adjust
2733 sub si, #0x0800 ;; sub 2 kbytes from offset
2734 add ax, #0x0080 ;; add 2 Kbytes to segment
2737 mov es, ax ;; segment in es
2739 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2741 mov ah, _ata_cmd_data_out.mode + 2[bp]
2742 cmp ah, #ATA_MODE_PIO32
2748 outsw ;; CX words transfered from port(DX) to ES:[SI]
2754 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2757 mov _ata_cmd_data_out.offset + 2[bp], si
2758 mov _ata_cmd_data_out.segment + 2[bp], es
2763 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2765 status = inb(iobase1 + ATA_CB_STAT);
2767 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2768 != ATA_CB_STAT_RDY ) {
2769 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2775 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2776 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2777 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2783 // Enable interrupts
2784 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2788 // ---------------------------------------------------------------------------
2789 // ATA/ATAPI driver : execute a packet command
2790 // ---------------------------------------------------------------------------
2793 // 1 : error in parameters
2797 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2799 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2803 Bit16u ebda_seg=read_word(0x0040,0x000E);
2804 Bit16u iobase1, iobase2;
2805 Bit16u lcount, lbefore, lafter, count;
2806 Bit8u channel, slave;
2807 Bit8u status, mode, lmode;
2808 Bit32u total, transfer;
2810 channel = device / 2;
2813 // Data out is not supported yet
2814 if (inout == ATA_DATA_OUT) {
2815 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2819 // The header length must be even
2821 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2825 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2826 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2827 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2830 if (cmdlen < 12) cmdlen=12;
2831 if (cmdlen > 12) cmdlen=16;
2834 // Reset count of transferred data
2835 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2836 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2838 status = inb(iobase1 + ATA_CB_STAT);
2839 if (status & ATA_CB_STAT_BSY) return 2;
2841 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2842 // outb(iobase1 + ATA_CB_FR, 0x00);
2843 // outb(iobase1 + ATA_CB_SC, 0x00);
2844 // outb(iobase1 + ATA_CB_SN, 0x00);
2845 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2846 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2847 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2848 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2850 // Device should ok to receive command
2852 status = inb(iobase1 + ATA_CB_STAT);
2853 if ( !(status & ATA_CB_STAT_BSY) ) break;
2856 if (status & ATA_CB_STAT_ERR) {
2857 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2859 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2860 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2864 // Normalize address
2865 cmdseg += (cmdoff / 16);
2868 // Send command to device
2870 sti ;; enable higher priority interrupts
2875 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2876 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2877 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2878 mov es, ax ;; segment in es
2880 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2884 outsw ;; CX words transfered from port(DX) to ES:[SI]
2889 if (inout == ATA_DATA_NO) {
2890 status = inb(iobase1 + ATA_CB_STAT);
2895 status = inb(iobase1 + ATA_CB_STAT);
2897 // Check if command completed
2898 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2900 if (status & ATA_CB_STAT_ERR) {
2901 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2905 // Device must be ready to send data
2906 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2907 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2908 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
2912 // Normalize address
2913 bufseg += (bufoff / 16);
2916 // Get the byte count
2917 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
2919 // adjust to read what we want
2932 lafter=lcount-length;
2944 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
2945 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
2947 // If counts not dividable by 4, use 16bits mode
2949 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
2950 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
2951 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
2953 // adds an extra byte if count are odd. before is always even
2954 if (lcount & 0x01) {
2956 if ((lafter > 0) && (lafter & 0x01)) {
2961 if (lmode == ATA_MODE_PIO32) {
2962 lcount>>=2; lbefore>>=2; lafter>>=2;
2965 lcount>>=1; lbefore>>=1; lafter>>=1;
2974 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
2976 mov cx, _ata_cmd_packet.lbefore + 2[bp]
2977 jcxz ata_packet_no_before
2979 mov ah, _ata_cmd_packet.lmode + 2[bp]
2980 cmp ah, #ATA_MODE_PIO32
2981 je ata_packet_in_before_32
2983 ata_packet_in_before_16:
2985 loop ata_packet_in_before_16
2986 jmp ata_packet_no_before
2988 ata_packet_in_before_32:
2990 ata_packet_in_before_32_loop:
2992 loop ata_packet_in_before_32_loop
2995 ata_packet_no_before:
2996 mov cx, _ata_cmd_packet.lcount + 2[bp]
2997 jcxz ata_packet_after
2999 mov di, _ata_cmd_packet.bufoff + 2[bp]
3000 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3003 mov ah, _ata_cmd_packet.lmode + 2[bp]
3004 cmp ah, #ATA_MODE_PIO32
3009 insw ;; CX words transfered tp port(DX) to ES:[DI]
3010 jmp ata_packet_after
3014 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3017 mov cx, _ata_cmd_packet.lafter + 2[bp]
3018 jcxz ata_packet_done
3020 mov ah, _ata_cmd_packet.lmode + 2[bp]
3021 cmp ah, #ATA_MODE_PIO32
3022 je ata_packet_in_after_32
3024 ata_packet_in_after_16:
3026 loop ata_packet_in_after_16
3029 ata_packet_in_after_32:
3031 ata_packet_in_after_32_loop:
3033 loop ata_packet_in_after_32_loop
3040 // Compute new buffer address
3043 // Save transferred bytes count
3045 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3049 // Final check, device must be ready
3050 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3051 != ATA_CB_STAT_RDY ) {
3052 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3056 // Enable interrupts
3057 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3061 // ---------------------------------------------------------------------------
3062 // End of ATA/ATAPI Driver
3063 // ---------------------------------------------------------------------------
3065 // ---------------------------------------------------------------------------
3066 // Start of ATA/ATAPI generic functions
3067 // ---------------------------------------------------------------------------
3070 atapi_get_sense(device)
3077 memsetb(get_SS(),atacmd,0,12);
3082 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3085 if ((buffer[0] & 0x7e) == 0x70) {
3086 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3093 atapi_is_ready(device)
3099 memsetb(get_SS(),atacmd,0,12);
3102 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3105 if (atapi_get_sense(device) !=0 ) {
3106 memsetb(get_SS(),atacmd,0,12);
3108 // try to send Test Unit Ready again
3109 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3112 return atapi_get_sense(device);
3118 atapi_is_cdrom(device)
3121 Bit16u ebda_seg=read_word(0x0040,0x000E);
3123 if (device >= BX_MAX_ATA_DEVICES)
3126 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3129 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3135 // ---------------------------------------------------------------------------
3136 // End of ATA/ATAPI generic functions
3137 // ---------------------------------------------------------------------------
3139 #endif // BX_USE_ATADRV
3141 #if BX_ELTORITO_BOOT
3143 // ---------------------------------------------------------------------------
3144 // Start of El-Torito boot functions
3145 // ---------------------------------------------------------------------------
3150 Bit16u ebda_seg=read_word(0x0040,0x000E);
3152 // the only important data is this one for now
3153 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3159 Bit16u ebda_seg=read_word(0x0040,0x000E);
3161 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3165 cdemu_emulated_drive()
3167 Bit16u ebda_seg=read_word(0x0040,0x000E);
3169 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3172 static char isotag[6]="CD001";
3173 static char eltorito[24]="EL TORITO SPECIFICATION";
3175 // Returns ah: emulated drive, al: error code
3180 Bit16u ebda_seg=read_word(0x0040,0x000E);
3181 Bit8u atacmd[12], buffer[2048];
3183 Bit16u boot_segment, nbsectors, i, error;
3186 // Find out the first cdrom
3187 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3188 if (atapi_is_cdrom(device)) break;
3192 if(device >= BX_MAX_ATA_DEVICES) return 2;
3194 // Read the Boot Record Volume Descriptor
3195 memsetb(get_SS(),atacmd,0,12);
3196 atacmd[0]=0x28; // READ command
3197 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3198 atacmd[8]=(0x01 & 0x00ff); // Sectors
3199 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3200 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3201 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3202 atacmd[5]=(0x11 & 0x000000ff);
3203 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3207 if(buffer[0]!=0)return 4;
3209 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3212 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3214 // ok, now we calculate the Boot catalog address
3215 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3217 // And we read the Boot Catalog
3218 memsetb(get_SS(),atacmd,0,12);
3219 atacmd[0]=0x28; // READ command
3220 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3221 atacmd[8]=(0x01 & 0x00ff); // Sectors
3222 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3223 atacmd[3]=(lba & 0x00ff0000) >> 16;
3224 atacmd[4]=(lba & 0x0000ff00) >> 8;
3225 atacmd[5]=(lba & 0x000000ff);
3226 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3230 if(buffer[0x00]!=0x01)return 8; // Header
3231 if(buffer[0x01]!=0x00)return 9; // Platform
3232 if(buffer[0x1E]!=0x55)return 10; // key 1
3233 if(buffer[0x1F]!=0xAA)return 10; // key 2
3235 // Initial/Default Entry
3236 if(buffer[0x20]!=0x88)return 11; // Bootable
3238 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3239 if(buffer[0x21]==0){
3240 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3241 // Win2000 cd boot needs to know it booted from cd
3242 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3244 else if(buffer[0x21]<4)
3245 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3247 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3249 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3250 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3252 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3253 if(boot_segment==0x0000)boot_segment=0x07C0;
3255 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3256 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3258 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3259 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3261 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3262 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3264 // And we read the image in memory
3265 memsetb(get_SS(),atacmd,0,12);
3266 atacmd[0]=0x28; // READ command
3267 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3268 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3269 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3270 atacmd[3]=(lba & 0x00ff0000) >> 16;
3271 atacmd[4]=(lba & 0x0000ff00) >> 8;
3272 atacmd[5]=(lba & 0x000000ff);
3273 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3276 // Remember the media type
3277 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3278 case 0x01: // 1.2M floppy
3279 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3280 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3281 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3283 case 0x02: // 1.44M floppy
3284 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3285 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3286 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3288 case 0x03: // 2.88M floppy
3289 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3290 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3291 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3293 case 0x04: // Harddrive
3294 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3295 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3296 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3297 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3301 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3302 // Increase bios installed hardware number of devices
3303 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3304 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3306 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3310 // everything is ok, so from now on, the emulation is active
3311 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3312 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3314 // return the boot drive + no error
3315 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3318 // ---------------------------------------------------------------------------
3319 // End of El-Torito boot functions
3320 // ---------------------------------------------------------------------------
3321 #endif // BX_ELTORITO_BOOT
3324 int14_function(regs, ds, iret_addr)
3325 pusha_regs_t regs; // regs pushed from PUSHA instruction
3326 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3327 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3329 Bit16u addr,timer,val16;
3336 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3337 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3338 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3339 switch (regs.u.r8.ah) {
3341 outb(addr+3, inb(addr+3) | 0x80);
3342 if (regs.u.r8.al & 0xE0 == 0) {
3346 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3347 outb(addr, val16 & 0xFF);
3348 outb(addr+1, val16 >> 8);
3350 outb(addr+3, regs.u.r8.al & 0x1F);
3351 regs.u.r8.ah = inb(addr+5);
3352 regs.u.r8.al = inb(addr+6);
3353 ClearCF(iret_addr.flags);
3356 timer = read_word(0x0040, 0x006C);
3357 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3358 val16 = read_word(0x0040, 0x006C);
3359 if (val16 != timer) {
3364 if (timeout) outb(addr, regs.u.r8.al);
3365 regs.u.r8.ah = inb(addr+5);
3366 if (!timeout) regs.u.r8.ah |= 0x80;
3367 ClearCF(iret_addr.flags);
3370 timer = read_word(0x0040, 0x006C);
3371 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3372 val16 = read_word(0x0040, 0x006C);
3373 if (val16 != timer) {
3380 regs.u.r8.al = inb(addr);
3382 regs.u.r8.ah = inb(addr+5);
3384 ClearCF(iret_addr.flags);
3387 regs.u.r8.ah = inb(addr+5);
3388 regs.u.r8.al = inb(addr+6);
3389 ClearCF(iret_addr.flags);
3392 SetCF(iret_addr.flags); // Unsupported
3395 SetCF(iret_addr.flags); // Unsupported
3400 int15_function(regs, ES, DS, FLAGS)
3401 pusha_regs_t regs; // REGS pushed via pusha
3402 Bit16u ES, DS, FLAGS;
3404 Bit16u ebda_seg=read_word(0x0040,0x000E);
3405 bx_bool prev_a20_enable;
3414 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3416 switch (regs.u.r8.ah) {
3417 case 0x24: /* A20 Control */
3418 switch (regs.u.r8.al) {
3430 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3440 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3442 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3448 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3452 /* keyboard intercept */
3454 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3461 case 0x52: // removable media eject
3463 regs.u.r8.ah = 0; // "ok ejection may proceed"
3467 if( regs.u.r8.al == 0 ) {
3468 // Set Interval requested.
3469 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3470 // Interval not already set.
3471 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3472 write_word( 0x40, 0x98, ES ); // Byte location, segment
3473 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3474 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3475 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3477 irqDisable = inb( 0xA1 );
3478 outb( 0xA1, irqDisable & 0xFE );
3479 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3480 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3482 // Interval already set.
3483 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3485 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3487 } else if( regs.u.r8.al == 1 ) {
3488 // Clear Interval requested
3489 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3491 bRegister = inb_cmos( 0xB );
3492 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3494 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3496 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3505 # error "Int15 function 87h not supported on < 80386"
3507 // +++ should probably have descriptor checks
3508 // +++ should have exception handlers
3510 // turn off interrupts
3515 prev_a20_enable = set_enable_a20(1); // enable A20 line
3517 // 128K max of transfer on 386+ ???
3518 // source == destination ???
3520 // ES:SI points to descriptor table
3521 // offset use initially comments
3522 // ==============================================
3523 // 00..07 Unused zeros Null descriptor
3524 // 08..0f GDT zeros filled in by BIOS
3525 // 10..17 source ssssssss source of data
3526 // 18..1f dest dddddddd destination of data
3527 // 20..27 CS zeros filled in by BIOS
3528 // 28..2f SS zeros filled in by BIOS
3535 // check for access rights of source & dest here
3537 // Initialize GDT descriptor
3538 base15_00 = (ES << 4) + regs.u.r16.si;
3539 base23_16 = ES >> 12;
3540 if (base15_00 < (ES<<4))
3542 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3543 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3544 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3545 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3546 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3548 // Initialize CS descriptor
3549 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3550 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3551 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3552 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3553 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3555 // Initialize SS descriptor
3557 base15_00 = ss << 4;
3558 base23_16 = ss >> 12;
3559 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3560 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3561 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3562 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3563 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3567 // Compile generates locals offset info relative to SP.
3568 // Get CX (word count) from stack.
3571 mov cx, _int15_function.CX [bx]
3573 // since we need to set SS:SP, save them to the BDA
3574 // for future restore
3584 lidt [pmode_IDT_info]
3585 ;; perhaps do something with IDT here
3587 ;; set PE bit in CR0
3591 ;; far jump to flush CPU queue after transition to protected mode
3592 JMP_AP(0x0020, protected_mode)
3595 ;; GDT points to valid descriptor table, now load SS, DS, ES
3596 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3598 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3600 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3606 movsw ;; move CX words from DS:SI to ES:DI
3608 ;; make sure DS and ES limits are 64KB
3613 ;; reset PG bit in CR0 ???
3618 ;; far jump to flush CPU queue after transition to real mode
3619 JMP_AP(0xf000, real_mode)
3622 ;; restore IDT to normal real-mode defaults
3624 lidt [rmode_IDT_info]
3626 // restore SS:SP from the BDA
3634 set_enable_a20(prev_a20_enable);
3636 // turn back on interrupts
3647 // Get the amount of extended memory (above 1M)
3649 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3652 regs.u.r8.al = inb_cmos(0x30);
3653 regs.u.r8.ah = inb_cmos(0x31);
3656 if(regs.u.r16.ax > 0x3c00)
3657 regs.u.r16.ax = 0x3c00;
3664 /* Device busy interrupt. Called by Int 16h when no key available */
3668 /* Interrupt complete. Called by Int 16h when key becomes available */
3672 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3674 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3680 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3685 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3695 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3697 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3701 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3702 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3704 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3709 #if BX_USE_PS2_MOUSE
3711 int15_function_mouse(regs, ES, DS, FLAGS)
3712 pusha_regs_t regs; // REGS pushed via pusha
3713 Bit16u ES, DS, FLAGS;
3715 Bit16u ebda_seg=read_word(0x0040,0x000E);
3716 Bit8u mouse_flags_1, mouse_flags_2;
3717 Bit16u mouse_driver_seg;
3718 Bit16u mouse_driver_offset;
3719 Bit8u comm_byte, prev_command_byte;
3720 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3722 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3724 switch (regs.u.r8.ah) {
3726 // Return Codes status in AH
3727 // =========================
3729 // 01: invalid subfunction (AL > 7)
3730 // 02: invalid input value (out of allowable range)
3731 // 03: interface error
3732 // 04: resend command received from mouse controller,
3733 // device driver should attempt command again
3734 // 05: cannot enable mouse, since no far call has been installed
3735 // 80/86: mouse service not implemented
3737 switch (regs.u.r8.al) {
3738 case 0: // Disable/Enable Mouse
3739 BX_DEBUG_INT15("case 0:\n");
3740 switch (regs.u.r8.bh) {
3741 case 0: // Disable Mouse
3742 BX_DEBUG_INT15("case 0: disable mouse\n");
3743 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3744 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3746 ret = get_mouse_data(&mouse_data1);
3747 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3760 case 1: // Enable Mouse
3761 BX_DEBUG_INT15("case 1: enable mouse\n");
3762 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3763 if ( (mouse_flags_2 & 0x80) == 0 ) {
3764 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3766 regs.u.r8.ah = 5; // no far call installed
3769 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3770 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3772 ret = get_mouse_data(&mouse_data1);
3773 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3774 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3784 default: // invalid subfunction
3785 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3787 regs.u.r8.ah = 1; // invalid subfunction
3792 case 1: // Reset Mouse
3793 case 5: // Initialize Mouse
3794 BX_DEBUG_INT15("case 1 or 5:\n");
3795 if (regs.u.r8.al == 5) {
3796 if (regs.u.r8.bh != 3) {
3798 regs.u.r8.ah = 0x02; // invalid input
3801 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3802 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3803 mouse_flags_1 = 0x00;
3804 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3805 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3808 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3809 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3811 ret = get_mouse_data(&mouse_data3);
3812 // if no mouse attached, it will return RESEND
3813 if (mouse_data3 == 0xfe) {
3817 if (mouse_data3 != 0xfa)
3818 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3820 ret = get_mouse_data(&mouse_data1);
3822 ret = get_mouse_data(&mouse_data2);
3824 // turn IRQ12 and packet generation on
3825 enable_mouse_int_and_events();
3828 regs.u.r8.bl = mouse_data1;
3829 regs.u.r8.bh = mouse_data2;
3841 case 2: // Set Sample Rate
3842 BX_DEBUG_INT15("case 2:\n");
3843 switch (regs.u.r8.bh) {
3844 case 0: mouse_data1 = 10; break; // 10 reports/sec
3845 case 1: mouse_data1 = 20; break; // 20 reports/sec
3846 case 2: mouse_data1 = 40; break; // 40 reports/sec
3847 case 3: mouse_data1 = 60; break; // 60 reports/sec
3848 case 4: mouse_data1 = 80; break; // 80 reports/sec
3849 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3850 case 6: mouse_data1 = 200; break; // 200 reports/sec
3851 default: mouse_data1 = 0;
3853 if (mouse_data1 > 0) {
3854 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3856 ret = get_mouse_data(&mouse_data2);
3857 ret = send_to_mouse_ctrl(mouse_data1);
3858 ret = get_mouse_data(&mouse_data2);
3864 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3869 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3873 case 3: // Set Resolution
3874 BX_DEBUG_INT15("case 3:\n");
3876 // 0 = 25 dpi, 1 count per millimeter
3877 // 1 = 50 dpi, 2 counts per millimeter
3878 // 2 = 100 dpi, 4 counts per millimeter
3879 // 3 = 200 dpi, 8 counts per millimeter
3884 case 4: // Get Device ID
3885 BX_DEBUG_INT15("case 4:\n");
3886 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3887 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3889 ret = get_mouse_data(&mouse_data1);
3890 ret = get_mouse_data(&mouse_data2);
3893 regs.u.r8.bh = mouse_data2;
3897 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3901 case 6: // Return Status & Set Scaling Factor...
3902 BX_DEBUG_INT15("case 6:\n");
3903 switch (regs.u.r8.bh) {
3904 case 0: // Return Status
3905 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3906 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
3908 ret = get_mouse_data(&mouse_data1);
3909 if (mouse_data1 != 0xfa)
3910 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
3912 ret = get_mouse_data(&mouse_data1);
3914 ret = get_mouse_data(&mouse_data2);
3916 ret = get_mouse_data(&mouse_data3);
3920 regs.u.r8.bl = mouse_data1;
3921 regs.u.r8.cl = mouse_data2;
3922 regs.u.r8.dl = mouse_data3;
3923 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3934 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3937 case 1: // Set Scaling Factor to 1:1
3938 case 2: // Set Scaling Factor to 2:1
3939 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3940 if (regs.u.r8.bh == 1) {
3941 ret = send_to_mouse_ctrl(0xE6);
3943 ret = send_to_mouse_ctrl(0xE7);
3946 get_mouse_data(&mouse_data1);
3947 ret = (mouse_data1 != 0xFA);
3955 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3957 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3961 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
3965 case 7: // Set Mouse Handler Address
3966 BX_DEBUG_INT15("case 7:\n");
3967 mouse_driver_seg = ES;
3968 mouse_driver_offset = regs.u.r16.bx;
3969 write_word(ebda_seg, 0x0022, mouse_driver_offset);
3970 write_word(ebda_seg, 0x0024, mouse_driver_seg);
3971 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3972 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
3973 /* remove handler */
3974 if ( (mouse_flags_2 & 0x80) != 0 ) {
3975 mouse_flags_2 &= ~0x80;
3976 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3980 /* install handler */
3981 mouse_flags_2 |= 0x80;
3983 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3989 BX_DEBUG_INT15("case default:\n");
3990 regs.u.r8.ah = 1; // invalid function
3996 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3997 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3999 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4006 void set_e820_range(ES, DI, start, end, type)
4013 write_word(ES, DI, start);
4014 write_word(ES, DI+2, start >> 16);
4015 write_word(ES, DI+4, 0x00);
4016 write_word(ES, DI+6, 0x00);
4019 write_word(ES, DI+8, end);
4020 write_word(ES, DI+10, end >> 16);
4021 write_word(ES, DI+12, 0x0000);
4022 write_word(ES, DI+14, 0x0000);
4024 write_word(ES, DI+16, type);
4025 write_word(ES, DI+18, 0x0);
4029 int15_function32(regs, ES, DS, FLAGS)
4030 pushad_regs_t regs; // REGS pushed via pushad
4031 Bit16u ES, DS, FLAGS;
4033 Bit32u extended_memory_size=0; // 64bits long
4036 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4038 switch (regs.u.r8.ah) {
4040 // Wait for CX:DX microseconds. currently using the
4041 // refresh request port 0x61 bit4, toggling every 15usec
4049 ;; Get the count in eax
4052 mov ax, _int15_function.CX [bx]
4055 mov ax, _int15_function.DX [bx]
4057 ;; convert to numbers of 15usec ticks
4063 ;; wait for ecx number of refresh requests
4084 switch(regs.u.r8.al)
4086 case 0x20: // coded by osmaker aka K.J.
4087 if(regs.u.r32.edx == 0x534D4150)
4089 switch(regs.u.r16.bx)
4092 set_e820_range(ES, regs.u.r16.di,
4093 0x0000000L, 0x0009fc00L, 1);
4095 regs.u.r32.eax = 0x534D4150;
4096 regs.u.r32.ecx = 0x14;
4101 set_e820_range(ES, regs.u.r16.di,
4102 0x0009fc00L, 0x000a0000L, 2);
4104 regs.u.r32.eax = 0x534D4150;
4105 regs.u.r32.ecx = 0x14;
4110 set_e820_range(ES, regs.u.r16.di,
4111 0x000e8000L, 0x00100000L, 2);
4113 regs.u.r32.eax = 0x534D4150;
4114 regs.u.r32.ecx = 0x14;
4119 extended_memory_size = inb_cmos(0x35);
4120 extended_memory_size <<= 8;
4121 extended_memory_size |= inb_cmos(0x34);
4122 extended_memory_size *= 64;
4123 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4125 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4127 extended_memory_size *= 1024;
4128 extended_memory_size += (16L * 1024 * 1024);
4130 if(extended_memory_size <= (16L * 1024 * 1024))
4132 extended_memory_size = inb_cmos(0x31);
4133 extended_memory_size <<= 8;
4134 extended_memory_size |= inb_cmos(0x30);
4135 extended_memory_size *= 1024;
4138 set_e820_range(ES, regs.u.r16.di,
4139 0x00100000L, extended_memory_size, 1);
4141 regs.u.r32.eax = 0x534D4150;
4142 regs.u.r32.ecx = 0x14;
4147 /* 256KB BIOS area at the end of 4 GB */
4148 set_e820_range(ES, regs.u.r16.di,
4149 0xfffc0000L, 0x00000000L, 2);
4151 regs.u.r32.eax = 0x534D4150;
4152 regs.u.r32.ecx = 0x14;
4155 default: /* AX=E820, DX=534D4150, BX unrecognized */
4156 goto int15_unimplemented;
4160 // if DX != 0x534D4150)
4161 goto int15_unimplemented;
4166 // do we have any reason to fail here ?
4169 // my real system sets ax and bx to 0
4170 // this is confirmed by Ralph Brown list
4171 // but syslinux v1.48 is known to behave
4172 // strangely if ax is set to 0
4173 // regs.u.r16.ax = 0;
4174 // regs.u.r16.bx = 0;
4176 // Get the amount of extended memory (above 1M)
4177 regs.u.r8.cl = inb_cmos(0x30);
4178 regs.u.r8.ch = inb_cmos(0x31);
4181 if(regs.u.r16.cx > 0x3c00)
4183 regs.u.r16.cx = 0x3c00;
4186 // Get the amount of extended memory above 16M in 64k blocs
4187 regs.u.r8.dl = inb_cmos(0x34);
4188 regs.u.r8.dh = inb_cmos(0x35);
4190 // Set configured memory equal to extended memory
4191 regs.u.r16.ax = regs.u.r16.cx;
4192 regs.u.r16.bx = regs.u.r16.dx;
4194 default: /* AH=0xE8?? but not implemented */
4195 goto int15_unimplemented;
4198 int15_unimplemented:
4199 // fall into the default
4201 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4202 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4204 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4210 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4211 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4213 Bit8u scan_code, ascii_code, shift_flags, count;
4214 Bit16u kbd_code, max;
4216 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4219 case 0x00: /* read keyboard input */
4221 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4222 BX_PANIC("KBD: int16h: out of keyboard input\n");
4224 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4225 else if (ascii_code == 0xE0) ascii_code = 0;
4226 AX = (scan_code << 8) | ascii_code;
4229 case 0x01: /* check keyboard status */
4230 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4234 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4235 else if (ascii_code == 0xE0) ascii_code = 0;
4236 AX = (scan_code << 8) | ascii_code;
4240 case 0x02: /* get shift flag status */
4241 shift_flags = read_byte(0x0040, 0x17);
4242 SET_AL(shift_flags);
4245 case 0x05: /* store key-stroke into buffer */
4246 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4254 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4255 // bit Bochs Description
4257 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4258 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4259 // 4 1 INT 16/AH=0Ah supported
4260 // 3 0 INT 16/AX=0306h supported
4261 // 2 0 INT 16/AX=0305h supported
4262 // 1 0 INT 16/AX=0304h supported
4263 // 0 0 INT 16/AX=0300h supported
4268 case 0x0A: /* GET KEYBOARD ID */
4274 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4276 if ((inb(0x60) == 0xfa)) {
4279 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4282 kbd_code |= (inb(0x60) << 8);
4284 } while (--count>0);
4290 case 0x10: /* read MF-II keyboard input */
4292 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4293 BX_PANIC("KBD: int16h: out of keyboard input\n");
4295 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4296 AX = (scan_code << 8) | ascii_code;
4299 case 0x11: /* check MF-II keyboard status */
4300 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4304 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4305 AX = (scan_code << 8) | ascii_code;
4309 case 0x12: /* get extended keyboard status */
4310 shift_flags = read_byte(0x0040, 0x17);
4311 SET_AL(shift_flags);
4312 shift_flags = read_byte(0x0040, 0x18) & 0x73;
4313 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
4314 SET_AH(shift_flags);
4315 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4318 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4319 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4322 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4323 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4327 if (GET_AL() == 0x08)
4328 SET_AH(0x02); // unsupported, aka normal keyboard
4331 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4336 dequeue_key(scan_code, ascii_code, incr)
4341 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4346 buffer_start = 0x001E;
4347 buffer_end = 0x003E;
4349 buffer_start = read_word(0x0040, 0x0080);
4350 buffer_end = read_word(0x0040, 0x0082);
4353 buffer_head = read_word(0x0040, 0x001a);
4354 buffer_tail = read_word(0x0040, 0x001c);
4356 if (buffer_head != buffer_tail) {
4358 acode = read_byte(0x0040, buffer_head);
4359 scode = read_byte(0x0040, buffer_head+1);
4360 write_byte(ss, ascii_code, acode);
4361 write_byte(ss, scan_code, scode);
4365 if (buffer_head >= buffer_end)
4366 buffer_head = buffer_start;
4367 write_word(0x0040, 0x001a, buffer_head);
4376 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4379 inhibit_mouse_int_and_events()
4381 Bit8u command_byte, prev_command_byte;
4383 // Turn off IRQ generation and aux data line
4384 if ( inb(0x64) & 0x02 )
4385 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4386 outb(0x64, 0x20); // get command byte
4387 while ( (inb(0x64) & 0x01) != 0x01 );
4388 prev_command_byte = inb(0x60);
4389 command_byte = prev_command_byte;
4390 //while ( (inb(0x64) & 0x02) );
4391 if ( inb(0x64) & 0x02 )
4392 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4393 command_byte &= 0xfd; // turn off IRQ 12 generation
4394 command_byte |= 0x20; // disable mouse serial clock line
4395 outb(0x64, 0x60); // write command byte
4396 outb(0x60, command_byte);
4397 return(prev_command_byte);
4401 enable_mouse_int_and_events()
4405 // Turn on IRQ generation and aux data line
4406 if ( inb(0x64) & 0x02 )
4407 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4408 outb(0x64, 0x20); // get command byte
4409 while ( (inb(0x64) & 0x01) != 0x01 );
4410 command_byte = inb(0x60);
4411 //while ( (inb(0x64) & 0x02) );
4412 if ( inb(0x64) & 0x02 )
4413 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4414 command_byte |= 0x02; // turn on IRQ 12 generation
4415 command_byte &= 0xdf; // enable mouse serial clock line
4416 outb(0x64, 0x60); // write command byte
4417 outb(0x60, command_byte);
4421 send_to_mouse_ctrl(sendbyte)
4426 // wait for chance to write to ctrl
4427 if ( inb(0x64) & 0x02 )
4428 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4430 outb(0x60, sendbyte);
4436 get_mouse_data(data)
4442 while ( (inb(0x64) & 0x21) != 0x21 ) {
4445 response = inb(0x60);
4448 write_byte(ss, data, response);
4453 set_kbd_command_byte(command_byte)
4456 if ( inb(0x64) & 0x02 )
4457 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4460 outb(0x64, 0x60); // write command byte
4461 outb(0x60, command_byte);
4465 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4466 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4468 Bit8u scancode, asciicode, shift_flags;
4469 Bit8u mf2_flags, mf2_state, led_flags;
4472 // DS has been set to F000 before call
4476 scancode = GET_AL();
4478 if (scancode == 0) {
4479 BX_INFO("KBD: int09 handler: AL=0\n");
4484 shift_flags = read_byte(0x0040, 0x17);
4485 mf2_flags = read_byte(0x0040, 0x18);
4486 mf2_state = read_byte(0x0040, 0x96);
4487 led_flags = read_byte(0x0040, 0x97);
4491 case 0x3a: /* Caps Lock press */
4492 shift_flags ^= 0x40;
4493 write_byte(0x0040, 0x17, shift_flags);
4496 write_byte(0x0040, 0x18, mf2_flags);
4497 write_byte(0x0040, 0x97, led_flags);
4499 case 0xba: /* Caps Lock release */
4501 write_byte(0x0040, 0x18, mf2_flags);
4504 case 0x2a: /* L Shift press */
4505 shift_flags |= 0x02;
4506 write_byte(0x0040, 0x17, shift_flags);
4508 case 0xaa: /* L Shift release */
4509 shift_flags &= ~0x02;
4510 write_byte(0x0040, 0x17, shift_flags);
4513 case 0x36: /* R Shift press */
4514 shift_flags |= 0x01;
4515 write_byte(0x0040, 0x17, shift_flags);
4517 case 0xb6: /* R Shift release */
4518 shift_flags &= ~0x01;
4519 write_byte(0x0040, 0x17, shift_flags);
4522 case 0x1d: /* Ctrl press */
4523 if ((mf2_state & 0x01) == 0) {
4524 shift_flags |= 0x04;
4525 write_byte(0x0040, 0x17, shift_flags);
4526 if (mf2_state & 0x02) {
4528 write_byte(0x0040, 0x96, mf2_state);
4531 write_byte(0x0040, 0x18, mf2_flags);
4535 case 0x9d: /* Ctrl release */
4536 if ((mf2_state & 0x01) == 0) {
4537 shift_flags &= ~0x04;
4538 write_byte(0x0040, 0x17, shift_flags);
4539 if (mf2_state & 0x02) {
4541 write_byte(0x0040, 0x96, mf2_state);
4544 write_byte(0x0040, 0x18, mf2_flags);
4549 case 0x38: /* Alt press */
4550 shift_flags |= 0x08;
4551 write_byte(0x0040, 0x17, shift_flags);
4552 if (mf2_state & 0x02) {
4554 write_byte(0x0040, 0x96, mf2_state);
4557 write_byte(0x0040, 0x18, mf2_flags);
4560 case 0xb8: /* Alt release */
4561 shift_flags &= ~0x08;
4562 write_byte(0x0040, 0x17, shift_flags);
4563 if (mf2_state & 0x02) {
4565 write_byte(0x0040, 0x96, mf2_state);
4568 write_byte(0x0040, 0x18, mf2_flags);
4572 case 0x45: /* Num Lock press */
4573 if ((mf2_state & 0x03) == 0) {
4575 write_byte(0x0040, 0x18, mf2_flags);
4576 shift_flags ^= 0x20;
4578 write_byte(0x0040, 0x17, shift_flags);
4579 write_byte(0x0040, 0x97, led_flags);
4582 case 0xc5: /* Num Lock release */
4583 if ((mf2_state & 0x03) == 0) {
4585 write_byte(0x0040, 0x18, mf2_flags);
4589 case 0x46: /* Scroll Lock press */
4591 write_byte(0x0040, 0x18, mf2_flags);
4592 shift_flags ^= 0x10;
4594 write_byte(0x0040, 0x17, shift_flags);
4595 write_byte(0x0040, 0x97, led_flags);
4598 case 0xc6: /* Scroll Lock release */
4600 write_byte(0x0040, 0x18, mf2_flags);
4604 if (scancode & 0x80) {
4605 break; /* toss key releases ... */
4607 if (scancode > MAX_SCAN_CODE) {
4608 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
4611 if (shift_flags & 0x08) { /* ALT */
4612 asciicode = scan_to_scanascii[scancode].alt;
4613 scancode = scan_to_scanascii[scancode].alt >> 8;
4614 } else if (shift_flags & 0x04) { /* CONTROL */
4615 asciicode = scan_to_scanascii[scancode].control;
4616 scancode = scan_to_scanascii[scancode].control >> 8;
4617 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4618 /* check if lock state should be ignored
4619 * because a SHIFT key are pressed */
4621 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4622 asciicode = scan_to_scanascii[scancode].normal;
4623 scancode = scan_to_scanascii[scancode].normal >> 8;
4625 asciicode = scan_to_scanascii[scancode].shift;
4626 scancode = scan_to_scanascii[scancode].shift >> 8;
4629 /* check if lock is on */
4630 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4631 asciicode = scan_to_scanascii[scancode].shift;
4632 scancode = scan_to_scanascii[scancode].shift >> 8;
4634 asciicode = scan_to_scanascii[scancode].normal;
4635 scancode = scan_to_scanascii[scancode].normal >> 8;
4638 if (scancode==0 && asciicode==0) {
4639 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4641 enqueue_key(scancode, asciicode);
4644 if ((scancode & 0x7f) != 0x1d) {
4648 write_byte(0x0040, 0x96, mf2_state);
4652 enqueue_key(scan_code, ascii_code)
4653 Bit8u scan_code, ascii_code;
4655 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4658 buffer_start = 0x001E;
4659 buffer_end = 0x003E;
4661 buffer_start = read_word(0x0040, 0x0080);
4662 buffer_end = read_word(0x0040, 0x0082);
4665 buffer_head = read_word(0x0040, 0x001A);
4666 buffer_tail = read_word(0x0040, 0x001C);
4668 temp_tail = buffer_tail;
4670 if (buffer_tail >= buffer_end)
4671 buffer_tail = buffer_start;
4673 if (buffer_tail == buffer_head) {
4677 write_byte(0x0040, temp_tail, ascii_code);
4678 write_byte(0x0040, temp_tail+1, scan_code);
4679 write_word(0x0040, 0x001C, buffer_tail);
4685 int74_function(make_farcall, Z, Y, X, status)
4686 Bit16u make_farcall, Z, Y, X, status;
4688 Bit16u ebda_seg=read_word(0x0040,0x000E);
4689 Bit8u in_byte, index, package_count;
4690 Bit8u mouse_flags_1, mouse_flags_2;
4692 BX_DEBUG_INT74("entering int74_function\n");
4695 in_byte = inb(0x64);
4696 if ( (in_byte & 0x21) != 0x21 ) {
4699 in_byte = inb(0x60);
4700 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4702 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4703 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4705 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4709 package_count = mouse_flags_2 & 0x07;
4710 index = mouse_flags_1 & 0x07;
4711 write_byte(ebda_seg, 0x28 + index, in_byte);
4713 if ( (index+1) >= package_count ) {
4714 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4715 status = read_byte(ebda_seg, 0x0028 + 0);
4716 X = read_byte(ebda_seg, 0x0028 + 1);
4717 Y = read_byte(ebda_seg, 0x0028 + 2);
4720 // check if far call handler installed
4721 if (mouse_flags_2 & 0x80)
4727 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4730 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4735 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4736 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4739 Bit16u ebda_seg=read_word(0x0040,0x000E);
4740 Bit16u cylinder, head, sector;
4741 Bit16u segment, offset;
4742 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4744 Bit8u device, status;
4746 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4748 write_byte(0x0040, 0x008e, 0); // clear completion flag
4750 // basic check : device has to be defined
4751 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4752 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4756 // Get the ata channel
4757 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4759 // basic check : device has to be valid
4760 if (device >= BX_MAX_ATA_DEVICES) {
4761 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4767 case 0x00: /* disk controller reset */
4772 case 0x01: /* read disk status */
4773 status = read_byte(0x0040, 0x0074);
4775 SET_DISK_RET_STATUS(0);
4776 /* set CF if error status read */
4777 if (status) goto int13_fail_nostatus;
4778 else goto int13_success_noah;
4781 case 0x02: // read disk sectors
4782 case 0x03: // write disk sectors
4783 case 0x04: // verify disk sectors
4786 cylinder = GET_CH();
4787 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4788 sector = (GET_CL() & 0x3f);
4794 if ( (count > 128) || (count == 0) ) {
4795 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4799 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4800 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4801 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4803 // sanity check on cyl heads, sec
4804 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4805 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4810 if ( GET_AH() == 0x04 ) goto int13_success;
4812 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4813 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4815 // if needed, translate lchs to lba, and execute command
4816 if ( (nph != nlh) || (npspt != nlspt)) {
4817 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4818 sector = 0; // this forces the command to be lba
4821 if ( GET_AH() == 0x02 )
4822 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4824 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4826 // Set nb of sector transferred
4827 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4830 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4832 goto int13_fail_noah;
4838 case 0x05: /* format disk track */
4839 BX_INFO("format disk track called\n");
4844 case 0x08: /* read disk drive parameters */
4846 // Get logical geometry from table
4847 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4848 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4849 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4850 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4852 nlc = nlc - 2; /* 0 based , last sector not used */
4855 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4857 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4859 // FIXME should set ES & DI
4864 case 0x10: /* check drive ready */
4865 // should look at 40:8E also???
4867 // Read the status from controller
4868 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
4869 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
4874 goto int13_fail_noah;
4878 case 0x15: /* read disk drive size */
4880 // Get physical geometry from table
4881 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4882 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4883 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4885 // Compute sector count seen by int13
4886 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
4890 SET_AH(3); // hard disk accessible
4891 goto int13_success_noah;
4894 case 0x41: // IBM/MS installation check
4895 BX=0xaa55; // install check
4896 SET_AH(0x30); // EDD 3.0
4897 CX=0x0007; // ext disk access and edd, removable supported
4898 goto int13_success_noah;
4901 case 0x42: // IBM/MS extended read
4902 case 0x43: // IBM/MS extended write
4903 case 0x44: // IBM/MS verify
4904 case 0x47: // IBM/MS extended seek
4906 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
4907 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
4908 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
4910 // Can't use 64 bits lba
4911 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
4913 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4917 // Get 32 bits lba and check
4918 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
4919 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
4920 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4924 // If verify or seek
4925 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4928 // Execute the command
4929 if ( GET_AH() == 0x42 )
4930 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
4932 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
4934 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
4935 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
4938 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4940 goto int13_fail_noah;
4946 case 0x45: // IBM/MS lock/unlock drive
4947 case 0x49: // IBM/MS extended media change
4948 goto int13_success; // Always success for HD
4951 case 0x46: // IBM/MS eject media
4952 SET_AH(0xb2); // Volume Not Removable
4953 goto int13_fail_noah; // Always fail for HD
4956 case 0x48: // IBM/MS get drive parameters
4957 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
4959 // Buffer is too small
4967 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4968 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4969 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4970 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
4971 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
4973 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
4974 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
4975 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
4976 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
4977 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
4978 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
4979 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
4980 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
4985 Bit8u channel, dev, irq, mode, checksum, i, translation;
4986 Bit16u iobase1, iobase2, options;
4988 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
4990 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
4991 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
4994 channel = device / 2;
4995 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
4996 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
4997 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
4998 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
4999 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5001 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5002 options |= (1<<4); // lba translation
5003 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5004 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5005 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5007 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5008 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5009 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5010 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5011 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5012 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5013 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5014 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5015 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5016 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5017 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5020 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5021 checksum = ~checksum;
5022 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5027 Bit8u channel, iface, checksum, i;
5030 channel = device / 2;
5031 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5032 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5034 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5035 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5036 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5037 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5038 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5040 if (iface==ATA_IFACE_ISA) {
5041 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5042 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5043 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5044 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5049 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5050 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5051 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5052 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5054 if (iface==ATA_IFACE_ISA) {
5055 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5056 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5057 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5062 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5063 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5064 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5065 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5068 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5069 checksum = ~checksum;
5070 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5076 case 0x4e: // // IBM/MS set hardware configuration
5077 // DMA, prefetch, PIO maximum not supported
5090 case 0x09: /* initialize drive parameters */
5091 case 0x0c: /* seek to specified cylinder */
5092 case 0x0d: /* alternate disk reset */
5093 case 0x11: /* recalibrate */
5094 case 0x14: /* controller internal diagnostic */
5095 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5099 case 0x0a: /* read disk sectors with ECC */
5100 case 0x0b: /* write disk sectors with ECC */
5101 case 0x18: // set media type for format
5102 case 0x50: // IBM/MS send packet command
5104 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5110 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5112 SET_DISK_RET_STATUS(GET_AH());
5113 int13_fail_nostatus:
5114 SET_CF(); // error occurred
5118 SET_AH(0x00); // no error
5120 SET_DISK_RET_STATUS(0x00);
5121 CLEAR_CF(); // no error
5125 // ---------------------------------------------------------------------------
5126 // Start of int13 for cdrom
5127 // ---------------------------------------------------------------------------
5130 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5131 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5133 Bit16u ebda_seg=read_word(0x0040,0x000E);
5134 Bit8u device, status, locks;
5137 Bit16u count, segment, offset, i, size;
5139 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5141 SET_DISK_RET_STATUS(0x00);
5143 /* basic check : device should be 0xE0+ */
5144 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5145 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5149 // Get the ata channel
5150 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5152 /* basic check : device has to be valid */
5153 if (device >= BX_MAX_ATA_DEVICES) {
5154 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5160 // all those functions return SUCCESS
5161 case 0x00: /* disk controller reset */
5162 case 0x09: /* initialize drive parameters */
5163 case 0x0c: /* seek to specified cylinder */
5164 case 0x0d: /* alternate disk reset */
5165 case 0x10: /* check drive ready */
5166 case 0x11: /* recalibrate */
5167 case 0x14: /* controller internal diagnostic */
5168 case 0x16: /* detect disk change */
5172 // all those functions return disk write-protected
5173 case 0x03: /* write disk sectors */
5174 case 0x05: /* format disk track */
5175 case 0x43: // IBM/MS extended write
5177 goto int13_fail_noah;
5180 case 0x01: /* read disk status */
5181 status = read_byte(0x0040, 0x0074);
5183 SET_DISK_RET_STATUS(0);
5185 /* set CF if error status read */
5186 if (status) goto int13_fail_nostatus;
5187 else goto int13_success_noah;
5190 case 0x15: /* read disk drive size */
5192 goto int13_fail_noah;
5195 case 0x41: // IBM/MS installation check
5196 BX=0xaa55; // install check
5197 SET_AH(0x30); // EDD 2.1
5198 CX=0x0007; // ext disk access, removable and edd
5199 goto int13_success_noah;
5202 case 0x42: // IBM/MS extended read
5203 case 0x44: // IBM/MS verify sectors
5204 case 0x47: // IBM/MS extended seek
5206 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5207 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5208 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5210 // Can't use 64 bits lba
5211 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5213 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5218 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5220 // If verify or seek
5221 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5224 memsetb(get_SS(),atacmd,0,12);
5225 atacmd[0]=0x28; // READ command
5226 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5227 atacmd[8]=(count & 0x00ff); // Sectors
5228 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5229 atacmd[3]=(lba & 0x00ff0000) >> 16;
5230 atacmd[4]=(lba & 0x0000ff00) >> 8;
5231 atacmd[5]=(lba & 0x000000ff);
5232 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5234 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5235 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5238 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5240 goto int13_fail_noah;
5246 case 0x45: // IBM/MS lock/unlock drive
5247 if (GET_AL() > 2) goto int13_fail;
5249 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5253 if (locks == 0xff) {
5256 goto int13_fail_noah;
5258 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5262 if (locks == 0x00) {
5265 goto int13_fail_noah;
5267 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5268 SET_AL(locks==0?0:1);
5271 SET_AL(locks==0?0:1);
5277 case 0x46: // IBM/MS eject media
5278 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5281 SET_AH(0xb1); // media locked
5282 goto int13_fail_noah;
5284 // FIXME should handle 0x31 no media in device
5285 // FIXME should handle 0xb5 valid request failed
5287 // Call removable media eject
5294 mov _int13_cdrom.status + 2[bp], ah
5295 jnc int13_cdrom_rme_end
5296 mov _int13_cdrom.status, #1
5297 int13_cdrom_rme_end:
5302 SET_AH(0xb1); // media locked
5303 goto int13_fail_noah;
5309 case 0x48: // IBM/MS get drive parameters
5310 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5312 // Buffer is too small
5318 Bit16u cylinders, heads, spt, blksize;
5320 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5322 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5323 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5324 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5325 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5326 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5327 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5328 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5329 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5334 Bit8u channel, dev, irq, mode, checksum, i;
5335 Bit16u iobase1, iobase2, options;
5337 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5339 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5340 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5343 channel = device / 2;
5344 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5345 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5346 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5347 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5349 // FIXME atapi device
5350 options = (1<<4); // lba translation
5351 options |= (1<<5); // removable device
5352 options |= (1<<6); // atapi device
5353 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5355 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5356 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5357 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5358 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5359 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5360 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5361 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5362 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5363 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5364 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5365 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5368 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5369 checksum = ~checksum;
5370 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5375 Bit8u channel, iface, checksum, i;
5378 channel = device / 2;
5379 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5380 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5382 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5383 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5384 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5385 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5386 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5388 if (iface==ATA_IFACE_ISA) {
5389 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5390 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5391 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5392 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5397 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5398 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5399 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5400 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5402 if (iface==ATA_IFACE_ISA) {
5403 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5404 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5405 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5410 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5411 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5412 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5413 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5416 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5417 checksum = ~checksum;
5418 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5424 case 0x49: // IBM/MS extended media change
5425 // always send changed ??
5427 goto int13_fail_nostatus;
5430 case 0x4e: // // IBM/MS set hardware configuration
5431 // DMA, prefetch, PIO maximum not supported
5444 // all those functions return unimplemented
5445 case 0x02: /* read sectors */
5446 case 0x04: /* verify sectors */
5447 case 0x08: /* read disk drive parameters */
5448 case 0x0a: /* read disk sectors with ECC */
5449 case 0x0b: /* write disk sectors with ECC */
5450 case 0x18: /* set media type for format */
5451 case 0x50: // ? - send packet command
5453 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5459 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5461 SET_DISK_RET_STATUS(GET_AH());
5462 int13_fail_nostatus:
5463 SET_CF(); // error occurred
5467 SET_AH(0x00); // no error
5469 SET_DISK_RET_STATUS(0x00);
5470 CLEAR_CF(); // no error
5474 // ---------------------------------------------------------------------------
5475 // End of int13 for cdrom
5476 // ---------------------------------------------------------------------------
5478 #if BX_ELTORITO_BOOT
5479 // ---------------------------------------------------------------------------
5480 // Start of int13 for eltorito functions
5481 // ---------------------------------------------------------------------------
5484 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5485 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5487 Bit16u ebda_seg=read_word(0x0040,0x000E);
5489 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5490 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5494 // FIXME ElTorito Various. Should be implemented
5495 case 0x4a: // ElTorito - Initiate disk emu
5496 case 0x4c: // ElTorito - Initiate disk emu and boot
5497 case 0x4d: // ElTorito - Return Boot catalog
5498 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5502 case 0x4b: // ElTorito - Terminate disk emu
5503 // FIXME ElTorito Hardcoded
5504 write_byte(DS,SI+0x00,0x13);
5505 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5506 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5507 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5508 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5509 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5510 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5511 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5512 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5513 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5514 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5515 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5517 // If we have to terminate emulation
5518 if(GET_AL() == 0x00) {
5519 // FIXME ElTorito Various. Should be handled accordingly to spec
5520 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5527 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5533 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5534 SET_DISK_RET_STATUS(GET_AH());
5535 SET_CF(); // error occurred
5539 SET_AH(0x00); // no error
5540 SET_DISK_RET_STATUS(0x00);
5541 CLEAR_CF(); // no error
5545 // ---------------------------------------------------------------------------
5546 // End of int13 for eltorito functions
5547 // ---------------------------------------------------------------------------
5549 // ---------------------------------------------------------------------------
5550 // Start of int13 when emulating a device from the cd
5551 // ---------------------------------------------------------------------------
5554 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5555 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5557 Bit16u ebda_seg=read_word(0x0040,0x000E);
5558 Bit8u device, status;
5559 Bit16u vheads, vspt, vcylinders;
5560 Bit16u head, sector, cylinder, nbsectors;
5561 Bit32u vlba, ilba, slba, elba;
5562 Bit16u before, segment, offset;
5565 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5567 /* at this point, we are emulating a floppy/harddisk */
5569 // Recompute the device number
5570 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5571 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5573 SET_DISK_RET_STATUS(0x00);
5575 /* basic checks : emulation should be active, dl should equal the emulated drive */
5576 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5577 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5578 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5584 // all those functions return SUCCESS
5585 case 0x00: /* disk controller reset */
5586 case 0x09: /* initialize drive parameters */
5587 case 0x0c: /* seek to specified cylinder */
5588 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5589 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5590 case 0x11: /* recalibrate */
5591 case 0x14: /* controller internal diagnostic */
5592 case 0x16: /* detect disk change */
5596 // all those functions return disk write-protected
5597 case 0x03: /* write disk sectors */
5598 case 0x05: /* format disk track */
5600 goto int13_fail_noah;
5603 case 0x01: /* read disk status */
5604 status=read_byte(0x0040, 0x0074);
5606 SET_DISK_RET_STATUS(0);
5608 /* set CF if error status read */
5609 if (status) goto int13_fail_nostatus;
5610 else goto int13_success_noah;
5613 case 0x02: // read disk sectors
5614 case 0x04: // verify disk sectors
5615 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5616 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5617 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5619 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5621 sector = GET_CL() & 0x003f;
5622 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5624 nbsectors = GET_AL();
5628 // no sector to read ?
5629 if(nbsectors==0) goto int13_success;
5631 // sanity checks sco openserver needs this!
5633 || (cylinder >= vcylinders)
5634 || (head >= vheads)) {
5638 // After controls, verify do nothing
5639 if (GET_AH() == 0x04) goto int13_success;
5641 segment = ES+(BX / 16);
5644 // calculate the virtual lba inside the image
5645 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5647 // In advance so we don't loose the count
5651 slba = (Bit32u)vlba/4;
5652 before= (Bit16u)vlba%4;
5655 elba = (Bit32u)(vlba+nbsectors-1)/4;
5657 memsetb(get_SS(),atacmd,0,12);
5658 atacmd[0]=0x28; // READ command
5659 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5660 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5661 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5662 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5663 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5664 atacmd[5]=(ilba+slba & 0x000000ff);
5665 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5666 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5669 goto int13_fail_noah;
5675 case 0x08: /* read disk drive parameters */
5676 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5677 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5678 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5682 SET_CH( vcylinders & 0xff );
5683 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5685 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5686 // FIXME ElTorito Harddisk. should send the HD count
5688 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5689 case 0x01: SET_BL( 0x02 ); break;
5690 case 0x02: SET_BL( 0x04 ); break;
5691 case 0x03: SET_BL( 0x06 ); break;
5697 mov ax, #diskette_param_table2
5698 mov _int13_cdemu.DI+2[bp], ax
5699 mov _int13_cdemu.ES+2[bp], cs
5705 case 0x15: /* read disk drive size */
5706 // FIXME ElTorito Harddisk. What geometry to send ?
5708 goto int13_success_noah;
5711 // all those functions return unimplemented
5712 case 0x0a: /* read disk sectors with ECC */
5713 case 0x0b: /* write disk sectors with ECC */
5714 case 0x18: /* set media type for format */
5715 case 0x41: // IBM/MS installation check
5716 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5717 case 0x42: // IBM/MS extended read
5718 case 0x43: // IBM/MS extended write
5719 case 0x44: // IBM/MS verify sectors
5720 case 0x45: // IBM/MS lock/unlock drive
5721 case 0x46: // IBM/MS eject media
5722 case 0x47: // IBM/MS extended seek
5723 case 0x48: // IBM/MS get drive parameters
5724 case 0x49: // IBM/MS extended media change
5725 case 0x4e: // ? - set hardware configuration
5726 case 0x50: // ? - send packet command
5728 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5734 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5736 SET_DISK_RET_STATUS(GET_AH());
5737 int13_fail_nostatus:
5738 SET_CF(); // error occurred
5742 SET_AH(0x00); // no error
5744 SET_DISK_RET_STATUS(0x00);
5745 CLEAR_CF(); // no error
5749 // ---------------------------------------------------------------------------
5750 // End of int13 when emulating a device from the cd
5751 // ---------------------------------------------------------------------------
5753 #endif // BX_ELTORITO_BOOT
5755 #else //BX_USE_ATADRV
5758 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5773 mov ax,4[bp] // cylinder
5775 mov bl,6[bp] // hd_heads
5778 mov bl,8[bp] // head
5780 mov bl,10[bp] // hd_sectors
5782 mov bl,12[bp] // sector
5811 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5812 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5814 Bit8u drive, num_sectors, sector, head, status, mod;
5818 Bit16u max_cylinder, cylinder, total_sectors;
5819 Bit16u hd_cylinders;
5820 Bit8u hd_heads, hd_sectors;
5827 Bit16u count, segment, offset;
5831 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5833 write_byte(0x0040, 0x008e, 0); // clear completion flag
5835 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5837 /* check how many disks first (cmos reg 0x12), return an error if
5838 drive not present */
5839 drive_map = inb_cmos(0x12);
5840 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5841 (((drive_map & 0x0f)==0) ? 0 : 2);
5842 n_drives = (drive_map==0) ? 0 :
5843 ((drive_map==3) ? 2 : 1);
5845 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5847 SET_DISK_RET_STATUS(0x01);
5848 SET_CF(); /* error occurred */
5854 case 0x00: /* disk controller reset */
5855 BX_DEBUG_INT13_HD("int13_f00\n");
5858 SET_DISK_RET_STATUS(0);
5859 set_diskette_ret_status(0);
5860 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5861 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5862 CLEAR_CF(); /* successful */
5866 case 0x01: /* read disk status */
5867 BX_DEBUG_INT13_HD("int13_f01\n");
5868 status = read_byte(0x0040, 0x0074);
5870 SET_DISK_RET_STATUS(0);
5871 /* set CF if error status read */
5872 if (status) SET_CF();
5877 case 0x04: // verify disk sectors
5878 case 0x02: // read disk sectors
5880 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5882 num_sectors = GET_AL();
5883 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5884 sector = (GET_CL() & 0x3f);
5888 if (hd_cylinders > 1024) {
5889 if (hd_cylinders <= 2048) {
5892 else if (hd_cylinders <= 4096) {
5895 else if (hd_cylinders <= 8192) {
5898 else { // hd_cylinders <= 16384
5902 ax = head / hd_heads;
5903 cyl_mod = ax & 0xff;
5905 cylinder |= cyl_mod;
5908 if ( (cylinder >= hd_cylinders) ||
5909 (sector > hd_sectors) ||
5910 (head >= hd_heads) ) {
5912 SET_DISK_RET_STATUS(1);
5913 SET_CF(); /* error occurred */
5917 if ( (num_sectors > 128) || (num_sectors == 0) )
5918 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5921 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5923 if ( GET_AH() == 0x04 ) {
5925 SET_DISK_RET_STATUS(0);
5930 status = inb(0x1f7);
5931 if (status & 0x80) {
5932 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5934 outb(0x01f2, num_sectors);
5935 /* activate LBA? (tomv) */
5936 if (hd_heads > 16) {
5937 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
5938 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
5941 outb(0x01f3, sector);
5942 outb(0x01f4, cylinder & 0x00ff);
5943 outb(0x01f5, cylinder >> 8);
5944 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
5949 status = inb(0x1f7);
5950 if ( !(status & 0x80) ) break;
5953 if (status & 0x01) {
5954 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
5955 } else if ( !(status & 0x08) ) {
5956 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
5957 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
5964 sti ;; enable higher priority interrupts
5969 ;; store temp bx in real DI register
5972 mov di, _int13_harddisk.tempbx + 2 [bp]
5975 ;; adjust if there will be an overrun
5977 jbe i13_f02_no_adjust
5979 sub di, #0x0200 ; sub 512 bytes from offset
5981 add ax, #0x0020 ; add 512 to segment
5985 mov cx, #0x0100 ;; counter (256 words = 512b)
5986 mov dx, #0x01f0 ;; AT data read port
5989 insw ;; CX words transfered from port(DX) to ES:[DI]
5992 ;; store real DI register back to temp bx
5995 mov _int13_harddisk.tempbx + 2 [bp], di
6001 if (num_sectors == 0) {
6002 status = inb(0x1f7);
6003 if ( (status & 0xc9) != 0x40 )
6004 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6008 status = inb(0x1f7);
6009 if ( (status & 0xc9) != 0x48 )
6010 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6016 SET_DISK_RET_STATUS(0);
6017 SET_AL(sector_count);
6018 CLEAR_CF(); /* successful */
6023 case 0x03: /* write disk sectors */
6024 BX_DEBUG_INT13_HD("int13_f03\n");
6025 drive = GET_ELDL ();
6026 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6028 num_sectors = GET_AL();
6029 cylinder = GET_CH();
6030 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6031 sector = (GET_CL() & 0x3f);
6034 if (hd_cylinders > 1024) {
6035 if (hd_cylinders <= 2048) {
6038 else if (hd_cylinders <= 4096) {
6041 else if (hd_cylinders <= 8192) {
6044 else { // hd_cylinders <= 16384
6048 ax = head / hd_heads;
6049 cyl_mod = ax & 0xff;
6051 cylinder |= cyl_mod;
6054 if ( (cylinder >= hd_cylinders) ||
6055 (sector > hd_sectors) ||
6056 (head >= hd_heads) ) {
6058 SET_DISK_RET_STATUS(1);
6059 SET_CF(); /* error occurred */
6063 if ( (num_sectors > 128) || (num_sectors == 0) )
6064 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6067 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6069 status = inb(0x1f7);
6070 if (status & 0x80) {
6071 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6073 // should check for Drive Ready Bit also in status reg
6074 outb(0x01f2, num_sectors);
6076 /* activate LBA? (tomv) */
6077 if (hd_heads > 16) {
6078 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6079 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6082 outb(0x01f3, sector);
6083 outb(0x01f4, cylinder & 0x00ff);
6084 outb(0x01f5, cylinder >> 8);
6085 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6089 // wait for busy bit to turn off after seeking
6091 status = inb(0x1f7);
6092 if ( !(status & 0x80) ) break;
6095 if ( !(status & 0x08) ) {
6096 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6097 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6104 sti ;; enable higher priority interrupts
6109 ;; store temp bx in real SI register
6112 mov si, _int13_harddisk.tempbx + 2 [bp]
6115 ;; adjust if there will be an overrun
6117 jbe i13_f03_no_adjust
6119 sub si, #0x0200 ; sub 512 bytes from offset
6121 add ax, #0x0020 ; add 512 to segment
6125 mov cx, #0x0100 ;; counter (256 words = 512b)
6126 mov dx, #0x01f0 ;; AT data read port
6130 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6132 ;; store real SI register back to temp bx
6135 mov _int13_harddisk.tempbx + 2 [bp], si
6141 if (num_sectors == 0) {
6142 status = inb(0x1f7);
6143 if ( (status & 0xe9) != 0x40 )
6144 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6148 status = inb(0x1f7);
6149 if ( (status & 0xc9) != 0x48 )
6150 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6156 SET_DISK_RET_STATUS(0);
6157 SET_AL(sector_count);
6158 CLEAR_CF(); /* successful */
6162 case 0x05: /* format disk track */
6163 BX_DEBUG_INT13_HD("int13_f05\n");
6164 BX_PANIC("format disk track called\n");
6167 SET_DISK_RET_STATUS(0);
6168 CLEAR_CF(); /* successful */
6172 case 0x08: /* read disk drive parameters */
6173 BX_DEBUG_INT13_HD("int13_f08\n");
6175 drive = GET_ELDL ();
6176 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6180 if (hd_cylinders <= 1024) {
6181 // hd_cylinders >>= 0;
6184 else if (hd_cylinders <= 2048) {
6188 else if (hd_cylinders <= 4096) {
6192 else if (hd_cylinders <= 8192) {
6196 else { // hd_cylinders <= 16384
6201 max_cylinder = hd_cylinders - 2; /* 0 based */
6203 SET_CH(max_cylinder & 0xff);
6204 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6205 SET_DH(hd_heads - 1);
6206 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6208 SET_DISK_RET_STATUS(0);
6209 CLEAR_CF(); /* successful */
6214 case 0x09: /* initialize drive parameters */
6215 BX_DEBUG_INT13_HD("int13_f09\n");
6217 SET_DISK_RET_STATUS(0);
6218 CLEAR_CF(); /* successful */
6222 case 0x0a: /* read disk sectors with ECC */
6223 BX_DEBUG_INT13_HD("int13_f0a\n");
6224 case 0x0b: /* write disk sectors with ECC */
6225 BX_DEBUG_INT13_HD("int13_f0b\n");
6226 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6230 case 0x0c: /* seek to specified cylinder */
6231 BX_DEBUG_INT13_HD("int13_f0c\n");
6232 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6234 SET_DISK_RET_STATUS(0);
6235 CLEAR_CF(); /* successful */
6239 case 0x0d: /* alternate disk reset */
6240 BX_DEBUG_INT13_HD("int13_f0d\n");
6242 SET_DISK_RET_STATUS(0);
6243 CLEAR_CF(); /* successful */
6247 case 0x10: /* check drive ready */
6248 BX_DEBUG_INT13_HD("int13_f10\n");
6250 //SET_DISK_RET_STATUS(0);
6251 //CLEAR_CF(); /* successful */
6255 // should look at 40:8E also???
6256 status = inb(0x01f7);
6257 if ( (status & 0xc0) == 0x40 ) {
6259 SET_DISK_RET_STATUS(0);
6260 CLEAR_CF(); // drive ready
6265 SET_DISK_RET_STATUS(0xAA);
6266 SET_CF(); // not ready
6271 case 0x11: /* recalibrate */
6272 BX_DEBUG_INT13_HD("int13_f11\n");
6274 SET_DISK_RET_STATUS(0);
6275 CLEAR_CF(); /* successful */
6279 case 0x14: /* controller internal diagnostic */
6280 BX_DEBUG_INT13_HD("int13_f14\n");
6282 SET_DISK_RET_STATUS(0);
6283 CLEAR_CF(); /* successful */
6288 case 0x15: /* read disk drive size */
6290 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6294 mov al, _int13_harddisk.hd_heads + 2 [bp]
6295 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6296 mul al, ah ;; ax = heads * sectors
6297 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6298 dec bx ;; use (cylinders - 1) ???
6299 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6300 ;; now we need to move the 32bit result dx:ax to what the
6301 ;; BIOS wants which is cx:dx.
6302 ;; and then into CX:DX on the stack
6303 mov _int13_harddisk.CX + 2 [bp], dx
6304 mov _int13_harddisk.DX + 2 [bp], ax
6307 SET_AH(3); // hard disk accessible
6308 SET_DISK_RET_STATUS(0); // ??? should this be 0
6309 CLEAR_CF(); // successful
6313 case 0x18: // set media type for format
6314 case 0x41: // IBM/MS
6315 case 0x42: // IBM/MS
6316 case 0x43: // IBM/MS
6317 case 0x44: // IBM/MS
6318 case 0x45: // IBM/MS lock/unlock drive
6319 case 0x46: // IBM/MS eject media
6320 case 0x47: // IBM/MS extended seek
6321 case 0x49: // IBM/MS extended media change
6322 case 0x50: // IBM/MS send packet command
6324 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6326 SET_AH(1); // code=invalid function in AH or invalid parameter
6327 SET_DISK_RET_STATUS(1);
6328 SET_CF(); /* unsuccessful */
6334 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6335 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6338 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6340 Bit16u *hd_cylinders;
6350 if (drive == 0x80) {
6351 hd_type = inb_cmos(0x12) & 0xf0;
6352 if (hd_type != 0xf0)
6353 BX_INFO(panic_msg_reg12h,0);
6354 hd_type = inb_cmos(0x19); // HD0: extended type
6356 BX_INFO(panic_msg_reg19h,0,0x19);
6359 hd_type = inb_cmos(0x12) & 0x0f;
6360 if (hd_type != 0x0f)
6361 BX_INFO(panic_msg_reg12h,1);
6362 hd_type = inb_cmos(0x1a); // HD0: extended type
6364 BX_INFO(panic_msg_reg19h,0,0x1a);
6369 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6370 write_word(ss, hd_cylinders, cylinders);
6373 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6375 // sectors per track
6376 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6379 #endif //else BX_USE_ATADRV
6382 //////////////////////
6383 // FLOPPY functions //
6384 //////////////////////
6386 void floppy_reset_controller()
6392 outb(0x03f2, val8 & ~0x04);
6393 outb(0x03f2, val8 | 0x04);
6395 // Wait for controller to come out of reset
6398 } while ( (val8 & 0xc0) != 0x80 );
6401 void floppy_prepare_controller(drive)
6404 Bit8u val8, dor, prev_reset;
6406 // set 40:3e bit 7 to 0
6407 val8 = read_byte(0x0040, 0x003e);
6409 write_byte(0x0040, 0x003e, val8);
6411 // turn on motor of selected drive, DMA & int enabled, normal operation
6412 prev_reset = inb(0x03f2) & 0x04;
6421 // reset the disk motor timeout value of INT 08
6422 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6424 // wait for drive readiness
6427 } while ( (val8 & 0xc0) != 0x80 );
6429 if (prev_reset == 0) {
6430 // turn on interrupts
6434 // wait on 40:3e bit 7 to become 1
6436 val8 = read_byte(0x0040, 0x003e);
6437 } while ( (val8 & 0x80) == 0 );
6442 write_byte(0x0040, 0x003e, val8);
6447 floppy_media_known(drive)
6451 Bit16u media_state_offset;
6453 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6460 media_state_offset = 0x0090;
6462 media_state_offset += 1;
6464 val8 = read_byte(0x0040, media_state_offset);
6465 val8 = (val8 >> 4) & 0x01;
6469 // check pass, return KNOWN
6474 floppy_media_sense(drive)
6478 Bit16u media_state_offset;
6479 Bit8u drive_type, config_data, media_state;
6481 if (floppy_drive_recal(drive) == 0) {
6485 // for now cheat and get drive type from CMOS,
6486 // assume media is same as drive type
6488 // ** config_data **
6489 // Bitfields for diskette media control:
6490 // Bit(s) Description (Table M0028)
6491 // 7-6 last data rate set by controller
6492 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6493 // 5-4 last diskette drive step rate selected
6494 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6495 // 3-2 {data rate at start of operation}
6498 // ** media_state **
6499 // Bitfields for diskette drive media state:
6500 // Bit(s) Description (Table M0030)
6502 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6503 // 5 double stepping required (e.g. 360kB in 1.2MB)
6504 // 4 media type established
6505 // 3 drive capable of supporting 4MB media
6506 // 2-0 on exit from BIOS, contains
6507 // 000 trying 360kB in 360kB
6508 // 001 trying 360kB in 1.2MB
6509 // 010 trying 1.2MB in 1.2MB
6510 // 011 360kB in 360kB established
6511 // 100 360kB in 1.2MB established
6512 // 101 1.2MB in 1.2MB established
6514 // 111 all other formats/drives
6516 drive_type = inb_cmos(0x10);
6521 if ( drive_type == 1 ) {
6523 config_data = 0x00; // 0000 0000
6524 media_state = 0x25; // 0010 0101
6527 else if ( drive_type == 2 ) {
6528 // 1.2 MB 5.25" drive
6529 config_data = 0x00; // 0000 0000
6530 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6533 else if ( drive_type == 3 ) {
6535 config_data = 0x00; // 0000 0000 ???
6536 media_state = 0x17; // 0001 0111
6539 else if ( drive_type == 4 ) {
6540 // 1.44 MB 3.5" drive
6541 config_data = 0x00; // 0000 0000
6542 media_state = 0x17; // 0001 0111
6545 else if ( drive_type == 5 ) {
6546 // 2.88 MB 3.5" drive
6547 config_data = 0xCC; // 1100 1100
6548 media_state = 0xD7; // 1101 0111
6552 // Extended floppy size uses special cmos setting
6553 else if ( drive_type == 6 ) {
6555 config_data = 0x00; // 0000 0000
6556 media_state = 0x27; // 0010 0111
6559 else if ( drive_type == 7 ) {
6561 config_data = 0x00; // 0000 0000
6562 media_state = 0x27; // 0010 0111
6565 else if ( drive_type == 8 ) {
6567 config_data = 0x00; // 0000 0000
6568 media_state = 0x27; // 0010 0111
6574 config_data = 0x00; // 0000 0000
6575 media_state = 0x00; // 0000 0000
6580 media_state_offset = 0x90;
6582 media_state_offset = 0x91;
6583 write_byte(0x0040, 0x008B, config_data);
6584 write_byte(0x0040, media_state_offset, media_state);
6590 floppy_drive_recal(drive)
6594 Bit16u curr_cyl_offset;
6596 floppy_prepare_controller(drive);
6598 // send Recalibrate command (2 bytes) to controller
6599 outb(0x03f5, 0x07); // 07: Recalibrate
6600 outb(0x03f5, drive); // 0=drive0, 1=drive1
6602 // turn on interrupts
6607 // wait on 40:3e bit 7 to become 1
6609 val8 = (read_byte(0x0040, 0x003e) & 0x80);
6610 } while ( val8 == 0 );
6612 val8 = 0; // separate asm from while() loop
6613 // turn off interrupts
6618 // set 40:3e bit 7 to 0, and calibrated bit
6619 val8 = read_byte(0x0040, 0x003e);
6622 val8 |= 0x02; // Drive 1 calibrated
6623 curr_cyl_offset = 0x0095;
6625 val8 |= 0x01; // Drive 0 calibrated
6626 curr_cyl_offset = 0x0094;
6628 write_byte(0x0040, 0x003e, val8);
6629 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6637 floppy_drive_exists(drive)
6642 // check CMOS to see if drive exists
6643 drive_type = inb_cmos(0x10);
6648 if ( drive_type == 0 )
6654 #if BX_SUPPORT_FLOPPY
6656 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6657 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6659 Bit8u drive, num_sectors, track, sector, head, status;
6660 Bit16u base_address, base_count, base_es;
6661 Bit8u page, mode_register, val8, dor;
6662 Bit8u return_status[7];
6663 Bit8u drive_type, num_floppies, ah;
6664 Bit16u es, last_addr;
6666 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6671 case 0x00: // diskette controller reset
6672 BX_DEBUG_INT13_FL("floppy f00\n");
6675 SET_AH(1); // invalid param
6676 set_diskette_ret_status(1);
6680 drive_type = inb_cmos(0x10);
6686 if (drive_type == 0) {
6687 SET_AH(0x80); // drive not responding
6688 set_diskette_ret_status(0x80);
6693 set_diskette_ret_status(0);
6694 CLEAR_CF(); // successful
6695 set_diskette_current_cyl(drive, 0); // current cylinder
6698 case 0x01: // Read Diskette Status
6700 val8 = read_byte(0x0000, 0x0441);
6707 case 0x02: // Read Diskette Sectors
6708 case 0x03: // Write Diskette Sectors
6709 case 0x04: // Verify Diskette Sectors
6710 num_sectors = GET_AL();
6716 if ( (drive > 1) || (head > 1) ||
6717 (num_sectors == 0) || (num_sectors > 72) ) {
6718 BX_INFO("floppy: drive>1 || head>1 ...\n");
6720 set_diskette_ret_status(1);
6721 SET_AL(0); // no sectors read
6722 SET_CF(); // error occurred
6726 // see if drive exists
6727 if (floppy_drive_exists(drive) == 0) {
6728 SET_AH(0x80); // not responding
6729 set_diskette_ret_status(0x80);
6730 SET_AL(0); // no sectors read
6731 SET_CF(); // error occurred
6735 // see if media in drive, and type is known
6736 if (floppy_media_known(drive) == 0) {
6737 if (floppy_media_sense(drive) == 0) {
6738 SET_AH(0x0C); // Media type not found
6739 set_diskette_ret_status(0x0C);
6740 SET_AL(0); // no sectors read
6741 SET_CF(); // error occurred
6747 // Read Diskette Sectors
6749 //-----------------------------------
6750 // set up DMA controller for transfer
6751 //-----------------------------------
6753 // es:bx = pointer to where to place information from diskette
6754 // port 04: DMA-1 base and current address, channel 2
6755 // port 05: DMA-1 base and current count, channel 2
6756 page = (ES >> 12); // upper 4 bits
6757 base_es = (ES << 4); // lower 16bits contributed by ES
6758 base_address = base_es + BX; // lower 16 bits of address
6759 // contributed by ES:BX
6760 if ( base_address < base_es ) {
6761 // in case of carry, adjust page by 1
6764 base_count = (num_sectors * 512) - 1;
6766 // check for 64K boundary overrun
6767 last_addr = base_address + base_count;
6768 if (last_addr < base_address) {
6770 set_diskette_ret_status(0x09);
6771 SET_AL(0); // no sectors read
6772 SET_CF(); // error occurred
6776 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6779 BX_DEBUG_INT13_FL("clear flip-flop\n");
6780 outb(0x000c, 0x00); // clear flip-flop
6781 outb(0x0004, base_address);
6782 outb(0x0004, base_address>>8);
6783 BX_DEBUG_INT13_FL("clear flip-flop\n");
6784 outb(0x000c, 0x00); // clear flip-flop
6785 outb(0x0005, base_count);
6786 outb(0x0005, base_count>>8);
6788 // port 0b: DMA-1 Mode Register
6789 mode_register = 0x46; // single mode, increment, autoinit disable,
6790 // transfer type=write, channel 2
6791 BX_DEBUG_INT13_FL("setting mode register\n");
6792 outb(0x000b, mode_register);
6794 BX_DEBUG_INT13_FL("setting page register\n");
6795 // port 81: DMA-1 Page Register, channel 2
6798 BX_DEBUG_INT13_FL("unmask chan 2\n");
6799 outb(0x000a, 0x02); // unmask channel 2
6801 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6804 //--------------------------------------
6805 // set up floppy controller for transfer
6806 //--------------------------------------
6807 floppy_prepare_controller(drive);
6809 // send read-normal-data command (9 bytes) to controller
6810 outb(0x03f5, 0xe6); // e6: read normal data
6811 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6812 outb(0x03f5, track);
6814 outb(0x03f5, sector);
6815 outb(0x03f5, 2); // 512 byte sector size
6816 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
6817 outb(0x03f5, 0); // Gap length
6818 outb(0x03f5, 0xff); // Gap length
6820 // turn on interrupts
6825 // wait on 40:3e bit 7 to become 1
6827 val8 = read_byte(0x0040, 0x0040);
6829 floppy_reset_controller();
6830 SET_AH(0x80); // drive not ready (timeout)
6831 set_diskette_ret_status(0x80);
6832 SET_AL(0); // no sectors read
6833 SET_CF(); // error occurred
6836 val8 = (read_byte(0x0040, 0x003e) & 0x80);
6837 } while ( val8 == 0 );
6839 val8 = 0; // separate asm from while() loop
6840 // turn off interrupts
6845 // set 40:3e bit 7 to 0
6846 val8 = read_byte(0x0040, 0x003e);
6848 write_byte(0x0040, 0x003e, val8);
6850 // check port 3f4 for accessibility to status bytes
6852 if ( (val8 & 0xc0) != 0xc0 )
6853 BX_PANIC("int13_diskette: ctrl not ready\n");
6855 // read 7 return status bytes from controller
6856 // using loop index broken, have to unroll...
6857 return_status[0] = inb(0x3f5);
6858 return_status[1] = inb(0x3f5);
6859 return_status[2] = inb(0x3f5);
6860 return_status[3] = inb(0x3f5);
6861 return_status[4] = inb(0x3f5);
6862 return_status[5] = inb(0x3f5);
6863 return_status[6] = inb(0x3f5);
6864 // record in BIOS Data Area
6865 write_byte(0x0040, 0x0042, return_status[0]);
6866 write_byte(0x0040, 0x0043, return_status[1]);
6867 write_byte(0x0040, 0x0044, return_status[2]);
6868 write_byte(0x0040, 0x0045, return_status[3]);
6869 write_byte(0x0040, 0x0046, return_status[4]);
6870 write_byte(0x0040, 0x0047, return_status[5]);
6871 write_byte(0x0040, 0x0048, return_status[6]);
6873 if ( (return_status[0] & 0xc0) != 0 ) {
6875 set_diskette_ret_status(0x20);
6876 SET_AL(0); // no sectors read
6877 SET_CF(); // error occurred
6881 // ??? should track be new val from return_status[3] ?
6882 set_diskette_current_cyl(drive, track);
6883 // AL = number of sectors read (same value as passed)
6884 SET_AH(0x00); // success
6885 CLEAR_CF(); // success
6887 } else if (ah == 0x03) {
6888 // Write Diskette Sectors
6890 //-----------------------------------
6891 // set up DMA controller for transfer
6892 //-----------------------------------
6894 // es:bx = pointer to where to place information from diskette
6895 // port 04: DMA-1 base and current address, channel 2
6896 // port 05: DMA-1 base and current count, channel 2
6897 page = (ES >> 12); // upper 4 bits
6898 base_es = (ES << 4); // lower 16bits contributed by ES
6899 base_address = base_es + BX; // lower 16 bits of address
6900 // contributed by ES:BX
6901 if ( base_address < base_es ) {
6902 // in case of carry, adjust page by 1
6905 base_count = (num_sectors * 512) - 1;
6907 // check for 64K boundary overrun
6908 last_addr = base_address + base_count;
6909 if (last_addr < base_address) {
6911 set_diskette_ret_status(0x09);
6912 SET_AL(0); // no sectors read
6913 SET_CF(); // error occurred
6917 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6920 outb(0x000c, 0x00); // clear flip-flop
6921 outb(0x0004, base_address);
6922 outb(0x0004, base_address>>8);
6923 outb(0x000c, 0x00); // clear flip-flop
6924 outb(0x0005, base_count);
6925 outb(0x0005, base_count>>8);
6927 // port 0b: DMA-1 Mode Register
6928 mode_register = 0x4a; // single mode, increment, autoinit disable,
6929 // transfer type=read, channel 2
6930 outb(0x000b, mode_register);
6932 // port 81: DMA-1 Page Register, channel 2
6935 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6938 //--------------------------------------
6939 // set up floppy controller for transfer
6940 //--------------------------------------
6941 floppy_prepare_controller(drive);
6943 // send write-normal-data command (9 bytes) to controller
6944 outb(0x03f5, 0xc5); // c5: write normal data
6945 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6946 outb(0x03f5, track);
6948 outb(0x03f5, sector);
6949 outb(0x03f5, 2); // 512 byte sector size
6950 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
6951 outb(0x03f5, 0); // Gap length
6952 outb(0x03f5, 0xff); // Gap length
6954 // turn on interrupts
6959 // wait on 40:3e bit 7 to become 1
6961 val8 = read_byte(0x0040, 0x0040);
6963 floppy_reset_controller();
6964 SET_AH(0x80); // drive not ready (timeout)
6965 set_diskette_ret_status(0x80);
6966 SET_AL(0); // no sectors written
6967 SET_CF(); // error occurred
6970 val8 = (read_byte(0x0040, 0x003e) & 0x80);
6971 } while ( val8 == 0 );
6973 val8 = 0; // separate asm from while() loop
6974 // turn off interrupts
6979 // set 40:3e bit 7 to 0
6980 val8 = read_byte(0x0040, 0x003e);
6982 write_byte(0x0040, 0x003e, val8);
6984 // check port 3f4 for accessibility to status bytes
6986 if ( (val8 & 0xc0) != 0xc0 )
6987 BX_PANIC("int13_diskette: ctrl not ready\n");
6989 // read 7 return status bytes from controller
6990 // using loop index broken, have to unroll...
6991 return_status[0] = inb(0x3f5);
6992 return_status[1] = inb(0x3f5);
6993 return_status[2] = inb(0x3f5);
6994 return_status[3] = inb(0x3f5);
6995 return_status[4] = inb(0x3f5);
6996 return_status[5] = inb(0x3f5);
6997 return_status[6] = inb(0x3f5);
6998 // record in BIOS Data Area
6999 write_byte(0x0040, 0x0042, return_status[0]);
7000 write_byte(0x0040, 0x0043, return_status[1]);
7001 write_byte(0x0040, 0x0044, return_status[2]);
7002 write_byte(0x0040, 0x0045, return_status[3]);
7003 write_byte(0x0040, 0x0046, return_status[4]);
7004 write_byte(0x0040, 0x0047, return_status[5]);
7005 write_byte(0x0040, 0x0048, return_status[6]);
7007 if ( (return_status[0] & 0xc0) != 0 ) {
7008 if ( (return_status[1] & 0x02) != 0 ) {
7009 // diskette not writable.
7010 // AH=status code=0x03 (tried to write on write-protected disk)
7011 // AL=number of sectors written=0
7016 BX_PANIC("int13_diskette_function: read error\n");
7020 // ??? should track be new val from return_status[3] ?
7021 set_diskette_current_cyl(drive, track);
7022 // AL = number of sectors read (same value as passed)
7023 SET_AH(0x00); // success
7024 CLEAR_CF(); // success
7026 } else { // if (ah == 0x04)
7027 // Verify Diskette Sectors
7029 // ??? should track be new val from return_status[3] ?
7030 set_diskette_current_cyl(drive, track);
7031 // AL = number of sectors verified (same value as passed)
7032 CLEAR_CF(); // success
7033 SET_AH(0x00); // success
7038 case 0x05: // format diskette track
7039 BX_DEBUG_INT13_FL("floppy f05\n");
7041 num_sectors = GET_AL();
7046 if ((drive > 1) || (head > 1) || (track > 79) ||
7047 (num_sectors == 0) || (num_sectors > 18)) {
7049 set_diskette_ret_status(1);
7050 SET_CF(); // error occurred
7053 // see if drive exists
7054 if (floppy_drive_exists(drive) == 0) {
7055 SET_AH(0x80); // drive not responding
7056 set_diskette_ret_status(0x80);
7057 SET_CF(); // error occurred
7061 // see if media in drive, and type is known
7062 if (floppy_media_known(drive) == 0) {
7063 if (floppy_media_sense(drive) == 0) {
7064 SET_AH(0x0C); // Media type not found
7065 set_diskette_ret_status(0x0C);
7066 SET_AL(0); // no sectors read
7067 SET_CF(); // error occurred
7072 // set up DMA controller for transfer
7073 page = (ES >> 12); // upper 4 bits
7074 base_es = (ES << 4); // lower 16bits contributed by ES
7075 base_address = base_es + BX; // lower 16 bits of address
7076 // contributed by ES:BX
7077 if ( base_address < base_es ) {
7078 // in case of carry, adjust page by 1
7081 base_count = (num_sectors * 4) - 1;
7083 // check for 64K boundary overrun
7084 last_addr = base_address + base_count;
7085 if (last_addr < base_address) {
7087 set_diskette_ret_status(0x09);
7088 SET_AL(0); // no sectors read
7089 SET_CF(); // error occurred
7094 outb(0x000c, 0x00); // clear flip-flop
7095 outb(0x0004, base_address);
7096 outb(0x0004, base_address>>8);
7097 outb(0x000c, 0x00); // clear flip-flop
7098 outb(0x0005, base_count);
7099 outb(0x0005, base_count>>8);
7100 mode_register = 0x4a; // single mode, increment, autoinit disable,
7101 // transfer type=read, channel 2
7102 outb(0x000b, mode_register);
7103 // port 81: DMA-1 Page Register, channel 2
7107 // set up floppy controller for transfer
7108 floppy_prepare_controller(drive);
7110 // send format-track command (6 bytes) to controller
7111 outb(0x03f5, 0x4d); // 4d: format track
7112 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7113 outb(0x03f5, 2); // 512 byte sector size
7114 outb(0x03f5, num_sectors); // number of sectors per track
7115 outb(0x03f5, 0); // Gap length
7116 outb(0x03f5, 0xf6); // Fill byte
7117 // turn on interrupts
7122 // wait on 40:3e bit 7 to become 1
7124 val8 = read_byte(0x0040, 0x0040);
7126 floppy_reset_controller();
7127 SET_AH(0x80); // drive not ready (timeout)
7128 set_diskette_ret_status(0x80);
7129 SET_CF(); // error occurred
7132 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7133 } while ( val8 == 0 );
7135 val8 = 0; // separate asm from while() loop
7136 // turn off interrupts
7140 // set 40:3e bit 7 to 0
7141 val8 = read_byte(0x0040, 0x003e);
7143 write_byte(0x0040, 0x003e, val8);
7144 // check port 3f4 for accessibility to status bytes
7146 if ( (val8 & 0xc0) != 0xc0 )
7147 BX_PANIC("int13_diskette: ctrl not ready\n");
7149 // read 7 return status bytes from controller
7150 // using loop index broken, have to unroll...
7151 return_status[0] = inb(0x3f5);
7152 return_status[1] = inb(0x3f5);
7153 return_status[2] = inb(0x3f5);
7154 return_status[3] = inb(0x3f5);
7155 return_status[4] = inb(0x3f5);
7156 return_status[5] = inb(0x3f5);
7157 return_status[6] = inb(0x3f5);
7158 // record in BIOS Data Area
7159 write_byte(0x0040, 0x0042, return_status[0]);
7160 write_byte(0x0040, 0x0043, return_status[1]);
7161 write_byte(0x0040, 0x0044, return_status[2]);
7162 write_byte(0x0040, 0x0045, return_status[3]);
7163 write_byte(0x0040, 0x0046, return_status[4]);
7164 write_byte(0x0040, 0x0047, return_status[5]);
7165 write_byte(0x0040, 0x0048, return_status[6]);
7167 if ( (return_status[0] & 0xc0) != 0 ) {
7168 if ( (return_status[1] & 0x02) != 0 ) {
7169 // diskette not writable.
7170 // AH=status code=0x03 (tried to write on write-protected disk)
7171 // AL=number of sectors written=0
7176 BX_PANIC("int13_diskette_function: write error\n");
7181 set_diskette_ret_status(0);
7182 set_diskette_current_cyl(drive, 0);
7183 CLEAR_CF(); // successful
7187 case 0x08: // read diskette drive parameters
7188 BX_DEBUG_INT13_FL("floppy f08\n");
7198 SET_DL(num_floppies);
7203 drive_type = inb_cmos(0x10);
7205 if (drive_type & 0xf0)
7207 if (drive_type & 0x0f)
7219 SET_DL(num_floppies);
7221 switch (drive_type) {
7224 SET_DH(0); // max head #
7227 case 1: // 360KB, 5.25"
7228 CX = 0x2709; // 40 tracks, 9 sectors
7229 SET_DH(1); // max head #
7232 case 2: // 1.2MB, 5.25"
7233 CX = 0x4f0f; // 80 tracks, 15 sectors
7234 SET_DH(1); // max head #
7237 case 3: // 720KB, 3.5"
7238 CX = 0x4f09; // 80 tracks, 9 sectors
7239 SET_DH(1); // max head #
7242 case 4: // 1.44MB, 3.5"
7243 CX = 0x4f12; // 80 tracks, 18 sectors
7244 SET_DH(1); // max head #
7247 case 5: // 2.88MB, 3.5"
7248 CX = 0x4f24; // 80 tracks, 36 sectors
7249 SET_DH(1); // max head #
7252 case 6: // 160k, 5.25"
7253 CX = 0x2708; // 40 tracks, 8 sectors
7254 SET_DH(0); // max head #
7257 case 7: // 180k, 5.25"
7258 CX = 0x2709; // 40 tracks, 9 sectors
7259 SET_DH(0); // max head #
7262 case 8: // 320k, 5.25"
7263 CX = 0x2708; // 40 tracks, 8 sectors
7264 SET_DH(1); // max head #
7268 BX_PANIC("floppy: int13: bad floppy type\n");
7271 /* set es & di to point to 11 byte diskette param table in ROM */
7275 mov ax, #diskette_param_table2
7276 mov _int13_diskette_function.DI+2[bp], ax
7277 mov _int13_diskette_function.ES+2[bp], cs
7280 CLEAR_CF(); // success
7281 /* disk status not changed upon success */
7285 case 0x15: // read diskette drive type
7286 BX_DEBUG_INT13_FL("floppy f15\n");
7289 SET_AH(0); // only 2 drives supported
7290 // set_diskette_ret_status here ???
7294 drive_type = inb_cmos(0x10);
7300 CLEAR_CF(); // successful, not present
7301 if (drive_type==0) {
7302 SET_AH(0); // drive not present
7305 SET_AH(1); // drive present, does not support change line
7310 case 0x16: // get diskette change line status
7311 BX_DEBUG_INT13_FL("floppy f16\n");
7314 SET_AH(0x01); // invalid drive
7315 set_diskette_ret_status(0x01);
7320 SET_AH(0x06); // change line not supported
7321 set_diskette_ret_status(0x06);
7325 case 0x17: // set diskette type for format(old)
7326 BX_DEBUG_INT13_FL("floppy f17\n");
7327 /* not used for 1.44M floppies */
7328 SET_AH(0x01); // not supported
7329 set_diskette_ret_status(1); /* not supported */
7333 case 0x18: // set diskette type for format(new)
7334 BX_DEBUG_INT13_FL("floppy f18\n");
7335 SET_AH(0x01); // do later
7336 set_diskette_ret_status(1);
7341 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7343 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7344 SET_AH(0x01); // ???
7345 set_diskette_ret_status(1);
7351 #else // #if BX_SUPPORT_FLOPPY
7353 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7354 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7358 switch ( GET_AH() ) {
7360 case 0x01: // Read Diskette Status
7362 val8 = read_byte(0x0000, 0x0441);
7371 write_byte(0x0000, 0x0441, 0x01);
7375 #endif // #if BX_SUPPORT_FLOPPY
7378 set_diskette_ret_status(value)
7381 write_byte(0x0040, 0x0041, value);
7385 set_diskette_current_cyl(drive, cyl)
7390 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7391 write_byte(0x0040, 0x0094+drive, cyl);
7395 determine_floppy_media(drive)
7399 Bit8u val8, DOR, ctrl_info;
7401 ctrl_info = read_byte(0x0040, 0x008F);
7409 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7412 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7416 if ( (ctrl_info & 0x04) != 0x04 ) {
7417 // Drive not determined means no drive exists, done.
7422 // check Main Status Register for readiness
7423 val8 = inb(0x03f4) & 0x80; // Main Status Register
7425 BX_PANIC("d_f_m: MRQ bit not set\n");
7429 // existing BDA values
7431 // turn on drive motor
7432 outb(0x03f2, DOR); // Digital Output Register
7435 BX_PANIC("d_f_m: OK so far\n");
7440 int17_function(regs, ds, iret_addr)
7441 pusha_regs_t regs; // regs pushed from PUSHA instruction
7442 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7443 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7445 Bit16u addr,timeout;
7452 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7453 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7454 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7455 if (regs.u.r8.ah == 0) {
7456 outb(addr, regs.u.r8.al);
7458 outb(addr+2, val8 | 0x01); // send strobe
7462 outb(addr+2, val8 & ~0x01);
7463 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7467 if (regs.u.r8.ah == 1) {
7469 outb(addr+2, val8 & ~0x04); // send init
7473 outb(addr+2, val8 | 0x04);
7476 regs.u.r8.ah = (val8 ^ 0x48);
7477 if (!timeout) regs.u.r8.ah |= 0x01;
7478 ClearCF(iret_addr.flags);
7480 SetCF(iret_addr.flags); // Unsupported
7484 // returns bootsegment in ax, drive in bl
7486 int19_function(bseqnr)
7489 Bit16u ebda_seg=read_word(0x0040,0x000E);
7498 // if BX_ELTORITO_BOOT is not defined, old behavior
7499 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7500 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7501 // 0: system boot sequence, first drive C: then A:
7502 // 1: system boot sequence, first drive A: then C:
7503 // else BX_ELTORITO_BOOT is defined
7504 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7505 // CMOS reg 0x3D & 0x0f : 1st boot device
7506 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7507 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7508 // boot device codes:
7509 // 0x00 : not defined
7510 // 0x01 : first floppy
7511 // 0x02 : first harddrive
7512 // 0x03 : first cdrom
7513 // else : boot failure
7515 // Get the boot sequence
7516 #if BX_ELTORITO_BOOT
7517 bootseq=inb_cmos(0x3d);
7518 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7520 if (bseqnr==2) bootseq >>= 4;
7521 if (bseqnr==3) bootseq >>= 8;
7522 if (bootseq<0x10) lastdrive = 1;
7523 bootdrv=0x00; bootcd=0;
7524 switch(bootseq & 0x0f) {
7525 case 0x01: bootdrv=0x00; bootcd=0; break;
7526 case 0x02: bootdrv=0x80; bootcd=0; break;
7527 case 0x03: bootdrv=0x00; bootcd=1; break;
7528 default: return 0x00000000;
7531 bootseq=inb_cmos(0x2d);
7537 bootdrv=0x00; bootcd=0;
7538 if((bootseq&0x20)==0) bootdrv=0x80;
7539 #endif // BX_ELTORITO_BOOT
7541 #if BX_ELTORITO_BOOT
7542 // We have to boot from cd
7544 status = cdrom_boot();
7547 if ( (status & 0x00ff) !=0 ) {
7548 print_cdromboot_failure(status);
7549 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7553 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7554 bootdrv = (Bit8u)(status>>8);
7557 #endif // BX_ELTORITO_BOOT
7559 // We have to boot from harddisk or floppy
7568 mov _int19_function.status + 2[bp], ax
7569 mov dl, _int19_function.bootdrv + 2[bp]
7570 mov ax, _int19_function.bootseg + 2[bp]
7571 mov es, ax ;; segment
7572 mov bx, #0x0000 ;; offset
7573 mov ah, #0x02 ;; function 2, read diskette sector
7574 mov al, #0x01 ;; read 1 sector
7575 mov ch, #0x00 ;; track 0
7576 mov cl, #0x01 ;; sector 1
7577 mov dh, #0x00 ;; head 0
7578 int #0x13 ;; read sector
7581 mov _int19_function.status + 2[bp], ax
7588 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7593 // check signature if instructed by cmos reg 0x38, only for floppy
7594 // bootchk = 1 : signature check disabled
7595 // bootchk = 0 : signature check enabled
7596 if (bootdrv != 0) bootchk = 0;
7597 else bootchk = inb_cmos(0x38) & 0x01;
7599 #if BX_ELTORITO_BOOT
7600 // if boot from cd, no signature check
7603 #endif // BX_ELTORITO_BOOT
7606 if (read_word(bootseg,0x1fe) != 0xaa55) {
7607 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7612 #if BX_ELTORITO_BOOT
7613 // Print out the boot string
7614 print_boot_device(bootcd, bootdrv);
7615 #else // BX_ELTORITO_BOOT
7616 print_boot_device(0, bootdrv);
7617 #endif // BX_ELTORITO_BOOT
7619 // return the boot segment
7620 return (((Bit32u)bootdrv) << 16) + bootseg;
7624 int1a_function(regs, ds, iret_addr)
7625 pusha_regs_t regs; // regs pushed from PUSHA instruction
7626 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7627 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7631 BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
7637 switch (regs.u.r8.ah) {
7638 case 0: // get current clock count
7642 regs.u.r16.cx = BiosData->ticks_high;
7643 regs.u.r16.dx = BiosData->ticks_low;
7644 regs.u.r8.al = BiosData->midnight_flag;
7645 BiosData->midnight_flag = 0; // reset flag
7650 ClearCF(iret_addr.flags); // OK
7653 case 1: // Set Current Clock Count
7657 BiosData->ticks_high = regs.u.r16.cx;
7658 BiosData->ticks_low = regs.u.r16.dx;
7659 BiosData->midnight_flag = 0; // reset flag
7664 ClearCF(iret_addr.flags); // OK
7668 case 2: // Read CMOS Time
7669 if (rtc_updating()) {
7670 SetCF(iret_addr.flags);
7674 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7675 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7676 regs.u.r8.ch = inb_cmos(0x04); // Hours
7677 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7679 regs.u.r8.al = regs.u.r8.ch;
7680 ClearCF(iret_addr.flags); // OK
7683 case 3: // Set CMOS Time
7684 // Using a debugger, I notice the following masking/setting
7685 // of bits in Status Register B, by setting Reg B to
7686 // a few values and getting its value after INT 1A was called.
7688 // try#1 try#2 try#3
7689 // before 1111 1101 0111 1101 0000 0000
7690 // after 0110 0010 0110 0010 0000 0010
7692 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7693 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7694 if (rtc_updating()) {
7696 // fall through as if an update were not in progress
7698 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7699 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7700 outb_cmos(0x04, regs.u.r8.ch); // Hours
7701 // Set Daylight Savings time enabled bit to requested value
7702 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7703 // (reg B already selected)
7704 outb_cmos(0x0b, val8);
7706 regs.u.r8.al = val8; // val last written to Reg B
7707 ClearCF(iret_addr.flags); // OK
7710 case 4: // Read CMOS Date
7712 if (rtc_updating()) {
7713 SetCF(iret_addr.flags);
7716 regs.u.r8.cl = inb_cmos(0x09); // Year
7717 regs.u.r8.dh = inb_cmos(0x08); // Month
7718 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7719 regs.u.r8.ch = inb_cmos(0x32); // Century
7720 regs.u.r8.al = regs.u.r8.ch;
7721 ClearCF(iret_addr.flags); // OK
7724 case 5: // Set CMOS Date
7725 // Using a debugger, I notice the following masking/setting
7726 // of bits in Status Register B, by setting Reg B to
7727 // a few values and getting its value after INT 1A was called.
7729 // try#1 try#2 try#3 try#4
7730 // before 1111 1101 0111 1101 0000 0010 0000 0000
7731 // after 0110 1101 0111 1101 0000 0010 0000 0000
7733 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7734 // My assumption: RegB = (RegB & 01111111b)
7735 if (rtc_updating()) {
7737 SetCF(iret_addr.flags);
7740 outb_cmos(0x09, regs.u.r8.cl); // Year
7741 outb_cmos(0x08, regs.u.r8.dh); // Month
7742 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7743 outb_cmos(0x32, regs.u.r8.ch); // Century
7744 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7745 outb_cmos(0x0b, val8);
7747 regs.u.r8.al = val8; // AL = val last written to Reg B
7748 ClearCF(iret_addr.flags); // OK
7751 case 6: // Set Alarm Time in CMOS
7752 // Using a debugger, I notice the following masking/setting
7753 // of bits in Status Register B, by setting Reg B to
7754 // a few values and getting its value after INT 1A was called.
7756 // try#1 try#2 try#3
7757 // before 1101 1111 0101 1111 0000 0000
7758 // after 0110 1111 0111 1111 0010 0000
7760 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7761 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7762 val8 = inb_cmos(0x0b); // Get Status Reg B
7765 // Alarm interrupt enabled already
7766 SetCF(iret_addr.flags); // Error: alarm in use
7769 if (rtc_updating()) {
7771 // fall through as if an update were not in progress
7773 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7774 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7775 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7776 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7777 // enable Status Reg B alarm bit, clear halt clock bit
7778 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7779 ClearCF(iret_addr.flags); // OK
7782 case 7: // Turn off Alarm
7783 // Using a debugger, I notice the following masking/setting
7784 // of bits in Status Register B, by setting Reg B to
7785 // a few values and getting its value after INT 1A was called.
7787 // try#1 try#2 try#3 try#4
7788 // before 1111 1101 0111 1101 0010 0000 0010 0010
7789 // after 0100 0101 0101 0101 0000 0000 0000 0010
7791 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7792 // My assumption: RegB = (RegB & 01010111b)
7793 val8 = inb_cmos(0x0b); // Get Status Reg B
7794 // clear clock-halt bit, disable alarm bit
7795 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7797 regs.u.r8.al = val8; // val last written to Reg B
7798 ClearCF(iret_addr.flags); // OK
7802 // real mode PCI BIOS functions now handled in assembler code
7803 // this C code handles the error code for information only
7804 if (regs.u.r8.bl == 0xff) {
7805 BX_INFO("PCI BIOS: PCI not present\n");
7806 } else if (regs.u.r8.bl == 0x81) {
7807 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7808 } else if (regs.u.r8.bl == 0x83) {
7809 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7810 } else if (regs.u.r8.bl == 0x86) {
7811 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
7813 regs.u.r8.ah = regs.u.r8.bl;
7814 SetCF(iret_addr.flags);
7819 SetCF(iret_addr.flags); // Unsupported
7824 int70_function(regs, ds, iret_addr)
7825 pusha_regs_t regs; // regs pushed from PUSHA instruction
7826 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7827 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7829 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7830 Bit8u registerB = 0, registerC = 0;
7832 // Check which modes are enabled and have occurred.
7833 registerB = inb_cmos( 0xB );
7834 registerC = inb_cmos( 0xC );
7836 if( ( registerB & 0x60 ) != 0 ) {
7837 if( ( registerC & 0x20 ) != 0 ) {
7838 // Handle Alarm Interrupt.
7845 if( ( registerC & 0x40 ) != 0 ) {
7846 // Handle Periodic Interrupt.
7848 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7849 // Wait Interval (Int 15, AH=83) active.
7850 Bit32u time, toggle;
7852 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
7853 if( time < 0x3D1 ) {
7855 Bit16u segment, offset;
7857 segment = read_word( 0x40, 0x98 );
7858 offset = read_word( 0x40, 0x9A );
7859 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7860 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
7861 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
7863 // Continue waiting.
7865 write_dword( 0x40, 0x9C, time );
7878 ;------------------------------------------
7879 ;- INT74h : PS/2 mouse hardware interrupt -
7880 ;------------------------------------------
7885 push #0x00 ;; placeholder for status
7886 push #0x00 ;; placeholder for X
7887 push #0x00 ;; placeholder for Y
7888 push #0x00 ;; placeholder for Z
7889 push #0x00 ;; placeholder for make_far_call boolean
7890 call _int74_function
7891 pop cx ;; remove make_far_call from stack
7894 ;; make far call to EBDA:0022
7897 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
7899 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7904 add sp, #8 ;; pop status, x, y, z
7906 pop ds ;; restore DS
7911 ;; This will perform an IRET, but will retain value of current CF
7912 ;; by altering flags on stack. Better than RETF #02.
7917 and BYTE [bp + 0x06], #0xfe
7923 or BYTE [bp + 0x06], #0x01
7928 ;----------------------
7929 ;- INT13h (relocated) -
7930 ;----------------------
7932 ; int13_relocated is a little bit messed up since I played with it
7933 ; I have to rewrite it:
7934 ; - call a function that detect which function to call
7935 ; - make all called C function get the same parameters list
7939 #if BX_ELTORITO_BOOT
7940 ;; check for an eltorito function
7942 jb int13_not_eltorito
7944 ja int13_not_eltorito
7953 jmp _int13_eltorito ;; ELDX not used
7961 ;; check if emulation active
7962 call _cdemu_isactive
7964 je int13_cdemu_inactive
7966 ;; check if access to the emulated drive
7967 call _cdemu_emulated_drive
7970 cmp al,dl ;; int13 on emulated drive
7985 jmp _int13_cdemu ;; ELDX not used
7988 and dl,#0xE0 ;; mask to get device class, including cdroms
7989 cmp al,dl ;; al is 0x00 or 0x80
7990 jne int13_cdemu_inactive ;; inactive for device class
8002 dec dl ;; real drive is dl - 1
8005 int13_cdemu_inactive:
8011 #endif // BX_ELTORITO_BOOT
8022 push dx ;; push eltorito value of dx instead of sp
8033 ;; now the 16-bit registers can be restored with:
8034 ;; pop ds; pop es; popa; iret
8035 ;; arguments passed to functions should be
8036 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8042 jmp _int13_diskette_function
8051 // ebx is modified: BSD 5.2.1 boot loader problem
8052 // someone should figure out which 32 bit register that actually are used
8069 call _int13_harddisk
8081 int18_handler: ;; Boot Failure routing
8082 call _int18_panic_msg
8089 int19_relocated: ;; Boot function, relocated
8091 ;; int19 was beginning to be really complex, so now it
8092 ;; just calls an C function, that does the work
8093 ;; it returns in BL the boot drive, and in AX the boot segment
8094 ;; the boot segment will be 0x0000 if something has failed
8106 call _int19_function
8109 ;; bl contains the boot drive
8110 ;; ax contains the boot segment or 0 if failure
8112 test ax, ax ;; if ax is 0 try next boot device
8118 call _int19_function
8121 test ax, ax ;; if ax is 0 try next boot device
8127 call _int19_function
8130 test ax, ax ;; if ax is 0 call int18
8134 mov dl, bl ;; set drive so guest os find it
8135 shl eax, #0x04 ;; convert seg to ip
8136 mov 2[bp], ax ;; set ip
8138 shr eax, #0x04 ;; get cs back
8139 and ax, #0xF000 ;; remove what went in ip
8140 mov 4[bp], ax ;; set cs
8142 mov es, ax ;; set es to zero fixes [ 549815 ]
8143 mov [bp], ax ;; set bp to zero
8144 mov ax, #0xaa55 ;; set ok flag
8147 iret ;; Beam me up Scotty
8152 int1c_handler: ;; User Timer Tick
8156 ;----------------------
8157 ;- POST: Floppy Drive -
8158 ;----------------------
8164 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8166 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8168 mov 0x0440, al ;; diskette motor timeout counter: not active
8169 mov 0x0441, al ;; diskette controller status return code
8171 mov 0x0442, al ;; disk & diskette controller status register 0
8172 mov 0x0443, al ;; diskette controller status register 1
8173 mov 0x0444, al ;; diskette controller status register 2
8174 mov 0x0445, al ;; diskette controller cylinder number
8175 mov 0x0446, al ;; diskette controller head number
8176 mov 0x0447, al ;; diskette controller sector number
8177 mov 0x0448, al ;; diskette controller bytes written
8179 mov 0x048b, al ;; diskette configuration data
8181 ;; -----------------------------------------------------------------
8182 ;; (048F) diskette controller information
8184 mov al, #0x10 ;; get CMOS diskette drive type
8187 mov ah, al ;; save byte to AH
8190 shr al, #4 ;; look at top 4 bits for drive 0
8191 jz f0_missing ;; jump if no drive0
8192 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8195 mov bl, #0x00 ;; no drive0
8198 mov al, ah ;; restore from AH
8199 and al, #0x0f ;; look at bottom 4 bits for drive 1
8200 jz f1_missing ;; jump if no drive1
8201 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8203 ;; leave high bits in BL zerod
8204 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8205 ;; -----------------------------------------------------------------
8208 mov 0x0490, al ;; diskette 0 media state
8209 mov 0x0491, al ;; diskette 1 media state
8211 ;; diskette 0,1 operational starting state
8212 ;; drive type has not been determined,
8213 ;; has no changed detection line
8217 mov 0x0494, al ;; diskette 0 current cylinder
8218 mov 0x0495, al ;; diskette 1 current cylinder
8221 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8223 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8224 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8225 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8230 ;--------------------
8231 ;- POST: HARD DRIVE -
8232 ;--------------------
8233 ; relocated here because the primary POST area isnt big enough.
8236 // INT 76h calls INT 15h function ax=9100
8238 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8244 mov 0x0474, al /* hard disk status of last operation */
8245 mov 0x0477, al /* hard disk port offset (XT only ???) */
8246 mov 0x048c, al /* hard disk status register */
8247 mov 0x048d, al /* hard disk error register */
8248 mov 0x048e, al /* hard disk task complete flag */
8250 mov 0x0475, al /* hard disk number attached */
8252 mov 0x0476, al /* hard disk control byte */
8253 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8254 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8255 ;; INT 41h: hard disk 0 configuration pointer
8256 ;; INT 46h: hard disk 1 configuration pointer
8257 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8258 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8260 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8272 cmp al, #47 ;; decimal 47 - user definable
8276 ;; CMOS purpose param table offset
8277 ;; 1b cylinders low 0
8278 ;; 1c cylinders high 1
8280 ;; 1e write pre-comp low 5
8281 ;; 1f write pre-comp high 6
8282 ;; 20 retries/bad map/heads>8 8
8283 ;; 21 landing zone low C
8284 ;; 22 landing zone high D
8285 ;; 23 sectors/track E
8290 ;;; Filling EBDA table for hard disk 0.
8298 mov (0x003d + 0x05), ax ;; write precomp word
8303 mov (0x003d + 0x08), al ;; drive control byte
8312 mov (0x003d + 0x0C), ax ;; landing zone word
8314 mov al, #0x1c ;; get cylinders word in AX
8316 in al, #0x71 ;; high byte
8320 in al, #0x71 ;; low byte
8321 mov bx, ax ;; BX = cylinders
8326 mov cl, al ;; CL = heads
8331 mov dl, al ;; DL = sectors
8334 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8336 hd0_post_physical_chs:
8337 ;; no logical CHS mapping used, just physical CHS
8338 ;; use Standard Fixed Disk Parameter Table (FDPT)
8339 mov (0x003d + 0x00), bx ;; number of physical cylinders
8340 mov (0x003d + 0x02), cl ;; number of physical heads
8341 mov (0x003d + 0x0E), dl ;; number of physical sectors
8344 hd0_post_logical_chs:
8345 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8346 mov (0x003d + 0x09), bx ;; number of physical cylinders
8347 mov (0x003d + 0x0b), cl ;; number of physical heads
8348 mov (0x003d + 0x04), dl ;; number of physical sectors
8349 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8351 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8354 jnbe hd0_post_above_2048
8355 ;; 1024 < c <= 2048 cylinders
8358 jmp hd0_post_store_logical
8360 hd0_post_above_2048:
8362 jnbe hd0_post_above_4096
8363 ;; 2048 < c <= 4096 cylinders
8366 jmp hd0_post_store_logical
8368 hd0_post_above_4096:
8370 jnbe hd0_post_above_8192
8371 ;; 4096 < c <= 8192 cylinders
8374 jmp hd0_post_store_logical
8376 hd0_post_above_8192:
8377 ;; 8192 < c <= 16384 cylinders
8381 hd0_post_store_logical:
8382 mov (0x003d + 0x00), bx ;; number of physical cylinders
8383 mov (0x003d + 0x02), cl ;; number of physical heads
8385 mov cl, #0x0f ;; repeat count
8386 mov si, #0x003d ;; offset to disk0 FDPT
8387 mov al, #0x00 ;; sum
8388 hd0_post_checksum_loop:
8392 jnz hd0_post_checksum_loop
8393 not al ;; now take 2s complement
8396 ;;; Done filling EBDA table for hard disk 0.
8400 ;; is there really a second hard disk? if not, return now
8408 ;; check that the hd type is really 0x0f.
8413 ;; check that the extended type is 47 - user definable
8417 cmp al, #47 ;; decimal 47 - user definable
8422 ;; CMOS purpose param table offset
8423 ;; 0x24 cylinders low 0
8424 ;; 0x25 cylinders high 1
8426 ;; 0x27 write pre-comp low 5
8427 ;; 0x28 write pre-comp high 6
8429 ;; 0x2a landing zone low C
8430 ;; 0x2b landing zone high D
8431 ;; 0x2c sectors/track E
8432 ;;; Fill EBDA table for hard disk 1.
8442 mov (0x004d + 0x05), ax ;; write precomp word
8447 mov (0x004d + 0x08), al ;; drive control byte
8456 mov (0x004d + 0x0C), ax ;; landing zone word
8458 mov al, #0x25 ;; get cylinders word in AX
8460 in al, #0x71 ;; high byte
8464 in al, #0x71 ;; low byte
8465 mov bx, ax ;; BX = cylinders
8470 mov cl, al ;; CL = heads
8475 mov dl, al ;; DL = sectors
8478 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8480 hd1_post_physical_chs:
8481 ;; no logical CHS mapping used, just physical CHS
8482 ;; use Standard Fixed Disk Parameter Table (FDPT)
8483 mov (0x004d + 0x00), bx ;; number of physical cylinders
8484 mov (0x004d + 0x02), cl ;; number of physical heads
8485 mov (0x004d + 0x0E), dl ;; number of physical sectors
8488 hd1_post_logical_chs:
8489 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8490 mov (0x004d + 0x09), bx ;; number of physical cylinders
8491 mov (0x004d + 0x0b), cl ;; number of physical heads
8492 mov (0x004d + 0x04), dl ;; number of physical sectors
8493 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8495 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8498 jnbe hd1_post_above_2048
8499 ;; 1024 < c <= 2048 cylinders
8502 jmp hd1_post_store_logical
8504 hd1_post_above_2048:
8506 jnbe hd1_post_above_4096
8507 ;; 2048 < c <= 4096 cylinders
8510 jmp hd1_post_store_logical
8512 hd1_post_above_4096:
8514 jnbe hd1_post_above_8192
8515 ;; 4096 < c <= 8192 cylinders
8518 jmp hd1_post_store_logical
8520 hd1_post_above_8192:
8521 ;; 8192 < c <= 16384 cylinders
8525 hd1_post_store_logical:
8526 mov (0x004d + 0x00), bx ;; number of physical cylinders
8527 mov (0x004d + 0x02), cl ;; number of physical heads
8529 mov cl, #0x0f ;; repeat count
8530 mov si, #0x004d ;; offset to disk0 FDPT
8531 mov al, #0x00 ;; sum
8532 hd1_post_checksum_loop:
8536 jnz hd1_post_checksum_loop
8537 not al ;; now take 2s complement
8540 ;;; Done filling EBDA table for hard disk 1.
8544 ;--------------------
8545 ;- POST: EBDA segment
8546 ;--------------------
8547 ; relocated here because the primary POST area isnt big enough.
8552 mov byte ptr [0x0], #EBDA_SIZE
8554 xor ax, ax ; mov EBDA seg into 40E
8556 mov word ptr [0x40E], #EBDA_SEG
8559 ;--------------------
8560 ;- POST: EOI + jmp via [0x40:67)
8561 ;--------------------
8562 ; relocated here because the primary POST area isnt big enough.
8572 ;--------------------
8575 out #0xA0, al ;; slave PIC EOI
8578 out #0x20, al ;; master PIC EOI
8581 ;--------------------
8583 ;; in: AL in BCD format
8584 ;; out: AL in binary format, AH will always be 0
8587 and bl, #0x0f ;; bl has low digit
8588 shr al, #4 ;; al has high digit
8590 mul al, bh ;; multiply high digit by 10 (result in AX)
8591 add al, bl ;; then add low digit
8594 ;--------------------
8596 ;; Setup the Timer Ticks Count (0x46C:dword) and
8597 ;; Timer Ticks Roller Flag (0x470:byte)
8598 ;; The Timer Ticks Count needs to be set according to
8599 ;; the current CMOS time, as if ticks have been occurring
8600 ;; at 18.2hz since midnight up to this point. Calculating
8601 ;; this is a little complicated. Here are the factors I gather
8602 ;; regarding this. 14,318,180 hz was the original clock speed,
8603 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8604 ;; at the time, or 4 to drive the CGA video adapter. The div3
8605 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8606 ;; the timer. With a maximum 16bit timer count, this is again
8607 ;; divided down by 65536 to 18.2hz.
8609 ;; 14,318,180 Hz clock
8610 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8611 ;; /4 = 1,193,181 Hz fed to timer
8612 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8613 ;; 1 second = 18.20650736 ticks
8614 ;; 1 minute = 1092.390442 ticks
8615 ;; 1 hour = 65543.42651 ticks
8617 ;; Given the values in the CMOS clock, one could calculate
8618 ;; the number of ticks by the following:
8619 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8620 ;; (BcdToBin(minutes) * 1092.3904)
8621 ;; (BcdToBin(hours) * 65543.427)
8622 ;; To get a little more accuracy, since Im using integer
8623 ;; arithmatic, I use:
8624 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8625 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8626 ;; (BcdToBin(hours) * 65543427) / 1000
8631 xor eax, eax ;; clear EAX
8634 in al, #0x71 ;; AL has CMOS seconds in BCD
8635 call BcdToBin ;; EAX now has seconds in binary
8641 mov ecx, eax ;; ECX will accumulate total ticks
8644 xor eax, eax ;; clear EAX
8647 in al, #0x71 ;; AL has CMOS minutes in BCD
8648 call BcdToBin ;; EAX now has minutes in binary
8654 add ecx, eax ;; add to total ticks
8657 xor eax, eax ;; clear EAX
8660 in al, #0x71 ;; AL has CMOS hours in BCD
8661 call BcdToBin ;; EAX now has hours in binary
8667 add ecx, eax ;; add to total ticks
8669 mov 0x46C, ecx ;; Timer Ticks Count
8671 mov 0x470, al ;; Timer Ticks Rollover Flag
8674 ;--------------------
8676 ;; record completion in BIOS task complete flag
8688 ;--------------------
8690 ;--------------------
8695 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8696 dw bios32_entry_point, 0xf ;; 32 bit physical address
8697 db 0 ;; revision level
8698 ;; length in paragraphs and checksum stored in a word to prevent errors
8699 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8700 & 0xff) << 8) + 0x01
8701 db 0,0,0,0,0 ;; reserved
8706 cmp eax, #0x49435024 ;; "$PCI"
8708 mov eax, #0x80000000
8713 #ifdef PCI_FIXED_HOST_BRIDGE
8714 cmp eax, #PCI_FIXED_HOST_BRIDGE
8717 ;; say ok if a device is present
8718 cmp eax, #0xffffffff
8721 mov ebx, #0x000f0000
8723 mov edx, #pcibios_protected
8738 cmp al, #0x01 ;; installation check
8742 mov edx, #0x20494350 ;; "PCI "
8745 pci_pro_f02: ;; find pci device
8753 call pci_pro_select_reg
8767 pci_pro_f08: ;; read configuration byte
8770 call pci_pro_select_reg
8779 pci_pro_f09: ;; read configuration word
8782 call pci_pro_select_reg
8791 pci_pro_f0a: ;; read configuration dword
8794 call pci_pro_select_reg
8801 pci_pro_f0b: ;; write configuration byte
8804 call pci_pro_select_reg
8813 pci_pro_f0c: ;; write configuration word
8816 call pci_pro_select_reg
8825 pci_pro_f0d: ;; write configuration dword
8828 call pci_pro_select_reg
8869 mov eax, #0x80000000
8874 #ifdef PCI_FIXED_HOST_BRIDGE
8875 cmp eax, #PCI_FIXED_HOST_BRIDGE
8878 ;; say ok if a device is present
8879 cmp eax, #0xffffffff
8890 cmp al, #0x01 ;; installation check
8895 mov edx, #0x20494350 ;; "PCI "
8897 mov di, #pcibios_protected
8900 pci_real_f02: ;; find pci device
8910 call pci_real_select_reg
8914 jne pci_real_nextdev
8921 jne pci_real_devloop
8926 pci_real_f08: ;; read configuration byte
8929 call pci_real_select_reg
8938 pci_real_f09: ;; read configuration word
8941 call pci_real_select_reg
8950 pci_real_f0a: ;; read configuration dword
8953 call pci_real_select_reg
8960 pci_real_f0b: ;; write configuration byte
8963 call pci_real_select_reg
8972 pci_real_f0c: ;; write configuration word
8975 call pci_real_select_reg
8984 pci_real_f0d: ;; write configuration dword
8987 call pci_real_select_reg
8994 pci_real_f0e: ;; get irq routing options
8996 jne pci_real_unknown
8998 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
8999 jb pci_real_too_small
9001 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9009 mov si, #pci_routing_table_structure_start
9017 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
9026 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9030 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9048 pci_real_select_reg:
9062 pci_routing_table_structure:
9063 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9065 dw 32 + (6 * 16) ;; table size
9066 db 0 ;; PCI interrupt router bus
9067 db 0x08 ;; PCI interrupt router DevFunc
9068 dw 0x0000 ;; PCI exclusive IRQs
9069 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9070 dw 0x7000 ;; compatible PCI interrupt router device ID
9071 dw 0,0 ;; Miniport data
9072 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9074 pci_routing_table_structure_start:
9075 ;; first slot entry PCI-to-ISA (embedded)
9076 db 0 ;; pci bus number
9077 db 0x08 ;; pci device number (bit 7-3)
9078 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9079 dw 0xdef8 ;; IRQ bitmap INTA#
9080 db 0x61 ;; link value INTB#
9081 dw 0xdef8 ;; IRQ bitmap INTB#
9082 db 0x62 ;; link value INTC#
9083 dw 0xdef8 ;; IRQ bitmap INTC#
9084 db 0x63 ;; link value INTD#
9085 dw 0xdef8 ;; IRQ bitmap INTD#
9086 db 0 ;; physical slot (0 = embedded)
9088 ;; second slot entry: 1st PCI slot
9089 db 0 ;; pci bus number
9090 db 0x10 ;; pci device number (bit 7-3)
9091 db 0x61 ;; link value INTA#
9092 dw 0xdef8 ;; IRQ bitmap INTA#
9093 db 0x62 ;; link value INTB#
9094 dw 0xdef8 ;; IRQ bitmap INTB#
9095 db 0x63 ;; link value INTC#
9096 dw 0xdef8 ;; IRQ bitmap INTC#
9097 db 0x60 ;; link value INTD#
9098 dw 0xdef8 ;; IRQ bitmap INTD#
9099 db 1 ;; physical slot (0 = embedded)
9101 ;; third slot entry: 2nd PCI slot
9102 db 0 ;; pci bus number
9103 db 0x18 ;; pci device number (bit 7-3)
9104 db 0x62 ;; link value INTA#
9105 dw 0xdef8 ;; IRQ bitmap INTA#
9106 db 0x63 ;; link value INTB#
9107 dw 0xdef8 ;; IRQ bitmap INTB#
9108 db 0x60 ;; link value INTC#
9109 dw 0xdef8 ;; IRQ bitmap INTC#
9110 db 0x61 ;; link value INTD#
9111 dw 0xdef8 ;; IRQ bitmap INTD#
9112 db 2 ;; physical slot (0 = embedded)
9114 ;; 4th slot entry: 3rd PCI slot
9115 db 0 ;; pci bus number
9116 db 0x20 ;; pci device number (bit 7-3)
9117 db 0x63 ;; link value INTA#
9118 dw 0xdef8 ;; IRQ bitmap INTA#
9119 db 0x60 ;; link value INTB#
9120 dw 0xdef8 ;; IRQ bitmap INTB#
9121 db 0x61 ;; link value INTC#
9122 dw 0xdef8 ;; IRQ bitmap INTC#
9123 db 0x62 ;; link value INTD#
9124 dw 0xdef8 ;; IRQ bitmap INTD#
9125 db 3 ;; physical slot (0 = embedded)
9127 ;; 5th slot entry: 4rd PCI slot
9128 db 0 ;; pci bus number
9129 db 0x28 ;; pci device number (bit 7-3)
9130 db 0x60 ;; link value INTA#
9131 dw 0xdef8 ;; IRQ bitmap INTA#
9132 db 0x61 ;; link value INTB#
9133 dw 0xdef8 ;; IRQ bitmap INTB#
9134 db 0x62 ;; link value INTC#
9135 dw 0xdef8 ;; IRQ bitmap INTC#
9136 db 0x63 ;; link value INTD#
9137 dw 0xdef8 ;; IRQ bitmap INTD#
9138 db 4 ;; physical slot (0 = embedded)
9140 ;; 6th slot entry: 5rd PCI slot
9141 db 0 ;; pci bus number
9142 db 0x30 ;; pci device number (bit 7-3)
9143 db 0x61 ;; link value INTA#
9144 dw 0xdef8 ;; IRQ bitmap INTA#
9145 db 0x62 ;; link value INTB#
9146 dw 0xdef8 ;; IRQ bitmap INTB#
9147 db 0x63 ;; link value INTC#
9148 dw 0xdef8 ;; IRQ bitmap INTC#
9149 db 0x60 ;; link value INTD#
9150 dw 0xdef8 ;; IRQ bitmap INTD#
9151 db 5 ;; physical slot (0 = embedded)
9153 pci_routing_table_structure_end:
9158 pcibios_init_sel_reg:
9170 pcibios_init_iomem_bases:
9173 mov eax, #0xe0000000 ;; base for memory init
9175 mov ax, #0xc000 ;; base for i/o init
9177 mov ax, #0x0010 ;; start at base address #0
9182 call pcibios_init_sel_reg
9187 mov dl, #0x04 ;; disable i/o and memory space access
9188 call pcibios_init_sel_reg
9195 call pcibios_init_sel_reg
9201 mov eax, #0xffffffff
9206 xor eax, #0xffffffff
9210 add eax, ecx ;; calculate next free mem base
9211 add eax, #0x01000000
9212 and eax, #0xff000000
9226 add ax, cx ;; calculate next free i/o base
9234 je enable_iomem_space
9235 mov byte ptr[bp-8], al
9236 jmp pci_init_io_loop2
9238 mov dl, #0x04 ;; enable i/o and memory space access if available
9239 call pcibios_init_sel_reg
9245 mov byte ptr[bp-8], #0x10
9248 jne pci_init_io_loop1
9253 pcibios_init_set_elcr:
9277 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9282 mov si, #pci_routing_table_structure
9286 call pcibios_init_sel_reg
9289 cmp eax, [si+12] ;; check irq router
9292 call pcibios_init_sel_reg
9293 push bx ;; save irq router bus + devfunc
9296 out dx, ax ;; reset PIRQ route control
9304 add si, #0x20 ;; set pointer to 1st entry
9306 mov ax, #pci_irq_list
9315 call pcibios_init_sel_reg
9319 jnz pci_test_int_pin
9325 call pcibios_init_sel_reg
9330 dec al ;; determine pirq reg
9339 call pcibios_init_sel_reg
9346 mov bx, [bp-2] ;; pci irq list pointer
9351 call pcibios_init_set_elcr
9355 add bl, [bp-3] ;; pci function number
9357 call pcibios_init_sel_reg
9364 jnz pci_init_irq_loop2
9367 mov byte ptr[bp-3], #0x00
9368 loop pci_init_irq_loop1
9375 #endif // BX_PCIBIOS
9377 ; parallel port detection: base address in DX, index in BX, timeout in CL
9382 and al, #0xdf ; clear input mode
9392 mov [bx+0x408], dx ; Parallel I/O address
9394 mov [bx+0x478], cl ; Parallel printer timeout
9399 ; serial port detection: base address in DX, index in BX, timeout in CL
9418 mov [bx+0x400], dx ; Serial I/O address
9420 mov [bx+0x47c], cl ; Serial timeout
9447 ;; Scan for existence of valid expansion ROMS.
9448 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9449 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9450 ;; System ROM: only 0xE0000
9456 ;; 2 ROM length in 512-byte blocks
9457 ;; 3 ROM initialization entry point (FAR CALL)
9462 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9463 cmp [0], #0xAA55 ;; look for signature
9464 jne rom_scan_increment
9466 jnz rom_scan_increment
9467 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9469 ;; We want our increment in 512-byte quantities, rounded to
9470 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9472 jz block_count_rounded
9473 and al, #0xfc ;; needs rounding up
9475 block_count_rounded:
9477 xor bx, bx ;; Restore DS back to 0000:
9480 ;; Push addr of ROM entry point
9482 push #0x0003 ;; Push offset
9483 mov bp, sp ;; Call ROM init routine using seg:off on stack
9484 db 0xff ;; call_far ss:[bp+0]
9487 cli ;; In case expansion ROM BIOS turns IF on
9488 add sp, #2 ;; Pop offset value
9489 pop cx ;; Pop seg value (restore CX)
9490 pop ax ;; Restore AX
9492 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9493 ;; because the segment selector is shifted left 4 bits.
9498 xor ax, ax ;; Restore DS back to 0000:
9502 ;; for 'C' strings and other data, insert them here with
9503 ;; a the following hack:
9504 ;; DATA_SEG_DEFS_HERE
9510 .org 0xe05b ; POST Entry Point
9515 ;; first reset the DMA controllers
9519 ;; then initialize the DMA controllers
9521 out 0xD6, al ; cascade mode of channel 4 enabled
9523 out 0xD4, al ; unmask channel 4
9525 ;; Examine CMOS shutdown status.
9533 ;; Reset CMOS shutdown status.
9535 out 0x70, AL ; select CMOS register Fh
9537 out 0x71, AL ; set shutdown action to normal
9539 ;; Examine CMOS shutdown status.
9542 ;; 0x00, 0x09, 0x0D+ = normal startup
9550 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9554 ;; Examine CMOS shutdown status.
9555 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9557 call _shutdown_status_panic
9563 ; 0xb0, 0x20, /* mov al, #0x20 */
9564 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9574 ; case 0: normal startup
9583 ;; zero out BIOS data area (40:00..40:ff)
9585 mov cx, #0x0080 ;; 128 words
9591 call _log_bios_start
9593 ;; set all interrupts to default handler
9594 mov bx, #0x0000 ;; offset index
9595 mov cx, #0x0100 ;; counter (256 interrupts)
9596 mov ax, #dummy_iret_handler
9606 loop post_default_ints
9608 ;; set vector 0x79 to zero
9609 ;; this is used by 'gardian angel' protection system
9610 SET_INT_VECTOR(0x79, #0, #0)
9612 ;; base memory in K 40:13 (word)
9613 mov ax, #BASE_MEM_IN_K
9617 ;; Manufacturing Test 40:12
9620 ;; Warm Boot Flag 0040:0072
9621 ;; value of 1234h = skip memory checks
9625 ;; Printer Services vector
9626 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9628 ;; Bootstrap failure vector
9629 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9631 ;; Bootstrap Loader vector
9632 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9634 ;; User Timer Tick vector
9635 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9637 ;; Memory Size Check vector
9638 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9640 ;; Equipment Configuration Check vector
9641 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9644 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9650 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9651 ;; int 1C already points at dummy_iret_handler (above)
9652 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9654 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9659 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9660 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9664 mov 0x0417, al /* keyboard shift flags, set 1 */
9665 mov 0x0418, al /* keyboard shift flags, set 2 */
9666 mov 0x0419, al /* keyboard alt-numpad work area */
9667 mov 0x0471, al /* keyboard ctrl-break flag */
9668 mov 0x0497, al /* keyboard status flags 4 */
9670 mov 0x0496, al /* keyboard status flags 3 */
9673 /* keyboard head of buffer pointer */
9677 /* keyboard end of buffer pointer */
9680 /* keyboard pointer to start of buffer */
9684 /* keyboard pointer to end of buffer */
9688 /* init the keyboard */
9691 ;; mov CMOS Equipment Byte to BDA Equipment Word
9700 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9704 mov cl, #0x14 ; timeout value
9705 mov dx, #0x378 ; Parallel I/O address, port 1
9707 mov dx, #0x278 ; Parallel I/O address, port 2
9710 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9712 or ax, bx ; set number of parallel ports
9716 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9717 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9719 mov cl, #0x0a ; timeout value
9720 mov dx, #0x03f8 ; Serial I/O address, port 1
9722 mov dx, #0x02f8 ; Serial I/O address, port 2
9724 mov dx, #0x03e8 ; Serial I/O address, port 3
9726 mov dx, #0x02e8 ; Serial I/O address, port 4
9729 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9731 or ax, bx ; set number of serial port
9735 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9736 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9737 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9738 ;; BIOS DATA AREA 0x4CE ???
9739 call timer_tick_post
9742 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9744 ;; IRQ13 (FPU exception) setup
9745 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9748 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9751 mov al, #0x11 ; send initialisation commands
9766 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9767 #if BX_USE_PS2_MOUSE
9772 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9775 call pcibios_init_iomem_bases
9776 call pcibios_init_irqs
9781 call _print_bios_banner
9786 call floppy_drive_post
9793 call hard_drive_post
9796 ;; ATA/ATAPI driver setup
9801 #else // BX_USE_ATADRV
9806 call hard_drive_post
9808 #endif // BX_USE_ATADRV
9810 #if BX_ELTORITO_BOOT
9812 ;; eltorito floppy/harddisk emulation from cd
9816 #endif // BX_ELTORITO_BOOT
9818 sti ;; enable interrupts
9822 .org 0xe2c3 ; NMI Handler Entry Point
9824 ;; FIXME the NMI handler should not panic
9825 ;; but iret when called from int75 (fpu exception)
9826 call _nmi_handler_msg
9830 out 0xf0, al // clear irq13
9831 call eoi_both_pics // clear interrupt
9832 int 2 // legacy nmi call
9835 ;-------------------------------------------
9836 ;- INT 13h Fixed Disk Services Entry Point -
9837 ;-------------------------------------------
9838 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9840 //JMPL(int13_relocated)
9843 .org 0xe401 ; Fixed Disk Parameter Table
9848 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9852 ;-------------------------------------------
9853 ;- System BIOS Configuration Data Table
9854 ;-------------------------------------------
9855 .org BIOS_CONFIG_TABLE
9856 db 0x08 ; Table size (bytes) -Lo
9857 db 0x00 ; Table size (bytes) -Hi
9862 ; b7: 1=DMA channel 3 used by hard disk
9863 ; b6: 1=2 interrupt controllers present
9865 ; b4: 1=BIOS calls int 15h/4Fh every key
9866 ; b3: 1=wait for extern event supported (Int 15h/41h)
9867 ; b2: 1=extended BIOS data area used
9868 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9869 ; b0: 1=Dual bus (MicroChannel + ISA)
9873 (BX_CALL_INT15_4F << 4) | \
9875 (BX_USE_EBDA << 2) | \
9879 ; b7: 1=32-bit DMA supported
9880 ; b6: 1=int16h, function 9 supported
9881 ; b5: 1=int15h/C6h (get POS data) supported
9882 ; b4: 1=int15h/C7h (get mem map info) supported
9883 ; b3: 1=int15h/C8h (en/dis CPU) supported
9884 ; b2: 1=non-8042 kb controller
9885 ; b1: 1=data streaming supported
9899 ; b4: POST supports ROM-to-RAM enable/disable
9900 ; b3: SCSI on system board
9901 ; b2: info panel installed
9902 ; b1: Initial Machine Load (IML) system - BIOS on disk
9903 ; b0: SCSI supported in IML
9907 ; b6: EEPROM present
9908 ; b5-3: ABIOS presence (011 = not supported)
9910 ; b1: memory split above 16Mb supported
9911 ; b0: POSTEXT directly supported by POST
9913 ; Feature byte 5 (IBM)
9914 ; b1: enhanced mouse
9920 .org 0xe729 ; Baud Rate Generator Table
9925 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
9931 call _int14_function
9937 ;----------------------------------------
9938 ;- INT 16h Keyboard Service Entry Point -
9939 ;----------------------------------------
9955 call _int16_function
9965 and BYTE [bp + 0x06], #0xbf
9973 or BYTE [bp + 0x06], #0x40
9989 /* no key yet, call int 15h, function AX=9002 */
9991 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9992 0xcd, 0x15, /* int 15h */
9994 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
9996 jmp int16_wait_for_key
10001 call _int16_function
10006 /* notify int16 complete w/ int 15h, function AX=9102 */
10007 0x50, /* push AX */
10008 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10009 0xcd, 0x15, /* int 15h */
10016 ;-------------------------------------------------
10017 ;- INT09h : Keyboard Hardware Service Entry Point -
10018 ;-------------------------------------------------
10024 mov al, #0xAD ;;disable keyboard
10033 in al, #0x60 ;;read key from keyboard controller
10037 #ifdef BX_CALL_INT15_4F
10038 mov ah, #0x4f ;; allow for keyboard intercept
10044 ;; check for extended key
10046 jne int09_check_pause
10049 mov al, BYTE [0x496] ;; mf2_state |= 0x02
10051 mov BYTE [0x496], al
10054 int09_check_pause: ;; check for pause key
10056 jne int09_process_key
10059 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10061 mov BYTE [0x496], al
10067 call _int09_function
10073 call eoi_master_pic
10076 mov al, #0xAE ;;enable keyboard
10082 ;----------------------------------------
10083 ;- INT 13h Diskette Service Entry Point -
10084 ;----------------------------------------
10087 jmp int13_noeltorito
10089 ;---------------------------------------------
10090 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10091 ;---------------------------------------------
10092 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10102 mov al, #0x08 ; sense interrupt status
10120 mov ax, #0x0000 ;; segment 0000
10122 call eoi_master_pic
10124 or al, #0x80 ;; diskette interrupt has occurred
10132 .org 0xefc7 ; Diskette Controller Parameter Table
10133 diskette_param_table:
10134 ;; Since no provisions are made for multiple drive types, most
10135 ;; values in this table are ignored. I set parameters for 1.44M
10138 db 0x02 ;; head load time 0000001, DMA used
10150 ;----------------------------------------
10151 ;- INT17h : Printer Service Entry Point -
10152 ;----------------------------------------
10159 call _int17_function
10164 diskette_param_table2:
10165 ;; New diskette parameter table adding 3 parameters from IBM
10166 ;; Since no provisions are made for multiple drive types, most
10167 ;; values in this table are ignored. I set parameters for 1.44M
10170 db 0x02 ;; head load time 0000001, DMA used
10180 db 79 ;; maximum track
10181 db 0 ;; data transfer rate
10182 db 4 ;; drive type in cmos
10184 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10191 .org 0xf065 ; INT 10h Video Support Service Entry Point
10193 ;; dont do anything, since the VGA BIOS handles int10h requests
10196 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10201 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10202 ; ??? different for Pentium (machine check)?
10214 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10226 .org 0xf859 ; INT 15h System Services Entry Point
10236 #if BX_USE_PS2_MOUSE
10238 je int15_handler_mouse
10240 call _int15_function
10241 int15_handler_mouse_ret:
10243 int15_handler32_ret:
10249 #if BX_USE_PS2_MOUSE
10250 int15_handler_mouse:
10251 call _int15_function_mouse
10252 jmp int15_handler_mouse_ret
10257 call _int15_function32
10259 jmp int15_handler32_ret
10261 ;; Protected mode IDT descriptor
10263 ;; I just make the limit 0, so the machine will shutdown
10264 ;; if an exception occurs during protected mode memory
10267 ;; Set base to f0000 to correspond to beginning of BIOS,
10268 ;; in case I actually define an IDT later
10272 dw 0x0000 ;; limit 15:00
10273 dw 0x0000 ;; base 15:00
10274 db 0x0f ;; base 23:16
10276 ;; Real mode IDT descriptor
10278 ;; Set to typical real-mode values.
10283 dw 0x03ff ;; limit 15:00
10284 dw 0x0000 ;; base 15:00
10285 db 0x00 ;; base 23:16
10291 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10304 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10305 mov ds, ax ; on 16bit protected mode.
10306 jmp int1a_callfunction
10313 int1a_callfunction:
10314 call _int1a_function
10320 ;; int70h: IRQ8 - CMOS RTC
10327 call _int70_function
10335 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10343 ;; time to turn off drive(s)?
10346 jz int08_floppy_off
10349 jnz int08_floppy_off
10350 ;; turn motor(s) off
10359 mov eax, 0x046c ;; get ticks dword
10362 ;; compare eax to one days worth of timer ticks at 18.2 hz
10363 cmp eax, #0x001800B0
10364 jb int08_store_ticks
10365 ;; there has been a midnight rollover at this point
10366 xor eax, eax ;; zero out counter
10367 inc BYTE 0x0470 ;; increment rollover flag
10370 mov 0x046c, eax ;; store new ticks dword
10371 ;; chain to user timer tick INT #0x1c
10373 //;; call_ep [ds:loc]
10374 //CALL_EP( 0x1c << 2 )
10377 call eoi_master_pic
10382 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10386 .ascii BIOS_COPYRIGHT_STRING
10388 ;------------------------------------------------
10389 ;- IRET Instruction for Dummy Interrupt Handler -
10390 ;------------------------------------------------
10391 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10392 dummy_iret_handler:
10395 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10399 .org 0xfff0 ; Power-up Entry Point
10402 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10403 .ascii BIOS_BUILD_DATE
10405 .org 0xfffe ; System Model ID
10409 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10412 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10413 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10414 * This font is public domain
10416 static Bit8u vgafont8[128*8]=
10418 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10419 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10420 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10421 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10422 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10423 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10424 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10425 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10426 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10427 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10428 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10429 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10430 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10431 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10432 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10433 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10434 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10435 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10436 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10437 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10438 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10439 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10440 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10441 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10442 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10443 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10444 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10445 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10446 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10447 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10448 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10449 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10451 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10452 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10453 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10454 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10455 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10456 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10457 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10458 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10459 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10460 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10461 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10462 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10463 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10464 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10465 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10466 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10467 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10468 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10469 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10470 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10471 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10472 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10473 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10474 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10475 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10476 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10477 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10478 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10479 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10480 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10481 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10482 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10483 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10484 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10485 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10486 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10487 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10488 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10489 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10490 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10491 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10492 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10493 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10494 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10495 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10496 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10497 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10498 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10499 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10500 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10501 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10502 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10503 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10504 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10505 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10506 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10507 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10508 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10509 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10510 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10511 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10512 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10514 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10515 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10516 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10517 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10518 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10519 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10520 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10521 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10522 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10523 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10524 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10525 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10526 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10527 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10528 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10529 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10530 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10531 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10532 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10533 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10534 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10535 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10536 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10537 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10538 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10539 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10540 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10541 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10542 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10543 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10544 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10545 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10550 // bcc-generated data will be placed here