2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.16 2008/08/14 20:04:33 cuizheng Exp $
4 /////////////////////////////////////////////////////////////////////////
6 // Copyright (C) 2002 MandrakeSoft S.A.
10 // 75002 Paris - France
11 // http://www.linux-mandrake.com/
12 // http://www.mandrakesoft.com/
14 // This library is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Lesser General Public
16 // License as published by the Free Software Foundation; either
17 // version 2 of the License, or (at your option) any later version.
19 // This library is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 // Lesser General Public License for more details.
24 // You should have received a copy of the GNU Lesser General Public
25 // License along with this library; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 // ROM BIOS for use with Bochs/Plex x86 emulation environment
33 // Xen full virtualization does not handle unaligned IO with page crossing.
34 // Disable 32-bit PIO as a workaround.
38 // ROM BIOS compatability entry points:
39 // ===================================
40 // $e05b ; POST Entry Point
41 // $e2c3 ; NMI Handler Entry Point
42 // $e3fe ; INT 13h Fixed Disk Services Entry Point
43 // $e401 ; Fixed Disk Parameter Table
44 // $e6f2 ; INT 19h Boot Load Service Entry Point
45 // $e6f5 ; Configuration Data Table
46 // $e729 ; Baud Rate Generator Table
47 // $e739 ; INT 14h Serial Communications Service Entry Point
48 // $e82e ; INT 16h Keyboard Service Entry Point
49 // $e987 ; INT 09h Keyboard Service Entry Point
50 // $ec59 ; INT 13h Diskette Service Entry Point
51 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
52 // $efc7 ; Diskette Controller Parameter Table
53 // $efd2 ; INT 17h Printer Service Entry Point
54 // $f045 ; INT 10 Functions 0-Fh Entry Point
55 // $f065 ; INT 10h Video Support Service Entry Point
56 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
57 // $f841 ; INT 12h Memory Size Service Entry Point
58 // $f84d ; INT 11h Equipment List Service Entry Point
59 // $f859 ; INT 15h System Services Entry Point
60 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
61 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
62 /// $fea5 ; INT 08h System Timer ISR Entry Point
63 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
64 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
65 // $ff54 ; INT 05h Print Screen Service Entry Point
66 // $fff0 ; Power-up Entry Point
67 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
68 // $fffe ; System Model ID
70 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
72 // - supports up to 4 ATA interfaces
73 // - device/geometry detection
74 // - 16bits/32bits device access
76 // - datain/dataout/packet command support
78 // NOTES for El-Torito Boot (cbbochs@free.fr)
79 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
80 // - Current code is only able to boot mono-session cds
81 // - Current code can not boot and emulate a hard-disk
82 // the bios will panic otherwise
83 // - Current code also use memory in EBDA segement.
84 // - I used cmos byte 0x3D to store extended information on boot-device
85 // - Code has to be modified modified to handle multiple cdrom drives
86 // - Here are the cdrom boot failure codes:
87 // 1 : no atapi device found
88 // 2 : no atapi cdrom found
89 // 3 : can not read cd - BRVD
90 // 4 : cd is not eltorito (BRVD)
91 // 5 : cd is not eltorito (ISO TAG)
92 // 6 : cd is not eltorito (ELTORITO TAG)
93 // 7 : can not read cd - boot catalog
94 // 8 : boot catalog : bad header
95 // 9 : boot catalog : bad platform
96 // 10 : boot catalog : bad signature
97 // 11 : boot catalog : bootable flag not set
98 // 12 : can not read cd - boot image
102 // I used memory starting at 0x121 in the segment
103 // - the translation policy is defined in cmos regs 0x39 & 0x3a
108 // - needs to be reworked. Uses direct [bp] offsets. (?)
111 // - f04 (verify sectors) isn't complete (?)
112 // - f02/03/04 should set current cyl,etc in BDA (?)
113 // - rewrite int13_relocated & clean up int13 entry code
116 // - NMI access (bit7 of addr written to 70h)
119 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
120 // - could send the multiple-sector read/write commands
123 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
124 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
125 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
126 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
127 // This is ok. But DL should be reincremented afterwards.
128 // - Fix all "FIXME ElTorito Various"
129 // - should be able to boot any cdrom instead of the first one
131 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
133 #define DEBUG_ROMBIOS 1
135 #define DEBUG_RAMDISK 0
137 #define DEBUG_INT13_HD 0
138 #define DEBUG_INT13_CD 0
139 #define DEBUG_INT13_ET 0
140 #define DEBUG_INT13_FL 0
141 #define DEBUG_INT15 0
142 #define DEBUG_INT16 0
143 #define DEBUG_INT1A 0
144 #define DEBUG_INT74 0
148 #define BX_USE_PS2_MOUSE 1
149 #define BX_CALL_INT15_4F 1
150 #define BX_USE_EBDA 1
151 #define BX_SUPPORT_FLOPPY 1
152 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
156 #define BX_USE_ATADRV 1
157 #define BX_ELTORITO_BOOT 1
159 #define BX_MAX_ATA_INTERFACES 4
160 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
162 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
163 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
165 /* model byte 0xFC = AT */
166 #define SYS_MODEL_ID 0xFC
167 #define SYS_SUBMODEL_ID 0x00
168 #define BIOS_REVISION 1
169 #define BIOS_CONFIG_TABLE 0xe6f5
171 #ifndef BIOS_BUILD_DATE
172 # define BIOS_BUILD_DATE "06/23/99"
175 // 1K of base memory used for Extended Bios Data Area (EBDA)
176 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
177 #define EBDA_SEG 0x9FC0
178 #define EBDA_SIZE 1 // In KiB
179 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
181 // Define the application NAME
183 # define BX_APPNAME "HVMAssist"
185 # define BX_APPNAME "Plex86"
187 # define BX_APPNAME "Bochs"
191 #if BX_USE_ATADRV && BX_CPU<3
192 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
194 #if BX_USE_ATADRV && !BX_USE_EBDA
195 # error ATA/ATAPI Driver can only be used if EBDA is available
197 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
198 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
200 #if BX_PCIBIOS && BX_CPU<3
201 # error PCI BIOS can only be used with 386+ cpu
203 #if BX_APM && BX_CPU<3
204 # error APM BIOS can only be used with 386+ cpu
207 #ifndef BX_SMP_PROCESSORS
208 #define BX_SMP_PROCESSORS 1
209 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
212 #define PANIC_PORT 0x400
213 #define PANIC_PORT2 0x401
214 #define INFO_PORT 0x402
215 #define DEBUG_PORT 0x403
218 // #$20 is hex 20 = 32
219 // #0x20 is hex 20 = 32
226 // all hex literals should be prefixed with '0x'
227 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
228 // no mov SEG-REG, #value, must mov register into seg-reg
229 // grep -i "mov[ ]*.s" rombios.c
231 // This is for compiling with gcc2 and gcc3
232 #define ASM_START #asm
233 #define ASM_END #endasm
247 ;; the HALT macro is called with the line number of the HALT call.
248 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
249 ;; to print a BX_PANIC message. This will normally halt the simulation
250 ;; with a message such as "BIOS panic at rombios.c, line 4091".
251 ;; However, users can choose to make panics non-fatal and continue.
278 typedef unsigned char Bit8u;
279 typedef unsigned short Bit16u;
280 typedef unsigned short bx_bool;
281 typedef unsigned long Bit32u;
285 void memsetb(seg,offset,value,count);
286 void memcpyb(dseg,doffset,sseg,soffset,count);
287 void memcpyd(dseg,doffset,sseg,soffset,count);
289 // memset of count bytes
291 memsetb(seg,offset,value,count)
306 mov cx, 10[bp] ; count
309 mov ax, 4[bp] ; segment
311 mov ax, 6[bp] ; offset
313 mov al, 8[bp] ; value
328 // memcpy of count bytes
330 memcpyb(dseg,doffset,sseg,soffset,count)
348 mov cx, 12[bp] ; count
351 mov ax, 4[bp] ; dsegment
353 mov ax, 6[bp] ; doffset
355 mov ax, 8[bp] ; ssegment
357 mov ax, 10[bp] ; soffset
376 // memcpy of count dword
378 memcpyd(dseg,doffset,sseg,soffset,count)
396 mov cx, 12[bp] ; count
399 mov ax, 4[bp] ; dsegment
401 mov ax, 6[bp] ; doffset
403 mov ax, 8[bp] ; ssegment
405 mov ax, 10[bp] ; soffset
423 #endif //BX_USE_ATADRV
425 // read_dword and write_dword functions
426 static Bit32u read_dword();
427 static void write_dword();
430 read_dword(seg, offset)
440 mov ax, 4[bp] ; segment
442 mov bx, 6[bp] ; offset
447 ;; ax = return value (word)
448 ;; dx = return value (word)
457 write_dword(seg, offset, data)
469 mov ax, 4[bp] ; segment
471 mov bx, 6[bp] ; offset
472 mov ax, 8[bp] ; data word
473 mov [bx], ax ; write data word
476 mov ax, 10[bp] ; data word
477 mov [bx], ax ; write data word
486 // Bit32u (unsigned long) and long helper functions
515 cmp eax, dword ptr [di]
534 mul eax, dword ptr [di]
630 // for access to RAM area which is used by interrupt vectors
631 // and BIOS Data Area
634 unsigned char filler1[0x400];
635 unsigned char filler2[0x6c];
641 #define BiosData ((bios_data_t *) 0)
645 Bit16u heads; // # heads
646 Bit16u cylinders; // # cylinders
647 Bit16u spt; // # sectors / track
667 Bit8u iface; // ISA or PCI
668 Bit16u iobase1; // IO Base 1
669 Bit16u iobase2; // IO Base 2
674 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
675 Bit8u device; // Detected type of attached devices (hd/cd/none)
676 Bit8u removable; // Removable device flag
677 Bit8u lock; // Locks for removable devices
678 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
679 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
680 Bit16u blksize; // block size
682 Bit8u translation; // type of translation
683 chs_t lchs; // Logical CHS
684 chs_t pchs; // Physical CHS
686 Bit32u sectors; // Total sectors count
691 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
694 ata_device_t devices[BX_MAX_ATA_DEVICES];
696 // map between (bios hd id - 0x80) and ata channels
697 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
699 // map between (bios cd id - 0xE0) and ata channels
700 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
702 // Buffer for DPTE table
705 // Count of transferred sectors and bytes
712 // ElTorito Device Emulation data
716 Bit8u emulated_drive;
717 Bit8u controller_index;
720 Bit16u buffer_segment;
727 #endif // BX_ELTORITO_BOOT
729 // for access to EBDA area
730 // The EBDA structure should conform to
731 // http://www.cybertrails.com/~fys/rombios.htm document
732 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
734 unsigned char filler1[0x3D];
736 // FDPT - Can be splitted in data members if needed
737 unsigned char fdpt0[0x10];
738 unsigned char fdpt1[0x10];
740 unsigned char filler2[0xC4];
746 // El Torito Emulation data
748 #endif // BX_ELTORITO_BOOT
752 #define EbdaData ((ebda_data_t *) 0)
754 // for access to the int13ext structure
765 #define Int13Ext ((int13ext_t *) 0)
767 // Disk Physical Table definition
774 Bit32u sector_count1;
775 Bit32u sector_count2;
786 Bit8u device_path[8];
791 #define Int13DPT ((dpt_t *) 0)
793 #endif // BX_USE_ATADRV
798 Bit16u di, si, bp, sp;
799 Bit16u bx, dx, cx, ax;
803 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
811 Bit32u edi, esi, ebp, esp;
812 Bit32u ebx, edx, ecx, eax;
815 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
816 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
844 #define SetCF(x) x.u.r8.flagsl |= 0x01
845 #define SetZF(x) x.u.r8.flagsl |= 0x40
846 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
847 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
848 #define GetCF(x) (x.u.r8.flagsl & 0x01)
859 static Bit8u inb_cmos();
861 static void outb_cmos();
864 static void init_rtc();
865 static bx_bool rtc_updating();
867 static Bit8u read_byte();
868 static Bit16u read_word();
869 static void write_byte();
870 static void write_word();
871 static void bios_printf();
872 static void copy_e820_table();
874 static Bit8u inhibit_mouse_int_and_events();
875 static void enable_mouse_int_and_events();
876 static Bit8u send_to_mouse_ctrl();
877 static Bit8u get_mouse_data();
878 static void set_kbd_command_byte();
880 static void int09_function();
881 static void int13_harddisk();
882 static void int13_cdrom();
883 static void int13_cdemu();
884 static void int13_eltorito();
885 static void int13_diskette_function();
886 static void int14_function();
887 static void int15_function();
888 static void int16_function();
889 static void int17_function();
890 static Bit32u int19_function();
891 static void int1a_function();
892 static void int70_function();
893 static void int74_function();
894 static Bit16u get_CS();
895 //static Bit16u get_DS();
896 //static void set_DS();
897 static Bit16u get_SS();
898 static unsigned int enqueue_key();
899 static unsigned int dequeue_key();
900 static void get_hd_geometry();
901 static void set_diskette_ret_status();
902 static void set_diskette_current_cyl();
903 static void determine_floppy_media();
904 static bx_bool floppy_drive_exists();
905 static bx_bool floppy_drive_recal();
906 static bx_bool floppy_media_known();
907 static bx_bool floppy_media_sense();
908 static bx_bool set_enable_a20();
909 static void debugger_on();
910 static void debugger_off();
911 static void keyboard_init();
912 static void keyboard_panic();
913 static void shutdown_status_panic();
914 static void nmi_handler_msg();
916 static void print_bios_banner();
917 static void print_boot_device();
918 static void print_boot_failure();
919 static void print_cdromboot_failure();
923 // ATA / ATAPI driver
928 Bit16u ata_cmd_non_data();
929 Bit16u ata_cmd_data_in();
930 Bit16u ata_cmd_data_out();
931 Bit16u ata_cmd_packet();
933 Bit16u atapi_get_sense();
934 Bit16u atapi_is_ready();
935 Bit16u atapi_is_cdrom();
937 #endif // BX_USE_ATADRV
942 Bit8u cdemu_isactive();
943 Bit8u cdemu_emulated_drive();
947 #endif // BX_ELTORITO_BOOT
949 static char bios_cvs_version_string[] = "$Revision: 1.16 $";
950 static char bios_date_string[] = "$Date: 2008/08/14 20:04:33 $";
952 static char CVSID[] = "$Id: rombios.c,v 1.16 2008/08/14 20:04:33 cuizheng Exp $";
954 /* Offset to skip the CVS $Id: prefix */
955 #define bios_version_string (CVSID + 4)
957 #define BIOS_PRINTF_HALT 1
958 #define BIOS_PRINTF_SCREEN 2
959 #define BIOS_PRINTF_INFO 4
960 #define BIOS_PRINTF_DEBUG 8
961 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
962 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
964 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
966 // Defines the output macros.
967 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
968 // per-device basis. Debug info are sent only in debug mode
970 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_ALL, format, ##p)
972 # define BX_DEBUG(format, p...)
974 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
975 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
980 # define debug_outb(a...) outb(a)
982 # define debug_outb(a...)
987 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
989 # define BX_DEBUG_ATA(a...)
992 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
994 # define BX_DEBUG_INT13_HD(a...)
997 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
999 # define BX_DEBUG_INT13_CD(a...)
1002 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1004 # define BX_DEBUG_INT13_ET(a...)
1007 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1009 # define BX_DEBUG_INT13_FL(a...)
1012 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1014 # define BX_DEBUG_INT15(a...)
1017 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1019 # define BX_DEBUG_INT16(a...)
1022 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1024 # define BX_DEBUG_INT1A(a...)
1027 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1029 # define BX_DEBUG_INT74(a...)
1032 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1033 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1034 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1035 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1036 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1037 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1038 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1039 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1041 #define GET_AL() ( AX & 0x00ff )
1042 #define GET_BL() ( BX & 0x00ff )
1043 #define GET_CL() ( CX & 0x00ff )
1044 #define GET_DL() ( DX & 0x00ff )
1045 #define GET_AH() ( AX >> 8 )
1046 #define GET_BH() ( BX >> 8 )
1047 #define GET_CH() ( CX >> 8 )
1048 #define GET_DH() ( DX >> 8 )
1050 #define GET_ELDL() ( ELDX & 0x00ff )
1051 #define GET_ELDH() ( ELDX >> 8 )
1053 #define SET_CF() FLAGS |= 0x0001
1054 #define CLEAR_CF() FLAGS &= 0xfffe
1055 #define GET_CF() (FLAGS & 0x0001)
1057 #define SET_ZF() FLAGS |= 0x0040
1058 #define CLEAR_ZF() FLAGS &= 0xffbf
1059 #define GET_ZF() (FLAGS & 0x0040)
1061 #define UNSUPPORTED_FUNCTION 0x86
1064 #define MAX_SCAN_CODE 0x53
1072 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1073 { none, none, none, none, none },
1074 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1075 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1076 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1077 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1078 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1079 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1080 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1081 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1082 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1083 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1084 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1085 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1086 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1087 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1088 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1089 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1090 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1091 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1092 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1093 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1094 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1095 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1096 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1097 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1098 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1099 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1100 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1101 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1102 { none, none, none, none, none }, /* L Ctrl */
1103 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1104 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1105 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1106 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1107 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1108 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1109 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1110 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1111 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1112 { 0x273b, 0x273a, none, none, none }, /* ;: */
1113 { 0x2827, 0x2822, none, none, none }, /* '" */
1114 { 0x2960, 0x297e, none, none, none }, /* `~ */
1115 { none, none, none, none, none }, /* L shift */
1116 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1117 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1118 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1119 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1120 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1121 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1122 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1123 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1124 { 0x332c, 0x333c, none, none, none }, /* ,< */
1125 { 0x342e, 0x343e, none, none, none }, /* .> */
1126 { 0x352f, 0x353f, none, none, none }, /* /? */
1127 { none, none, none, none, none }, /* R Shift */
1128 { 0x372a, 0x372a, none, none, none }, /* * */
1129 { none, none, none, none, none }, /* L Alt */
1130 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1131 { none, none, none, none, none }, /* caps lock */
1132 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1133 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1134 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1135 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1136 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1137 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1138 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1139 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1140 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1141 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1142 { none, none, none, none, none }, /* Num Lock */
1143 { none, none, none, none, none }, /* Scroll Lock */
1144 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1145 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1146 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1147 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1148 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1149 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1150 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1151 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1152 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1153 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1154 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1155 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1156 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1240 outb_cmos(cmos_reg, val)
1248 mov al, 4[bp] ;; cmos_reg
1250 mov al, 6[bp] ;; val
1265 mov al, 4[bp] ;; cmos_reg
1276 printf("rombios: init_rtc()\n");
1277 outb_cmos(0x0a, 0x26);
1278 outb_cmos(0x0b, 0x02);
1286 // This function checks to see if the update-in-progress bit
1287 // is set in CMOS Status Register A. If not, it returns 0.
1288 // If it is set, it tries to wait until there is a transition
1289 // to 0, and will return 0 if such a transition occurs. A 1
1290 // is returned only after timing out. The maximum period
1291 // that this bit should be set is constrained to 244useconds.
1292 // The count I use below guarantees coverage or more than
1293 // this time, with any reasonable IPS setting.
1298 while (--count != 0) {
1299 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1302 return(1); // update-in-progress never transitioned to 0
1307 read_byte(seg, offset)
1317 mov ax, 4[bp] ; segment
1319 mov bx, 6[bp] ; offset
1321 ;; al = return value (byte)
1330 read_word(seg, offset)
1340 mov ax, 4[bp] ; segment
1342 mov bx, 6[bp] ; offset
1344 ;; ax = return value (word)
1353 write_byte(seg, offset, data)
1365 mov ax, 4[bp] ; segment
1367 mov bx, 6[bp] ; offset
1368 mov al, 8[bp] ; data byte
1369 mov [bx], al ; write data byte
1379 write_word(seg, offset, data)
1391 mov ax, 4[bp] ; segment
1393 mov bx, 6[bp] ; offset
1394 mov ax, 8[bp] ; data word
1395 mov [bx], ax ; write data word
1422 //set_DS(ds_selector)
1423 // Bit16u ds_selector;
1430 // mov ax, 4[bp] ; ds_selector
1450 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1451 if (nr_entries > 32)
1453 write_word(0xe000, 0x8, nr_entries);
1454 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1456 #endif /* HVMASSIST */
1459 /* serial debug port*/
1460 #define BX_DEBUG_PORT 0x03f8
1463 #define UART_RBR 0x00
1464 #define UART_THR 0x00
1467 #define UART_IER 0x01
1468 #define UART_IIR 0x02
1469 #define UART_FCR 0x02
1470 #define UART_LCR 0x03
1471 #define UART_MCR 0x04
1472 #define UART_DLL 0x00
1473 #define UART_DLM 0x01
1476 #define UART_LSR 0x05
1477 #define UART_MSR 0x06
1478 #define UART_SCR 0x07
1480 int uart_can_tx_byte(base_port)
1483 return inb(base_port + UART_LSR) & 0x20;
1486 void uart_wait_to_tx_byte(base_port)
1489 while (!uart_can_tx_byte(base_port));
1492 void uart_wait_until_sent(base_port)
1495 while (!(inb(base_port + UART_LSR) & 0x40));
1498 void uart_tx_byte(base_port, data)
1502 uart_wait_to_tx_byte(base_port);
1503 outb(base_port + UART_THR, data);
1504 uart_wait_until_sent(base_port);
1533 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1534 uart_tx_byte(BX_DEBUG_PORT, c);
1539 #if BX_VIRTUAL_PORTS
1540 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1541 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1543 if (action & BIOS_PRINTF_SCREEN) {
1544 if (c == '\n') wrch('\r');
1550 put_int(action, val, width, neg)
1555 short nval = val / 10;
1557 put_int(action, nval, width - 1, neg);
1559 while (--width > 0) send(action, ' ');
1560 if (neg) send(action, '-');
1562 send(action, val - (nval * 10) + '0');
1566 put_uint(action, val, width, neg)
1572 unsigned short nval = val / 10;
1574 put_uint(action, nval, width - 1, neg);
1576 while (--width > 0) send(action, ' ');
1577 if (neg) send(action, '-');
1579 send(action, val - (nval * 10) + '0');
1582 //--------------------------------------------------------------------------
1584 // A compact variable argument printf function which prints its output via
1585 // an I/O port so that it can be logged by Bochs/Plex.
1586 // Currently, only %x is supported (or %02x, %04x, etc).
1588 // Supports %[format_width][format]
1589 // where format can be d,x,c,s
1590 //--------------------------------------------------------------------------
1592 bios_printf(action, s)
1596 Bit8u c, format_char;
1600 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1608 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1609 #if BX_VIRTUAL_PORTS
1610 outb(PANIC_PORT2, 0x00);
1612 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1615 while (c = read_byte(get_CS(), s)) {
1620 else if (in_format) {
1621 if ( (c>='0') && (c<='9') ) {
1622 format_width = (format_width * 10) + (c - '0');
1625 arg_ptr++; // increment to next arg
1626 arg = read_word(arg_seg, arg_ptr);
1628 if (format_width == 0)
1630 for (i=format_width-1; i>=0; i--) {
1631 nibble = (arg >> (4 * i)) & 0x000f;
1632 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1635 else if (c == 'u') {
1636 put_uint(action, arg, format_width, 0);
1638 else if (c == 'd') {
1640 put_int(action, -arg, format_width - 1, 1);
1642 put_int(action, arg, format_width, 0);
1644 else if (c == 's') {
1645 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1647 else if (c == 'c') {
1651 BX_PANIC("bios_printf: unknown format\n");
1661 if (action & BIOS_PRINTF_HALT) {
1662 // freeze in a busy loop.
1672 //--------------------------------------------------------------------------
1674 //--------------------------------------------------------------------------
1675 // this file is based on LinuxBIOS implementation of keyboard.c
1676 // could convert to #asm to gain space
1683 BX_DEBUG("rombios: keyboard_init\n");
1685 /* printf("Assuming keyboard already inited and returning\n");
1688 /* ------------------- Flush buffers ------------------------*/
1689 /* Wait until buffer is empty */
1691 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1693 /* flush incoming keys */
1694 // temporarily chaged for debug -PAD
1699 if (inb(0x64) & 0x01) {
1705 // Due to timer issues, and if the IPS setting is > 15000000,
1706 // the incoming keys might not be flushed here. That will
1707 // cause a panic a few lines below. See sourceforge bug report :
1708 // [ 642031 ] FATAL: Keyboard RESET error:993
1710 /* ------------------- controller side ----------------------*/
1711 /* send cmd = 0xAA, self test 8042 */
1714 /* Wait until buffer is empty */
1716 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x02);
1717 if (max==0x0) keyboard_panic(00);
1721 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x03);
1722 if (max==0x0) keyboard_panic(01);
1724 /* read self-test result, 0x55 should be returned from 0x60 */
1725 if ((inb(0x60) != 0x55)){
1726 keyboard_panic(991);
1729 /* send cmd = 0xAB, keyboard interface test */
1732 /* Wait until buffer is empty */
1734 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1735 if (max==0x0) keyboard_panic(10);
1739 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1740 if (max==0x0) keyboard_panic(11);
1742 /* read keyboard interface test result, */
1743 /* 0x00 should be returned form 0x60 */
1744 if ((inb(0x60) != 0x00)) {
1745 keyboard_panic(992);
1748 /* Enable Keyboard clock */
1752 /* ------------------- keyboard side ------------------------*/
1753 /* reset kerboard and self test (keyboard side) */
1756 /* Wait until buffer is empty */
1758 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1759 if (max==0x0) keyboard_panic(20);
1763 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1764 if (max==0x0) keyboard_panic(21);
1766 /* keyboard should return ACK */
1767 if ((inb(0x60) != 0xfa)) {
1768 keyboard_panic(993);
1773 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1774 if (max==0x0) keyboard_panic(31);
1776 if ((inb(0x60) != 0xaa)) {
1777 keyboard_panic(994);
1780 /* Disable keyboard */
1783 /* Wait until buffer is empty */
1785 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1786 if (max==0x0) keyboard_panic(40);
1790 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1791 if (max==0x0) keyboard_panic(41);
1793 /* keyboard should return ACK */
1796 printf("rc=0x%x\n",rc);
1797 keyboard_panic(995);
1800 /* Write Keyboard Mode */
1803 /* Wait until buffer is empty */
1805 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1806 if (max==0x0) keyboard_panic(50);
1808 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1811 /* Wait until buffer is empty */
1813 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1814 if (max==0x0) keyboard_panic(60);
1816 /* Enable keyboard */
1819 /* Wait until buffer is empty */
1821 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1822 if (max==0x0) keyboard_panic(70);
1826 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1827 if (max==0x0) keyboard_panic(70);
1829 /* keyboard should return ACK */
1830 if ((inb(0x60) != 0xfa)) {
1831 keyboard_panic(996);
1835 printf("keyboard init done.\n");
1838 //--------------------------------------------------------------------------
1840 //--------------------------------------------------------------------------
1842 keyboard_panic(status)
1845 // If you're getting a 993 keyboard panic here,
1846 // please see the comment in keyboard_init
1847 printf("Keyboard error:%u CONTINUING\n",status); return;
1848 BX_PANIC("Keyboard error:%u\n",status);
1851 //--------------------------------------------------------------------------
1852 // shutdown_status_panic
1853 // called when the shutdown statsu is not implemented, displays the status
1854 //--------------------------------------------------------------------------
1856 shutdown_status_panic(status)
1859 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1862 //--------------------------------------------------------------------------
1863 // print_bios_banner
1864 // displays a the bios version
1865 //--------------------------------------------------------------------------
1869 printf("Hi from peter's modified bios\n");
1870 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1871 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1875 //--------------------------------------------------------------------------
1876 // print_boot_device
1877 // displays the boot device
1878 //--------------------------------------------------------------------------
1880 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1883 print_boot_device(cdboot, drive)
1884 Bit8u cdboot; Bit16u drive;
1888 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1889 // drive contains real/emulated boot drive
1891 if(cdboot)i=2; // CD-Rom
1892 else if((drive&0x0080)==0x00)i=0; // Floppy
1893 else if((drive&0x0080)==0x80)i=1; // Hard drive
1896 printf("Booting from %s...\n",drivetypes[i]);
1899 //--------------------------------------------------------------------------
1900 // print_boot_failure
1901 // displays the reason why boot failed
1902 //--------------------------------------------------------------------------
1904 print_boot_failure(cdboot, drive, reason, lastdrive)
1905 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1907 Bit16u drivenum = drive&0x7f;
1909 // cdboot: 1 if boot from cd, 0 otherwise
1910 // drive : drive number
1911 // reason: 0 signature check failed, 1 read error
1912 // lastdrive: 1 boot drive is the last one in boot sequence
1915 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1916 else if (drive & 0x80)
1917 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1919 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1923 BX_PANIC("Not a bootable disk\n");
1925 BX_PANIC("Could not read the boot disk\n");
1929 //--------------------------------------------------------------------------
1930 // print_cdromboot_failure
1931 // displays the reason why boot failed
1932 //--------------------------------------------------------------------------
1934 print_cdromboot_failure( code )
1937 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1945 BX_PANIC("NMI Handler called\n");
1951 BX_PANIC("INT18: BOOT FAILURE\n");
1958 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1960 BX_INFO("%s\n", bios_version_string);
1969 // Use PS2 System Control port A to set A20 enable
1971 // get current setting first
1974 // change A20 status
1976 outb(0x92, oldval | 0x02);
1978 outb(0x92, oldval & 0xfd);
1980 return((oldval & 0x02) != 0);
1997 // ---------------------------------------------------------------------------
1998 // Start of ATA/ATAPI Driver
1999 // ---------------------------------------------------------------------------
2001 // Global defines -- ATA register and register bits.
2002 // command block & control block regs
2003 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2004 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2005 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2006 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2007 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2008 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2009 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2010 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2011 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2012 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2013 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2014 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2015 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2017 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2018 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2019 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2020 #define ATA_CB_ER_MC 0x20 // ATA media change
2021 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2022 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2023 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2024 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2025 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2027 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2028 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2029 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2030 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2031 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2033 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2034 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2035 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2036 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2037 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2039 // bits 7-4 of the device/head (CB_DH) reg
2040 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2041 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2043 // status reg (CB_STAT and CB_ASTAT) bits
2044 #define ATA_CB_STAT_BSY 0x80 // busy
2045 #define ATA_CB_STAT_RDY 0x40 // ready
2046 #define ATA_CB_STAT_DF 0x20 // device fault
2047 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2048 #define ATA_CB_STAT_SKC 0x10 // seek complete
2049 #define ATA_CB_STAT_SERV 0x10 // service
2050 #define ATA_CB_STAT_DRQ 0x08 // data request
2051 #define ATA_CB_STAT_CORR 0x04 // corrected
2052 #define ATA_CB_STAT_IDX 0x02 // index
2053 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2054 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2056 // device control reg (CB_DC) bits
2057 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2058 #define ATA_CB_DC_SRST 0x04 // soft reset
2059 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2061 // Most mandtory and optional ATA commands (from ATA-3),
2062 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2063 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2064 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2065 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2066 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2067 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2068 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2069 #define ATA_CMD_DEVICE_RESET 0x08
2070 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2071 #define ATA_CMD_FLUSH_CACHE 0xE7
2072 #define ATA_CMD_FORMAT_TRACK 0x50
2073 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2074 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2075 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2076 #define ATA_CMD_IDLE1 0xE3
2077 #define ATA_CMD_IDLE2 0x97
2078 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2079 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2080 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2081 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2082 #define ATA_CMD_NOP 0x00
2083 #define ATA_CMD_PACKET 0xA0
2084 #define ATA_CMD_READ_BUFFER 0xE4
2085 #define ATA_CMD_READ_DMA 0xC8
2086 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2087 #define ATA_CMD_READ_MULTIPLE 0xC4
2088 #define ATA_CMD_READ_SECTORS 0x20
2089 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2090 #define ATA_CMD_RECALIBRATE 0x10
2091 #define ATA_CMD_SEEK 0x70
2092 #define ATA_CMD_SET_FEATURES 0xEF
2093 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2094 #define ATA_CMD_SLEEP1 0xE6
2095 #define ATA_CMD_SLEEP2 0x99
2096 #define ATA_CMD_STANDBY1 0xE2
2097 #define ATA_CMD_STANDBY2 0x96
2098 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2099 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2100 #define ATA_CMD_WRITE_BUFFER 0xE8
2101 #define ATA_CMD_WRITE_DMA 0xCA
2102 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2103 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2104 #define ATA_CMD_WRITE_SECTORS 0x30
2105 #define ATA_CMD_WRITE_VERIFY 0x3C
2107 #define ATA_IFACE_NONE 0x00
2108 #define ATA_IFACE_ISA 0x00
2109 #define ATA_IFACE_PCI 0x01
2111 #define ATA_TYPE_NONE 0x00
2112 #define ATA_TYPE_UNKNOWN 0x01
2113 #define ATA_TYPE_ATA 0x02
2114 #define ATA_TYPE_ATAPI 0x03
2116 #define ATA_DEVICE_NONE 0x00
2117 #define ATA_DEVICE_HD 0xFF
2118 #define ATA_DEVICE_CDROM 0x05
2120 #define ATA_MODE_NONE 0x00
2121 #define ATA_MODE_PIO16 0x00
2122 #define ATA_MODE_PIO32 0x01
2123 #define ATA_MODE_ISADMA 0x02
2124 #define ATA_MODE_PCIDMA 0x03
2125 #define ATA_MODE_USEIRQ 0x10
2127 #define ATA_TRANSLATION_NONE 0
2128 #define ATA_TRANSLATION_LBA 1
2129 #define ATA_TRANSLATION_LARGE 2
2130 #define ATA_TRANSLATION_RECHS 3
2132 #define ATA_DATA_NO 0x00
2133 #define ATA_DATA_IN 0x01
2134 #define ATA_DATA_OUT 0x02
2136 // ---------------------------------------------------------------------------
2137 // ATA/ATAPI driver : initialization
2138 // ---------------------------------------------------------------------------
2141 Bit16u ebda_seg=read_word(0x0040,0x000E);
2142 Bit8u channel, device;
2144 //BX_DEBUG("rombios: ata_init\n");
2146 // Channels info init.
2147 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2148 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2149 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2150 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2151 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2154 // Devices info init.
2155 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2156 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2157 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2158 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2159 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2160 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2161 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2162 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2163 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2164 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2165 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2166 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2167 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2168 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2170 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2173 // hdidmap and cdidmap init.
2174 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2175 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2176 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2179 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2180 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2183 // ---------------------------------------------------------------------------
2184 // ATA/ATAPI driver : device detection
2185 // ---------------------------------------------------------------------------
2189 Bit16u ebda_seg=read_word(0x0040,0x000E);
2190 Bit8u hdcount, cdcount, device, type;
2191 Bit8u buffer[0x0200];
2193 debug_outb(0x3e8, 0xf0);
2195 //BX_DEBUG("rombios: ata_detect\n");
2197 #if BX_MAX_ATA_INTERFACES > 0
2198 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2199 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2200 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2201 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2203 #if BX_MAX_ATA_INTERFACES > 1
2204 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2205 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2206 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2207 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2209 #if BX_MAX_ATA_INTERFACES > 2
2210 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2211 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2212 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2213 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2215 #if BX_MAX_ATA_INTERFACES > 3
2216 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2217 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2218 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2219 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2221 #if BX_MAX_ATA_INTERFACES > 4
2222 #error Please fill the ATA interface informations
2228 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2229 Bit16u iobase1, iobase2;
2230 Bit8u channel, slave, shift;
2231 Bit8u sc, sn, cl, ch, st;
2233 channel = device / 2;
2236 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2237 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2239 // Disable interrupts
2240 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2243 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2244 outb(iobase1+ATA_CB_SC, 0x55);
2245 outb(iobase1+ATA_CB_SN, 0xaa);
2246 outb(iobase1+ATA_CB_SC, 0xaa);
2247 outb(iobase1+ATA_CB_SN, 0x55);
2248 outb(iobase1+ATA_CB_SC, 0x55);
2249 outb(iobase1+ATA_CB_SN, 0xaa);
2251 // If we found something
2252 sc = inb(iobase1+ATA_CB_SC);
2253 sn = inb(iobase1+ATA_CB_SN);
2255 if ( (sc == 0x55) && (sn == 0xaa) ) {
2256 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2258 // reset the channel
2261 // check for ATA or ATAPI
2262 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2263 sc = inb(iobase1+ATA_CB_SC);
2264 sn = inb(iobase1+ATA_CB_SN);
2265 if ( (sc==0x01) && (sn==0x01) ) {
2266 cl = inb(iobase1+ATA_CB_CL);
2267 ch = inb(iobase1+ATA_CB_CH);
2268 st = inb(iobase1+ATA_CB_STAT);
2270 if ( (cl==0x14) && (ch==0xeb) ) {
2271 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2273 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2274 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2279 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2281 // Now we send a IDENTIFY command to ATA device
2282 if(type == ATA_TYPE_ATA) {
2284 Bit16u cylinders, heads, spt, blksize;
2285 Bit8u translation, removable, mode;
2287 // default mode to PIO16
2288 mode = ATA_MODE_PIO16;
2290 //Temporary values to do the transfer
2291 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2292 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2294 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2295 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2297 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2299 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2302 blksize = read_word(get_SS(),buffer+10);
2304 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2305 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2306 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2308 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2310 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2311 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2312 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2313 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2314 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2315 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2316 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2317 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2318 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2320 translation = inb_cmos(0x39 + channel/2);
2321 for (shift=device%4; shift>0; shift--) translation >>= 2;
2322 translation &= 0x03;
2324 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2326 switch (translation) {
2327 case ATA_TRANSLATION_NONE:
2330 case ATA_TRANSLATION_LBA:
2333 case ATA_TRANSLATION_LARGE:
2336 case ATA_TRANSLATION_RECHS:
2340 switch (translation) {
2341 case ATA_TRANSLATION_NONE:
2343 case ATA_TRANSLATION_LBA:
2346 heads = sectors / 1024;
2347 if (heads>128) heads = 255;
2348 else if (heads>64) heads = 128;
2349 else if (heads>32) heads = 64;
2350 else if (heads>16) heads = 32;
2352 cylinders = sectors / heads;
2354 case ATA_TRANSLATION_RECHS:
2355 // Take care not to overflow
2357 if(cylinders>61439) cylinders=61439;
2359 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2361 // then go through the large bitshift process
2362 case ATA_TRANSLATION_LARGE:
2363 while(cylinders > 1024) {
2367 // If we max out the head count
2368 if (heads > 127) break;
2372 // clip to 1024 cylinders in lchs
2373 if (cylinders > 1024) cylinders=1024;
2374 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2376 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2377 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2378 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2381 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2385 // Now we send a IDENTIFY command to ATAPI device
2386 if(type == ATA_TYPE_ATAPI) {
2388 Bit8u type, removable, mode;
2391 // default mode to PIO16
2392 mode = ATA_MODE_PIO16;
2394 //Temporary values to do the transfer
2395 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2396 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2398 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2399 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2401 type = read_byte(get_SS(),buffer+1) & 0x1f;
2402 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2404 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2408 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2409 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2410 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2411 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2414 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2421 Bit8u c, i, version, model[41];
2425 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2427 case ATA_TYPE_ATAPI:
2428 // Read ATA/ATAPI version
2429 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2430 for(version=15;version>0;version--) {
2431 if((ataversion&(1<<version))!=0)
2437 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2438 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2442 write_byte(get_SS(),model+40,0x00);
2444 if(read_byte(get_SS(),model+i)==0x20)
2445 write_byte(get_SS(),model+i,0x00);
2451 debug_outb(0x2ed, device);
2452 debug_outb(0x2ee, type);
2455 printf("ata%d %s: ",channel,slave?" slave":"master");
2456 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2457 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2459 case ATA_TYPE_ATAPI:
2460 printf("ata%d %s: ",channel,slave?" slave":"master");
2461 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2462 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2463 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2465 printf(" ATAPI-%d Device\n",version);
2467 case ATA_TYPE_UNKNOWN:
2468 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2476 // Store the devices counts
2477 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2478 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2479 write_byte(0x40,0x75, hdcount);
2482 debug_outb(0x3e8, 0xf0);
2484 // FIXME : should use bios=cmos|auto|disable bits
2485 // FIXME : should know about translation bits
2486 // FIXME : move hard_drive_post here
2490 // ---------------------------------------------------------------------------
2491 // ATA/ATAPI driver : software reset
2492 // ---------------------------------------------------------------------------
2494 // 8.2.1 Software reset - Device 0
2496 void ata_reset(device)
2499 Bit16u ebda_seg=read_word(0x0040,0x000E);
2500 Bit16u iobase1, iobase2;
2501 Bit8u channel, slave, sn, sc;
2504 debug_outb(0x3e9, 0xf1);
2506 channel = device / 2;
2509 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2510 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2514 // 8.2.1 (a) -- set SRST in DC
2515 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2517 // 8.2.1 (b) -- wait for BSY
2520 Bit8u status = inb(iobase1+ATA_CB_STAT);
2521 if ((status & ATA_CB_STAT_BSY) != 0) break;
2524 // 8.2.1 (f) -- clear SRST
2525 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2527 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2529 // 8.2.1 (g) -- check for sc==sn==0x01
2531 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2532 sc = inb(iobase1+ATA_CB_SC);
2533 sn = inb(iobase1+ATA_CB_SN);
2535 if ( (sc==0x01) && (sn==0x01) ) {
2537 // 8.2.1 (h) -- wait for not BSY
2540 Bit8u status = inb(iobase1+ATA_CB_STAT);
2541 if ((status & ATA_CB_STAT_BSY) == 0) break;
2546 // 8.2.1 (i) -- wait for DRDY
2549 Bit8u status = inb(iobase1+ATA_CB_STAT);
2550 if ((status & ATA_CB_STAT_RDY) != 0) break;
2553 // Enable interrupts
2554 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2556 debug_outb(0x3e9, 0xf1);
2559 // ---------------------------------------------------------------------------
2560 // ATA/ATAPI driver : execute a non data command
2561 // ---------------------------------------------------------------------------
2563 Bit16u ata_cmd_non_data()
2566 // ---------------------------------------------------------------------------
2567 // ATA/ATAPI driver : execute a data-in command
2568 // ---------------------------------------------------------------------------
2573 // 3 : expected DRQ=1
2574 // 4 : no sectors left to read/verify
2575 // 5 : more sectors to read/verify
2576 // 6 : no sectors left to write
2577 // 7 : more sectors to write
2578 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2579 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2582 Bit16u ebda_seg=read_word(0x0040,0x000E);
2583 Bit16u iobase1, iobase2, blksize;
2584 Bit8u channel, slave;
2585 Bit8u status, current, mode;
2587 debug_outb(0x3ea, 0xf2);
2590 channel = device / 2;
2593 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2594 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2595 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2596 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2597 if (mode == ATA_MODE_PIO32) blksize>>=2;
2600 // sector will be 0 only on lba access. Convert to lba-chs
2602 sector = (Bit16u) (lba & 0x000000ffL);
2604 cylinder = (Bit16u) (lba & 0x0000ffffL);
2606 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2609 // Reset count of transferred data
2610 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2611 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2614 status = inb(iobase1 + ATA_CB_STAT);
2615 if (status & ATA_CB_STAT_BSY) return 1;
2617 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2618 outb(iobase1 + ATA_CB_FR, 0x00);
2619 outb(iobase1 + ATA_CB_SC, count);
2620 outb(iobase1 + ATA_CB_SN, sector);
2621 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2622 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2623 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2624 outb(iobase1 + ATA_CB_CMD, command);
2627 status = inb(iobase1 + ATA_CB_STAT);
2628 if ( !(status & ATA_CB_STAT_BSY) ) break;
2631 if (status & ATA_CB_STAT_ERR) {
2632 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2633 debug_outb(0x3ea, 0xf2);
2635 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2636 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2637 debug_outb(0x3ea, 0xf2);
2641 // FIXME : move seg/off translation here
2644 sti ;; enable higher priority interrupts
2652 mov di, _ata_cmd_data_in.offset + 2[bp]
2653 mov ax, _ata_cmd_data_in.segment + 2[bp]
2654 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2656 ;; adjust if there will be an overrun. 2K max sector size
2658 jbe ata_in_no_adjust
2661 sub di, #0x0800 ;; sub 2 kbytes from offset
2662 add ax, #0x0080 ;; add 2 Kbytes to segment
2665 mov es, ax ;; segment in es
2667 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2669 mov ah, _ata_cmd_data_in.mode + 2[bp]
2670 cmp ah, #ATA_MODE_PIO32
2675 insw ;; CX words transfered from port(DX) to ES:[DI]
2680 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2683 mov _ata_cmd_data_in.offset + 2[bp], di
2684 mov _ata_cmd_data_in.segment + 2[bp], es
2689 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2691 status = inb(iobase1 + ATA_CB_STAT);
2693 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2694 != ATA_CB_STAT_RDY ) {
2695 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2696 debug_outb(0x3ea, 0xf2);
2702 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2703 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2704 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2705 debug_outb(0x3ea, 0xf2);
2711 // Enable interrupts
2712 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2713 debug_outb(0x3ea, 0xf2);
2717 // ---------------------------------------------------------------------------
2718 // ATA/ATAPI driver : execute a data-out command
2719 // ---------------------------------------------------------------------------
2724 // 3 : expected DRQ=1
2725 // 4 : no sectors left to read/verify
2726 // 5 : more sectors to read/verify
2727 // 6 : no sectors left to write
2728 // 7 : more sectors to write
2729 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2730 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2733 Bit16u ebda_seg=read_word(0x0040,0x000E);
2734 Bit16u iobase1, iobase2, blksize;
2735 Bit8u channel, slave;
2736 Bit8u status, current, mode;
2738 debug_outb(0x3eb, 0xf3);
2740 channel = device / 2;
2743 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2744 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2745 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2746 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2747 if (mode == ATA_MODE_PIO32) blksize>>=2;
2750 // sector will be 0 only on lba access. Convert to lba-chs
2752 sector = (Bit16u) (lba & 0x000000ffL);
2754 cylinder = (Bit16u) (lba & 0x0000ffffL);
2756 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2759 // Reset count of transferred data
2760 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2761 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2764 status = inb(iobase1 + ATA_CB_STAT);
2765 if (status & ATA_CB_STAT_BSY) return 1;
2767 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2768 outb(iobase1 + ATA_CB_FR, 0x00);
2769 outb(iobase1 + ATA_CB_SC, count);
2770 outb(iobase1 + ATA_CB_SN, sector);
2771 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2772 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2773 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2774 outb(iobase1 + ATA_CB_CMD, command);
2777 status = inb(iobase1 + ATA_CB_STAT);
2778 if ( !(status & ATA_CB_STAT_BSY) ) break;
2781 if (status & ATA_CB_STAT_ERR) {
2782 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2783 debug_outb(0x3eb, 0xf3);
2785 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2786 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2787 debug_outb(0x3eb, 0xf3);
2791 // FIXME : move seg/off translation here
2794 sti ;; enable higher priority interrupts
2802 mov si, _ata_cmd_data_out.offset + 2[bp]
2803 mov ax, _ata_cmd_data_out.segment + 2[bp]
2804 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2806 ;; adjust if there will be an overrun. 2K max sector size
2808 jbe ata_out_no_adjust
2811 sub si, #0x0800 ;; sub 2 kbytes from offset
2812 add ax, #0x0080 ;; add 2 Kbytes to segment
2815 mov es, ax ;; segment in es
2817 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2819 mov ah, _ata_cmd_data_out.mode + 2[bp]
2820 cmp ah, #ATA_MODE_PIO32
2826 outsw ;; CX words transfered from port(DX) to ES:[SI]
2832 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2835 mov _ata_cmd_data_out.offset + 2[bp], si
2836 mov _ata_cmd_data_out.segment + 2[bp], es
2841 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2843 status = inb(iobase1 + ATA_CB_STAT);
2845 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2846 != ATA_CB_STAT_RDY ) {
2847 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2848 debug_outb(0x3eb, 0xf3);
2854 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2855 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2856 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2857 debug_outb(0x3eb, 0xf3);
2863 // Enable interrupts
2864 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2865 debug_outb(0x3eb, 0xf3);
2869 // ---------------------------------------------------------------------------
2870 // ATA/ATAPI driver : execute a packet command
2871 // ---------------------------------------------------------------------------
2874 // 1 : error in parameters
2878 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2880 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2884 Bit16u ebda_seg=read_word(0x0040,0x000E);
2885 Bit16u iobase1, iobase2;
2886 Bit16u lcount, lbefore, lafter, count;
2887 Bit8u channel, slave;
2888 Bit8u status, error, mode, lmode;
2889 Bit32u total, transfer;
2891 debug_outb(0x3ec, 0xf4);
2893 channel = device / 2;
2896 // Data out is not supported yet
2897 if (inout == ATA_DATA_OUT) {
2898 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2899 debug_outb(0x3ec, 0xf4);
2903 // The header length must be even
2905 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2906 debug_outb(0x3ec, 0xf4);
2910 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2911 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2912 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2915 if (cmdlen < 12) cmdlen=12;
2916 if (cmdlen > 12) cmdlen=16;
2919 // Reset count of transferred data
2920 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2921 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2923 #define STATUS_WAIT_FOR(x) do { status=inb(iobase1+ATA_CB_STAT); } while (!(x))
2924 #define ALT_STATUS_WAIT_FOR(x) do { status=inb(iobase2+ATA_CB_ASTAT); } while (!(x))
2925 #define ERROR_UPDATE() do { error=inb(iobase1+ATA_CB_ERR); } while (0)
2926 #define STATUS_UPDATE() do { status=inb(iobase1+ATA_CB_STAT); } while (0)
2927 #define ALT_STATUS_UPDATE() do { status=inb(iobase1+ATA_CB_STAT); } while (0)
2928 #define WAIT_FOR_NOT_BUSY() STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0)
2929 #define WAIT_FOR_DATA_REQUEST() STATUS_WAIT_FOR((status&ATA_CB_STAT_DRQ))
2930 #define WAIT_FOR_DRIVE_READY() STATUS_WAIT_FOR((status&ATA_CB_STAT_RDY))
2931 #define WAIT_FOR_NOT_BUSY_AND_DRIVE_READY() STATUS_WAIT_FOR(((status&ATA_CB_STAT_BSY)==0)&&((status&ATA_CB_STAT_RDY)))
2932 #define WAIT_FOR_NOT_BUSY_AND_DATA_REQUEST() STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0)&&((status&ATA_CB_STAT_DRQ)))
2936 retry_on_media_change:
2938 WAIT_FOR_NOT_BUSY();
2940 //BX_DEBUG_ATA("ata_cmd_packet: not busy done\n");
2942 // We have already selected the appropriate controller (iobase1,2)
2943 // select master or slave
2944 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2948 //BX_DEBUG_ATA("ata_cmd_packet: drive selected (%d) status=0x%x\n", slave,(unsigned)status);
2951 // Technically, we should be calling this here
2952 // but QEMU's device model appears to be broken and RDY never is assserted
2953 // on a drive change
2954 // WAIT_FOR_NOT_BUSY_AND_DRIVE_READY();
2955 WAIT_FOR_NOT_BUSY();
2957 BX_DEBUG_ATA("ata_cmd_packet: not busy\n");
2959 // set "noninterruptable"
2960 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2962 outb(iobase1 + ATA_CB_FR, 0x00);
2963 // This conveys the maximum bytecount. count&0xff in low, count>>8 in high
2964 // it is not actually doing anything with cylinders
2965 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2966 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2967 // Not sure about these
2968 outb(iobase1 + ATA_CB_SC, 0x00);
2969 outb(iobase1 + ATA_CB_SN, 0x00);
2971 BX_DEBUG_ATA("ata_cmd_packet: configuration done\n");
2973 // Issue command for packet
2974 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2976 BX_DEBUG_ATA("ata_cmd_packet: A0 issued to drive\n");
2978 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
2980 BX_DEBUG_ATA("ata_cmd_packet: alt status shows not busy\n");
2984 BX_DEBUG_ATA("ata_cmd_packet: main status shows 0x%x\n",(unsigned)status);
2986 WAIT_FOR_DATA_REQUEST();
2988 BX_DEBUG_ATA("ata_cmd_packet: data request is set\n");
2990 // Normalize address
2991 cmdseg += (cmdoff / 16);
2994 // Send command to device
2996 sti ;; enable higher priority interrupts
3001 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3002 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3003 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3004 mov es, ax ;; segment in es
3006 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3010 outsw ;; CX words transfered from port(DX) to ES:[SI]
3016 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
3021 BX_DEBUG_ATA("ata_cmd_packet: after packet: 0x%x error 0x%x\n",(unsigned)status,(unsigned)error);
3023 if (status&ATA_CB_STAT_ERR && error&ATA_CB_ER_MC) {
3024 BX_DEBUG_ATA("ata_cmd_packet: caught unexpected media change. Retrying\n");
3025 goto retry_on_media_change;
3030 if (inout == ATA_DATA_NO) {
3037 // This while loop is quite bizarre
3038 // Under both success and failure, you'll go through it once
3039 // and then just a wee bit the second time - PAD
3042 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
3047 BX_DEBUG_ATA("ata_cmd_packet/dataxferloop: status=0x%x, error=0x%x\n",(unsigned)status,(unsigned)error);
3053 // According to specatapi, the following is how you're supposed
3054 // To tell when there is no more data for you
3055 // But it doesn't work on at least some hardware - PAD
3056 if ((status&ATA_CB_STAT_BSY) && !(status&ATA_CB_STAT_DRQ)) {
3057 // done with data tranfer
3058 // we wait for it to flip
3059 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
3060 // then read one more time
3068 // Check if command completed
3069 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3072 if (status & ATA_CB_STAT_ERR) {
3073 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3074 debug_outb(0x3ec, 0xf4);
3078 // If we get here, we are ready and should have DRQ
3079 // and so data is available
3080 // Device must be ready to send data
3081 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3082 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3083 BX_DEBUG_ATA("ata_cmd_packet 1: not ready (status %02x)\n", status);
3084 debug_outb(0x3ec, 0xf4);
3088 // Normalize address
3089 bufseg += (bufoff / 16);
3092 // Get the byte count
3093 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3095 // adjust to read what we want
3108 lafter=lcount-length;
3120 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3121 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3123 // If counts not dividable by 4, use 16bits mode
3125 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3126 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3127 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3129 // adds an extra byte if count are odd. before is always even
3130 if (lcount & 0x01) {
3132 if ((lafter > 0) && (lafter & 0x01)) {
3137 if (lmode == ATA_MODE_PIO32) {
3138 lcount>>=2; lbefore>>=2; lafter>>=2;
3141 lcount>>=1; lbefore>>=1; lafter>>=1;
3150 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3152 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3153 jcxz ata_packet_no_before
3155 mov ah, _ata_cmd_packet.lmode + 2[bp]
3156 cmp ah, #ATA_MODE_PIO32
3157 je ata_packet_in_before_32
3159 ata_packet_in_before_16:
3161 loop ata_packet_in_before_16
3162 jmp ata_packet_no_before
3164 ata_packet_in_before_32:
3166 ata_packet_in_before_32_loop:
3168 loop ata_packet_in_before_32_loop
3171 ata_packet_no_before:
3172 mov cx, _ata_cmd_packet.lcount + 2[bp]
3173 jcxz ata_packet_after
3175 mov di, _ata_cmd_packet.bufoff + 2[bp]
3176 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3179 mov ah, _ata_cmd_packet.lmode + 2[bp]
3180 cmp ah, #ATA_MODE_PIO32
3185 insw ;; CX words transfered tp port(DX) to ES:[DI]
3186 jmp ata_packet_after
3190 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3193 mov cx, _ata_cmd_packet.lafter + 2[bp]
3194 jcxz ata_packet_done
3196 mov ah, _ata_cmd_packet.lmode + 2[bp]
3197 cmp ah, #ATA_MODE_PIO32
3198 je ata_packet_in_after_32
3200 ata_packet_in_after_16:
3202 loop ata_packet_in_after_16
3205 ata_packet_in_after_32:
3207 ata_packet_in_after_32_loop:
3209 loop ata_packet_in_after_32_loop
3216 // Compute new buffer address
3219 // Save transferred bytes count
3221 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3225 // Final check, device must be ready
3226 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3227 != ATA_CB_STAT_RDY ) {
3228 BX_DEBUG_ATA("ata_cmd_packet 2 : not ready (status %02x)\n", (unsigned) status);
3229 debug_outb(0x3ec, 0xf4);
3233 // Enable interrupts
3234 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3235 debug_outb(0x3ec, 0xf4);
3240 // ---------------------------------------------------------------------------
3241 // End of ATA/ATAPI Driver
3242 // ---------------------------------------------------------------------------
3245 // ---------------------------------------------------------------------------
3246 // Start of ATA/ATAPI generic functions
3247 // ---------------------------------------------------------------------------
3250 atapi_get_sense(device)
3257 debug_outb(0x3ed, 0xf5);
3259 memsetb(get_SS(),atacmd,0,12);
3264 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0) {
3265 debug_outb(0x3ed, 0xf5);
3269 if ((buffer[0] & 0x7e) == 0x70) {
3270 debug_outb(0x3ed, 0xf5);
3271 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3274 debug_outb(0x3ed, 0xf5);
3279 atapi_is_ready(device)
3285 debug_outb(0x3ee, 0xf6);
3287 memsetb(get_SS(),atacmd,0,12);
3290 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) {
3291 debug_outb(0x3ee, 0xf6);
3295 if (atapi_get_sense(device) !=0 ) {
3296 memsetb(get_SS(),atacmd,0,12);
3298 // try to send Test Unit Ready again
3299 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) {
3300 debug_outb(0x3ee, 0xf6);
3304 debug_outb(0x3ee, 0xf6);
3305 return atapi_get_sense(device);
3307 debug_outb(0x3ee, 0xf6);
3312 atapi_is_cdrom(device)
3317 Bit16u ebda_seg=read_word(0x0040,0x000E);
3319 debug_outb(0x3ef, 0xf7);
3321 if (device >= BX_MAX_ATA_DEVICES) {
3322 debug_outb(0x3ef, 0xf7);
3326 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) {
3327 debug_outb(0x3ef, 0xf7);
3331 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM) {
3332 debug_outb(0x3ef, 0xf7);
3336 debug_outb(0x3ef, 0xf7);
3340 // ---------------------------------------------------------------------------
3341 // End of ATA/ATAPI generic functions
3342 // ---------------------------------------------------------------------------
3344 #endif // BX_USE_ATADRV
3346 #if BX_ELTORITO_BOOT
3348 // ---------------------------------------------------------------------------
3349 // Start of El-Torito boot functions
3350 // ---------------------------------------------------------------------------
3357 Bit16u ebda_seg=read_word(0x0040,0x000E);
3359 debug_outb(0x2e8, 0xf8);
3361 //BX_DEBUG("rombios: cdemu_init\n");
3363 // the only important data is this one for now
3364 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3365 debug_outb(0x2e8, 0xf8);
3374 Bit16u ebda_seg=read_word(0x0040,0x000E);
3377 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3381 cdemu_emulated_drive()
3384 Bit16u ebda_seg=read_word(0x0040,0x000E);
3386 debug_outb(0x2ea, 0xfa);
3387 debug_outb(0x2ea, 0xfa);
3388 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3391 static char isotag[6]="CD001";
3392 static char eltorito[24]="EL TORITO SPECIFICATION";
3394 // Returns ah: emulated drive, al: error code
3399 Bit16u ebda_seg=read_word(0x0040,0x000E);
3400 Bit8u atacmd[12], buffer[2048];
3402 Bit16u boot_segment, nbsectors, i, error;
3405 debug_outb(0x2eb, 0xfb);
3407 // Find out the first cdrom
3408 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3409 if (atapi_is_cdrom(device)) break;
3413 if(device >= BX_MAX_ATA_DEVICES) {
3414 debug_outb(0x2eb, 0xfb);
3420 // Read the Boot Record Volume Descriptor
3421 memsetb(get_SS(),atacmd,0,12);
3422 atacmd[0]=0x28; // READ command
3423 atacmd[1]=0x0 ; // reserved - not sure why this wasn't zeroed to begin with -PAD
3424 atacmd[6]=0x0 ; // reserved - ... -PAD
3425 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3426 atacmd[8]=(0x01 & 0x00ff); // Sectors
3427 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3428 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3429 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3430 atacmd[5]=(0x11 & 0x000000ff);
3431 atacmd[9]=atacmd[10]=atacmd[11]=0x0; // just to be safe -PAD
3432 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0) {
3433 debug_outb(0x2eb, 0xfb);
3439 if(buffer[0]!=0)return 4;
3441 if(buffer[1+i]!=read_byte(0xf000,&isotag[i])) {
3442 debug_outb(0x2eb, 0xfb); return 5;
3446 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i])) {
3447 debug_outb(0x2eb, 0xfb); return 6;
3450 // ok, now we calculate the Boot catalog address
3451 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3453 // And we read the Boot Catalog
3454 memsetb(get_SS(),atacmd,0,12);
3455 atacmd[0]=0x28; // READ command
3456 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3457 atacmd[8]=(0x01 & 0x00ff); // Sectors
3458 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3459 atacmd[3]=(lba & 0x00ff0000) >> 16;
3460 atacmd[4]=(lba & 0x0000ff00) >> 8;
3461 atacmd[5]=(lba & 0x000000ff);
3462 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0) {
3463 debug_outb(0x2eb, 0xfb);
3470 if(buffer[0x00]!=0x01) { debug_outb(0x2eb, 0xfb); return 8;} // Header
3471 if(buffer[0x01]!=0x00){ debug_outb(0x2eb, 0xfb); return 9;} // Platform
3472 if(buffer[0x1E]!=0x55) { debug_outb(0x2eb, 0xfb); return 10;} // key 1
3473 if(buffer[0x1F]!=0xAA) { debug_outb(0x2eb, 0xfb); return 10;} // key 2
3475 // Initial/Default Entry
3476 if(buffer[0x20]!=0x88) { debug_outb(0x2eb, 0xfb); return 11;} // Bootable
3478 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3479 if(buffer[0x21]==0){
3480 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3481 // Win2000 cd boot needs to know it booted from cd
3482 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3484 else if(buffer[0x21]<4)
3485 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3487 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3489 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3490 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3492 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3493 if(boot_segment==0x0000)boot_segment=0x07C0;
3495 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3496 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3498 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3499 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3501 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3502 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3504 // And we read the image in memory
3505 memsetb(get_SS(),atacmd,0,12);
3506 atacmd[0]=0x28; // READ command
3507 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3508 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3509 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3510 atacmd[3]=(lba & 0x00ff0000) >> 16;
3511 atacmd[4]=(lba & 0x0000ff00) >> 8;
3512 atacmd[5]=(lba & 0x000000ff);
3513 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0) {
3514 debug_outb(0x2eb, 0xfb);
3519 // Remember the media type
3520 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3521 case 0x01: // 1.2M floppy
3522 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3523 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3524 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3526 case 0x02: // 1.44M floppy
3527 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3528 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3529 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3531 case 0x03: // 2.88M floppy
3532 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3533 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3534 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3536 case 0x04: // Harddrive
3537 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3538 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3539 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3540 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3544 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3545 // Increase bios installed hardware number of devices
3546 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3547 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3549 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3553 // everything is ok, so from now on, the emulation is active
3554 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3555 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3557 // return the boot drive + no error
3558 debug_outb(0x2eb, 0xfb);
3559 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3562 // ---------------------------------------------------------------------------
3563 // End of El-Torito boot functions
3564 // ---------------------------------------------------------------------------
3565 #endif // BX_ELTORITO_BOOT
3568 int14_function(regs, ds, iret_addr)
3569 pusha_regs_t regs; // regs pushed from PUSHA instruction
3570 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3571 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3573 Bit16u addr,timer,val16;
3580 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3581 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3582 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3583 switch (regs.u.r8.ah) {
3585 outb(addr+3, inb(addr+3) | 0x80);
3586 if (regs.u.r8.al & 0xE0 == 0) {
3590 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3591 outb(addr, val16 & 0xFF);
3592 outb(addr+1, val16 >> 8);
3594 outb(addr+3, regs.u.r8.al & 0x1F);
3595 regs.u.r8.ah = inb(addr+5);
3596 regs.u.r8.al = inb(addr+6);
3597 ClearCF(iret_addr.flags);
3600 timer = read_word(0x0040, 0x006C);
3601 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3602 val16 = read_word(0x0040, 0x006C);
3603 if (val16 != timer) {
3608 if (timeout) outb(addr, regs.u.r8.al);
3609 regs.u.r8.ah = inb(addr+5);
3610 if (!timeout) regs.u.r8.ah |= 0x80;
3611 ClearCF(iret_addr.flags);
3614 timer = read_word(0x0040, 0x006C);
3615 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3616 val16 = read_word(0x0040, 0x006C);
3617 if (val16 != timer) {
3624 regs.u.r8.al = inb(addr);
3626 regs.u.r8.ah = inb(addr+5);
3628 ClearCF(iret_addr.flags);
3631 regs.u.r8.ah = inb(addr+5);
3632 regs.u.r8.al = inb(addr+6);
3633 ClearCF(iret_addr.flags);
3636 SetCF(iret_addr.flags); // Unsupported
3639 SetCF(iret_addr.flags); // Unsupported
3644 int15_function(regs, ES, DS, FLAGS)
3645 pusha_regs_t regs; // REGS pushed via pusha
3646 Bit16u ES, DS, FLAGS;
3648 Bit16u ebda_seg=read_word(0x0040,0x000E);
3649 bx_bool prev_a20_enable;
3658 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3660 switch (regs.u.r8.ah) {
3661 case 0x24: /* A20 Control */
3662 switch (regs.u.r8.al) {
3674 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3684 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3686 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3692 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3696 /* keyboard intercept */
3698 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3705 case 0x52: // removable media eject
3707 regs.u.r8.ah = 0; // "ok ejection may proceed"
3711 if( regs.u.r8.al == 0 ) {
3712 // Set Interval requested.
3713 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3714 // Interval not already set.
3715 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3716 write_word( 0x40, 0x98, ES ); // Byte location, segment
3717 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3718 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3719 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3721 irqDisable = inb( 0xA1 );
3722 outb( 0xA1, irqDisable & 0xFE );
3723 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3724 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3726 // Interval already set.
3727 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3729 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3731 } else if( regs.u.r8.al == 1 ) {
3732 // Clear Interval requested
3733 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3735 bRegister = inb_cmos( 0xB );
3736 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3738 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3740 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3749 # error "Int15 function 87h not supported on < 80386"
3751 // +++ should probably have descriptor checks
3752 // +++ should have exception handlers
3754 // turn off interrupts
3759 prev_a20_enable = set_enable_a20(1); // enable A20 line
3761 // 128K max of transfer on 386+ ???
3762 // source == destination ???
3764 // ES:SI points to descriptor table
3765 // offset use initially comments
3766 // ==============================================
3767 // 00..07 Unused zeros Null descriptor
3768 // 08..0f GDT zeros filled in by BIOS
3769 // 10..17 source ssssssss source of data
3770 // 18..1f dest dddddddd destination of data
3771 // 20..27 CS zeros filled in by BIOS
3772 // 28..2f SS zeros filled in by BIOS
3779 // check for access rights of source & dest here
3781 // Initialize GDT descriptor
3782 base15_00 = (ES << 4) + regs.u.r16.si;
3783 base23_16 = ES >> 12;
3784 if (base15_00 < (ES<<4))
3786 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3787 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3788 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3789 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3790 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3792 // Initialize CS descriptor
3793 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3794 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3795 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3796 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3797 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3799 // Initialize SS descriptor
3801 base15_00 = ss << 4;
3802 base23_16 = ss >> 12;
3803 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3804 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3805 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3806 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3807 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3811 // Compile generates locals offset info relative to SP.
3812 // Get CX (word count) from stack.
3815 mov cx, _int15_function.CX [bx]
3817 // since we need to set SS:SP, save them to the BDA
3818 // for future restore
3828 lidt [pmode_IDT_info]
3829 ;; perhaps do something with IDT here
3831 ;; set PE bit in CR0
3835 ;; far jump to flush CPU queue after transition to protected mode
3836 JMP_AP(0x0020, protected_mode)
3839 ;; GDT points to valid descriptor table, now load SS, DS, ES
3840 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3842 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3844 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3850 movsw ;; move CX words from DS:SI to ES:DI
3852 ;; make sure DS and ES limits are 64KB
3857 ;; reset PG bit in CR0 ???
3862 ;; far jump to flush CPU queue after transition to real mode
3863 JMP_AP(0xf000, real_mode)
3866 ;; restore IDT to normal real-mode defaults
3868 lidt [rmode_IDT_info]
3870 // restore SS:SP from the BDA
3878 set_enable_a20(prev_a20_enable);
3880 // turn back on interrupts
3891 // Get the amount of extended memory (above 1M)
3893 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3896 regs.u.r8.al = inb_cmos(0x30);
3897 regs.u.r8.ah = inb_cmos(0x31);
3900 if(regs.u.r16.ax > 0x3c00)
3901 regs.u.r16.ax = 0x3c00;
3908 /* Device busy interrupt. Called by Int 16h when no key available */
3912 /* Interrupt complete. Called by Int 16h when key becomes available */
3916 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3918 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3924 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3929 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3939 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3941 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3945 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3946 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3948 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3953 #if BX_USE_PS2_MOUSE
3955 int15_function_mouse(regs, ES, DS, FLAGS)
3956 pusha_regs_t regs; // REGS pushed via pusha
3957 Bit16u ES, DS, FLAGS;
3959 Bit16u ebda_seg=read_word(0x0040,0x000E);
3960 Bit8u mouse_flags_1, mouse_flags_2;
3961 Bit16u mouse_driver_seg;
3962 Bit16u mouse_driver_offset;
3963 Bit8u comm_byte, prev_command_byte;
3964 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3966 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3968 switch (regs.u.r8.ah) {
3970 // Return Codes status in AH
3971 // =========================
3973 // 01: invalid subfunction (AL > 7)
3974 // 02: invalid input value (out of allowable range)
3975 // 03: interface error
3976 // 04: resend command received from mouse controller,
3977 // device driver should attempt command again
3978 // 05: cannot enable mouse, since no far call has been installed
3979 // 80/86: mouse service not implemented
3981 switch (regs.u.r8.al) {
3982 case 0: // Disable/Enable Mouse
3983 BX_DEBUG_INT15("case 0:\n");
3984 switch (regs.u.r8.bh) {
3985 case 0: // Disable Mouse
3986 BX_DEBUG_INT15("case 0: disable mouse\n");
3987 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3988 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3990 ret = get_mouse_data(&mouse_data1);
3991 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4004 case 1: // Enable Mouse
4005 BX_DEBUG_INT15("case 1: enable mouse\n");
4006 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4007 if ( (mouse_flags_2 & 0x80) == 0 ) {
4008 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4010 regs.u.r8.ah = 5; // no far call installed
4013 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4014 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
4016 ret = get_mouse_data(&mouse_data1);
4017 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
4018 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4028 default: // invalid subfunction
4029 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4031 regs.u.r8.ah = 1; // invalid subfunction
4036 case 1: // Reset Mouse
4037 case 5: // Initialize Mouse
4038 BX_DEBUG_INT15("case 1 or 5:\n");
4039 if (regs.u.r8.al == 5) {
4040 if (regs.u.r8.bh != 3) {
4042 regs.u.r8.ah = 0x02; // invalid input
4045 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4046 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
4047 mouse_flags_1 = 0x00;
4048 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4049 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4052 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4053 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4055 ret = get_mouse_data(&mouse_data3);
4056 // if no mouse attached, it will return RESEND
4057 if (mouse_data3 == 0xfe) {
4061 if (mouse_data3 != 0xfa)
4062 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4064 ret = get_mouse_data(&mouse_data1);
4066 ret = get_mouse_data(&mouse_data2);
4068 // turn IRQ12 and packet generation on
4069 enable_mouse_int_and_events();
4072 regs.u.r8.bl = mouse_data1;
4073 regs.u.r8.bh = mouse_data2;
4085 case 2: // Set Sample Rate
4086 BX_DEBUG_INT15("case 2:\n");
4087 switch (regs.u.r8.bh) {
4088 case 0: mouse_data1 = 10; break; // 10 reports/sec
4089 case 1: mouse_data1 = 20; break; // 20 reports/sec
4090 case 2: mouse_data1 = 40; break; // 40 reports/sec
4091 case 3: mouse_data1 = 60; break; // 60 reports/sec
4092 case 4: mouse_data1 = 80; break; // 80 reports/sec
4093 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4094 case 6: mouse_data1 = 200; break; // 200 reports/sec
4095 default: mouse_data1 = 0;
4097 if (mouse_data1 > 0) {
4098 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4100 ret = get_mouse_data(&mouse_data2);
4101 ret = send_to_mouse_ctrl(mouse_data1);
4102 ret = get_mouse_data(&mouse_data2);
4108 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4113 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4117 case 3: // Set Resolution
4118 BX_DEBUG_INT15("case 3:\n");
4120 // 0 = 25 dpi, 1 count per millimeter
4121 // 1 = 50 dpi, 2 counts per millimeter
4122 // 2 = 100 dpi, 4 counts per millimeter
4123 // 3 = 200 dpi, 8 counts per millimeter
4128 case 4: // Get Device ID
4129 BX_DEBUG_INT15("case 4:\n");
4130 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4131 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4133 ret = get_mouse_data(&mouse_data1);
4134 ret = get_mouse_data(&mouse_data2);
4137 regs.u.r8.bh = mouse_data2;
4141 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4145 case 6: // Return Status & Set Scaling Factor...
4146 BX_DEBUG_INT15("case 6:\n");
4147 switch (regs.u.r8.bh) {
4148 case 0: // Return Status
4149 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4150 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4152 ret = get_mouse_data(&mouse_data1);
4153 if (mouse_data1 != 0xfa)
4154 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4156 ret = get_mouse_data(&mouse_data1);
4158 ret = get_mouse_data(&mouse_data2);
4160 ret = get_mouse_data(&mouse_data3);
4164 regs.u.r8.bl = mouse_data1;
4165 regs.u.r8.cl = mouse_data2;
4166 regs.u.r8.dl = mouse_data3;
4167 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4178 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4181 case 1: // Set Scaling Factor to 1:1
4182 case 2: // Set Scaling Factor to 2:1
4183 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4184 if (regs.u.r8.bh == 1) {
4185 ret = send_to_mouse_ctrl(0xE6);
4187 ret = send_to_mouse_ctrl(0xE7);
4190 get_mouse_data(&mouse_data1);
4191 ret = (mouse_data1 != 0xFA);
4199 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4201 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4205 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4209 case 7: // Set Mouse Handler Address
4210 BX_DEBUG_INT15("case 7:\n");
4211 mouse_driver_seg = ES;
4212 mouse_driver_offset = regs.u.r16.bx;
4213 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4214 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4215 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4216 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4217 /* remove handler */
4218 if ( (mouse_flags_2 & 0x80) != 0 ) {
4219 mouse_flags_2 &= ~0x80;
4220 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4224 /* install handler */
4225 mouse_flags_2 |= 0x80;
4227 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4233 BX_DEBUG_INT15("case default:\n");
4234 regs.u.r8.ah = 1; // invalid function
4240 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4241 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4243 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4250 int15_function32(regs, ES, DS, FLAGS)
4251 pushad_regs_t regs; // REGS pushed via pushad
4252 Bit16u ES, DS, FLAGS;
4254 Bit32u extended_memory_size=0; // 64bits long
4257 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4259 switch (regs.u.r8.ah) {
4261 // Wait for CX:DX microseconds. currently using the
4262 // refresh request port 0x61 bit4, toggling every 15usec
4270 ;; Get the count in eax
4273 mov ax, _int15_function.CX [bx]
4276 mov ax, _int15_function.DX [bx]
4278 ;; convert to numbers of 15usec ticks
4284 ;; wait for ecx number of refresh requests
4305 switch(regs.u.r8.al)
4307 case 0x20: // coded by osmaker aka K.J.
4308 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4310 #if defined(HVMASSIST) && 0
4311 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4313 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4315 BX_DEBUG_INT15("OK bx=%x\n",regs.u.r16.bx);
4317 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4318 memcpyb(ES, regs.u.r16.di,
4319 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4321 regs.u.r32.ebx += 0x14;
4322 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4324 regs.u.r32.eax = 0x534D4150;
4325 regs.u.r32.ecx = 0x14;
4328 } else if (regs.u.r16.bx == 1) {
4329 extended_memory_size = inb_cmos(0x35);
4330 extended_memory_size <<= 8;
4331 extended_memory_size |= inb_cmos(0x34);
4332 extended_memory_size *= 64;
4333 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4335 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4337 extended_memory_size *= 1024;
4338 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4340 if (extended_memory_size <= 15728640)
4342 extended_memory_size = inb_cmos(0x31);
4343 extended_memory_size <<= 8;
4344 extended_memory_size |= inb_cmos(0x30);
4345 extended_memory_size *= 1024;
4348 write_word(ES, regs.u.r16.di, 0x0000);
4349 write_word(ES, regs.u.r16.di+2, 0x0010);
4350 write_word(ES, regs.u.r16.di+4, 0x0000);
4351 write_word(ES, regs.u.r16.di+6, 0x0000);
4353 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4354 extended_memory_size >>= 16;
4355 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4356 extended_memory_size >>= 16;
4357 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4358 extended_memory_size >>= 16;
4359 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4361 write_word(ES, regs.u.r16.di+16, 0x1);
4362 write_word(ES, regs.u.r16.di+18, 0x0);
4365 regs.u.r32.eax = 0x534D4150;
4366 regs.u.r32.ecx = 0x14;
4369 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4370 goto int15_unimplemented;
4373 switch(regs.u.r16.bx)
4376 write_word(ES, regs.u.r16.di, 0x00);
4377 write_word(ES, regs.u.r16.di+2, 0x00);
4378 write_word(ES, regs.u.r16.di+4, 0x00);
4379 write_word(ES, regs.u.r16.di+6, 0x00);
4381 write_word(ES, regs.u.r16.di+8, 0xFC00);
4382 write_word(ES, regs.u.r16.di+10, 0x0009);
4383 write_word(ES, regs.u.r16.di+12, 0x0000);
4384 write_word(ES, regs.u.r16.di+14, 0x0000);
4386 write_word(ES, regs.u.r16.di+16, 0x1);
4387 write_word(ES, regs.u.r16.di+18, 0x0);
4391 regs.u.r32.eax = 0x534D4150;
4392 regs.u.r32.ecx = 0x14;
4397 extended_memory_size = inb_cmos(0x35);
4398 extended_memory_size <<= 8;
4399 extended_memory_size |= inb_cmos(0x34);
4400 extended_memory_size *= 64;
4401 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4403 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4405 extended_memory_size *= 1024;
4406 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4408 if(extended_memory_size <= 15728640)
4410 extended_memory_size = inb_cmos(0x31);
4411 extended_memory_size <<= 8;
4412 extended_memory_size |= inb_cmos(0x30);
4413 extended_memory_size *= 1024;
4416 write_word(ES, regs.u.r16.di, 0x0000);
4417 write_word(ES, regs.u.r16.di+2, 0x0010);
4418 write_word(ES, regs.u.r16.di+4, 0x0000);
4419 write_word(ES, regs.u.r16.di+6, 0x0000);
4421 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4422 extended_memory_size >>= 16;
4423 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4424 extended_memory_size >>= 16;
4425 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4426 extended_memory_size >>= 16;
4427 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4429 write_word(ES, regs.u.r16.di+16, 0x1);
4430 write_word(ES, regs.u.r16.di+18, 0x0);
4433 regs.u.r32.eax = 0x534D4150;
4434 regs.u.r32.ecx = 0x14;
4438 default: /* AX=E820, DX=534D4150, BX unrecognized */
4439 goto int15_unimplemented;
4444 // if DX != 0x534D4150)
4445 goto int15_unimplemented;
4450 // do we have any reason to fail here ?
4453 // my real system sets ax and bx to 0
4454 // this is confirmed by Ralph Brown list
4455 // but syslinux v1.48 is known to behave
4456 // strangely if ax is set to 0
4457 // regs.u.r16.ax = 0;
4458 // regs.u.r16.bx = 0;
4460 // Get the amount of extended memory (above 1M)
4461 regs.u.r8.cl = inb_cmos(0x30);
4462 regs.u.r8.ch = inb_cmos(0x31);
4465 if(regs.u.r16.cx > 0x3c00)
4467 regs.u.r16.cx = 0x3c00;
4470 // Get the amount of extended memory above 16M in 64k blocs
4471 regs.u.r8.dl = inb_cmos(0x34);
4472 regs.u.r8.dh = inb_cmos(0x35);
4474 // Set configured memory equal to extended memory
4475 regs.u.r16.ax = regs.u.r16.cx;
4476 regs.u.r16.bx = regs.u.r16.dx;
4478 default: /* AH=0xE8?? but not implemented */
4479 goto int15_unimplemented;
4482 int15_unimplemented:
4483 // fall into the default
4485 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4486 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4488 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4494 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4495 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4497 Bit8u scan_code, ascii_code, shift_flags, count;
4498 Bit16u kbd_code, max;
4500 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4503 case 0x00: /* read keyboard input */
4505 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4506 BX_PANIC("KBD: int16h: out of keyboard input\n");
4508 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4509 else if (ascii_code == 0xE0) ascii_code = 0;
4510 AX = (scan_code << 8) | ascii_code;
4513 case 0x01: /* check keyboard status */
4514 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4518 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4519 else if (ascii_code == 0xE0) ascii_code = 0;
4520 AX = (scan_code << 8) | ascii_code;
4524 case 0x02: /* get shift flag status */
4525 shift_flags = read_byte(0x0040, 0x17);
4526 SET_AL(shift_flags);
4529 case 0x05: /* store key-stroke into buffer */
4530 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4538 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4539 // bit Bochs Description
4541 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4542 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4543 // 4 1 INT 16/AH=0Ah supported
4544 // 3 0 INT 16/AX=0306h supported
4545 // 2 0 INT 16/AX=0305h supported
4546 // 1 0 INT 16/AX=0304h supported
4547 // 0 0 INT 16/AX=0300h supported
4552 case 0x0A: /* GET KEYBOARD ID */
4558 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4560 if ((inb(0x60) == 0xfa)) {
4563 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4566 kbd_code |= (inb(0x60) << 8);
4568 } while (--count>0);
4574 case 0x10: /* read MF-II keyboard input */
4576 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4577 BX_PANIC("KBD: int16h: out of keyboard input\n");
4579 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4580 AX = (scan_code << 8) | ascii_code;
4583 case 0x11: /* check MF-II keyboard status */
4584 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4588 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4589 AX = (scan_code << 8) | ascii_code;
4593 case 0x12: /* get extended keyboard status */
4594 shift_flags = read_byte(0x0040, 0x17);
4595 SET_AL(shift_flags);
4596 shift_flags = read_byte(0x0040, 0x18);
4597 SET_AH(shift_flags);
4598 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4601 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4602 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4605 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4606 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4610 if (GET_AL() == 0x08)
4611 SET_AH(0x02); // unsupported, aka normal keyboard
4614 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4619 dequeue_key(scan_code, ascii_code, incr)
4624 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4629 buffer_start = 0x001E;
4630 buffer_end = 0x003E;
4632 buffer_start = read_word(0x0040, 0x0080);
4633 buffer_end = read_word(0x0040, 0x0082);
4636 buffer_head = read_word(0x0040, 0x001a);
4637 buffer_tail = read_word(0x0040, 0x001c);
4639 if (buffer_head != buffer_tail) {
4641 acode = read_byte(0x0040, buffer_head);
4642 scode = read_byte(0x0040, buffer_head+1);
4643 write_byte(ss, ascii_code, acode);
4644 write_byte(ss, scan_code, scode);
4648 if (buffer_head >= buffer_end)
4649 buffer_head = buffer_start;
4650 write_word(0x0040, 0x001a, buffer_head);
4659 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4662 inhibit_mouse_int_and_events()
4664 Bit8u command_byte, prev_command_byte;
4666 // Turn off IRQ generation and aux data line
4667 if ( inb(0x64) & 0x02 )
4668 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4669 outb(0x64, 0x20); // get command byte
4670 while ( (inb(0x64) & 0x01) != 0x01 );
4671 prev_command_byte = inb(0x60);
4672 command_byte = prev_command_byte;
4673 //while ( (inb(0x64) & 0x02) );
4674 if ( inb(0x64) & 0x02 )
4675 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4676 command_byte &= 0xfd; // turn off IRQ 12 generation
4677 command_byte |= 0x20; // disable mouse serial clock line
4678 outb(0x64, 0x60); // write command byte
4679 outb(0x60, command_byte);
4680 return(prev_command_byte);
4684 enable_mouse_int_and_events()
4688 // Turn on IRQ generation and aux data line
4689 if ( inb(0x64) & 0x02 )
4690 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4691 outb(0x64, 0x20); // get command byte
4692 while ( (inb(0x64) & 0x01) != 0x01 );
4693 command_byte = inb(0x60);
4694 //while ( (inb(0x64) & 0x02) );
4695 if ( inb(0x64) & 0x02 )
4696 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4697 command_byte |= 0x02; // turn on IRQ 12 generation
4698 command_byte &= 0xdf; // enable mouse serial clock line
4699 outb(0x64, 0x60); // write command byte
4700 outb(0x60, command_byte);
4704 send_to_mouse_ctrl(sendbyte)
4709 // wait for chance to write to ctrl
4710 if ( inb(0x64) & 0x02 )
4711 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4713 outb(0x60, sendbyte);
4719 get_mouse_data(data)
4725 while ( (inb(0x64) & 0x21) != 0x21 ) {
4728 response = inb(0x60);
4731 write_byte(ss, data, response);
4736 set_kbd_command_byte(command_byte)
4739 if ( inb(0x64) & 0x02 )
4740 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4743 outb(0x64, 0x60); // write command byte
4744 outb(0x60, command_byte);
4748 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4749 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4751 Bit8u scancode, asciicode, shift_flags;
4752 Bit8u mf2_flags, mf2_state, led_flags;
4755 // DS has been set to F000 before call
4759 scancode = GET_AL();
4761 if (scancode == 0) {
4762 BX_INFO("KBD: int09 handler: AL=0\n");
4767 shift_flags = read_byte(0x0040, 0x17);
4768 mf2_flags = read_byte(0x0040, 0x18);
4769 mf2_state = read_byte(0x0040, 0x96);
4770 led_flags = read_byte(0x0040, 0x97);
4774 case 0x3a: /* Caps Lock press */
4775 shift_flags ^= 0x40;
4776 write_byte(0x0040, 0x17, shift_flags);
4778 write_byte(0x0040, 0x18, mf2_flags);
4780 write_byte(0x0040, 0x97, led_flags);
4782 case 0xba: /* Caps Lock release */
4784 write_byte(0x0040, 0x18, mf2_flags);
4787 case 0x2a: /* L Shift press */
4788 /*shift_flags &= ~0x40;*/
4789 shift_flags |= 0x02;
4790 write_byte(0x0040, 0x17, shift_flags);
4792 write_byte(0x0040, 0x97, led_flags);
4794 case 0xaa: /* L Shift release */
4795 shift_flags &= ~0x02;
4796 write_byte(0x0040, 0x17, shift_flags);
4799 case 0x36: /* R Shift press */
4800 /*shift_flags &= ~0x40;*/
4801 shift_flags |= 0x01;
4802 write_byte(0x0040, 0x17, shift_flags);
4804 write_byte(0x0040, 0x97, led_flags);
4806 case 0xb6: /* R Shift release */
4807 shift_flags &= ~0x01;
4808 write_byte(0x0040, 0x17, shift_flags);
4811 case 0x1d: /* Ctrl press */
4812 shift_flags |= 0x04;
4813 write_byte(0x0040, 0x17, shift_flags);
4814 if (mf2_state & 0x01) {
4819 write_byte(0x0040, 0x18, mf2_flags);
4821 case 0x9d: /* Ctrl release */
4822 shift_flags &= ~0x04;
4823 write_byte(0x0040, 0x17, shift_flags);
4824 if (mf2_state & 0x01) {
4829 write_byte(0x0040, 0x18, mf2_flags);
4832 case 0x38: /* Alt press */
4833 shift_flags |= 0x08;
4834 write_byte(0x0040, 0x17, shift_flags);
4835 if (mf2_state & 0x01) {
4840 write_byte(0x0040, 0x18, mf2_flags);
4842 case 0xb8: /* Alt release */
4843 shift_flags &= ~0x08;
4844 write_byte(0x0040, 0x17, shift_flags);
4845 if (mf2_state & 0x01) {
4850 write_byte(0x0040, 0x18, mf2_flags);
4853 case 0x45: /* Num Lock press */
4854 if ((mf2_state & 0x01) == 0) {
4856 write_byte(0x0040, 0x18, mf2_flags);
4857 shift_flags ^= 0x20;
4859 write_byte(0x0040, 0x17, shift_flags);
4860 write_byte(0x0040, 0x97, led_flags);
4863 case 0xc5: /* Num Lock release */
4864 if ((mf2_state & 0x01) == 0) {
4866 write_byte(0x0040, 0x18, mf2_flags);
4870 case 0x46: /* Scroll Lock press */
4872 write_byte(0x0040, 0x18, mf2_flags);
4873 shift_flags ^= 0x10;
4875 write_byte(0x0040, 0x17, shift_flags);
4876 write_byte(0x0040, 0x97, led_flags);
4879 case 0xc6: /* Scroll Lock release */
4881 write_byte(0x0040, 0x18, mf2_flags);
4885 if (scancode & 0x80) return; /* toss key releases ... */
4886 if (scancode > MAX_SCAN_CODE) {
4887 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4890 if (shift_flags & 0x08) { /* ALT */
4891 asciicode = scan_to_scanascii[scancode].alt;
4892 scancode = scan_to_scanascii[scancode].alt >> 8;
4894 else if (shift_flags & 0x04) { /* CONTROL */
4895 asciicode = scan_to_scanascii[scancode].control;
4896 scancode = scan_to_scanascii[scancode].control >> 8;
4898 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4899 /* check if lock state should be ignored
4900 * because a SHIFT key are pressed */
4902 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4903 asciicode = scan_to_scanascii[scancode].normal;
4904 scancode = scan_to_scanascii[scancode].normal >> 8;
4907 asciicode = scan_to_scanascii[scancode].shift;
4908 scancode = scan_to_scanascii[scancode].shift >> 8;
4912 /* check if lock is on */
4913 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4914 asciicode = scan_to_scanascii[scancode].shift;
4915 scancode = scan_to_scanascii[scancode].shift >> 8;
4918 asciicode = scan_to_scanascii[scancode].normal;
4919 scancode = scan_to_scanascii[scancode].normal >> 8;
4922 if (scancode==0 && asciicode==0) {
4923 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4925 enqueue_key(scancode, asciicode);
4932 enqueue_key(scan_code, ascii_code)
4933 Bit8u scan_code, ascii_code;
4935 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4937 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4938 // scan_code, ascii_code);
4941 buffer_start = 0x001E;
4942 buffer_end = 0x003E;
4944 buffer_start = read_word(0x0040, 0x0080);
4945 buffer_end = read_word(0x0040, 0x0082);
4948 buffer_head = read_word(0x0040, 0x001A);
4949 buffer_tail = read_word(0x0040, 0x001C);
4951 temp_tail = buffer_tail;
4953 if (buffer_tail >= buffer_end)
4954 buffer_tail = buffer_start;
4956 if (buffer_tail == buffer_head) {
4960 write_byte(0x0040, temp_tail, ascii_code);
4961 write_byte(0x0040, temp_tail+1, scan_code);
4962 write_word(0x0040, 0x001C, buffer_tail);
4968 int74_function(make_farcall, Z, Y, X, status)
4969 Bit16u make_farcall, Z, Y, X, status;
4971 Bit16u ebda_seg=read_word(0x0040,0x000E);
4972 Bit8u in_byte, index, package_count;
4973 Bit8u mouse_flags_1, mouse_flags_2;
4975 BX_DEBUG_INT74("entering int74_function\n");
4978 in_byte = inb(0x64);
4979 if ( (in_byte & 0x21) != 0x21 ) {
4982 in_byte = inb(0x60);
4983 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4985 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4986 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4988 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4989 // BX_PANIC("int74_function:\n");
4993 package_count = mouse_flags_2 & 0x07;
4994 index = mouse_flags_1 & 0x07;
4995 write_byte(ebda_seg, 0x28 + index, in_byte);
4997 if ( (index+1) >= package_count ) {
4998 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4999 status = read_byte(ebda_seg, 0x0028 + 0);
5000 X = read_byte(ebda_seg, 0x0028 + 1);
5001 Y = read_byte(ebda_seg, 0x0028 + 2);
5004 // check if far call handler installed
5005 if (mouse_flags_2 & 0x80)
5011 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5014 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5019 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5020 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5023 Bit16u ebda_seg=read_word(0x0040,0x000E);
5024 Bit16u cylinder, head, sector;
5025 Bit16u segment, offset;
5026 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5028 Bit8u device, status;
5030 debug_outb(0x2ef, 0xff);
5031 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5033 write_byte(0x0040, 0x008e, 0); // clear completion flag
5035 // basic check : device has to be defined
5036 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5037 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5041 // Get the ata channel
5042 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5044 // basic check : device has to be valid
5045 if (device >= BX_MAX_ATA_DEVICES) {
5046 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5052 case 0x00: /* disk controller reset */
5057 case 0x01: /* read disk status */
5058 status = read_byte(0x0040, 0x0074);
5060 SET_DISK_RET_STATUS(0);
5061 /* set CF if error status read */
5062 if (status) goto int13_fail_nostatus;
5063 else goto int13_success_noah;
5066 case 0x02: // read disk sectors
5067 case 0x03: // write disk sectors
5068 case 0x04: // verify disk sectors
5071 cylinder = GET_CH();
5072 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5073 sector = (GET_CL() & 0x3f);
5079 if ( (count > 128) || (count == 0) ) {
5080 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5084 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5085 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5086 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5088 // sanity check on cyl heads, sec
5089 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5090 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5095 if ( GET_AH() == 0x04 ) goto int13_success;
5097 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5098 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5100 // if needed, translate lchs to lba, and execute command
5101 if ( (nph != nlh) || (npspt != nlspt)) {
5102 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5103 sector = 0; // this forces the command to be lba
5106 if ( GET_AH() == 0x02 )
5107 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5109 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5111 // Set nb of sector transferred
5112 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5115 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5117 goto int13_fail_noah;
5123 case 0x05: /* format disk track */
5124 BX_INFO("format disk track called\n");
5129 case 0x08: /* read disk drive parameters */
5131 // Get logical geometry from table
5132 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5133 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5134 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5135 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5137 nlc = nlc - 2; /* 0 based , last sector not used */
5140 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5142 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5144 // FIXME should set ES & DI
5149 case 0x10: /* check drive ready */
5150 // should look at 40:8E also???
5152 // Read the status from controller
5153 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5154 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5159 goto int13_fail_noah;
5163 case 0x15: /* read disk drive size */
5165 // Get physical geometry from table
5166 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5167 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5168 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5170 // Compute sector count seen by int13
5171 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5175 SET_AH(3); // hard disk accessible
5176 goto int13_success_noah;
5179 case 0x41: // IBM/MS installation check
5180 BX=0xaa55; // install check
5181 SET_AH(0x30); // EDD 3.0
5182 CX=0x0007; // ext disk access and edd, removable supported
5183 goto int13_success_noah;
5186 case 0x42: // IBM/MS extended read
5187 case 0x43: // IBM/MS extended write
5188 case 0x44: // IBM/MS verify
5189 case 0x47: // IBM/MS extended seek
5191 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5192 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5193 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5195 // Can't use 64 bits lba
5196 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5198 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5202 // Get 32 bits lba and check
5203 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5204 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5205 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5209 // If verify or seek
5210 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5213 // Execute the command
5214 if ( GET_AH() == 0x42 )
5215 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5217 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5219 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5220 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5223 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5225 goto int13_fail_noah;
5231 case 0x45: // IBM/MS lock/unlock drive
5232 case 0x49: // IBM/MS extended media change
5233 goto int13_success; // Always success for HD
5236 case 0x46: // IBM/MS eject media
5237 SET_AH(0xb2); // Volume Not Removable
5238 goto int13_fail_noah; // Always fail for HD
5241 case 0x48: // IBM/MS get drive parameters
5242 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5244 // Buffer is too small
5252 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5253 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5254 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5255 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5256 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5258 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5259 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5260 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5261 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5262 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5263 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5264 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5265 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5270 Bit8u channel, dev, irq, mode, checksum, i, translation;
5271 Bit16u iobase1, iobase2, options;
5273 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5275 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5276 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5279 channel = device / 2;
5280 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5281 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5282 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5283 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5284 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5286 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5287 options |= (1<<4); // lba translation
5288 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5289 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5290 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5292 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5293 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5294 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5295 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5296 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5297 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5298 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5299 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5300 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5301 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5302 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5305 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5306 checksum = ~checksum;
5307 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5312 Bit8u channel, iface, checksum, i;
5315 channel = device / 2;
5316 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5317 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5319 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5320 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5321 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5322 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5323 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5325 if (iface==ATA_IFACE_ISA) {
5326 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5327 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5328 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5329 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5334 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5335 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5336 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5337 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5339 if (iface==ATA_IFACE_ISA) {
5340 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5341 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5342 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5347 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5348 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5349 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5350 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5353 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5354 checksum = ~checksum;
5355 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5361 case 0x4e: // // IBM/MS set hardware configuration
5362 // DMA, prefetch, PIO maximum not supported
5375 case 0x09: /* initialize drive parameters */
5376 case 0x0c: /* seek to specified cylinder */
5377 case 0x0d: /* alternate disk reset */
5378 case 0x11: /* recalibrate */
5379 case 0x14: /* controller internal diagnostic */
5380 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5384 case 0x0a: /* read disk sectors with ECC */
5385 case 0x0b: /* write disk sectors with ECC */
5386 case 0x18: // set media type for format
5387 case 0x50: // IBM/MS send packet command
5389 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5395 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5397 SET_DISK_RET_STATUS(GET_AH());
5398 int13_fail_nostatus:
5399 SET_CF(); // error occurred
5400 debug_outb(0x2ef, 0xff);
5404 SET_AH(0x00); // no error
5406 SET_DISK_RET_STATUS(0x00);
5407 CLEAR_CF(); // no error
5408 debug_outb(0x2ef, 0xff);
5412 // ---------------------------------------------------------------------------
5413 // Start of int13 for cdrom
5414 // ---------------------------------------------------------------------------
5417 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5418 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5420 Bit16u ebda_seg=read_word(0x0040,0x000E);
5421 Bit8u device, status, locks;
5424 Bit16u count, segment, offset, i, size;
5426 debug_outb(0x2f8, 0xe0);
5428 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5429 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5431 SET_DISK_RET_STATUS(0x00);
5433 /* basic check : device should be 0xE0+ */
5434 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5435 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5439 // Get the ata channel
5440 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5442 /* basic check : device has to be valid */
5443 if (device >= BX_MAX_ATA_DEVICES) {
5444 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5450 // all those functions return SUCCESS
5451 case 0x00: /* disk controller reset */
5452 case 0x09: /* initialize drive parameters */
5453 case 0x0c: /* seek to specified cylinder */
5454 case 0x0d: /* alternate disk reset */
5455 case 0x10: /* check drive ready */
5456 case 0x11: /* recalibrate */
5457 case 0x14: /* controller internal diagnostic */
5458 case 0x16: /* detect disk change */
5462 // all those functions return disk write-protected
5463 case 0x03: /* write disk sectors */
5464 case 0x05: /* format disk track */
5465 case 0x43: // IBM/MS extended write
5467 goto int13_fail_noah;
5470 case 0x01: /* read disk status */
5471 status = read_byte(0x0040, 0x0074);
5473 SET_DISK_RET_STATUS(0);
5475 /* set CF if error status read */
5476 if (status) goto int13_fail_nostatus;
5477 else goto int13_success_noah;
5480 case 0x15: /* read disk drive size */
5482 goto int13_fail_noah;
5485 case 0x41: // IBM/MS installation check
5486 BX=0xaa55; // install check
5487 SET_AH(0x30); // EDD 2.1
5488 CX=0x0007; // ext disk access, removable and edd
5489 goto int13_success_noah;
5492 case 0x42: // IBM/MS extended read
5493 case 0x44: // IBM/MS verify sectors
5494 case 0x47: // IBM/MS extended seek
5496 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5497 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5498 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5500 // Can't use 64 bits lba
5501 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5503 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5508 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5510 // If verify or seek
5511 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5514 memsetb(get_SS(),atacmd,0,12);
5515 atacmd[0]=0x28; // READ command
5516 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5517 atacmd[8]=(count & 0x00ff); // Sectors
5518 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5519 atacmd[3]=(lba & 0x00ff0000) >> 16;
5520 atacmd[4]=(lba & 0x0000ff00) >> 8;
5521 atacmd[5]=(lba & 0x000000ff);
5522 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5524 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5525 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5528 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5530 goto int13_fail_noah;
5536 case 0x45: // IBM/MS lock/unlock drive
5537 if (GET_AL() > 2) goto int13_fail;
5539 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5543 if (locks == 0xff) {
5546 goto int13_fail_noah;
5548 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5552 if (locks == 0x00) {
5555 goto int13_fail_noah;
5557 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5558 SET_AL(locks==0?0:1);
5561 SET_AL(locks==0?0:1);
5567 case 0x46: // IBM/MS eject media
5568 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5571 SET_AH(0xb1); // media locked
5572 goto int13_fail_noah;
5574 // FIXME should handle 0x31 no media in device
5575 // FIXME should handle 0xb5 valid request failed
5577 // Call removable media eject
5584 mov _int13_cdrom.status + 2[bp], ah
5585 jnc int13_cdrom_rme_end
5586 mov _int13_cdrom.status, #1
5587 int13_cdrom_rme_end:
5592 SET_AH(0xb1); // media locked
5593 goto int13_fail_noah;
5599 case 0x48: // IBM/MS get drive parameters
5600 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5602 // Buffer is too small
5608 Bit16u cylinders, heads, spt, blksize;
5610 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5612 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5613 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5614 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5615 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5616 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5617 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5618 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5619 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5624 Bit8u channel, dev, irq, mode, checksum, i;
5625 Bit16u iobase1, iobase2, options;
5627 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5629 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5630 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5633 channel = device / 2;
5634 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5635 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5636 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5637 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5639 // FIXME atapi device
5640 options = (1<<4); // lba translation
5641 options |= (1<<5); // removable device
5642 options |= (1<<6); // atapi device
5643 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5645 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5646 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5647 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5648 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5649 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5650 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5651 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5652 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5653 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5654 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5655 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5658 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5659 checksum = ~checksum;
5660 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5665 Bit8u channel, iface, checksum, i;
5668 channel = device / 2;
5669 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5670 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5672 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5673 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5674 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5675 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5676 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5678 if (iface==ATA_IFACE_ISA) {
5679 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5680 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5681 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5682 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5687 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5688 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5689 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5690 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5692 if (iface==ATA_IFACE_ISA) {
5693 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5694 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5695 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5700 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5701 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5702 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5703 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5706 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5707 checksum = ~checksum;
5708 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5714 case 0x49: // IBM/MS extended media change
5715 // always send changed ??
5717 goto int13_fail_nostatus;
5720 case 0x4e: // // IBM/MS set hardware configuration
5721 // DMA, prefetch, PIO maximum not supported
5734 // all those functions return unimplemented
5735 case 0x02: /* read sectors */
5736 case 0x04: /* verify sectors */
5737 case 0x08: /* read disk drive parameters */
5738 case 0x0a: /* read disk sectors with ECC */
5739 case 0x0b: /* write disk sectors with ECC */
5740 case 0x18: /* set media type for format */
5741 case 0x50: // ? - send packet command
5743 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5749 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5751 SET_DISK_RET_STATUS(GET_AH());
5752 int13_fail_nostatus:
5753 SET_CF(); // error occurred
5754 debug_outb(0x2f8, 0xe0);
5758 SET_AH(0x00); // no error
5760 SET_DISK_RET_STATUS(0x00);
5761 CLEAR_CF(); // no error
5762 debug_outb(0x2f8, 0xe0);
5766 // ---------------------------------------------------------------------------
5767 // End of int13 for cdrom
5768 // ---------------------------------------------------------------------------
5770 #if BX_ELTORITO_BOOT
5771 // ---------------------------------------------------------------------------
5772 // Start of int13 for eltorito functions
5773 // ---------------------------------------------------------------------------
5776 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5777 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5779 Bit16u ebda_seg=read_word(0x0040,0x000E);
5781 debug_outb(0x2fa, 0xe2);
5783 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5784 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5788 // FIXME ElTorito Various. Should be implemented
5789 case 0x4a: // ElTorito - Initiate disk emu
5790 case 0x4c: // ElTorito - Initiate disk emu and boot
5791 case 0x4d: // ElTorito - Return Boot catalog
5792 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5796 case 0x4b: // ElTorito - Terminate disk emu
5797 // FIXME ElTorito Hardcoded
5798 write_byte(DS,SI+0x00,0x13);
5799 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5800 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5801 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5802 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5803 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5804 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5805 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5806 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5807 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5808 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5809 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5811 // If we have to terminate emulation
5812 if(GET_AL() == 0x00) {
5813 // FIXME ElTorito Various. Should be handled accordingly to spec
5814 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5821 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5827 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5828 SET_DISK_RET_STATUS(GET_AH());
5829 SET_CF(); // error occurred
5830 debug_outb(0x2fa, 0xe2);
5834 SET_AH(0x00); // no error
5835 SET_DISK_RET_STATUS(0x00);
5836 CLEAR_CF(); // no error
5837 debug_outb(0x2fa, 0xe2);
5841 // ---------------------------------------------------------------------------
5842 // End of int13 for eltorito functions
5843 // ---------------------------------------------------------------------------
5845 // ---------------------------------------------------------------------------
5846 // Start of int13 when emulating a device from the cd
5847 // ---------------------------------------------------------------------------
5850 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5851 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5853 Bit16u ebda_seg=read_word(0x0040,0x000E);
5854 Bit8u device, status;
5855 Bit16u vheads, vspt, vcylinders;
5856 Bit16u head, sector, cylinder, nbsectors;
5857 Bit32u vlba, ilba, slba, elba;
5858 Bit16u before, segment, offset;
5861 debug_outb(0x2f9, 0xe1);
5863 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5864 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5866 /* at this point, we are emulating a floppy/harddisk */
5868 // Recompute the device number
5869 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5870 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5872 SET_DISK_RET_STATUS(0x00);
5874 /* basic checks : emulation should be active, dl should equal the emulated drive */
5875 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5876 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5877 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5883 // all those functions return SUCCESS
5884 case 0x00: /* disk controller reset */
5885 case 0x09: /* initialize drive parameters */
5886 case 0x0c: /* seek to specified cylinder */
5887 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5888 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5889 case 0x11: /* recalibrate */
5890 case 0x14: /* controller internal diagnostic */
5891 case 0x16: /* detect disk change */
5895 // all those functions return disk write-protected
5896 case 0x03: /* write disk sectors */
5897 case 0x05: /* format disk track */
5899 goto int13_fail_noah;
5902 case 0x01: /* read disk status */
5903 status=read_byte(0x0040, 0x0074);
5905 SET_DISK_RET_STATUS(0);
5907 /* set CF if error status read */
5908 if (status) goto int13_fail_nostatus;
5909 else goto int13_success_noah;
5912 case 0x02: // read disk sectors
5913 case 0x04: // verify disk sectors
5914 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5915 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5916 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5918 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5920 sector = GET_CL() & 0x003f;
5921 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5923 nbsectors = GET_AL();
5927 // no sector to read ?
5928 if(nbsectors==0) goto int13_success;
5930 // sanity checks sco openserver needs this!
5932 || (cylinder >= vcylinders)
5933 || (head >= vheads)) {
5937 // After controls, verify do nothing
5938 if (GET_AH() == 0x04) goto int13_success;
5940 segment = ES+(BX / 16);
5943 // calculate the virtual lba inside the image
5944 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5946 // In advance so we don't loose the count
5950 slba = (Bit32u)vlba/4;
5951 before= (Bit16u)vlba%4;
5954 elba = (Bit32u)(vlba+nbsectors-1)/4;
5956 memsetb(get_SS(),atacmd,0,12);
5957 atacmd[0]=0x28; // READ command
5958 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5959 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5960 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5961 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5962 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5963 atacmd[5]=(ilba+slba & 0x000000ff);
5964 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5965 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5968 goto int13_fail_noah;
5974 case 0x08: /* read disk drive parameters */
5975 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5976 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5977 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5981 SET_CH( vcylinders & 0xff );
5982 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5984 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5985 // FIXME ElTorito Harddisk. should send the HD count
5987 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5988 case 0x01: SET_BL( 0x02 ); break;
5989 case 0x02: SET_BL( 0x04 ); break;
5990 case 0x03: SET_BL( 0x06 ); break;
5996 mov ax, #diskette_param_table2
5997 mov _int13_cdemu.DI+2[bp], ax
5998 mov _int13_cdemu.ES+2[bp], cs
6004 case 0x15: /* read disk drive size */
6005 // FIXME ElTorito Harddisk. What geometry to send ?
6007 goto int13_success_noah;
6010 // all those functions return unimplemented
6011 case 0x0a: /* read disk sectors with ECC */
6012 case 0x0b: /* write disk sectors with ECC */
6013 case 0x18: /* set media type for format */
6014 case 0x41: // IBM/MS installation check
6015 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6016 case 0x42: // IBM/MS extended read
6017 case 0x43: // IBM/MS extended write
6018 case 0x44: // IBM/MS verify sectors
6019 case 0x45: // IBM/MS lock/unlock drive
6020 case 0x46: // IBM/MS eject media
6021 case 0x47: // IBM/MS extended seek
6022 case 0x48: // IBM/MS get drive parameters
6023 case 0x49: // IBM/MS extended media change
6024 case 0x4e: // ? - set hardware configuration
6025 case 0x50: // ? - send packet command
6027 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6033 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6035 SET_DISK_RET_STATUS(GET_AH());
6036 int13_fail_nostatus:
6037 SET_CF(); // error occurred
6038 debug_outb(0x2f9, 0xe1);
6042 SET_AH(0x00); // no error
6044 SET_DISK_RET_STATUS(0x00);
6045 CLEAR_CF(); // no error
6046 debug_outb(0x2f9, 0xe1);
6050 // ---------------------------------------------------------------------------
6051 // End of int13 when emulating a device from the cd
6052 // ---------------------------------------------------------------------------
6054 #endif // BX_ELTORITO_BOOT
6056 #else //BX_USE_ATADRV
6059 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6074 mov ax,4[bp] // cylinder
6076 mov bl,6[bp] // hd_heads
6079 mov bl,8[bp] // head
6081 mov bl,10[bp] // hd_sectors
6083 mov bl,12[bp] // sector
6112 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6113 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6115 Bit8u drive, num_sectors, sector, head, status, mod;
6119 Bit16u max_cylinder, cylinder, total_sectors;
6120 Bit16u hd_cylinders;
6121 Bit8u hd_heads, hd_sectors;
6128 Bit16u count, segment, offset;
6133 debug_outb(0x2ef, 0xff);
6134 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6136 write_byte(0x0040, 0x008e, 0); // clear completion flag
6138 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6140 /* check how many disks first (cmos reg 0x12), return an error if
6141 drive not present */
6142 drive_map = inb_cmos(0x12);
6143 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6144 (((drive_map & 0x0f)==0) ? 0 : 2);
6145 n_drives = (drive_map==0) ? 0 :
6146 ((drive_map==3) ? 2 : 1);
6148 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6150 SET_DISK_RET_STATUS(0x01);
6151 SET_CF(); /* error occurred */
6152 debug_outb(0x2ef, 0xff);
6158 case 0x00: /* disk controller reset */
6159 BX_DEBUG_INT13_HD("int13_f00\n");
6162 SET_DISK_RET_STATUS(0);
6163 set_diskette_ret_status(0);
6164 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6165 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6166 CLEAR_CF(); /* successful */
6167 debug_outb(0x2ef, 0xff);
6171 case 0x01: /* read disk status */
6172 BX_DEBUG_INT13_HD("int13_f01\n");
6173 status = read_byte(0x0040, 0x0074);
6175 SET_DISK_RET_STATUS(0);
6176 /* set CF if error status read */
6177 if (status) SET_CF();
6179 debug_outb(0x2ef, 0xff);
6183 case 0x04: // verify disk sectors
6184 case 0x02: // read disk sectors
6186 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6188 num_sectors = GET_AL();
6189 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6190 sector = (GET_CL() & 0x3f);
6194 if (hd_cylinders > 1024) {
6195 if (hd_cylinders <= 2048) {
6198 else if (hd_cylinders <= 4096) {
6201 else if (hd_cylinders <= 8192) {
6204 else { // hd_cylinders <= 16384
6208 ax = head / hd_heads;
6209 cyl_mod = ax & 0xff;
6211 cylinder |= cyl_mod;
6214 if ( (cylinder >= hd_cylinders) ||
6215 (sector > hd_sectors) ||
6216 (head >= hd_heads) ) {
6218 SET_DISK_RET_STATUS(1);
6219 SET_CF(); /* error occurred */
6220 debug_outb(0x2ef, 0xff);
6224 if ( (num_sectors > 128) || (num_sectors == 0) ){
6225 debug_outb(0x2ef, 0xff);
6226 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6230 debug_outb(0x2ef, 0xff);
6231 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6234 if ( GET_AH() == 0x04 ) {
6236 SET_DISK_RET_STATUS(0);
6238 debug_outb(0x2ef, 0xff);
6242 status = inb(0x1f7);
6243 if (status & 0x80) {
6244 debug_outb(0x2ef, 0xff);
6245 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6247 outb(0x01f2, num_sectors);
6248 /* activate LBA? (tomv) */
6249 if (hd_heads > 16) {
6250 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6251 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6254 outb(0x01f3, sector);
6255 outb(0x01f4, cylinder & 0x00ff);
6256 outb(0x01f5, cylinder >> 8);
6257 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6262 status = inb(0x1f7);
6263 if ( !(status & 0x80) ) break;
6266 if (status & 0x01) {
6267 debug_outb(0x2ef, 0xff);
6268 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6269 } else if ( !(status & 0x08) ) {
6270 debug_outb(0x2ef, 0xff);
6271 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6272 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6279 sti ;; enable higher priority interrupts
6284 ;; store temp bx in real DI register
6287 mov di, _int13_harddisk.tempbx + 2 [bp]
6290 ;; adjust if there will be an overrun
6292 jbe i13_f02_no_adjust
6294 sub di, #0x0200 ; sub 512 bytes from offset
6296 add ax, #0x0020 ; add 512 to segment
6300 mov cx, #0x0100 ;; counter (256 words = 512b)
6301 mov dx, #0x01f0 ;; AT data read port
6304 insw ;; CX words transfered from port(DX) to ES:[DI]
6307 ;; store real DI register back to temp bx
6310 mov _int13_harddisk.tempbx + 2 [bp], di
6316 if (num_sectors == 0) {
6317 status = inb(0x1f7);
6318 if ( (status & 0xc9) != 0x40 )
6319 debug_outb(0x2ef, 0xff);
6320 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6324 status = inb(0x1f7);
6325 if ( (status & 0xc9) != 0x48 )
6326 debug_outb(0x2ef, 0xff);
6327 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6333 SET_DISK_RET_STATUS(0);
6334 SET_AL(sector_count);
6335 CLEAR_CF(); /* successful */
6336 debug_outb(0x2ef, 0xff);
6341 case 0x03: /* write disk sectors */
6342 BX_DEBUG_INT13_HD("int13_f03\n");
6343 drive = GET_ELDL ();
6344 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6346 num_sectors = GET_AL();
6347 cylinder = GET_CH();
6348 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6349 sector = (GET_CL() & 0x3f);
6352 if (hd_cylinders > 1024) {
6353 if (hd_cylinders <= 2048) {
6356 else if (hd_cylinders <= 4096) {
6359 else if (hd_cylinders <= 8192) {
6362 else { // hd_cylinders <= 16384
6366 ax = head / hd_heads;
6367 cyl_mod = ax & 0xff;
6369 cylinder |= cyl_mod;
6372 if ( (cylinder >= hd_cylinders) ||
6373 (sector > hd_sectors) ||
6374 (head >= hd_heads) ) {
6376 SET_DISK_RET_STATUS(1);
6377 SET_CF(); /* error occurred */
6378 debug_outb(0x2ef, 0xff);
6382 if ( (num_sectors > 128) || (num_sectors == 0) ) {
6383 debug_outb(0x2ef, 0xff);
6384 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6388 debug_outb(0x2ef, 0xff);
6389 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6392 status = inb(0x1f7);
6393 if (status & 0x80) {
6394 debug_outb(0x2ef, 0xff);
6395 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6397 // should check for Drive Ready Bit also in status reg
6398 outb(0x01f2, num_sectors);
6400 /* activate LBA? (tomv) */
6401 if (hd_heads > 16) {
6402 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6403 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6406 outb(0x01f3, sector);
6407 outb(0x01f4, cylinder & 0x00ff);
6408 outb(0x01f5, cylinder >> 8);
6409 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6413 // wait for busy bit to turn off after seeking
6415 status = inb(0x1f7);
6416 if ( !(status & 0x80) ) break;
6419 if ( !(status & 0x08) ) {
6420 debug_outb(0x2ef, 0xff);
6421 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6422 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6429 sti ;; enable higher priority interrupts
6434 ;; store temp bx in real SI register
6437 mov si, _int13_harddisk.tempbx + 2 [bp]
6440 ;; adjust if there will be an overrun
6442 jbe i13_f03_no_adjust
6444 sub si, #0x0200 ; sub 512 bytes from offset
6446 add ax, #0x0020 ; add 512 to segment
6450 mov cx, #0x0100 ;; counter (256 words = 512b)
6451 mov dx, #0x01f0 ;; AT data read port
6455 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6457 ;; store real SI register back to temp bx
6460 mov _int13_harddisk.tempbx + 2 [bp], si
6466 if (num_sectors == 0) {
6467 status = inb(0x1f7);
6468 if ( (status & 0xe9) != 0x40 ) {
6469 debug_outb(0x2ef, 0xff);
6470 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6475 status = inb(0x1f7);
6476 if ( (status & 0xc9) != 0x48 ) {
6477 debug_outb(0x2ef, 0xff);
6478 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6485 SET_DISK_RET_STATUS(0);
6486 SET_AL(sector_count);
6487 CLEAR_CF(); /* successful */
6488 debug_outb(0x2ef, 0xff);
6492 case 0x05: /* format disk track */
6493 BX_DEBUG_INT13_HD("int13_f05\n");
6494 BX_PANIC("format disk track called\n");
6497 SET_DISK_RET_STATUS(0);
6498 CLEAR_CF(); /* successful */
6499 debug_outb(0x2ef, 0xff);
6503 case 0x08: /* read disk drive parameters */
6504 BX_DEBUG_INT13_HD("int13_f08\n");
6506 drive = GET_ELDL ();
6507 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6511 if (hd_cylinders <= 1024) {
6512 // hd_cylinders >>= 0;
6515 else if (hd_cylinders <= 2048) {
6519 else if (hd_cylinders <= 4096) {
6523 else if (hd_cylinders <= 8192) {
6527 else { // hd_cylinders <= 16384
6532 max_cylinder = hd_cylinders - 2; /* 0 based */
6534 SET_CH(max_cylinder & 0xff);
6535 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6536 SET_DH(hd_heads - 1);
6537 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6539 SET_DISK_RET_STATUS(0);
6540 CLEAR_CF(); /* successful */
6541 debug_outb(0x2ef, 0xff);
6545 case 0x09: /* initialize drive parameters */
6546 BX_DEBUG_INT13_HD("int13_f09\n");
6548 SET_DISK_RET_STATUS(0);
6549 CLEAR_CF(); /* successful */
6550 debug_outb(0x2ef, 0xff);
6554 case 0x0a: /* read disk sectors with ECC */
6555 BX_DEBUG_INT13_HD("int13_f0a\n");
6556 case 0x0b: /* write disk sectors with ECC */
6557 BX_DEBUG_INT13_HD("int13_f0b\n");
6558 debug_outb(0x2ef, 0xff);
6559 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6563 case 0x0c: /* seek to specified cylinder */
6564 BX_DEBUG_INT13_HD("int13_f0c\n");
6565 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6567 SET_DISK_RET_STATUS(0);
6568 CLEAR_CF(); /* successful */
6569 debug_outb(0x2ef, 0xff);
6573 case 0x0d: /* alternate disk reset */
6574 BX_DEBUG_INT13_HD("int13_f0d\n");
6576 SET_DISK_RET_STATUS(0);
6577 CLEAR_CF(); /* successful */
6578 debug_outb(0x2ef, 0xff);
6582 case 0x10: /* check drive ready */
6583 BX_DEBUG_INT13_HD("int13_f10\n");
6585 //SET_DISK_RET_STATUS(0);
6586 //CLEAR_CF(); /* successful */
6590 // should look at 40:8E also???
6591 status = inb(0x01f7);
6592 if ( (status & 0xc0) == 0x40 ) {
6594 SET_DISK_RET_STATUS(0);
6595 CLEAR_CF(); // drive ready
6596 debug_outb(0x2ef, 0xff);
6601 SET_DISK_RET_STATUS(0xAA);
6602 SET_CF(); // not ready
6603 debug_outb(0x2ef, 0xff);
6608 case 0x11: /* recalibrate */
6609 BX_DEBUG_INT13_HD("int13_f11\n");
6611 SET_DISK_RET_STATUS(0);
6612 CLEAR_CF(); /* successful */
6613 debug_outb(0x2ef, 0xff);
6617 case 0x14: /* controller internal diagnostic */
6618 BX_DEBUG_INT13_HD("int13_f14\n");
6620 SET_DISK_RET_STATUS(0);
6621 CLEAR_CF(); /* successful */
6623 debug_outb(0x2ef, 0xff);
6627 case 0x15: /* read disk drive size */
6629 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6633 mov al, _int13_harddisk.hd_heads + 2 [bp]
6634 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6635 mul al, ah ;; ax = heads * sectors
6636 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6637 dec bx ;; use (cylinders - 1) ???
6638 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6639 ;; now we need to move the 32bit result dx:ax to what the
6640 ;; BIOS wants which is cx:dx.
6641 ;; and then into CX:DX on the stack
6642 mov _int13_harddisk.CX + 2 [bp], dx
6643 mov _int13_harddisk.DX + 2 [bp], ax
6646 SET_AH(3); // hard disk accessible
6647 SET_DISK_RET_STATUS(0); // ??? should this be 0
6648 CLEAR_CF(); // successful
6649 debug_outb(0x2ef, 0xff);
6653 case 0x18: // set media type for format
6654 case 0x41: // IBM/MS
6655 case 0x42: // IBM/MS
6656 case 0x43: // IBM/MS
6657 case 0x44: // IBM/MS
6658 case 0x45: // IBM/MS lock/unlock drive
6659 case 0x46: // IBM/MS eject media
6660 case 0x47: // IBM/MS extended seek
6661 case 0x49: // IBM/MS extended media change
6662 case 0x50: // IBM/MS send packet command
6664 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6666 SET_AH(1); // code=invalid function in AH or invalid parameter
6667 SET_DISK_RET_STATUS(1);
6668 SET_CF(); /* unsuccessful */
6669 debug_outb(0x2ef, 0xff);
6675 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6676 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6679 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6681 Bit16u *hd_cylinders;
6691 if (drive == 0x80) {
6692 hd_type = inb_cmos(0x12) & 0xf0;
6693 if (hd_type != 0xf0)
6694 BX_INFO(panic_msg_reg12h,0);
6695 hd_type = inb_cmos(0x19); // HD0: extended type
6697 BX_INFO(panic_msg_reg19h,0,0x19);
6700 hd_type = inb_cmos(0x12) & 0x0f;
6701 if (hd_type != 0x0f)
6702 BX_INFO(panic_msg_reg12h,1);
6703 hd_type = inb_cmos(0x1a); // HD0: extended type
6705 BX_INFO(panic_msg_reg19h,0,0x1a);
6710 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6711 write_word(ss, hd_cylinders, cylinders);
6714 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6716 // sectors per track
6717 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6720 #endif //else BX_USE_ATADRV
6723 //////////////////////
6724 // FLOPPY functions //
6725 //////////////////////
6728 floppy_media_known(drive)
6732 Bit16u media_state_offset;
6734 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6741 media_state_offset = 0x0090;
6743 media_state_offset += 1;
6745 val8 = read_byte(0x0040, media_state_offset);
6746 val8 = (val8 >> 4) & 0x01;
6750 // check pass, return KNOWN
6755 floppy_media_sense(drive)
6759 Bit16u media_state_offset;
6760 Bit8u drive_type, config_data, media_state;
6762 if (floppy_drive_recal(drive) == 0) {
6766 // for now cheat and get drive type from CMOS,
6767 // assume media is same as drive type
6769 // ** config_data **
6770 // Bitfields for diskette media control:
6771 // Bit(s) Description (Table M0028)
6772 // 7-6 last data rate set by controller
6773 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6774 // 5-4 last diskette drive step rate selected
6775 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6776 // 3-2 {data rate at start of operation}
6779 // ** media_state **
6780 // Bitfields for diskette drive media state:
6781 // Bit(s) Description (Table M0030)
6783 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6784 // 5 double stepping required (e.g. 360kB in 1.2MB)
6785 // 4 media type established
6786 // 3 drive capable of supporting 4MB media
6787 // 2-0 on exit from BIOS, contains
6788 // 000 trying 360kB in 360kB
6789 // 001 trying 360kB in 1.2MB
6790 // 010 trying 1.2MB in 1.2MB
6791 // 011 360kB in 360kB established
6792 // 100 360kB in 1.2MB established
6793 // 101 1.2MB in 1.2MB established
6795 // 111 all other formats/drives
6797 drive_type = inb_cmos(0x10);
6802 if ( drive_type == 1 ) {
6804 config_data = 0x00; // 0000 0000
6805 media_state = 0x25; // 0010 0101
6808 else if ( drive_type == 2 ) {
6809 // 1.2 MB 5.25" drive
6810 config_data = 0x00; // 0000 0000
6811 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6814 else if ( drive_type == 3 ) {
6816 config_data = 0x00; // 0000 0000 ???
6817 media_state = 0x17; // 0001 0111
6820 else if ( drive_type == 4 ) {
6821 // 1.44 MB 3.5" drive
6822 config_data = 0x00; // 0000 0000
6823 media_state = 0x17; // 0001 0111
6826 else if ( drive_type == 5 ) {
6827 // 2.88 MB 3.5" drive
6828 config_data = 0xCC; // 1100 1100
6829 media_state = 0xD7; // 1101 0111
6833 // Extended floppy size uses special cmos setting
6834 else if ( drive_type == 6 ) {
6836 config_data = 0x00; // 0000 0000
6837 media_state = 0x27; // 0010 0111
6840 else if ( drive_type == 7 ) {
6842 config_data = 0x00; // 0000 0000
6843 media_state = 0x27; // 0010 0111
6846 else if ( drive_type == 8 ) {
6848 config_data = 0x00; // 0000 0000
6849 media_state = 0x27; // 0010 0111
6855 config_data = 0x00; // 0000 0000
6856 media_state = 0x00; // 0000 0000
6861 media_state_offset = 0x90;
6863 media_state_offset = 0x91;
6864 write_byte(0x0040, 0x008B, config_data);
6865 write_byte(0x0040, media_state_offset, media_state);
6871 floppy_drive_recal(drive)
6875 Bit16u curr_cyl_offset;
6877 // set 40:3e bit 7 to 0
6878 val8 = read_byte(0x0000, 0x043e);
6880 write_byte(0x0000, 0x043e, val8);
6882 // turn on motor of selected drive, DMA & int enabled, normal operation
6891 // reset the disk motor timeout value of INT 08
6892 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6894 // check port 3f4 for drive readiness
6896 if ( (val8 & 0xf0) != 0x80 )
6897 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6899 // send Recalibrate command (2 bytes) to controller
6900 outb(0x03f5, 0x07); // 07: Recalibrate
6901 outb(0x03f5, drive); // 0=drive0, 1=drive1
6903 // turn on interrupts
6908 // wait on 40:3e bit 7 to become 1
6909 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6910 while ( val8 == 0 ) {
6911 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6914 val8 = 0; // separate asm from while() loop
6915 // turn off interrupts
6920 // set 40:3e bit 7 to 0, and calibrated bit
6921 val8 = read_byte(0x0000, 0x043e);
6924 val8 |= 0x02; // Drive 1 calibrated
6925 curr_cyl_offset = 0x0095;
6928 val8 |= 0x01; // Drive 0 calibrated
6929 curr_cyl_offset = 0x0094;
6931 write_byte(0x0040, 0x003e, val8);
6932 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6940 floppy_drive_exists(drive)
6945 // just tell it both drives exist - PAD
6948 // check CMOS to see if drive exists
6949 drive_type = inb_cmos(0x10);
6954 if ( drive_type == 0 )
6960 #if BX_SUPPORT_FLOPPY
6962 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6963 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6965 Bit8u drive, num_sectors, track, sector, head, status;
6966 Bit16u base_address, base_count, base_es;
6967 Bit8u page, mode_register, val8, dor;
6968 Bit8u return_status[7];
6969 Bit8u drive_type, num_floppies, ah;
6970 Bit16u es, last_addr;
6972 debug_outb(0x2fb, 0xe3);
6973 //printf("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6974 BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(),get_DS(), ES, DI, SI);
6979 case 0x00: // diskette controller reset
6980 BX_DEBUG_INT13_FL("floppy f00\n");
6983 SET_AH(1); // invalid param
6984 set_diskette_ret_status(1);
6986 debug_outb(0x2fb, 0xe3);
6989 drive_type = inb_cmos(0x10);
6995 if (drive_type == 0) {
6996 SET_AH(0x80); // drive not responding
6997 set_diskette_ret_status(0x80);
6999 debug_outb(0x2fb, 0xe3);
7003 set_diskette_ret_status(0);
7004 CLEAR_CF(); // successful
7005 set_diskette_current_cyl(drive, 0); // current cylinder
7006 debug_outb(0x2fb, 0xe3);
7009 case 0x01: // Read Diskette Status
7011 val8 = read_byte(0x0000, 0x0441);
7016 debug_outb(0x2fb, 0xe3);
7019 case 0x02: // Read Diskette Sectors
7020 case 0x03: // Write Diskette Sectors
7021 case 0x04: // Verify Diskette Sectors
7022 num_sectors = GET_AL();
7028 if ( (drive > 1) || (head > 1) ||
7029 (num_sectors == 0) || (num_sectors > 72) ) {
7030 BX_INFO("floppy: drive>1 || head>1 ...\n");
7032 set_diskette_ret_status(1);
7033 SET_AL(0); // no sectors read
7034 SET_CF(); // error occurred
7035 debug_outb(0x2fb, 0xe3);
7039 // see if drive exists
7040 if (floppy_drive_exists(drive) == 0) {
7041 SET_AH(0x80); // not responding
7042 set_diskette_ret_status(0x80);
7043 SET_AL(0); // no sectors read
7044 SET_CF(); // error occurred
7045 debug_outb(0x2fb, 0xe3);
7049 // see if media in drive, and type is known
7050 if (floppy_media_known(drive) == 0) {
7051 if (floppy_media_sense(drive) == 0) {
7052 SET_AH(0x0C); // Media type not found
7053 set_diskette_ret_status(0x0C);
7054 SET_AL(0); // no sectors read
7055 SET_CF(); // error occurred
7056 debug_outb(0x2fb, 0xe3);
7062 // Read Diskette Sectors
7064 //-----------------------------------
7065 // set up DMA controller for transfer
7066 //-----------------------------------
7068 // es:bx = pointer to where to place information from diskette
7069 // port 04: DMA-1 base and current address, channel 2
7070 // port 05: DMA-1 base and current count, channel 2
7071 page = (ES >> 12); // upper 4 bits
7072 base_es = (ES << 4); // lower 16bits contributed by ES
7073 base_address = base_es + BX; // lower 16 bits of address
7074 // contributed by ES:BX
7075 if ( base_address < base_es ) {
7076 // in case of carry, adjust page by 1
7079 base_count = (num_sectors * 512) - 1;
7081 // check for 64K boundary overrun
7082 last_addr = base_address + base_count;
7083 if (last_addr < base_address) {
7085 set_diskette_ret_status(0x09);
7086 SET_AL(0); // no sectors read
7087 SET_CF(); // error occurred
7088 debug_outb(0x2fb, 0xe3);
7092 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7095 BX_DEBUG_INT13_FL("clear flip-flop\n");
7096 outb(0x000c, 0x00); // clear flip-flop
7097 outb(0x0004, base_address);
7098 outb(0x0004, base_address>>8);
7099 BX_DEBUG_INT13_FL("clear flip-flop\n");
7100 outb(0x000c, 0x00); // clear flip-flop
7101 outb(0x0005, base_count);
7102 outb(0x0005, base_count>>8);
7104 // port 0b: DMA-1 Mode Register
7105 mode_register = 0x46; // single mode, increment, autoinit disable,
7106 // transfer type=write, channel 2
7107 BX_DEBUG_INT13_FL("setting mode register\n");
7108 outb(0x000b, mode_register);
7110 BX_DEBUG_INT13_FL("setting page register\n");
7111 // port 81: DMA-1 Page Register, channel 2
7114 BX_DEBUG_INT13_FL("unmask chan 2\n");
7115 outb(0x000a, 0x02); // unmask channel 2
7117 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7120 //--------------------------------------
7121 // set up floppy controller for transfer
7122 //--------------------------------------
7124 // set 40:3e bit 7 to 0
7125 val8 = read_byte(0x0000, 0x043e);
7127 write_byte(0x0000, 0x043e, val8);
7129 // turn on motor of selected drive, DMA & int enabled, normal operation
7138 // reset the disk motor timeout value of INT 08
7139 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7141 // check port 3f4 for drive readiness
7143 if ( (val8 & 0xf0) != 0x80 ) {
7144 debug_outb(0x2fb, 0xe3);
7145 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
7148 // send read-normal-data command (9 bytes) to controller
7149 outb(0x03f5, 0xe6); // e6: read normal data
7150 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7151 outb(0x03f5, track);
7153 outb(0x03f5, sector);
7154 outb(0x03f5, 2); // 512 byte sector size
7155 outb(0x03f5, 0); // last sector number possible on track
7156 outb(0x03f5, 0); // Gap length
7157 outb(0x03f5, 0xff); // Gap length
7159 // turn on interrupts
7164 // wait on 40:3e bit 7 to become 1
7165 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7166 while ( val8 == 0 ) {
7167 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7170 val8 = 0; // separate asm from while() loop
7171 // turn off interrupts
7176 // set 40:3e bit 7 to 0
7177 val8 = read_byte(0x0000, 0x043e);
7179 write_byte(0x0000, 0x043e, val8);
7181 // check port 3f4 for accessibility to status bytes
7183 if ( (val8 & 0xc0) != 0xc0 ) {
7184 debug_outb(0x2fb, 0xe3);
7185 BX_PANIC("int13_diskette: ctrl not ready\n");
7188 // read 7 return status bytes from controller
7189 // using loop index broken, have to unroll...
7190 return_status[0] = inb(0x3f5);
7191 return_status[1] = inb(0x3f5);
7192 return_status[2] = inb(0x3f5);
7193 return_status[3] = inb(0x3f5);
7194 return_status[4] = inb(0x3f5);
7195 return_status[5] = inb(0x3f5);
7196 return_status[6] = inb(0x3f5);
7197 // record in BIOS Data Area
7198 write_byte(0x0040, 0x0042, return_status[0]);
7199 write_byte(0x0040, 0x0043, return_status[1]);
7200 write_byte(0x0040, 0x0044, return_status[2]);
7201 write_byte(0x0040, 0x0045, return_status[3]);
7202 write_byte(0x0040, 0x0046, return_status[4]);
7203 write_byte(0x0040, 0x0047, return_status[5]);
7204 write_byte(0x0040, 0x0048, return_status[6]);
7206 if ( (return_status[0] & 0xc0) != 0 ) {
7208 set_diskette_ret_status(0x20);
7209 SET_AL(0); // no sectors read
7210 SET_CF(); // error occurred
7211 debug_outb(0x2fb, 0xe3);
7215 // ??? should track be new val from return_status[3] ?
7216 set_diskette_current_cyl(drive, track);
7217 // AL = number of sectors read (same value as passed)
7218 SET_AH(0x00); // success
7219 CLEAR_CF(); // success
7220 debug_outb(0x2fb, 0xe3);
7223 else if (ah == 0x03) {
7224 // Write Diskette Sectors
7226 //-----------------------------------
7227 // set up DMA controller for transfer
7228 //-----------------------------------
7230 // es:bx = pointer to where to place information from diskette
7231 // port 04: DMA-1 base and current address, channel 2
7232 // port 05: DMA-1 base and current count, channel 2
7233 page = (ES >> 12); // upper 4 bits
7234 base_es = (ES << 4); // lower 16bits contributed by ES
7235 base_address = base_es + BX; // lower 16 bits of address
7236 // contributed by ES:BX
7237 if ( base_address < base_es ) {
7238 // in case of carry, adjust page by 1
7241 base_count = (num_sectors * 512) - 1;
7243 // check for 64K boundary overrun
7244 last_addr = base_address + base_count;
7245 if (last_addr < base_address) {
7247 set_diskette_ret_status(0x09);
7248 SET_AL(0); // no sectors read
7249 SET_CF(); // error occurred
7250 debug_outb(0x2fb, 0xe3);
7254 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7257 outb(0x000c, 0x00); // clear flip-flop
7258 outb(0x0004, base_address);
7259 outb(0x0004, base_address>>8);
7260 outb(0x000c, 0x00); // clear flip-flop
7261 outb(0x0005, base_count);
7262 outb(0x0005, base_count>>8);
7264 // port 0b: DMA-1 Mode Register
7265 mode_register = 0x4a; // single mode, increment, autoinit disable,
7266 // transfer type=read, channel 2
7267 outb(0x000b, mode_register);
7269 // port 81: DMA-1 Page Register, channel 2
7272 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7275 //--------------------------------------
7276 // set up floppy controller for transfer
7277 //--------------------------------------
7279 // set 40:3e bit 7 to 0
7280 val8 = read_byte(0x0000, 0x043e);
7282 write_byte(0x0000, 0x043e, val8);
7284 // turn on motor of selected drive, DMA & int enabled, normal operation
7293 // reset the disk motor timeout value of INT 08
7294 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7296 // check port 3f4 for drive readiness
7298 if ( (val8 & 0xf0) != 0x80 ){
7299 debug_outb(0x2fb, 0xe3);
7300 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7303 // send read-normal-data command (9 bytes) to controller
7304 outb(0x03f5, 0xc5); // c5: write normal data
7305 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7306 outb(0x03f5, track);
7308 outb(0x03f5, sector);
7309 outb(0x03f5, 2); // 512 byte sector size
7310 outb(0x03f5, 0); // last sector number possible on track
7311 outb(0x03f5, 0); // Gap length
7312 outb(0x03f5, 0xff); // Gap length
7314 // turn on interrupts
7319 // wait on 40:3e bit 7 to become 1
7320 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7321 while ( val8 == 0 ) {
7322 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7325 val8 = 0; // separate asm from while() loop
7326 // turn off interrupts
7331 // set 40:3e bit 7 to 0
7332 val8 = read_byte(0x0000, 0x043e);
7334 write_byte(0x0000, 0x043e, val8);
7336 // check port 3f4 for accessibility to status bytes
7338 if ( (val8 & 0xc0) != 0xc0 ) {
7339 debug_outb(0x2fb, 0xe3);
7340 BX_PANIC("int13_diskette: ctrl not ready\n");
7343 // read 7 return status bytes from controller
7344 // using loop index broken, have to unroll...
7345 return_status[0] = inb(0x3f5);
7346 return_status[1] = inb(0x3f5);
7347 return_status[2] = inb(0x3f5);
7348 return_status[3] = inb(0x3f5);
7349 return_status[4] = inb(0x3f5);
7350 return_status[5] = inb(0x3f5);
7351 return_status[6] = inb(0x3f5);
7352 // record in BIOS Data Area
7353 write_byte(0x0040, 0x0042, return_status[0]);
7354 write_byte(0x0040, 0x0043, return_status[1]);
7355 write_byte(0x0040, 0x0044, return_status[2]);
7356 write_byte(0x0040, 0x0045, return_status[3]);
7357 write_byte(0x0040, 0x0046, return_status[4]);
7358 write_byte(0x0040, 0x0047, return_status[5]);
7359 write_byte(0x0040, 0x0048, return_status[6]);
7361 if ( (return_status[0] & 0xc0) != 0 ) {
7362 if ( (return_status[1] & 0x02) != 0 ) {
7363 // diskette not writable.
7364 // AH=status code=0x03 (tried to write on write-protected disk)
7365 // AL=number of sectors written=0
7368 debug_outb(0x2fb, 0xe3);
7371 debug_outb(0x2fb, 0xe3);
7372 BX_PANIC("int13_diskette_function: read error\n");
7376 // ??? should track be new val from return_status[3] ?
7377 set_diskette_current_cyl(drive, track);
7378 // AL = number of sectors read (same value as passed)
7379 SET_AH(0x00); // success
7380 CLEAR_CF(); // success
7381 debug_outb(0x2fb, 0xe3);
7384 else { // if (ah == 0x04)
7385 // Verify Diskette Sectors
7387 // ??? should track be new val from return_status[3] ?
7388 set_diskette_current_cyl(drive, track);
7389 // AL = number of sectors verified (same value as passed)
7390 CLEAR_CF(); // success
7391 SET_AH(0x00); // success
7392 debug_outb(0x2fb, 0xe3);
7397 case 0x05: // format diskette track
7398 BX_DEBUG_INT13_FL("floppy f05\n");
7400 num_sectors = GET_AL();
7405 if ((drive > 1) || (head > 1) || (track > 79) ||
7406 (num_sectors == 0) || (num_sectors > 18)) {
7408 set_diskette_ret_status(1);
7409 SET_CF(); // error occurred
7412 // see if drive exists
7413 if (floppy_drive_exists(drive) == 0) {
7414 SET_AH(0x80); // drive not responding
7415 set_diskette_ret_status(0x80);
7416 SET_CF(); // error occurred
7417 debug_outb(0x2fb, 0xe3);
7421 // see if media in drive, and type is known
7422 if (floppy_media_known(drive) == 0) {
7423 if (floppy_media_sense(drive) == 0) {
7424 SET_AH(0x0C); // Media type not found
7425 set_diskette_ret_status(0x0C);
7426 SET_AL(0); // no sectors read
7427 SET_CF(); // error occurred
7428 debug_outb(0x2fb, 0xe3);
7433 // set up DMA controller for transfer
7434 page = (ES >> 12); // upper 4 bits
7435 base_es = (ES << 4); // lower 16bits contributed by ES
7436 base_address = base_es + BX; // lower 16 bits of address
7437 // contributed by ES:BX
7438 if ( base_address < base_es ) {
7439 // in case of carry, adjust page by 1
7442 base_count = (num_sectors * 4) - 1;
7444 // check for 64K boundary overrun
7445 last_addr = base_address + base_count;
7446 if (last_addr < base_address) {
7448 set_diskette_ret_status(0x09);
7449 SET_AL(0); // no sectors read
7450 SET_CF(); // error occurred
7451 debug_outb(0x2fb, 0xe3);
7456 outb(0x000c, 0x00); // clear flip-flop
7457 outb(0x0004, base_address);
7458 outb(0x0004, base_address>>8);
7459 outb(0x000c, 0x00); // clear flip-flop
7460 outb(0x0005, base_count);
7461 outb(0x0005, base_count>>8);
7462 mode_register = 0x4a; // single mode, increment, autoinit disable,
7463 // transfer type=read, channel 2
7464 outb(0x000b, mode_register);
7465 // port 81: DMA-1 Page Register, channel 2
7469 // set up floppy controller for transfer
7470 val8 = read_byte(0x0000, 0x043e);
7472 write_byte(0x0000, 0x043e, val8);
7473 // turn on motor of selected drive, DMA & int enabled, normal operation
7482 // reset the disk motor timeout value of INT 08
7483 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7485 // check port 3f4 for drive readiness
7487 if ( (val8 & 0xf0) != 0x80 ) {
7488 debug_outb(0x2fb, 0xe3);
7489 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7492 // send read-normal-data command (6 bytes) to controller
7493 outb(0x03f5, 0x4d); // 4d: format track
7494 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7495 outb(0x03f5, 2); // 512 byte sector size
7496 outb(0x03f5, num_sectors); // number of sectors per track
7497 outb(0x03f5, 0); // Gap length
7498 outb(0x03f5, 0xf6); // Fill byte
7499 // turn on interrupts
7503 // wait on 40:3e bit 7 to become 1
7504 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7505 while ( val8 == 0 ) {
7506 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7508 val8 = 0; // separate asm from while() loop
7509 // turn off interrupts
7513 // set 40:3e bit 7 to 0
7514 val8 = read_byte(0x0000, 0x043e);
7516 write_byte(0x0000, 0x043e, val8);
7517 // check port 3f4 for accessibility to status bytes
7519 if ( (val8 & 0xc0) != 0xc0 ) {
7520 debug_outb(0x2fb, 0xe3);
7521 BX_PANIC("int13_diskette: ctrl not ready\n");
7524 // read 7 return status bytes from controller
7525 // using loop index broken, have to unroll...
7526 return_status[0] = inb(0x3f5);
7527 return_status[1] = inb(0x3f5);
7528 return_status[2] = inb(0x3f5);
7529 return_status[3] = inb(0x3f5);
7530 return_status[4] = inb(0x3f5);
7531 return_status[5] = inb(0x3f5);
7532 return_status[6] = inb(0x3f5);
7533 // record in BIOS Data Area
7534 write_byte(0x0040, 0x0042, return_status[0]);
7535 write_byte(0x0040, 0x0043, return_status[1]);
7536 write_byte(0x0040, 0x0044, return_status[2]);
7537 write_byte(0x0040, 0x0045, return_status[3]);
7538 write_byte(0x0040, 0x0046, return_status[4]);
7539 write_byte(0x0040, 0x0047, return_status[5]);
7540 write_byte(0x0040, 0x0048, return_status[6]);
7542 if ( (return_status[0] & 0xc0) != 0 ) {
7543 if ( (return_status[1] & 0x02) != 0 ) {
7544 // diskette not writable.
7545 // AH=status code=0x03 (tried to write on write-protected disk)
7546 // AL=number of sectors written=0
7549 debug_outb(0x2fb, 0xe3);
7552 debug_outb(0x2fb, 0xe3);
7553 BX_PANIC("int13_diskette_function: write error\n");
7558 set_diskette_ret_status(0);
7559 set_diskette_current_cyl(drive, 0);
7560 CLEAR_CF(); // successful
7561 debug_outb(0x2fb, 0xe3);
7565 case 0x08: // read diskette drive parameters
7566 BX_DEBUG_INT13_FL("floppy f08\n");
7576 SET_DL(num_floppies);
7578 debug_outb(0x2fb, 0xe3);
7582 drive_type = inb_cmos(0x10);
7584 if (drive_type & 0xf0)
7586 if (drive_type & 0x0f)
7598 SET_DL(num_floppies);
7600 switch (drive_type) {
7603 SET_DH(0); // max head #
7606 case 1: // 360KB, 5.25"
7607 CX = 0x2709; // 40 tracks, 9 sectors
7608 SET_DH(1); // max head #
7611 case 2: // 1.2MB, 5.25"
7612 CX = 0x4f0f; // 80 tracks, 15 sectors
7613 SET_DH(1); // max head #
7616 case 3: // 720KB, 3.5"
7617 CX = 0x4f09; // 80 tracks, 9 sectors
7618 SET_DH(1); // max head #
7621 case 4: // 1.44MB, 3.5"
7622 CX = 0x4f12; // 80 tracks, 18 sectors
7623 SET_DH(1); // max head #
7626 case 5: // 2.88MB, 3.5"
7627 CX = 0x4f24; // 80 tracks, 36 sectors
7628 SET_DH(1); // max head #
7631 case 6: // 160k, 5.25"
7632 CX = 0x2708; // 40 tracks, 8 sectors
7633 SET_DH(0); // max head #
7636 case 7: // 180k, 5.25"
7637 CX = 0x2709; // 40 tracks, 9 sectors
7638 SET_DH(0); // max head #
7641 case 8: // 320k, 5.25"
7642 CX = 0x2708; // 40 tracks, 8 sectors
7643 SET_DH(1); // max head #
7647 debug_outb(0x2fb, 0xe3);
7648 BX_PANIC("floppy: int13: bad floppy type\n");
7651 /* set es & di to point to 11 byte diskette param table in ROM */
7655 mov ax, #diskette_param_table2
7656 mov _int13_diskette_function.DI+2[bp], ax
7657 mov _int13_diskette_function.ES+2[bp], cs
7660 CLEAR_CF(); // success
7661 /* disk status not changed upon success */
7662 debug_outb(0x2fb, 0xe3);
7666 case 0x15: // read diskette drive type
7667 BX_DEBUG_INT13_FL("floppy f15\n");
7670 SET_AH(0); // only 2 drives supported
7671 // set_diskette_ret_status here ???
7673 debug_outb(0x2fb, 0xe3);
7676 drive_type = inb_cmos(0x10);
7682 CLEAR_CF(); // successful, not present
7683 if (drive_type==0) {
7684 SET_AH(0); // drive not present
7687 SET_AH(1); // drive present, does not support change line
7692 case 0x16: // get diskette change line status
7693 BX_DEBUG_INT13_FL("floppy f16\n");
7696 SET_AH(0x01); // invalid drive
7697 set_diskette_ret_status(0x01);
7699 debug_outb(0x2fb, 0xe3);
7703 SET_AH(0x06); // change line not supported
7704 set_diskette_ret_status(0x06);
7706 debug_outb(0x2fb, 0xe3);
7709 case 0x17: // set diskette type for format(old)
7710 BX_DEBUG_INT13_FL("floppy f17\n");
7711 /* not used for 1.44M floppies */
7712 SET_AH(0x01); // not supported
7713 set_diskette_ret_status(1); /* not supported */
7715 debug_outb(0x2fb, 0xe3);
7718 case 0x18: // set diskette type for format(new)
7719 BX_DEBUG_INT13_FL("floppy f18\n");
7720 SET_AH(0x01); // do later
7721 set_diskette_ret_status(1);
7723 debug_outb(0x2fb, 0xe3);
7727 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7729 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7730 SET_AH(0x01); // ???
7731 set_diskette_ret_status(1);
7733 debug_outb(0x2fb, 0xe3);
7738 #else // #if BX_SUPPORT_FLOPPY
7740 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7741 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7745 switch ( GET_AH() ) {
7747 case 0x01: // Read Diskette Status
7749 val8 = read_byte(0x0000, 0x0441);
7754 debug_outb(0x2fb, 0xe3);
7759 write_byte(0x0000, 0x0441, 0x01);
7762 debug_outb(0x2fb, 0xe3);
7764 #endif // #if BX_SUPPORT_FLOPPY
7767 set_diskette_ret_status(value)
7770 write_byte(0x0040, 0x0041, value);
7774 set_diskette_current_cyl(drive, cyl)
7779 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7780 write_byte(0x0040, 0x0094+drive, cyl);
7784 determine_floppy_media(drive)
7788 Bit8u val8, DOR, ctrl_info;
7790 ctrl_info = read_byte(0x0040, 0x008F);
7798 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7801 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7805 if ( (ctrl_info & 0x04) != 0x04 ) {
7806 // Drive not determined means no drive exists, done.
7811 // check Main Status Register for readiness
7812 val8 = inb(0x03f4) & 0x80; // Main Status Register
7814 BX_PANIC("d_f_m: MRQ bit not set\n");
7818 // existing BDA values
7820 // turn on drive motor
7821 outb(0x03f2, DOR); // Digital Output Register
7824 BX_PANIC("d_f_m: OK so far\n");
7829 int17_function(regs, ds, iret_addr)
7830 pusha_regs_t regs; // regs pushed from PUSHA instruction
7831 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7832 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7834 Bit16u addr,timeout;
7841 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7842 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7843 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7844 if (regs.u.r8.ah == 0) {
7845 outb(addr, regs.u.r8.al);
7847 outb(addr+2, val8 | 0x01); // send strobe
7851 outb(addr+2, val8 & ~0x01);
7852 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7856 if (regs.u.r8.ah == 1) {
7858 outb(addr+2, val8 & ~0x04); // send init
7862 outb(addr+2, val8 | 0x04);
7865 regs.u.r8.ah = (val8 ^ 0x48);
7866 if (!timeout) regs.u.r8.ah |= 0x01;
7867 ClearCF(iret_addr.flags);
7869 SetCF(iret_addr.flags); // Unsupported
7873 // returns bootsegment in ax, drive in bl
7875 int19_function(bseqnr)
7878 Bit16u ebda_seg=read_word(0x0040,0x000E);
7887 // BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7889 // if BX_ELTORITO_BOOT is not defined, old behavior
7890 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7891 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7892 // 0: system boot sequence, first drive C: then A:
7893 // 1: system boot sequence, first drive A: then C:
7894 // else BX_ELTORITO_BOOT is defined
7895 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7896 // CMOS reg 0x3D & 0x0f : 1st boot device
7897 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7898 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7899 // boot device codes:
7900 // 0x00 : not defined
7901 // 0x01 : first floppy
7902 // 0x02 : first harddrive
7903 // 0x03 : first cdrom
7904 // else : boot failure
7906 // Get the boot sequence
7907 #if BX_ELTORITO_BOOT
7908 bootseq=inb_cmos(0x3d);
7909 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7911 if (bseqnr==2) bootseq >>= 4;
7912 if (bseqnr==3) bootseq >>= 8;
7913 if (bootseq<0x10) lastdrive = 1;
7914 bootdrv=0x00; bootcd=0;
7915 switch(bootseq & 0x0f) {
7916 case 0x01: bootdrv=0x00; bootcd=0; break;
7917 case 0x02: bootdrv=0x80; bootcd=0; break;
7918 case 0x03: bootdrv=0x00; bootcd=1; break;
7919 default: return 0x00000000;
7922 bootseq=inb_cmos(0x2d);
7928 bootdrv=0x00; bootcd=0;
7929 if((bootseq&0x20)==0) bootdrv=0x80;
7930 #endif // BX_ELTORITO_BOOT
7932 #if BX_ELTORITO_BOOT
7933 // We have to boot from cd
7935 status = cdrom_boot();
7937 BX_DEBUG("CDBoot:%x\n",status);
7941 if ( (status & 0x00ff) !=0 ) {
7942 print_cdromboot_failure(status);
7943 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7947 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7948 bootdrv = (Bit8u)(status>>8);
7951 #endif // BX_ELTORITO_BOOT
7953 // We have to boot from harddisk or floppy
7964 mov _int19_function.status + 2[bp], ax
7965 mov dl, _int19_function.bootdrv + 2[bp]
7966 mov ax, _int19_function.bootseg + 2[bp]
7967 mov es, ax ;; segment
7968 mov bx, #0x0000 ;; offset
7969 mov ah, #0x02 ;; function 2, read diskette sector
7970 mov al, #0x01 ;; read 1 sector
7971 mov ch, #0x00 ;; track 0
7972 mov cl, #0x01 ;; sector 1
7973 mov dh, #0x00 ;; head 0
7974 int #0x13 ;; read sector
7977 mov _int19_function.status + 2[bp], ax
7985 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7990 // check signature if instructed by cmos reg 0x38, only for floppy
7991 // bootchk = 1 : signature check disabled
7992 // bootchk = 0 : signature check enabled
7993 if (bootdrv != 0) bootchk = 0;
7994 else bootchk = inb_cmos(0x38) & 0x01;
7996 #if BX_ELTORITO_BOOT
7997 // if boot from cd, no signature check
8000 #endif // BX_ELTORITO_BOOT
8003 if (read_word(bootseg,0x1fe) != 0xaa55) {
8004 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8009 #if BX_ELTORITO_BOOT
8010 // Print out the boot string
8011 BX_DEBUG("cdrom_boot: %x\n",status);
8012 print_boot_device(bootcd, bootdrv);
8013 #else // BX_ELTORITO_BOOT
8014 print_boot_device(0, bootdrv);
8015 #endif // BX_ELTORITO_BOOT
8017 BX_DEBUG("boot to %x\n", (((Bit32u)bootdrv) << 16) + bootseg);
8019 // return the boot segment
8020 return (((Bit32u)bootdrv) << 16) + bootseg;
8024 int1a_function(regs, ds, iret_addr)
8025 pusha_regs_t regs; // regs pushed from PUSHA instruction
8026 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8027 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8031 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);
8037 switch (regs.u.r8.ah) {
8038 case 0: // get current clock count
8042 regs.u.r16.cx = BiosData->ticks_high;
8043 regs.u.r16.dx = BiosData->ticks_low;
8044 regs.u.r8.al = BiosData->midnight_flag;
8045 BiosData->midnight_flag = 0; // reset flag
8050 ClearCF(iret_addr.flags); // OK
8053 case 1: // Set Current Clock Count
8057 BiosData->ticks_high = regs.u.r16.cx;
8058 BiosData->ticks_low = regs.u.r16.dx;
8059 BiosData->midnight_flag = 0; // reset flag
8064 ClearCF(iret_addr.flags); // OK
8068 case 2: // Read CMOS Time
8069 if (rtc_updating()) {
8070 SetCF(iret_addr.flags);
8074 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8075 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8076 regs.u.r8.ch = inb_cmos(0x04); // Hours
8077 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8079 regs.u.r8.al = regs.u.r8.ch;
8080 ClearCF(iret_addr.flags); // OK
8083 case 3: // Set CMOS Time
8084 // Using a debugger, I notice the following masking/setting
8085 // of bits in Status Register B, by setting Reg B to
8086 // a few values and getting its value after INT 1A was called.
8088 // try#1 try#2 try#3
8089 // before 1111 1101 0111 1101 0000 0000
8090 // after 0110 0010 0110 0010 0000 0010
8092 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8093 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8094 if (rtc_updating()) {
8096 // fall through as if an update were not in progress
8098 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8099 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8100 outb_cmos(0x04, regs.u.r8.ch); // Hours
8101 // Set Daylight Savings time enabled bit to requested value
8102 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8103 // (reg B already selected)
8104 outb_cmos(0x0b, val8);
8106 regs.u.r8.al = val8; // val last written to Reg B
8107 ClearCF(iret_addr.flags); // OK
8110 case 4: // Read CMOS Date
8112 if (rtc_updating()) {
8113 SetCF(iret_addr.flags);
8116 regs.u.r8.cl = inb_cmos(0x09); // Year
8117 regs.u.r8.dh = inb_cmos(0x08); // Month
8118 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8119 regs.u.r8.ch = inb_cmos(0x32); // Century
8120 regs.u.r8.al = regs.u.r8.ch;
8121 ClearCF(iret_addr.flags); // OK
8124 case 5: // Set CMOS Date
8125 // Using a debugger, I notice the following masking/setting
8126 // of bits in Status Register B, by setting Reg B to
8127 // a few values and getting its value after INT 1A was called.
8129 // try#1 try#2 try#3 try#4
8130 // before 1111 1101 0111 1101 0000 0010 0000 0000
8131 // after 0110 1101 0111 1101 0000 0010 0000 0000
8133 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8134 // My assumption: RegB = (RegB & 01111111b)
8135 if (rtc_updating()) {
8137 SetCF(iret_addr.flags);
8140 outb_cmos(0x09, regs.u.r8.cl); // Year
8141 outb_cmos(0x08, regs.u.r8.dh); // Month
8142 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8143 outb_cmos(0x32, regs.u.r8.ch); // Century
8144 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8145 outb_cmos(0x0b, val8);
8147 regs.u.r8.al = val8; // AL = val last written to Reg B
8148 ClearCF(iret_addr.flags); // OK
8151 case 6: // Set Alarm Time in CMOS
8152 // Using a debugger, I notice the following masking/setting
8153 // of bits in Status Register B, by setting Reg B to
8154 // a few values and getting its value after INT 1A was called.
8156 // try#1 try#2 try#3
8157 // before 1101 1111 0101 1111 0000 0000
8158 // after 0110 1111 0111 1111 0010 0000
8160 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8161 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8162 val8 = inb_cmos(0x0b); // Get Status Reg B
8165 // Alarm interrupt enabled already
8166 SetCF(iret_addr.flags); // Error: alarm in use
8169 if (rtc_updating()) {
8171 // fall through as if an update were not in progress
8173 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8174 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8175 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8176 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8177 // enable Status Reg B alarm bit, clear halt clock bit
8178 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8179 ClearCF(iret_addr.flags); // OK
8182 case 7: // Turn off Alarm
8183 // Using a debugger, I notice the following masking/setting
8184 // of bits in Status Register B, by setting Reg B to
8185 // a few values and getting its value after INT 1A was called.
8187 // try#1 try#2 try#3 try#4
8188 // before 1111 1101 0111 1101 0010 0000 0010 0010
8189 // after 0100 0101 0101 0101 0000 0000 0000 0010
8191 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8192 // My assumption: RegB = (RegB & 01010111b)
8193 val8 = inb_cmos(0x0b); // Get Status Reg B
8194 // clear clock-halt bit, disable alarm bit
8195 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8197 regs.u.r8.al = val8; // val last written to Reg B
8198 ClearCF(iret_addr.flags); // OK
8202 // real mode PCI BIOS functions now handled in assembler code
8203 // this C code handles the error code for information only
8204 if (regs.u.r8.bl == 0xff) {
8205 BX_INFO("PCI BIOS: PCI not present\n");
8206 } else if (regs.u.r8.bl == 0x81) {
8207 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8208 } else if (regs.u.r8.bl == 0x83) {
8209 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8210 } else if (regs.u.r8.bl == 0x86) {
8211 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
8213 regs.u.r8.ah = regs.u.r8.bl;
8214 SetCF(iret_addr.flags);
8219 SetCF(iret_addr.flags); // Unsupported
8224 int70_function(regs, ds, iret_addr)
8225 pusha_regs_t regs; // regs pushed from PUSHA instruction
8226 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8227 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8229 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8230 Bit8u registerB = 0, registerC = 0;
8232 // Check which modes are enabled and have occurred.
8233 registerB = inb_cmos( 0xB );
8234 registerC = inb_cmos( 0xC );
8236 if( ( registerB & 0x60 ) != 0 ) {
8237 if( ( registerC & 0x20 ) != 0 ) {
8238 // Handle Alarm Interrupt.
8245 if( ( registerC & 0x40 ) != 0 ) {
8246 // Handle Periodic Interrupt.
8248 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8249 // Wait Interval (Int 15, AH=83) active.
8250 Bit32u time, toggle;
8252 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8253 if( time < 0x3D1 ) {
8255 Bit16u segment, offset;
8257 offset = read_word( 0x40, 0x98 );
8258 segment = read_word( 0x40, 0x9A );
8259 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8260 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8261 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8263 // Continue waiting.
8265 write_dword( 0x40, 0x9C, time );
8278 ;------------------------------------------
8279 ;- INT74h : PS/2 mouse hardware interrupt -
8280 ;------------------------------------------
8285 push #0x00 ;; placeholder for status
8286 push #0x00 ;; placeholder for X
8287 push #0x00 ;; placeholder for Y
8288 push #0x00 ;; placeholder for Z
8289 push #0x00 ;; placeholder for make_far_call boolean
8290 call _int74_function
8291 pop cx ;; remove make_far_call from stack
8294 ;; make far call to EBDA:0022
8297 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8299 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8304 add sp, #8 ;; pop status, x, y, z
8306 pop ds ;; restore DS
8311 ;; This will perform an IRET, but will retain value of current CF
8312 ;; by altering flags on stack. Better than RETF #02.
8317 and BYTE [bp + 0x06], #0xfe
8323 or BYTE [bp + 0x06], #0x01
8328 ;----------------------
8329 ;- INT13h (relocated) -
8330 ;----------------------
8332 ; int13_relocated is a little bit messed up since I played with it
8333 ; I have to rewrite it:
8334 ; - call a function that detect which function to call
8335 ; - make all called C function get the same parameters list
8339 #if BX_ELTORITO_BOOT
8340 ;; check for an eltorito function
8342 jb int13_not_eltorito
8344 ja int13_not_eltorito
8353 jmp _int13_eltorito ;; ELDX not used
8361 ;; check if emulation active
8362 call _cdemu_isactive
8364 je int13_cdemu_inactive
8366 ;; check if access to the emulated drive
8367 call _cdemu_emulated_drive
8370 cmp al,dl ;; int13 on emulated drive
8385 jmp _int13_cdemu ;; ELDX not used
8388 and dl,#0xE0 ;; mask to get device class, including cdroms
8389 cmp al,dl ;; al is 0x00 or 0x80
8390 jne int13_cdemu_inactive ;; inactive for device class
8402 dec dl ;; real drive is dl - 1
8405 int13_cdemu_inactive:
8411 #endif // BX_ELTORITO_BOOT
8422 push dx ;; push eltorito value of dx instead of sp
8433 ;; now the 16-bit registers can be restored with:
8434 ;; pop ds; pop es; popa; iret
8435 ;; arguments passed to functions should be
8436 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8442 jmp _int13_diskette_function
8451 // ebx is modified: BSD 5.2.1 boot loader problem
8452 // someone should figure out which 32 bit register that actually are used
8469 call _int13_harddisk
8481 int18_handler: ;; Boot Failure routing
8482 call _int18_panic_msg
8489 int19_relocated: ;; Boot function, relocated
8491 ;; int19 was beginning to be really complex, so now it
8492 ;; just calls an C function, that does the work
8493 ;; it returns in BL the boot drive, and in AX the boot segment
8494 ;; the boot segment will be 0x0000 if something has failed
8506 call _int19_function
8509 ;; bl contains the boot drive
8510 ;; ax contains the boot segment or 0 if failure
8512 test ax, ax ;; if ax is 0 try next boot device
8518 call _int19_function
8521 test ax, ax ;; if ax is 0 try next boot device
8527 call _int19_function
8530 test ax, ax ;; if ax is 0 call int18
8534 mov dl, bl ;; set drive so guest os find it
8535 shl eax, #0x04 ;; convert seg to ip
8536 mov 2[bp], ax ;; set ip
8538 shr eax, #0x04 ;; get cs back
8539 and ax, #0xF000 ;; remove what went in ip
8540 mov 4[bp], ax ;; set cs
8542 mov es, ax ;; set es to zero fixes [ 549815 ]
8543 mov [bp], ax ;; set bp to zero
8544 mov ax, #0xaa55 ;; set ok flag
8549 iret ;; Beam me up Scotty
8554 int1c_handler: ;; User Timer Tick
8558 ;----------------------
8559 ;- POST: Floppy Drive -
8560 ;----------------------
8566 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8568 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8570 mov 0x0440, al ;; diskette motor timeout counter: not active
8571 mov 0x0441, al ;; diskette controller status return code
8573 mov 0x0442, al ;; disk & diskette controller status register 0
8574 mov 0x0443, al ;; diskette controller status register 1
8575 mov 0x0444, al ;; diskette controller status register 2
8576 mov 0x0445, al ;; diskette controller cylinder number
8577 mov 0x0446, al ;; diskette controller head number
8578 mov 0x0447, al ;; diskette controller sector number
8579 mov 0x0448, al ;; diskette controller bytes written
8581 mov 0x048b, al ;; diskette configuration data
8583 ;; -----------------------------------------------------------------
8584 ;; (048F) diskette controller information
8586 mov al, #0x10 ;; get CMOS diskette drive type
8589 mov ah, al ;; save byte to AH
8592 shr al, #4 ;; look at top 4 bits for drive 0
8593 jz f0_missing ;; jump if no drive0
8594 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8597 mov bl, #0x00 ;; no drive0
8600 mov al, ah ;; restore from AH
8601 and al, #0x0f ;; look at bottom 4 bits for drive 1
8602 jz f1_missing ;; jump if no drive1
8603 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8605 ;; leave high bits in BL zerod
8606 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8607 ;; -----------------------------------------------------------------
8610 mov 0x0490, al ;; diskette 0 media state
8611 mov 0x0491, al ;; diskette 1 media state
8613 ;; diskette 0,1 operational starting state
8614 ;; drive type has not been determined,
8615 ;; has no changed detection line
8619 mov 0x0494, al ;; diskette 0 current cylinder
8620 mov 0x0495, al ;; diskette 1 current cylinder
8623 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8625 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8626 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8627 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8632 ;--------------------
8633 ;- POST: HARD DRIVE -
8634 ;--------------------
8635 ; relocated here because the primary POST area isnt big enough.
8638 // INT 76h calls INT 15h function ax=9100
8650 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8656 mov 0x0474, al /* hard disk status of last operation */
8657 mov 0x0477, al /* hard disk port offset (XT only ???) */
8658 mov 0x048c, al /* hard disk status register */
8659 mov 0x048d, al /* hard disk error register */
8660 mov 0x048e, al /* hard disk task complete flag */
8662 mov 0x0475, al /* hard disk number attached */
8664 mov 0x0476, al /* hard disk control byte */
8665 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8666 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8667 ;; INT 41h: hard disk 0 configuration pointer
8668 ;; INT 46h: hard disk 1 configuration pointer
8669 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8670 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8672 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8684 cmp al, #47 ;; decimal 47 - user definable
8688 ;; CMOS purpose param table offset
8689 ;; 1b cylinders low 0
8690 ;; 1c cylinders high 1
8692 ;; 1e write pre-comp low 5
8693 ;; 1f write pre-comp high 6
8694 ;; 20 retries/bad map/heads>8 8
8695 ;; 21 landing zone low C
8696 ;; 22 landing zone high D
8697 ;; 23 sectors/track E
8702 ;;; Filling EBDA table for hard disk 0.
8710 mov (0x003d + 0x05), ax ;; write precomp word
8715 mov (0x003d + 0x08), al ;; drive control byte
8724 mov (0x003d + 0x0C), ax ;; landing zone word
8726 mov al, #0x1c ;; get cylinders word in AX
8728 in al, #0x71 ;; high byte
8732 in al, #0x71 ;; low byte
8733 mov bx, ax ;; BX = cylinders
8738 mov cl, al ;; CL = heads
8743 mov dl, al ;; DL = sectors
8746 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8748 hd0_post_physical_chs:
8749 ;; no logical CHS mapping used, just physical CHS
8750 ;; use Standard Fixed Disk Parameter Table (FDPT)
8751 mov (0x003d + 0x00), bx ;; number of physical cylinders
8752 mov (0x003d + 0x02), cl ;; number of physical heads
8753 mov (0x003d + 0x0E), dl ;; number of physical sectors
8756 hd0_post_logical_chs:
8757 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8758 mov (0x003d + 0x09), bx ;; number of physical cylinders
8759 mov (0x003d + 0x0b), cl ;; number of physical heads
8760 mov (0x003d + 0x04), dl ;; number of physical sectors
8761 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8763 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8766 jnbe hd0_post_above_2048
8767 ;; 1024 < c <= 2048 cylinders
8770 jmp hd0_post_store_logical
8772 hd0_post_above_2048:
8774 jnbe hd0_post_above_4096
8775 ;; 2048 < c <= 4096 cylinders
8778 jmp hd0_post_store_logical
8780 hd0_post_above_4096:
8782 jnbe hd0_post_above_8192
8783 ;; 4096 < c <= 8192 cylinders
8786 jmp hd0_post_store_logical
8788 hd0_post_above_8192:
8789 ;; 8192 < c <= 16384 cylinders
8793 hd0_post_store_logical:
8794 mov (0x003d + 0x00), bx ;; number of physical cylinders
8795 mov (0x003d + 0x02), cl ;; number of physical heads
8797 mov cl, #0x0f ;; repeat count
8798 mov si, #0x003d ;; offset to disk0 FDPT
8799 mov al, #0x00 ;; sum
8800 hd0_post_checksum_loop:
8804 jnz hd0_post_checksum_loop
8805 not al ;; now take 2s complement
8808 ;;; Done filling EBDA table for hard disk 0.
8812 ;; is there really a second hard disk? if not, return now
8820 ;; check that the hd type is really 0x0f.
8825 ;; check that the extended type is 47 - user definable
8829 cmp al, #47 ;; decimal 47 - user definable
8834 ;; CMOS purpose param table offset
8835 ;; 0x24 cylinders low 0
8836 ;; 0x25 cylinders high 1
8838 ;; 0x27 write pre-comp low 5
8839 ;; 0x28 write pre-comp high 6
8841 ;; 0x2a landing zone low C
8842 ;; 0x2b landing zone high D
8843 ;; 0x2c sectors/track E
8844 ;;; Fill EBDA table for hard disk 1.
8854 mov (0x004d + 0x05), ax ;; write precomp word
8859 mov (0x004d + 0x08), al ;; drive control byte
8868 mov (0x004d + 0x0C), ax ;; landing zone word
8870 mov al, #0x25 ;; get cylinders word in AX
8872 in al, #0x71 ;; high byte
8876 in al, #0x71 ;; low byte
8877 mov bx, ax ;; BX = cylinders
8882 mov cl, al ;; CL = heads
8887 mov dl, al ;; DL = sectors
8890 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8892 hd1_post_physical_chs:
8893 ;; no logical CHS mapping used, just physical CHS
8894 ;; use Standard Fixed Disk Parameter Table (FDPT)
8895 mov (0x004d + 0x00), bx ;; number of physical cylinders
8896 mov (0x004d + 0x02), cl ;; number of physical heads
8897 mov (0x004d + 0x0E), dl ;; number of physical sectors
8900 hd1_post_logical_chs:
8901 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8902 mov (0x004d + 0x09), bx ;; number of physical cylinders
8903 mov (0x004d + 0x0b), cl ;; number of physical heads
8904 mov (0x004d + 0x04), dl ;; number of physical sectors
8905 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8907 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8910 jnbe hd1_post_above_2048
8911 ;; 1024 < c <= 2048 cylinders
8914 jmp hd1_post_store_logical
8916 hd1_post_above_2048:
8918 jnbe hd1_post_above_4096
8919 ;; 2048 < c <= 4096 cylinders
8922 jmp hd1_post_store_logical
8924 hd1_post_above_4096:
8926 jnbe hd1_post_above_8192
8927 ;; 4096 < c <= 8192 cylinders
8930 jmp hd1_post_store_logical
8932 hd1_post_above_8192:
8933 ;; 8192 < c <= 16384 cylinders
8937 hd1_post_store_logical:
8938 mov (0x004d + 0x00), bx ;; number of physical cylinders
8939 mov (0x004d + 0x02), cl ;; number of physical heads
8941 mov cl, #0x0f ;; repeat count
8942 mov si, #0x004d ;; offset to disk0 FDPT
8943 mov al, #0x00 ;; sum
8944 hd1_post_checksum_loop:
8948 jnz hd1_post_checksum_loop
8949 not al ;; now take 2s complement
8952 ;;; Done filling EBDA table for hard disk 1.
8956 ;--------------------
8957 ;- POST: EBDA segment
8958 ;--------------------
8959 ; relocated here because the primary POST area isnt big enough.
8964 mov byte ptr [0x0], #EBDA_SIZE
8966 xor ax, ax ; mov EBDA seg into 40E
8968 mov word ptr [0x40E], #EBDA_SEG
8971 ;--------------------
8972 ;- POST: EOI + jmp via [0x40:67)
8973 ;--------------------
8974 ; relocated here because the primary POST area isnt big enough.
8984 ;--------------------
8987 out #0xA0, al ;; slave PIC EOI
8990 out #0x20, al ;; master PIC EOI
8993 ;--------------------
8995 ;; in: AL in BCD format
8996 ;; out: AL in binary format, AH will always be 0
8999 and bl, #0x0f ;; bl has low digit
9000 shr al, #4 ;; al has high digit
9002 mul al, bh ;; multiply high digit by 10 (result in AX)
9003 add al, bl ;; then add low digit
9006 ;--------------------
9008 ;; Setup the Timer Ticks Count (0x46C:dword) and
9009 ;; Timer Ticks Roller Flag (0x470:byte)
9010 ;; The Timer Ticks Count needs to be set according to
9011 ;; the current CMOS time, as if ticks have been occurring
9012 ;; at 18.2hz since midnight up to this point. Calculating
9013 ;; this is a little complicated. Here are the factors I gather
9014 ;; regarding this. 14,318,180 hz was the original clock speed,
9015 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9016 ;; at the time, or 4 to drive the CGA video adapter. The div3
9017 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9018 ;; the timer. With a maximum 16bit timer count, this is again
9019 ;; divided down by 65536 to 18.2hz.
9021 ;; 14,318,180 Hz clock
9022 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9023 ;; /4 = 1,193,181 Hz fed to timer
9024 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9025 ;; 1 second = 18.20650736 ticks
9026 ;; 1 minute = 1092.390442 ticks
9027 ;; 1 hour = 65543.42651 ticks
9029 ;; Given the values in the CMOS clock, one could calculate
9030 ;; the number of ticks by the following:
9031 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9032 ;; (BcdToBin(minutes) * 1092.3904)
9033 ;; (BcdToBin(hours) * 65543.427)
9034 ;; To get a little more accuracy, since Im using integer
9035 ;; arithmatic, I use:
9036 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9037 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9038 ;; (BcdToBin(hours) * 65543427) / 1000
9043 xor eax, eax ;; clear EAX
9046 in al, #0x71 ;; AL has CMOS seconds in BCD
9047 call BcdToBin ;; EAX now has seconds in binary
9053 mov ecx, eax ;; ECX will accumulate total ticks
9056 xor eax, eax ;; clear EAX
9059 in al, #0x71 ;; AL has CMOS minutes in BCD
9060 call BcdToBin ;; EAX now has minutes in binary
9066 add ecx, eax ;; add to total ticks
9069 xor eax, eax ;; clear EAX
9072 in al, #0x71 ;; AL has CMOS hours in BCD
9073 call BcdToBin ;; EAX now has hours in binary
9079 add ecx, eax ;; add to total ticks
9081 mov 0x46C, ecx ;; Timer Ticks Count
9083 mov 0x470, al ;; Timer Ticks Rollover Flag
9086 ;--------------------
9088 ;; record completion in BIOS task complete flag
9100 ;--------------------
9105 #include "apmbios.S"
9109 #include "apmbios.S"
9112 #include "apmbios.S"
9116 ;--------------------
9121 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9122 dw bios32_entry_point, 0xf ;; 32 bit physical address
9123 db 0 ;; revision level
9124 ;; length in paragraphs and checksum stored in a word to prevent errors
9125 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9126 & 0xff) << 8) + 0x01
9127 db 0,0,0,0,0 ;; reserved
9132 cmp eax, #0x49435024
9134 mov eax, #0x80000000
9139 cmp eax, #0x12378086
9141 mov ebx, #0x000f0000
9143 mov edx, #pcibios_protected
9158 cmp al, #0x01 ;; installation check
9162 mov edx, #0x20494350
9165 pci_pro_f02: ;; find pci device
9173 call pci_pro_select_reg
9187 pci_pro_f08: ;; read configuration byte
9190 call pci_pro_select_reg
9199 pci_pro_f09: ;; read configuration word
9202 call pci_pro_select_reg
9211 pci_pro_f0a: ;; read configuration dword
9214 call pci_pro_select_reg
9221 pci_pro_f0b: ;; write configuration byte
9224 call pci_pro_select_reg
9233 pci_pro_f0c: ;; write configuration word
9236 call pci_pro_select_reg
9245 pci_pro_f0d: ;; write configuration dword
9248 call pci_pro_select_reg
9291 mov eax, #0x80000000
9296 cmp eax, #0x12378086
9306 cmp al, #0x01 ;; installation check
9311 mov edx, #0x20494350
9313 mov di, #pcibios_protected
9316 pci_real_f02: ;; find pci device
9326 call pci_real_select_reg
9330 jne pci_real_nextdev
9337 jne pci_real_devloop
9342 pci_real_f08: ;; read configuration byte
9345 call pci_real_select_reg
9354 pci_real_f09: ;; read configuration word
9357 call pci_real_select_reg
9366 pci_real_f0a: ;; read configuration dword
9369 call pci_real_select_reg
9376 pci_real_f0b: ;; write configuration byte
9379 call pci_real_select_reg
9388 pci_real_f0c: ;; write configuration word
9391 call pci_real_select_reg
9400 pci_real_f0d: ;; write configuration dword
9403 call pci_real_select_reg
9410 pci_real_f0e: ;; get irq routing options
9412 jne pci_real_unknown
9414 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9415 jb pci_real_too_small
9417 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9425 mov si, #pci_routing_table_structure_start
9433 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
9442 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9446 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9464 pci_real_select_reg:
9478 pci_routing_table_structure:
9479 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9481 dw 32 + (6 * 16) ;; table size
9482 db 0 ;; PCI interrupt router bus
9483 db 0x08 ;; PCI interrupt router DevFunc
9484 dw 0x0000 ;; PCI exclusive IRQs
9485 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9486 dw 0x122e ;; compatible PCI interrupt router device ID
9487 dw 0,0 ;; Miniport data
9488 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9490 pci_routing_table_structure_start:
9491 ;; first slot entry PCI-to-ISA (embedded)
9492 db 0 ;; pci bus number
9493 db 0x08 ;; pci device number (bit 7-3)
9494 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9495 dw 0xdef8 ;; IRQ bitmap INTA#
9496 db 0x61 ;; link value INTB#
9497 dw 0xdef8 ;; IRQ bitmap INTB#
9498 db 0x62 ;; link value INTC#
9499 dw 0xdef8 ;; IRQ bitmap INTC#
9500 db 0x63 ;; link value INTD#
9501 dw 0xdef8 ;; IRQ bitmap INTD#
9502 db 0 ;; physical slot (0 = embedded)
9504 ;; second slot entry: 1st PCI slot
9505 db 0 ;; pci bus number
9506 db 0x10 ;; pci device number (bit 7-3)
9507 db 0x61 ;; link value INTA#
9508 dw 0xdef8 ;; IRQ bitmap INTA#
9509 db 0x62 ;; link value INTB#
9510 dw 0xdef8 ;; IRQ bitmap INTB#
9511 db 0x63 ;; link value INTC#
9512 dw 0xdef8 ;; IRQ bitmap INTC#
9513 db 0x60 ;; link value INTD#
9514 dw 0xdef8 ;; IRQ bitmap INTD#
9515 db 1 ;; physical slot (0 = embedded)
9517 ;; third slot entry: 2nd PCI slot
9518 db 0 ;; pci bus number
9519 db 0x18 ;; pci device number (bit 7-3)
9520 db 0x62 ;; link value INTA#
9521 dw 0xdef8 ;; IRQ bitmap INTA#
9522 db 0x63 ;; link value INTB#
9523 dw 0xdef8 ;; IRQ bitmap INTB#
9524 db 0x60 ;; link value INTC#
9525 dw 0xdef8 ;; IRQ bitmap INTC#
9526 db 0x61 ;; link value INTD#
9527 dw 0xdef8 ;; IRQ bitmap INTD#
9528 db 2 ;; physical slot (0 = embedded)
9530 ;; 4th slot entry: 3rd PCI slot
9531 db 0 ;; pci bus number
9532 db 0x20 ;; pci device number (bit 7-3)
9533 db 0x63 ;; link value INTA#
9534 dw 0xdef8 ;; IRQ bitmap INTA#
9535 db 0x60 ;; link value INTB#
9536 dw 0xdef8 ;; IRQ bitmap INTB#
9537 db 0x61 ;; link value INTC#
9538 dw 0xdef8 ;; IRQ bitmap INTC#
9539 db 0x62 ;; link value INTD#
9540 dw 0xdef8 ;; IRQ bitmap INTD#
9541 db 3 ;; physical slot (0 = embedded)
9543 ;; 5th slot entry: 4rd PCI slot
9544 db 0 ;; pci bus number
9545 db 0x28 ;; pci device number (bit 7-3)
9546 db 0x60 ;; link value INTA#
9547 dw 0xdef8 ;; IRQ bitmap INTA#
9548 db 0x61 ;; link value INTB#
9549 dw 0xdef8 ;; IRQ bitmap INTB#
9550 db 0x62 ;; link value INTC#
9551 dw 0xdef8 ;; IRQ bitmap INTC#
9552 db 0x63 ;; link value INTD#
9553 dw 0xdef8 ;; IRQ bitmap INTD#
9554 db 4 ;; physical slot (0 = embedded)
9556 ;; 6th slot entry: 5rd PCI slot
9557 db 0 ;; pci bus number
9558 db 0x30 ;; pci device number (bit 7-3)
9559 db 0x61 ;; link value INTA#
9560 dw 0xdef8 ;; IRQ bitmap INTA#
9561 db 0x62 ;; link value INTB#
9562 dw 0xdef8 ;; IRQ bitmap INTB#
9563 db 0x63 ;; link value INTC#
9564 dw 0xdef8 ;; IRQ bitmap INTC#
9565 db 0x60 ;; link value INTD#
9566 dw 0xdef8 ;; IRQ bitmap INTD#
9567 db 5 ;; physical slot (0 = embedded)
9569 pci_routing_table_structure_end:
9574 pcibios_init_sel_reg:
9586 pcibios_init_set_elcr:
9610 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9615 mov si, #pci_routing_table_structure
9619 call pcibios_init_sel_reg
9622 cmp eax, [si+12] ;; check irq router
9625 call pcibios_init_sel_reg
9626 push bx ;; save irq router bus + devfunc
9629 out dx, ax ;; reset PIRQ route control
9637 add si, #0x20 ;; set pointer to 1st entry
9639 mov ax, #pci_irq_list
9648 call pcibios_init_sel_reg
9652 jnz pci_test_int_pin
9658 call pcibios_init_sel_reg
9663 dec al ;; determine pirq reg
9672 call pcibios_init_sel_reg
9679 mov bx, [bp-2] ;; pci irq list pointer
9684 call pcibios_init_set_elcr
9688 add bl, [bp-3] ;; pci function number
9690 call pcibios_init_sel_reg
9700 mov byte ptr[bp-3], #0x00
9708 #endif // BX_PCIBIOS
9710 ; parallel port detection: base address in DX, index in BX, timeout in CL
9715 and al, #0xdf ; clear input mode
9725 mov [bx+0x408], dx ; Parallel I/O address
9727 mov [bx+0x478], cl ; Parallel printer timeout
9732 ; serial port detection: base address in DX, index in BX, timeout in CL
9734 ; no serial port in the VM -PAD
9754 mov [bx+0x400], dx ; Serial I/O address
9756 mov [bx+0x47c], cl ; Serial timeout
9783 ;; Scan for existence of valid expansion ROMS.
9784 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9785 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9786 ;; System ROM: only 0xE0000
9792 ;; 2 ROM length in 512-byte blocks
9793 ;; 3 ROM initialization entry point (FAR CALL)
9798 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9799 cmp [0], #0xAA55 ;; look for signature
9800 jne rom_scan_increment
9802 jnz rom_scan_increment
9804 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9806 ;; We want our increment in 512-byte quantities, rounded to
9807 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9809 jz block_count_rounded
9810 and al, #0xfc ;; needs rounding up
9812 block_count_rounded:
9814 xor bx, bx ;; Restore DS back to 0000:
9817 ;; Push addr of ROM entry point
9819 push #0x0003 ;; Push offset
9820 mov bp, sp ;; Call ROM init routine using seg:off on stack
9821 db 0xff ;; call_far ss:[bp+0]
9824 cli ;; In case expansion ROM BIOS turns IF on
9825 add sp, #2 ;; Pop offset value
9826 pop cx ;; Pop seg value (restore CX)
9827 pop ax ;; Restore AX
9829 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9830 ;; because the segment selector is shifted left 4 bits.
9835 xor ax, ax ;; Restore DS back to 0000:
9841 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9842 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9843 ; but the tables themeselves can be elsewhere.
9852 mov cx, #0x001f ; 0x1f bytes to copy
9854 mov es, ax ; destination segment is 0xf0000
9855 mov di, #smbios_entry_point ; destination offset
9857 mov ds, ax ; source segment is 0x9f000
9858 mov si, #0x0000 ; source offset is 0
9876 ;; for 'C' strings and other data, insert them here with
9877 ;; a the following hack:
9878 ;; DATA_SEG_DEFS_HERE
9884 .org 0xe05b ; POST Entry Point
9889 ;; first reset the DMA controllers
9893 ;; then initialize the DMA controllers
9895 out 0xD6, al ; cascade mode of channel 4 enabled
9897 out 0xD4, al ; unmask channel 4
9899 ;; Examine CMOS shutdown status.
9907 ;; Reset CMOS shutdown status.
9909 out 0x70, AL ; select CMOS register Fh
9911 out 0x71, AL ; set shutdown action to normal
9913 ;; Examine CMOS shutdown status.
9916 ;; 0x00, 0x09, 0x0D+ = normal startup
9924 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9928 ;; Examine CMOS shutdown status.
9929 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9931 call _shutdown_status_panic
9937 ; 0xb0, 0x20, /* mov al, #0x20 */
9938 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9948 ; case 0: normal startup
9957 ;; zero out BIOS data area (40:00..40:ff)
9959 mov cx, #0x0080 ;; 128 words
9965 call _log_bios_start
9967 ;; set all interrupts to default handler
9968 mov bx, #0x0000 ;; offset index
9969 mov cx, #0x0100 ;; counter (256 interrupts)
9970 mov ax, #dummy_iret_handler
9980 loop post_default_ints
9982 ;; set vector 0x79 to zero
9983 ;; this is used by 'gardian angel' protection system
9984 SET_INT_VECTOR(0x79, #0, #0)
9986 ;; base memory in K 40:13 (word)
9987 mov ax, #BASE_MEM_IN_K
9991 ;; Manufacturing Test 40:12
9994 ;; Warm Boot Flag 0040:0072
9995 ;; value of 1234h = skip memory checks
9999 ;; Printer Services vector
10000 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10002 ;; Bootstrap failure vector
10003 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10005 ;; Bootstrap Loader vector
10006 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10008 ;; User Timer Tick vector
10009 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10011 ;; Memory Size Check vector
10012 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10014 ;; Equipment Configuration Check vector
10015 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10018 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10024 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10025 ;; int 1C already points at dummy_iret_handler (above)
10026 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
10029 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
10034 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
10040 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10041 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10045 mov 0x0417, al /* keyboard shift flags, set 1 */
10046 mov 0x0418, al /* keyboard shift flags, set 2 */
10047 mov 0x0419, al /* keyboard alt-numpad work area */
10048 mov 0x0471, al /* keyboard ctrl-break flag */
10049 mov 0x0497, al /* keyboard status flags 4 */
10051 mov 0x0496, al /* keyboard status flags 3 */
10054 /* keyboard head of buffer pointer */
10058 /* keyboard end of buffer pointer */
10061 /* keyboard pointer to start of buffer */
10065 /* keyboard pointer to end of buffer */
10069 /* init the keyboard */
10070 call _keyboard_init
10072 ;; mov CMOS Equipment Byte to BDA Equipment Word
10081 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10085 mov cl, #0x14 ; timeout value
10086 mov dx, #0x378 ; Parallel I/O address, port 1
10087 call detect_parport
10088 mov dx, #0x278 ; Parallel I/O address, port 2
10089 call detect_parport
10091 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
10093 or ax, bx ; set number of parallel ports
10097 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10098 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10100 mov cl, #0x0a ; timeout value
10101 mov dx, #0x03f8 ; Serial I/O address, port 1
10103 mov dx, #0x02f8 ; Serial I/O address, port 2
10105 mov dx, #0x03e8 ; Serial I/O address, port 3
10107 mov dx, #0x02e8 ; Serial I/O address, port 4
10110 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
10112 or ax, bx ; set number of serial port
10116 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10117 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10118 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10119 ;; BIOS DATA AREA 0x4CE ???
10120 call timer_tick_post
10122 ;; PS/2 mouse setup
10123 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10125 ;; IRQ13 (FPU exception) setup
10126 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10129 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10134 mov al, #0x11 ; send initialisation commands
10149 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
10150 #if BX_USE_PS2_MOUSE
10155 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
10158 call _copy_e820_table
10177 call _print_bios_banner
10182 call floppy_drive_post
10187 ;; Hard Drive setup
10189 call hard_drive_post
10192 ;; ATA/ATAPI driver setup
10197 #else // BX_USE_ATADRV
10200 ;; Hard Drive setup
10202 call hard_drive_post
10204 #endif // BX_USE_ATADRV
10206 #if BX_ELTORITO_BOOT
10208 ;; eltorito floppy/harddisk emulation from cd
10212 #endif // BX_ELTORITO_BOOT
10215 //JMP_EP(0x0064) ; INT 19h location
10218 .org 0xe2c3 ; NMI Handler Entry Point
10220 ;; FIXME the NMI handler should not panic
10221 ;; but iret when called from int75 (fpu exception)
10222 call _nmi_handler_msg
10226 out 0xf0, al // clear irq13
10227 call eoi_both_pics // clear interrupt
10228 int 2 // legacy nmi call
10231 ;-------------------------------------------
10232 ;- INT 13h Fixed Disk Services Entry Point -
10233 ;-------------------------------------------
10234 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
10236 //JMPL(int13_relocated)
10237 jmp int13_relocated
10239 .org 0xe401 ; Fixed Disk Parameter Table
10244 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
10247 jmp int19_relocated
10248 ;-------------------------------------------
10249 ;- System BIOS Configuration Data Table
10250 ;-------------------------------------------
10251 .org BIOS_CONFIG_TABLE
10252 db 0x08 ; Table size (bytes) -Lo
10253 db 0x00 ; Table size (bytes) -Hi
10258 ; b7: 1=DMA channel 3 used by hard disk
10259 ; b6: 1=2 interrupt controllers present
10260 ; b5: 1=RTC present
10261 ; b4: 1=BIOS calls int 15h/4Fh every key
10262 ; b3: 1=wait for extern event supported (Int 15h/41h)
10263 ; b2: 1=extended BIOS data area used
10264 ; b1: 0=AT or ESDI bus, 1=MicroChannel
10265 ; b0: 1=Dual bus (MicroChannel + ISA)
10269 (BX_CALL_INT15_4F << 4) | \
10271 (BX_USE_EBDA << 2) | \
10275 ; b7: 1=32-bit DMA supported
10276 ; b6: 1=int16h, function 9 supported
10277 ; b5: 1=int15h/C6h (get POS data) supported
10278 ; b4: 1=int15h/C7h (get mem map info) supported
10279 ; b3: 1=int15h/C8h (en/dis CPU) supported
10280 ; b2: 1=non-8042 kb controller
10281 ; b1: 1=data streaming supported
10295 ; b4: POST supports ROM-to-RAM enable/disable
10296 ; b3: SCSI on system board
10297 ; b2: info panel installed
10298 ; b1: Initial Machine Load (IML) system - BIOS on disk
10299 ; b0: SCSI supported in IML
10303 ; b6: EEPROM present
10304 ; b5-3: ABIOS presence (011 = not supported)
10306 ; b1: memory split above 16Mb supported
10307 ; b0: POSTEXT directly supported by POST
10309 ; Feature byte 5 (IBM)
10310 ; b1: enhanced mouse
10316 .org 0xe729 ; Baud Rate Generator Table
10321 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10327 call _int14_function
10333 ;----------------------------------------
10334 ;- INT 16h Keyboard Service Entry Point -
10335 ;----------------------------------------
10351 call _int16_function
10361 and BYTE [bp + 0x06], #0xbf
10369 or BYTE [bp + 0x06], #0x40
10377 int16_wait_for_key:
10381 jne int16_key_found
10385 /* no key yet, call int 15h, function AX=9002 */
10386 0x50, /* push AX */
10387 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10388 0xcd, 0x15, /* int 15h */
10390 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10392 jmp int16_wait_for_key
10397 call _int16_function
10402 /* notify int16 complete w/ int 15h, function AX=9102 */
10403 0x50, /* push AX */
10404 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10405 0xcd, 0x15, /* int 15h */
10412 ;-------------------------------------------------
10413 ;- INT09h : Keyboard Hardware Service Entry Point -
10414 ;-------------------------------------------------
10420 mov al, #0xAD ;;disable keyboard
10429 in al, #0x60 ;;read key from keyboard controller
10430 //test al, #0x80 ;;look for key release
10431 //jnz int09_process_key ;; dont pass releases to intercept?
10433 ;; check for extended key
10435 jne int09_call_int15_4f
10440 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10442 mov BYTE [0x496], al
10445 in al, #0x60 ;;read another key from keyboard controller
10449 int09_call_int15_4f:
10452 #ifdef BX_CALL_INT15_4F
10453 mov ah, #0x4f ;; allow for keyboard intercept
10460 //int09_process_key:
10463 call _int09_function
10469 call eoi_master_pic
10472 mov al, #0xAE ;;enable keyboard
10480 ;----------------------------------------
10481 ;- INT 13h Diskette Service Entry Point -
10482 ;----------------------------------------
10485 jmp int13_noeltorito
10487 ;---------------------------------------------
10488 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10489 ;---------------------------------------------
10490 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10500 mov al, #0x08 ; sense interrupt status
10518 mov ax, #0x0000 ;; segment 0000
10520 call eoi_master_pic
10522 or al, #0x80 ;; diskette interrupt has occurred
10530 .org 0xefc7 ; Diskette Controller Parameter Table
10531 diskette_param_table:
10532 ;; Since no provisions are made for multiple drive types, most
10533 ;; values in this table are ignored. I set parameters for 1.44M
10536 db 0x02 ;; head load time 0000001, DMA used
10548 ;----------------------------------------
10549 ;- INT17h : Printer Service Entry Point -
10550 ;----------------------------------------
10557 call _int17_function
10562 diskette_param_table2:
10563 ;; New diskette parameter table adding 3 parameters from IBM
10564 ;; Since no provisions are made for multiple drive types, most
10565 ;; values in this table are ignored. I set parameters for 1.44M
10568 db 0x02 ;; head load time 0000001, DMA used
10578 db 79 ;; maximum track
10579 db 0 ;; data transfer rate
10580 db 4 ;; drive type in cmos
10582 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10589 .org 0xf065 ; INT 10h Video Support Service Entry Point
10591 ;; dont do anything, since the VGA BIOS handles int10h requests
10594 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10599 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10600 ; ??? different for Pentium (machine check)?
10612 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10624 .org 0xf859 ; INT 15h System Services Entry Point
10638 #if BX_USE_PS2_MOUSE
10640 je int15_handler_mouse
10642 call _int15_function
10643 int15_handler_mouse_ret:
10645 int15_handler32_ret:
10655 #if BX_USE_PS2_MOUSE
10656 int15_handler_mouse:
10657 call _int15_function_mouse
10658 jmp int15_handler_mouse_ret
10663 call _int15_function32
10665 jmp int15_handler32_ret
10667 ;; Protected mode IDT descriptor
10669 ;; I just make the limit 0, so the machine will shutdown
10670 ;; if an exception occurs during protected mode memory
10673 ;; Set base to f0000 to correspond to beginning of BIOS,
10674 ;; in case I actually define an IDT later
10678 dw 0x0000 ;; limit 15:00
10679 dw 0x0000 ;; base 15:00
10680 db 0x0f ;; base 23:16
10682 ;; Real mode IDT descriptor
10684 ;; Set to typical real-mode values.
10689 dw 0x03ff ;; limit 15:00
10690 dw 0x0000 ;; base 15:00
10691 db 0x00 ;; base 23:16
10697 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10710 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10711 mov ds, ax ; on 16bit protected mode.
10712 jmp int1a_callfunction
10719 int1a_callfunction:
10720 call _int1a_function
10726 ;; int70h: IRQ8 - CMOS RTC
10733 call _int70_function
10741 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10749 ;; time to turn off drive(s)?
10752 jz int08_floppy_off
10755 jnz int08_floppy_off
10756 ;; turn motor(s) off
10765 mov eax, 0x046c ;; get ticks dword
10768 ;; compare eax to one days worth of timer ticks at 18.2 hz
10769 cmp eax, #0x001800B0
10770 jb int08_store_ticks
10771 ;; there has been a midnight rollover at this point
10772 xor eax, eax ;; zero out counter
10773 inc BYTE 0x0470 ;; increment rollover flag
10776 mov 0x046c, eax ;; store new ticks dword
10777 ;; chain to user timer tick INT #0x1c
10779 //;; call_ep [ds:loc]
10780 //CALL_EP( 0x1c << 2 )
10783 call eoi_master_pic
10788 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10792 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10794 ;------------------------------------------------
10795 ;- IRET Instruction for Dummy Interrupt Handler -
10796 ;------------------------------------------------
10797 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10798 dummy_iret_handler:
10801 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10810 .org 0xfff0 ; Power-up Entry Point
10817 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10818 .ascii BIOS_BUILD_DATE
10820 .org 0xfffe ; System Model ID
10824 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10827 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10828 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10829 * This font is public domain
10831 static Bit8u vgafont8[128*8]=
10833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10834 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10835 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10836 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10837 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10838 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10839 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10840 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10841 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10842 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10843 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10844 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10845 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10846 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10847 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10848 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10849 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10850 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10851 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10852 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10853 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10854 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10855 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10856 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10857 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10858 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10859 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10860 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10861 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10862 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10863 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10864 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10865 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10866 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10867 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10868 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10869 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10870 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10871 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10872 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10873 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10874 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10875 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10876 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10877 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10878 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10879 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10880 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10881 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10882 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10883 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10884 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10885 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10886 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10887 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10888 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10889 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10890 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10891 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10892 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10893 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10894 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10895 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10896 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10897 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10898 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10899 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10900 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10901 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10902 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10903 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10904 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10905 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10906 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10907 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10908 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10909 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10910 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10911 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10912 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10913 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10914 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10915 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10916 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10917 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10918 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10919 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10920 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10921 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10922 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10923 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10924 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10925 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10926 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10927 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10929 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10930 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10931 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10932 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10933 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10934 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10935 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10936 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10937 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10938 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10939 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10940 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10941 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10942 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10943 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10944 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10945 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10946 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10947 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10948 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10949 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10950 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10951 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10952 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10953 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10954 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10955 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10956 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10957 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10958 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10959 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10960 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10966 // just carve out some blank space for HVMLOADER to write the MP tables to
10968 // NOTE: There should be enough space for a 32 processor entry MP table
10972 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10973 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 64 bytes
10974 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 128 bytes
10975 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 192 bytes
10976 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 256 bytes
10977 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 320 bytes
10978 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 384 bytes
10979 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 448 bytes
10980 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 512 bytes
10981 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 576 bytes
10982 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 640 bytes
10983 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 704 bytes
10984 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 768 bytes
10985 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 832 bytes
10986 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 896 bytes
10989 smbios_entry_point:
10990 db 0,0,0,0,0,0,0,0 ; 8 bytes
10991 db 0,0,0,0,0,0,0,0 ; 16 bytes
10992 db 0,0,0,0,0,0,0,0 ; 24 bytes
10993 db 0,0,0,0,0,0,0 ; 31 bytes
10996 #else // !HVMASSIST
11000 // bcc-generated data will be placed here
11002 // For documentation of this config structure, look on developer.intel.com and
11003 // search for multiprocessor specification. Note that when you change anything
11004 // you must update the checksum (a pain!). It would be better to construct this
11005 // with C structures, or at least fill in the checksum automatically.
11007 // Maybe this structs could be moved elsewhere than d000
11009 #if (BX_SMP_PROCESSORS==1)
11010 // no structure necessary.
11011 #elif (BX_SMP_PROCESSORS==2)
11012 // define the Intel MP Configuration Structure for 2 processors at
11013 // APIC ID 0,1. I/O APIC at ID=2.
11016 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
11017 dw (mp_config_end-mp_config_table) ;; table length
11019 db 0x65 ;; checksum
11020 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
11021 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
11022 db 0x20, 0x20, 0x20, 0x20
11023 db 0x20, 0x20, 0x20, 0x20
11024 dw 0,0 ;; oem table ptr
11025 dw 0 ;; oem table size
11026 dw 20 ;; entry count
11027 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
11028 dw 0 ;; extended table length
11029 db 0 ;; extended table checksum
11032 db 0 ;; entry type=processor
11033 db 0 ;; local APIC id
11034 db 0x11 ;; local APIC version number
11035 db 3 ;; cpu flags: enabled, bootstrap processor
11036 db 0,6,0,0 ;; cpu signature
11037 dw 0x201,0 ;; feature flags
11041 db 0 ;; entry type=processor
11042 db 1 ;; local APIC id
11043 db 0x11 ;; local APIC version number
11044 db 1 ;; cpu flags: enabled
11045 db 0,6,0,0 ;; cpu signature
11046 dw 0x201,0 ;; feature flags
11050 db 1 ;; entry type=bus
11052 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
11054 db 2 ;; entry type=I/O APIC
11055 db 2 ;; apic id=2. linux will set.
11056 db 0x11 ;; I/O APIC version number
11057 db 1 ;; flags=1=enabled
11058 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11060 db 3 ;; entry type=I/O interrupt
11061 db 0 ;; interrupt type=vectored interrupt
11062 db 0,0 ;; flags po=0, el=0 (linux uses as default)
11063 db 0 ;; source bus ID is ISA
11064 db 0 ;; source bus IRQ
11065 db 2 ;; destination I/O APIC ID
11066 db 0 ;; destination I/O APIC interrrupt in
11067 ;; repeat pattern for interrupts 0-15
11077 db 3,0,0,0,0,10,2,10
11078 db 3,0,0,0,0,11,2,11
11079 db 3,0,0,0,0,12,2,12
11080 db 3,0,0,0,0,13,2,13
11081 db 3,0,0,0,0,14,2,14
11082 db 3,0,0,0,0,15,2,15
11083 #elif (BX_SMP_PROCESSORS==4)
11084 // define the Intel MP Configuration Structure for 4 processors at
11085 // APIC ID 0,1,2,3. I/O APIC at ID=4.
11088 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
11089 dw (mp_config_end-mp_config_table) ;; table length
11091 db 0xdd ;; checksum
11092 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
11093 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
11094 db 0x20, 0x20, 0x20, 0x20
11095 db 0x20, 0x20, 0x20, 0x20
11096 dw 0,0 ;; oem table ptr
11097 dw 0 ;; oem table size
11098 dw 22 ;; entry count
11099 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
11100 dw 0 ;; extended table length
11101 db 0 ;; extended table checksum
11104 db 0 ;; entry type=processor
11105 db 0 ;; local APIC id
11106 db 0x11 ;; local APIC version number
11107 db 3 ;; cpu flags: enabled, bootstrap processor
11108 db 0,6,0,0 ;; cpu signature
11109 dw 0x201,0 ;; feature flags
11113 db 0 ;; entry type=processor
11114 db 1 ;; local APIC id
11115 db 0x11 ;; local APIC version number
11116 db 1 ;; cpu flags: enabled
11117 db 0,6,0,0 ;; cpu signature
11118 dw 0x201,0 ;; feature flags
11122 db 0 ;; entry type=processor
11123 db 2 ;; local APIC id
11124 db 0x11 ;; local APIC version number
11125 db 1 ;; cpu flags: enabled
11126 db 0,6,0,0 ;; cpu signature
11127 dw 0x201,0 ;; feature flags
11131 db 0 ;; entry type=processor
11132 db 3 ;; local APIC id
11133 db 0x11 ;; local APIC version number
11134 db 1 ;; cpu flags: enabled
11135 db 0,6,0,0 ;; cpu signature
11136 dw 0x201,0 ;; feature flags
11140 db 1 ;; entry type=bus
11142 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
11144 db 2 ;; entry type=I/O APIC
11145 db 4 ;; apic id=4. linux will set.
11146 db 0x11 ;; I/O APIC version number
11147 db 1 ;; flags=1=enabled
11148 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11150 db 3 ;; entry type=I/O interrupt
11151 db 0 ;; interrupt type=vectored interrupt
11152 db 0,0 ;; flags po=0, el=0 (linux uses as default)
11153 db 0 ;; source bus ID is ISA
11154 db 0 ;; source bus IRQ
11155 db 4 ;; destination I/O APIC ID
11156 db 0 ;; destination I/O APIC interrrupt in
11157 ;; repeat pattern for interrupts 0-15
11167 db 3,0,0,0,0,10,4,10
11168 db 3,0,0,0,0,11,4,11
11169 db 3,0,0,0,0,12,4,12
11170 db 3,0,0,0,0,13,4,13
11171 db 3,0,0,0,0,14,4,14
11172 db 3,0,0,0,0,15,4,15
11173 #elif (BX_SMP_PROCESSORS==8)
11174 // define the Intel MP Configuration Structure for 8 processors at
11175 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
11178 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
11179 dw (mp_config_end-mp_config_table) ;; table length
11181 db 0xc3 ;; checksum
11182 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
11183 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
11184 db 0x20, 0x20, 0x20, 0x20
11185 db 0x20, 0x20, 0x20, 0x20
11186 dw 0,0 ;; oem table ptr
11187 dw 0 ;; oem table size
11188 dw 26 ;; entry count
11189 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
11190 dw 0 ;; extended table length
11191 db 0 ;; extended table checksum
11194 db 0 ;; entry type=processor
11195 db 0 ;; local APIC id
11196 db 0x11 ;; local APIC version number
11197 db 3 ;; cpu flags: enabled, bootstrap processor
11198 db 0,6,0,0 ;; cpu signature
11199 dw 0x201,0 ;; feature flags
11203 db 0 ;; entry type=processor
11204 db 1 ;; local APIC id
11205 db 0x11 ;; local APIC version number
11206 db 1 ;; cpu flags: enabled
11207 db 0,6,0,0 ;; cpu signature
11208 dw 0x201,0 ;; feature flags
11212 db 0 ;; entry type=processor
11213 db 2 ;; local APIC id
11214 db 0x11 ;; local APIC version number
11215 db 1 ;; cpu flags: enabled
11216 db 0,6,0,0 ;; cpu signature
11217 dw 0x201,0 ;; feature flags
11221 db 0 ;; entry type=processor
11222 db 3 ;; local APIC id
11223 db 0x11 ;; local APIC version number
11224 db 1 ;; cpu flags: enabled
11225 db 0,6,0,0 ;; cpu signature
11226 dw 0x201,0 ;; feature flags
11230 db 0 ;; entry type=processor
11231 db 4 ;; local APIC id
11232 db 0x11 ;; local APIC version number
11233 db 1 ;; cpu flags: enabled
11234 db 0,6,0,0 ;; cpu signature
11235 dw 0x201,0 ;; feature flags
11239 db 0 ;; entry type=processor
11240 db 5 ;; local APIC id
11241 db 0x11 ;; local APIC version number
11242 db 1 ;; cpu flags: enabled
11243 db 0,6,0,0 ;; cpu signature
11244 dw 0x201,0 ;; feature flags
11248 db 0 ;; entry type=processor
11249 db 6 ;; local APIC id
11250 db 0x11 ;; local APIC version number
11251 db 1 ;; cpu flags: enabled
11252 db 0,6,0,0 ;; cpu signature
11253 dw 0x201,0 ;; feature flags
11257 db 0 ;; entry type=processor
11258 db 7 ;; local APIC id
11259 db 0x11 ;; local APIC version number
11260 db 1 ;; cpu flags: enabled
11261 db 0,6,0,0 ;; cpu signature
11262 dw 0x201,0 ;; feature flags
11266 db 1 ;; entry type=bus
11268 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
11270 db 2 ;; entry type=I/O APIC
11272 db 0x11 ;; I/O APIC version number
11273 db 1 ;; flags=1=enabled
11274 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11276 db 3 ;; entry type=I/O interrupt
11277 db 0 ;; interrupt type=vectored interrupt
11278 db 0,0 ;; flags po=0, el=0 (linux uses as default)
11279 db 0 ;; source bus ID is ISA
11280 db 0 ;; source bus IRQ
11281 db 8 ;; destination I/O APIC ID
11282 db 0 ;; destination I/O APIC interrrupt in
11283 ;; repeat pattern for interrupts 0-15
11293 db 3,0,0,0,0,10,8,10
11294 db 3,0,0,0,0,11,8,11
11295 db 3,0,0,0,0,12,8,12
11296 db 3,0,0,0,0,13,8,13
11297 db 3,0,0,0,0,14,8,14
11298 db 3,0,0,0,0,15,8,15
11300 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11301 #endif // if (BX_SMP_PROCESSORS==...)
11303 mp_config_end: // this label used to find length of mp structure
11306 #if (BX_SMP_PROCESSORS>1)
11308 mp_floating_pointer_structure:
11309 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
11310 dw mp_config_table, 0xf ;; pointer to MP configuration table
11311 db 1 ;; length of this struct in 16-bit byte chunks
11312 db 4 ;; MP spec revision
11313 db 0xc1 ;; checksum
11314 db 0 ;; MP feature byte 1. value 0 means look at the config table
11315 db 0,0,0,0 ;; MP feature bytes 2-5.
11320 #endif // HVMASSIST