2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.9 2008/07/02 17:58:44 pdinda 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
136 #define DEBUG_INT13_HD 0
137 #define DEBUG_INT13_CD 0
138 #define DEBUG_INT13_ET 0
139 #define DEBUG_INT13_FL 0
140 #define DEBUG_INT15 0
141 #define DEBUG_INT16 0
142 #define DEBUG_INT1A 0
143 #define DEBUG_INT74 0
147 #define BX_USE_PS2_MOUSE 1
148 #define BX_CALL_INT15_4F 1
149 #define BX_USE_EBDA 1
150 #define BX_SUPPORT_FLOPPY 1
151 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
155 #define BX_USE_ATADRV 1
156 #define BX_ELTORITO_BOOT 1
158 #define BX_MAX_ATA_INTERFACES 4
159 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
161 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
162 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
164 /* model byte 0xFC = AT */
165 #define SYS_MODEL_ID 0xFC
166 #define SYS_SUBMODEL_ID 0x00
167 #define BIOS_REVISION 1
168 #define BIOS_CONFIG_TABLE 0xe6f5
170 #ifndef BIOS_BUILD_DATE
171 # define BIOS_BUILD_DATE "06/23/99"
174 // 1K of base memory used for Extended Bios Data Area (EBDA)
175 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
176 #define EBDA_SEG 0x9FC0
177 #define EBDA_SIZE 1 // In KiB
178 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
180 // Define the application NAME
182 # define BX_APPNAME "HVMAssist"
184 # define BX_APPNAME "Plex86"
186 # define BX_APPNAME "Bochs"
190 #if BX_USE_ATADRV && BX_CPU<3
191 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
193 #if BX_USE_ATADRV && !BX_USE_EBDA
194 # error ATA/ATAPI Driver can only be used if EBDA is available
196 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
197 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
199 #if BX_PCIBIOS && BX_CPU<3
200 # error PCI BIOS can only be used with 386+ cpu
202 #if BX_APM && BX_CPU<3
203 # error APM BIOS can only be used with 386+ cpu
206 #ifndef BX_SMP_PROCESSORS
207 #define BX_SMP_PROCESSORS 1
208 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
211 #define PANIC_PORT 0x400
212 #define PANIC_PORT2 0x401
213 #define INFO_PORT 0x402
214 #define DEBUG_PORT 0x403
217 // #$20 is hex 20 = 32
218 // #0x20 is hex 20 = 32
225 // all hex literals should be prefixed with '0x'
226 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
227 // no mov SEG-REG, #value, must mov register into seg-reg
228 // grep -i "mov[ ]*.s" rombios.c
230 // This is for compiling with gcc2 and gcc3
231 #define ASM_START #asm
232 #define ASM_END #endasm
246 ;; the HALT macro is called with the line number of the HALT call.
247 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
248 ;; to print a BX_PANIC message. This will normally halt the simulation
249 ;; with a message such as "BIOS panic at rombios.c, line 4091".
250 ;; However, users can choose to make panics non-fatal and continue.
277 typedef unsigned char Bit8u;
278 typedef unsigned short Bit16u;
279 typedef unsigned short bx_bool;
280 typedef unsigned long Bit32u;
284 void memsetb(seg,offset,value,count);
285 void memcpyb(dseg,doffset,sseg,soffset,count);
286 void memcpyd(dseg,doffset,sseg,soffset,count);
288 // memset of count bytes
290 memsetb(seg,offset,value,count)
305 mov cx, 10[bp] ; count
308 mov ax, 4[bp] ; segment
310 mov ax, 6[bp] ; offset
312 mov al, 8[bp] ; value
327 // memcpy of count bytes
329 memcpyb(dseg,doffset,sseg,soffset,count)
347 mov cx, 12[bp] ; count
350 mov ax, 4[bp] ; dsegment
352 mov ax, 6[bp] ; doffset
354 mov ax, 8[bp] ; ssegment
356 mov ax, 10[bp] ; soffset
375 // memcpy of count dword
377 memcpyd(dseg,doffset,sseg,soffset,count)
395 mov cx, 12[bp] ; count
398 mov ax, 4[bp] ; dsegment
400 mov ax, 6[bp] ; doffset
402 mov ax, 8[bp] ; ssegment
404 mov ax, 10[bp] ; soffset
422 #endif //BX_USE_ATADRV
424 // read_dword and write_dword functions
425 static Bit32u read_dword();
426 static void write_dword();
429 read_dword(seg, offset)
439 mov ax, 4[bp] ; segment
441 mov bx, 6[bp] ; offset
446 ;; ax = return value (word)
447 ;; dx = return value (word)
456 write_dword(seg, offset, data)
468 mov ax, 4[bp] ; segment
470 mov bx, 6[bp] ; offset
471 mov ax, 8[bp] ; data word
472 mov [bx], ax ; write data word
475 mov ax, 10[bp] ; data word
476 mov [bx], ax ; write data word
485 // Bit32u (unsigned long) and long helper functions
514 cmp eax, dword ptr [di]
533 mul eax, dword ptr [di]
629 // for access to RAM area which is used by interrupt vectors
630 // and BIOS Data Area
633 unsigned char filler1[0x400];
634 unsigned char filler2[0x6c];
640 #define BiosData ((bios_data_t *) 0)
644 Bit16u heads; // # heads
645 Bit16u cylinders; // # cylinders
646 Bit16u spt; // # sectors / track
666 Bit8u iface; // ISA or PCI
667 Bit16u iobase1; // IO Base 1
668 Bit16u iobase2; // IO Base 2
673 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
674 Bit8u device; // Detected type of attached devices (hd/cd/none)
675 Bit8u removable; // Removable device flag
676 Bit8u lock; // Locks for removable devices
677 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
678 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
679 Bit16u blksize; // block size
681 Bit8u translation; // type of translation
682 chs_t lchs; // Logical CHS
683 chs_t pchs; // Physical CHS
685 Bit32u sectors; // Total sectors count
690 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
693 ata_device_t devices[BX_MAX_ATA_DEVICES];
695 // map between (bios hd id - 0x80) and ata channels
696 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
698 // map between (bios cd id - 0xE0) and ata channels
699 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
701 // Buffer for DPTE table
704 // Count of transferred sectors and bytes
711 // ElTorito Device Emulation data
715 Bit8u emulated_drive;
716 Bit8u controller_index;
719 Bit16u buffer_segment;
726 #endif // BX_ELTORITO_BOOT
728 // for access to EBDA area
729 // The EBDA structure should conform to
730 // http://www.cybertrails.com/~fys/rombios.htm document
731 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
733 unsigned char filler1[0x3D];
735 // FDPT - Can be splitted in data members if needed
736 unsigned char fdpt0[0x10];
737 unsigned char fdpt1[0x10];
739 unsigned char filler2[0xC4];
745 // El Torito Emulation data
747 #endif // BX_ELTORITO_BOOT
751 #define EbdaData ((ebda_data_t *) 0)
753 // for access to the int13ext structure
764 #define Int13Ext ((int13ext_t *) 0)
766 // Disk Physical Table definition
773 Bit32u sector_count1;
774 Bit32u sector_count2;
785 Bit8u device_path[8];
790 #define Int13DPT ((dpt_t *) 0)
792 #endif // BX_USE_ATADRV
797 Bit16u di, si, bp, sp;
798 Bit16u bx, dx, cx, ax;
802 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
810 Bit32u edi, esi, ebp, esp;
811 Bit32u ebx, edx, ecx, eax;
814 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
815 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
843 #define SetCF(x) x.u.r8.flagsl |= 0x01
844 #define SetZF(x) x.u.r8.flagsl |= 0x40
845 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
846 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
847 #define GetCF(x) (x.u.r8.flagsl & 0x01)
858 static Bit8u inb_cmos();
860 static void outb_cmos();
863 static void init_rtc();
864 static bx_bool rtc_updating();
866 static Bit8u read_byte();
867 static Bit16u read_word();
868 static void write_byte();
869 static void write_word();
870 static void bios_printf();
871 static void copy_e820_table();
873 static Bit8u inhibit_mouse_int_and_events();
874 static void enable_mouse_int_and_events();
875 static Bit8u send_to_mouse_ctrl();
876 static Bit8u get_mouse_data();
877 static void set_kbd_command_byte();
879 static void int09_function();
880 static void int13_harddisk();
881 static void int13_cdrom();
882 static void int13_cdemu();
883 static void int13_eltorito();
884 static void int13_diskette_function();
885 static void int14_function();
886 static void int15_function();
887 static void int16_function();
888 static void int17_function();
889 static Bit32u int19_function();
890 static void int1a_function();
891 static void int70_function();
892 static void int74_function();
893 static Bit16u get_CS();
894 //static Bit16u get_DS();
895 //static void set_DS();
896 static Bit16u get_SS();
897 static unsigned int enqueue_key();
898 static unsigned int dequeue_key();
899 static void get_hd_geometry();
900 static void set_diskette_ret_status();
901 static void set_diskette_current_cyl();
902 static void determine_floppy_media();
903 static bx_bool floppy_drive_exists();
904 static bx_bool floppy_drive_recal();
905 static bx_bool floppy_media_known();
906 static bx_bool floppy_media_sense();
907 static bx_bool set_enable_a20();
908 static void debugger_on();
909 static void debugger_off();
910 static void keyboard_init();
911 static void keyboard_panic();
912 static void shutdown_status_panic();
913 static void nmi_handler_msg();
915 static void print_bios_banner();
916 static void print_boot_device();
917 static void print_boot_failure();
918 static void print_cdromboot_failure();
922 // ATA / ATAPI driver
927 Bit16u ata_cmd_non_data();
928 Bit16u ata_cmd_data_in();
929 Bit16u ata_cmd_data_out();
930 Bit16u ata_cmd_packet();
932 Bit16u atapi_get_sense();
933 Bit16u atapi_is_ready();
934 Bit16u atapi_is_cdrom();
936 #endif // BX_USE_ATADRV
941 Bit8u cdemu_isactive();
942 Bit8u cdemu_emulated_drive();
946 #endif // BX_ELTORITO_BOOT
948 static char bios_cvs_version_string[] = "$Revision: 1.9 $";
949 static char bios_date_string[] = "$Date: 2008/07/02 17:58:44 $";
951 static char CVSID[] = "$Id: rombios.c,v 1.9 2008/07/02 17:58:44 pdinda Exp $";
953 /* Offset to skip the CVS $Id: prefix */
954 #define bios_version_string (CVSID + 4)
956 #define BIOS_PRINTF_HALT 1
957 #define BIOS_PRINTF_SCREEN 2
958 #define BIOS_PRINTF_INFO 4
959 #define BIOS_PRINTF_DEBUG 8
960 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
961 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
963 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
965 // Defines the output macros.
966 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
967 // per-device basis. Debug info are sent only in debug mode
969 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_ALL, format, ##p)
971 # define BX_DEBUG(format, p...)
973 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
974 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
977 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
979 # define BX_DEBUG_ATA(a...)
982 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
984 # define BX_DEBUG_INT13_HD(a...)
987 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
989 # define BX_DEBUG_INT13_CD(a...)
992 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
994 # define BX_DEBUG_INT13_ET(a...)
997 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
999 # define BX_DEBUG_INT13_FL(a...)
1002 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1004 # define BX_DEBUG_INT15(a...)
1007 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1009 # define BX_DEBUG_INT16(a...)
1012 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1014 # define BX_DEBUG_INT1A(a...)
1017 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1019 # define BX_DEBUG_INT74(a...)
1022 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1023 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1024 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1025 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1026 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1027 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1028 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1029 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1031 #define GET_AL() ( AX & 0x00ff )
1032 #define GET_BL() ( BX & 0x00ff )
1033 #define GET_CL() ( CX & 0x00ff )
1034 #define GET_DL() ( DX & 0x00ff )
1035 #define GET_AH() ( AX >> 8 )
1036 #define GET_BH() ( BX >> 8 )
1037 #define GET_CH() ( CX >> 8 )
1038 #define GET_DH() ( DX >> 8 )
1040 #define GET_ELDL() ( ELDX & 0x00ff )
1041 #define GET_ELDH() ( ELDX >> 8 )
1043 #define SET_CF() FLAGS |= 0x0001
1044 #define CLEAR_CF() FLAGS &= 0xfffe
1045 #define GET_CF() (FLAGS & 0x0001)
1047 #define SET_ZF() FLAGS |= 0x0040
1048 #define CLEAR_ZF() FLAGS &= 0xffbf
1049 #define GET_ZF() (FLAGS & 0x0040)
1051 #define UNSUPPORTED_FUNCTION 0x86
1054 #define MAX_SCAN_CODE 0x53
1062 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1063 { none, none, none, none, none },
1064 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1065 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1066 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1067 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1068 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1069 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1070 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1071 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1072 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1073 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1074 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1075 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1076 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1077 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1078 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1079 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1080 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1081 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1082 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1083 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1084 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1085 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1086 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1087 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1088 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1089 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1090 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1091 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1092 { none, none, none, none, none }, /* L Ctrl */
1093 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1094 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1095 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1096 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1097 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1098 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1099 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1100 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1101 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1102 { 0x273b, 0x273a, none, none, none }, /* ;: */
1103 { 0x2827, 0x2822, none, none, none }, /* '" */
1104 { 0x2960, 0x297e, none, none, none }, /* `~ */
1105 { none, none, none, none, none }, /* L shift */
1106 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1107 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1108 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1109 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1110 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1111 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1112 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1113 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1114 { 0x332c, 0x333c, none, none, none }, /* ,< */
1115 { 0x342e, 0x343e, none, none, none }, /* .> */
1116 { 0x352f, 0x353f, none, none, none }, /* /? */
1117 { none, none, none, none, none }, /* R Shift */
1118 { 0x372a, 0x372a, none, none, none }, /* * */
1119 { none, none, none, none, none }, /* L Alt */
1120 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1121 { none, none, none, none, none }, /* caps lock */
1122 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1123 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1124 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1125 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1126 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1127 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1128 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1129 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1130 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1131 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1132 { none, none, none, none, none }, /* Num Lock */
1133 { none, none, none, none, none }, /* Scroll Lock */
1134 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1135 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1136 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1137 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1138 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1139 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1140 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1141 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1142 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1143 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1144 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1145 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1146 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1230 outb_cmos(cmos_reg, val)
1238 mov al, 4[bp] ;; cmos_reg
1240 mov al, 6[bp] ;; val
1255 mov al, 4[bp] ;; cmos_reg
1266 printf("rombios: init_rtc()\n");
1267 outb_cmos(0x0a, 0x26);
1268 outb_cmos(0x0b, 0x02);
1276 // This function checks to see if the update-in-progress bit
1277 // is set in CMOS Status Register A. If not, it returns 0.
1278 // If it is set, it tries to wait until there is a transition
1279 // to 0, and will return 0 if such a transition occurs. A 1
1280 // is returned only after timing out. The maximum period
1281 // that this bit should be set is constrained to 244useconds.
1282 // The count I use below guarantees coverage or more than
1283 // this time, with any reasonable IPS setting.
1288 while (--count != 0) {
1289 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1292 return(1); // update-in-progress never transitioned to 0
1297 read_byte(seg, offset)
1307 mov ax, 4[bp] ; segment
1309 mov bx, 6[bp] ; offset
1311 ;; al = return value (byte)
1320 read_word(seg, offset)
1330 mov ax, 4[bp] ; segment
1332 mov bx, 6[bp] ; offset
1334 ;; ax = return value (word)
1343 write_byte(seg, offset, data)
1355 mov ax, 4[bp] ; segment
1357 mov bx, 6[bp] ; offset
1358 mov al, 8[bp] ; data byte
1359 mov [bx], al ; write data byte
1369 write_word(seg, offset, data)
1381 mov ax, 4[bp] ; segment
1383 mov bx, 6[bp] ; offset
1384 mov ax, 8[bp] ; data word
1385 mov [bx], ax ; write data word
1412 //set_DS(ds_selector)
1413 // Bit16u ds_selector;
1420 // mov ax, 4[bp] ; ds_selector
1440 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1441 if (nr_entries > 32)
1443 write_word(0xe000, 0x8, nr_entries);
1444 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1446 #endif /* HVMASSIST */
1449 /* serial debug port*/
1450 #define BX_DEBUG_PORT 0x03f8
1453 #define UART_RBR 0x00
1454 #define UART_THR 0x00
1457 #define UART_IER 0x01
1458 #define UART_IIR 0x02
1459 #define UART_FCR 0x02
1460 #define UART_LCR 0x03
1461 #define UART_MCR 0x04
1462 #define UART_DLL 0x00
1463 #define UART_DLM 0x01
1466 #define UART_LSR 0x05
1467 #define UART_MSR 0x06
1468 #define UART_SCR 0x07
1470 int uart_can_tx_byte(base_port)
1473 return inb(base_port + UART_LSR) & 0x20;
1476 void uart_wait_to_tx_byte(base_port)
1479 while (!uart_can_tx_byte(base_port));
1482 void uart_wait_until_sent(base_port)
1485 while (!(inb(base_port + UART_LSR) & 0x40));
1488 void uart_tx_byte(base_port, data)
1492 uart_wait_to_tx_byte(base_port);
1493 outb(base_port + UART_THR, data);
1494 uart_wait_until_sent(base_port);
1523 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1524 uart_tx_byte(BX_DEBUG_PORT, c);
1529 #if BX_VIRTUAL_PORTS
1530 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1531 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1533 if (action & BIOS_PRINTF_SCREEN) {
1534 if (c == '\n') wrch('\r');
1540 put_int(action, val, width, neg)
1545 short nval = val / 10;
1547 put_int(action, nval, width - 1, neg);
1549 while (--width > 0) send(action, ' ');
1550 if (neg) send(action, '-');
1552 send(action, val - (nval * 10) + '0');
1556 put_uint(action, val, width, neg)
1562 unsigned short nval = val / 10;
1564 put_uint(action, nval, width - 1, neg);
1566 while (--width > 0) send(action, ' ');
1567 if (neg) send(action, '-');
1569 send(action, val - (nval * 10) + '0');
1572 //--------------------------------------------------------------------------
1574 // A compact variable argument printf function which prints its output via
1575 // an I/O port so that it can be logged by Bochs/Plex.
1576 // Currently, only %x is supported (or %02x, %04x, etc).
1578 // Supports %[format_width][format]
1579 // where format can be d,x,c,s
1580 //--------------------------------------------------------------------------
1582 bios_printf(action, s)
1586 Bit8u c, format_char;
1590 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1598 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1599 #if BX_VIRTUAL_PORTS
1600 outb(PANIC_PORT2, 0x00);
1602 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1605 while (c = read_byte(get_CS(), s)) {
1610 else if (in_format) {
1611 if ( (c>='0') && (c<='9') ) {
1612 format_width = (format_width * 10) + (c - '0');
1615 arg_ptr++; // increment to next arg
1616 arg = read_word(arg_seg, arg_ptr);
1618 if (format_width == 0)
1620 for (i=format_width-1; i>=0; i--) {
1621 nibble = (arg >> (4 * i)) & 0x000f;
1622 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1625 else if (c == 'u') {
1626 put_uint(action, arg, format_width, 0);
1628 else if (c == 'd') {
1630 put_int(action, -arg, format_width - 1, 1);
1632 put_int(action, arg, format_width, 0);
1634 else if (c == 's') {
1635 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1637 else if (c == 'c') {
1641 BX_PANIC("bios_printf: unknown format\n");
1651 if (action & BIOS_PRINTF_HALT) {
1652 // freeze in a busy loop.
1662 //--------------------------------------------------------------------------
1664 //--------------------------------------------------------------------------
1665 // this file is based on LinuxBIOS implementation of keyboard.c
1666 // could convert to #asm to gain space
1673 BX_DEBUG("rombios: keyboard_init\n");
1675 /* printf("Assuming keyboard already inited and returning\n");
1678 /* ------------------- Flush buffers ------------------------*/
1679 /* Wait until buffer is empty */
1681 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1683 /* flush incoming keys */
1684 // temporarily chaged for debug -PAD
1689 if (inb(0x64) & 0x01) {
1695 // Due to timer issues, and if the IPS setting is > 15000000,
1696 // the incoming keys might not be flushed here. That will
1697 // cause a panic a few lines below. See sourceforge bug report :
1698 // [ 642031 ] FATAL: Keyboard RESET error:993
1700 /* ------------------- controller side ----------------------*/
1701 /* send cmd = 0xAA, self test 8042 */
1704 /* Wait until buffer is empty */
1706 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x02);
1707 if (max==0x0) keyboard_panic(00);
1711 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x03);
1712 if (max==0x0) keyboard_panic(01);
1714 /* read self-test result, 0x55 should be returned from 0x60 */
1715 if ((inb(0x60) != 0x55)){
1716 keyboard_panic(991);
1719 /* send cmd = 0xAB, keyboard interface test */
1722 /* Wait until buffer is empty */
1724 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1725 if (max==0x0) keyboard_panic(10);
1729 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1730 if (max==0x0) keyboard_panic(11);
1732 /* read keyboard interface test result, */
1733 /* 0x00 should be returned form 0x60 */
1734 if ((inb(0x60) != 0x00)) {
1735 keyboard_panic(992);
1738 /* Enable Keyboard clock */
1742 /* ------------------- keyboard side ------------------------*/
1743 /* reset kerboard and self test (keyboard side) */
1746 /* Wait until buffer is empty */
1748 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1749 if (max==0x0) keyboard_panic(20);
1753 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1754 if (max==0x0) keyboard_panic(21);
1756 /* keyboard should return ACK */
1757 if ((inb(0x60) != 0xfa)) {
1758 keyboard_panic(993);
1763 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1764 if (max==0x0) keyboard_panic(31);
1766 if ((inb(0x60) != 0xaa)) {
1767 keyboard_panic(994);
1770 /* Disable keyboard */
1773 /* Wait until buffer is empty */
1775 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1776 if (max==0x0) keyboard_panic(40);
1780 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1781 if (max==0x0) keyboard_panic(41);
1783 /* keyboard should return ACK */
1786 printf("rc=0x%x\n",rc);
1787 keyboard_panic(995);
1790 /* Write Keyboard Mode */
1793 /* Wait until buffer is empty */
1795 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1796 if (max==0x0) keyboard_panic(50);
1798 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1801 /* Wait until buffer is empty */
1803 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1804 if (max==0x0) keyboard_panic(60);
1806 /* Enable keyboard */
1809 /* Wait until buffer is empty */
1811 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1812 if (max==0x0) keyboard_panic(70);
1816 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1817 if (max==0x0) keyboard_panic(70);
1819 /* keyboard should return ACK */
1820 if ((inb(0x60) != 0xfa)) {
1821 keyboard_panic(996);
1825 printf("keyboard init done.\n");
1828 //--------------------------------------------------------------------------
1830 //--------------------------------------------------------------------------
1832 keyboard_panic(status)
1835 // If you're getting a 993 keyboard panic here,
1836 // please see the comment in keyboard_init
1837 printf("Keyboard error:%u CONTINUING\n",status); return;
1838 BX_PANIC("Keyboard error:%u\n",status);
1841 //--------------------------------------------------------------------------
1842 // shutdown_status_panic
1843 // called when the shutdown statsu is not implemented, displays the status
1844 //--------------------------------------------------------------------------
1846 shutdown_status_panic(status)
1849 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1852 //--------------------------------------------------------------------------
1853 // print_bios_banner
1854 // displays a the bios version
1855 //--------------------------------------------------------------------------
1859 printf("Hi from peter's modified bios\n");
1860 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1861 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1865 //--------------------------------------------------------------------------
1866 // print_boot_device
1867 // displays the boot device
1868 //--------------------------------------------------------------------------
1870 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1873 print_boot_device(cdboot, drive)
1874 Bit8u cdboot; Bit16u drive;
1878 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1879 // drive contains real/emulated boot drive
1881 if(cdboot)i=2; // CD-Rom
1882 else if((drive&0x0080)==0x00)i=0; // Floppy
1883 else if((drive&0x0080)==0x80)i=1; // Hard drive
1886 printf("Booting from %s...\n",drivetypes[i]);
1889 //--------------------------------------------------------------------------
1890 // print_boot_failure
1891 // displays the reason why boot failed
1892 //--------------------------------------------------------------------------
1894 print_boot_failure(cdboot, drive, reason, lastdrive)
1895 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1897 Bit16u drivenum = drive&0x7f;
1899 // cdboot: 1 if boot from cd, 0 otherwise
1900 // drive : drive number
1901 // reason: 0 signature check failed, 1 read error
1902 // lastdrive: 1 boot drive is the last one in boot sequence
1905 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1906 else if (drive & 0x80)
1907 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1909 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1913 BX_PANIC("Not a bootable disk\n");
1915 BX_PANIC("Could not read the boot disk\n");
1919 //--------------------------------------------------------------------------
1920 // print_cdromboot_failure
1921 // displays the reason why boot failed
1922 //--------------------------------------------------------------------------
1924 print_cdromboot_failure( code )
1927 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1935 BX_PANIC("NMI Handler called\n");
1941 BX_PANIC("INT18: BOOT FAILURE\n");
1948 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1950 BX_INFO("%s\n", bios_version_string);
1959 // Use PS2 System Control port A to set A20 enable
1961 // get current setting first
1964 // change A20 status
1966 outb(0x92, oldval | 0x02);
1968 outb(0x92, oldval & 0xfd);
1970 return((oldval & 0x02) != 0);
1987 // ---------------------------------------------------------------------------
1988 // Start of ATA/ATAPI Driver
1989 // ---------------------------------------------------------------------------
1991 // Global defines -- ATA register and register bits.
1992 // command block & control block regs
1993 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1994 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1995 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1996 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1997 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1998 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1999 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2000 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2001 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2002 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2003 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2004 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2005 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2007 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2008 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2009 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2010 #define ATA_CB_ER_MC 0x20 // ATA media change
2011 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2012 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2013 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2014 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2015 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2017 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2018 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2019 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2020 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2021 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2023 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2024 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2025 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2026 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2027 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2029 // bits 7-4 of the device/head (CB_DH) reg
2030 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2031 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2033 // status reg (CB_STAT and CB_ASTAT) bits
2034 #define ATA_CB_STAT_BSY 0x80 // busy
2035 #define ATA_CB_STAT_RDY 0x40 // ready
2036 #define ATA_CB_STAT_DF 0x20 // device fault
2037 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2038 #define ATA_CB_STAT_SKC 0x10 // seek complete
2039 #define ATA_CB_STAT_SERV 0x10 // service
2040 #define ATA_CB_STAT_DRQ 0x08 // data request
2041 #define ATA_CB_STAT_CORR 0x04 // corrected
2042 #define ATA_CB_STAT_IDX 0x02 // index
2043 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2044 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2046 // device control reg (CB_DC) bits
2047 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2048 #define ATA_CB_DC_SRST 0x04 // soft reset
2049 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2051 // Most mandtory and optional ATA commands (from ATA-3),
2052 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2053 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2054 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2055 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2056 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2057 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2058 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2059 #define ATA_CMD_DEVICE_RESET 0x08
2060 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2061 #define ATA_CMD_FLUSH_CACHE 0xE7
2062 #define ATA_CMD_FORMAT_TRACK 0x50
2063 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2064 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2065 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2066 #define ATA_CMD_IDLE1 0xE3
2067 #define ATA_CMD_IDLE2 0x97
2068 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2069 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2070 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2071 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2072 #define ATA_CMD_NOP 0x00
2073 #define ATA_CMD_PACKET 0xA0
2074 #define ATA_CMD_READ_BUFFER 0xE4
2075 #define ATA_CMD_READ_DMA 0xC8
2076 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2077 #define ATA_CMD_READ_MULTIPLE 0xC4
2078 #define ATA_CMD_READ_SECTORS 0x20
2079 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2080 #define ATA_CMD_RECALIBRATE 0x10
2081 #define ATA_CMD_SEEK 0x70
2082 #define ATA_CMD_SET_FEATURES 0xEF
2083 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2084 #define ATA_CMD_SLEEP1 0xE6
2085 #define ATA_CMD_SLEEP2 0x99
2086 #define ATA_CMD_STANDBY1 0xE2
2087 #define ATA_CMD_STANDBY2 0x96
2088 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2089 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2090 #define ATA_CMD_WRITE_BUFFER 0xE8
2091 #define ATA_CMD_WRITE_DMA 0xCA
2092 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2093 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2094 #define ATA_CMD_WRITE_SECTORS 0x30
2095 #define ATA_CMD_WRITE_VERIFY 0x3C
2097 #define ATA_IFACE_NONE 0x00
2098 #define ATA_IFACE_ISA 0x00
2099 #define ATA_IFACE_PCI 0x01
2101 #define ATA_TYPE_NONE 0x00
2102 #define ATA_TYPE_UNKNOWN 0x01
2103 #define ATA_TYPE_ATA 0x02
2104 #define ATA_TYPE_ATAPI 0x03
2106 #define ATA_DEVICE_NONE 0x00
2107 #define ATA_DEVICE_HD 0xFF
2108 #define ATA_DEVICE_CDROM 0x05
2110 #define ATA_MODE_NONE 0x00
2111 #define ATA_MODE_PIO16 0x00
2112 #define ATA_MODE_PIO32 0x01
2113 #define ATA_MODE_ISADMA 0x02
2114 #define ATA_MODE_PCIDMA 0x03
2115 #define ATA_MODE_USEIRQ 0x10
2117 #define ATA_TRANSLATION_NONE 0
2118 #define ATA_TRANSLATION_LBA 1
2119 #define ATA_TRANSLATION_LARGE 2
2120 #define ATA_TRANSLATION_RECHS 3
2122 #define ATA_DATA_NO 0x00
2123 #define ATA_DATA_IN 0x01
2124 #define ATA_DATA_OUT 0x02
2126 // ---------------------------------------------------------------------------
2127 // ATA/ATAPI driver : initialization
2128 // ---------------------------------------------------------------------------
2131 Bit16u ebda_seg=read_word(0x0040,0x000E);
2132 Bit8u channel, device;
2134 //BX_DEBUG("rombios: ata_init\n");
2136 // Channels info init.
2137 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2138 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2139 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2140 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2141 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2144 // Devices info init.
2145 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2146 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2147 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2148 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2149 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2150 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2151 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2152 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2153 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2154 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2155 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2156 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2157 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2158 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2160 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2163 // hdidmap and cdidmap init.
2164 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2165 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2166 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2169 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2170 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2173 // ---------------------------------------------------------------------------
2174 // ATA/ATAPI driver : device detection
2175 // ---------------------------------------------------------------------------
2179 Bit16u ebda_seg=read_word(0x0040,0x000E);
2180 Bit8u hdcount, cdcount, device, type;
2181 Bit8u buffer[0x0200];
2183 //BX_DEBUG("rombios: ata_detect\n");
2185 #if BX_MAX_ATA_INTERFACES > 0
2186 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2187 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2188 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2189 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2191 #if BX_MAX_ATA_INTERFACES > 1
2192 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2193 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2194 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2195 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2197 #if BX_MAX_ATA_INTERFACES > 2
2198 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2199 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2200 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2201 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2203 #if BX_MAX_ATA_INTERFACES > 3
2204 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2205 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2206 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2207 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2209 #if BX_MAX_ATA_INTERFACES > 4
2210 #error Please fill the ATA interface informations
2216 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2217 Bit16u iobase1, iobase2;
2218 Bit8u channel, slave, shift;
2219 Bit8u sc, sn, cl, ch, st;
2221 channel = device / 2;
2224 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2225 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2227 // Disable interrupts
2228 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2231 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2232 outb(iobase1+ATA_CB_SC, 0x55);
2233 outb(iobase1+ATA_CB_SN, 0xaa);
2234 outb(iobase1+ATA_CB_SC, 0xaa);
2235 outb(iobase1+ATA_CB_SN, 0x55);
2236 outb(iobase1+ATA_CB_SC, 0x55);
2237 outb(iobase1+ATA_CB_SN, 0xaa);
2239 // If we found something
2240 sc = inb(iobase1+ATA_CB_SC);
2241 sn = inb(iobase1+ATA_CB_SN);
2243 if ( (sc == 0x55) && (sn == 0xaa) ) {
2244 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2246 // reset the channel
2249 // check for ATA or ATAPI
2250 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2251 sc = inb(iobase1+ATA_CB_SC);
2252 sn = inb(iobase1+ATA_CB_SN);
2253 if ( (sc==0x01) && (sn==0x01) ) {
2254 cl = inb(iobase1+ATA_CB_CL);
2255 ch = inb(iobase1+ATA_CB_CH);
2256 st = inb(iobase1+ATA_CB_STAT);
2258 if ( (cl==0x14) && (ch==0xeb) ) {
2259 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2261 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2262 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2267 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2269 // Now we send a IDENTIFY command to ATA device
2270 if(type == ATA_TYPE_ATA) {
2272 Bit16u cylinders, heads, spt, blksize;
2273 Bit8u translation, removable, mode;
2275 // default mode to PIO16
2276 mode = ATA_MODE_PIO16;
2278 //Temporary values to do the transfer
2279 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2280 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2282 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2283 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2285 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2287 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2290 blksize = read_word(get_SS(),buffer+10);
2292 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2293 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2294 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2296 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2298 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2299 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2300 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2301 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2302 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2303 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2304 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2305 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2306 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2308 translation = inb_cmos(0x39 + channel/2);
2309 for (shift=device%4; shift>0; shift--) translation >>= 2;
2310 translation &= 0x03;
2312 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2314 switch (translation) {
2315 case ATA_TRANSLATION_NONE:
2318 case ATA_TRANSLATION_LBA:
2321 case ATA_TRANSLATION_LARGE:
2324 case ATA_TRANSLATION_RECHS:
2328 switch (translation) {
2329 case ATA_TRANSLATION_NONE:
2331 case ATA_TRANSLATION_LBA:
2334 heads = sectors / 1024;
2335 if (heads>128) heads = 255;
2336 else if (heads>64) heads = 128;
2337 else if (heads>32) heads = 64;
2338 else if (heads>16) heads = 32;
2340 cylinders = sectors / heads;
2342 case ATA_TRANSLATION_RECHS:
2343 // Take care not to overflow
2345 if(cylinders>61439) cylinders=61439;
2347 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2349 // then go through the large bitshift process
2350 case ATA_TRANSLATION_LARGE:
2351 while(cylinders > 1024) {
2355 // If we max out the head count
2356 if (heads > 127) break;
2360 // clip to 1024 cylinders in lchs
2361 if (cylinders > 1024) cylinders=1024;
2362 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2364 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2365 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2366 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2369 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2373 // Now we send a IDENTIFY command to ATAPI device
2374 if(type == ATA_TYPE_ATAPI) {
2376 Bit8u type, removable, mode;
2379 // default mode to PIO16
2380 mode = ATA_MODE_PIO16;
2382 //Temporary values to do the transfer
2383 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2384 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2386 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2387 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2389 type = read_byte(get_SS(),buffer+1) & 0x1f;
2390 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2392 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2396 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2397 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2398 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2399 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2402 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2409 Bit8u c, i, version, model[41];
2413 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2415 case ATA_TYPE_ATAPI:
2416 // Read ATA/ATAPI version
2417 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2418 for(version=15;version>0;version--) {
2419 if((ataversion&(1<<version))!=0)
2425 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2426 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2430 write_byte(get_SS(),model+40,0x00);
2432 if(read_byte(get_SS(),model+i)==0x20)
2433 write_byte(get_SS(),model+i,0x00);
2441 printf("ata%d %s: ",channel,slave?" slave":"master");
2442 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2443 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2445 case ATA_TYPE_ATAPI:
2446 printf("ata%d %s: ",channel,slave?" slave":"master");
2447 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2448 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2449 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2451 printf(" ATAPI-%d Device\n",version);
2453 case ATA_TYPE_UNKNOWN:
2454 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2460 // Store the devices counts
2461 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2462 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2463 write_byte(0x40,0x75, hdcount);
2467 // FIXME : should use bios=cmos|auto|disable bits
2468 // FIXME : should know about translation bits
2469 // FIXME : move hard_drive_post here
2473 // ---------------------------------------------------------------------------
2474 // ATA/ATAPI driver : software reset
2475 // ---------------------------------------------------------------------------
2477 // 8.2.1 Software reset - Device 0
2479 void ata_reset(device)
2482 Bit16u ebda_seg=read_word(0x0040,0x000E);
2483 Bit16u iobase1, iobase2;
2484 Bit8u channel, slave, sn, sc;
2487 channel = device / 2;
2490 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2491 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2495 // 8.2.1 (a) -- set SRST in DC
2496 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2498 // 8.2.1 (b) -- wait for BSY
2501 Bit8u status = inb(iobase1+ATA_CB_STAT);
2502 if ((status & ATA_CB_STAT_BSY) != 0) break;
2505 // 8.2.1 (f) -- clear SRST
2506 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2508 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2510 // 8.2.1 (g) -- check for sc==sn==0x01
2512 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2513 sc = inb(iobase1+ATA_CB_SC);
2514 sn = inb(iobase1+ATA_CB_SN);
2516 if ( (sc==0x01) && (sn==0x01) ) {
2518 // 8.2.1 (h) -- wait for not BSY
2521 Bit8u status = inb(iobase1+ATA_CB_STAT);
2522 if ((status & ATA_CB_STAT_BSY) == 0) break;
2527 // 8.2.1 (i) -- wait for DRDY
2530 Bit8u status = inb(iobase1+ATA_CB_STAT);
2531 if ((status & ATA_CB_STAT_RDY) != 0) break;
2534 // Enable interrupts
2535 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2538 // ---------------------------------------------------------------------------
2539 // ATA/ATAPI driver : execute a non data command
2540 // ---------------------------------------------------------------------------
2542 Bit16u ata_cmd_non_data()
2545 // ---------------------------------------------------------------------------
2546 // ATA/ATAPI driver : execute a data-in command
2547 // ---------------------------------------------------------------------------
2552 // 3 : expected DRQ=1
2553 // 4 : no sectors left to read/verify
2554 // 5 : more sectors to read/verify
2555 // 6 : no sectors left to write
2556 // 7 : more sectors to write
2557 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2558 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2561 Bit16u ebda_seg=read_word(0x0040,0x000E);
2562 Bit16u iobase1, iobase2, blksize;
2563 Bit8u channel, slave;
2564 Bit8u status, current, mode;
2566 channel = device / 2;
2569 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2570 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2571 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2572 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2573 if (mode == ATA_MODE_PIO32) blksize>>=2;
2576 // sector will be 0 only on lba access. Convert to lba-chs
2578 sector = (Bit16u) (lba & 0x000000ffL);
2580 cylinder = (Bit16u) (lba & 0x0000ffffL);
2582 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2585 // Reset count of transferred data
2586 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2587 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2590 status = inb(iobase1 + ATA_CB_STAT);
2591 if (status & ATA_CB_STAT_BSY) return 1;
2593 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2594 outb(iobase1 + ATA_CB_FR, 0x00);
2595 outb(iobase1 + ATA_CB_SC, count);
2596 outb(iobase1 + ATA_CB_SN, sector);
2597 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2598 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2599 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2600 outb(iobase1 + ATA_CB_CMD, command);
2603 status = inb(iobase1 + ATA_CB_STAT);
2604 if ( !(status & ATA_CB_STAT_BSY) ) break;
2607 if (status & ATA_CB_STAT_ERR) {
2608 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2610 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2611 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2615 // FIXME : move seg/off translation here
2618 sti ;; enable higher priority interrupts
2626 mov di, _ata_cmd_data_in.offset + 2[bp]
2627 mov ax, _ata_cmd_data_in.segment + 2[bp]
2628 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2630 ;; adjust if there will be an overrun. 2K max sector size
2632 jbe ata_in_no_adjust
2635 sub di, #0x0800 ;; sub 2 kbytes from offset
2636 add ax, #0x0080 ;; add 2 Kbytes to segment
2639 mov es, ax ;; segment in es
2641 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2643 mov ah, _ata_cmd_data_in.mode + 2[bp]
2644 cmp ah, #ATA_MODE_PIO32
2649 insw ;; CX words transfered from port(DX) to ES:[DI]
2654 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2657 mov _ata_cmd_data_in.offset + 2[bp], di
2658 mov _ata_cmd_data_in.segment + 2[bp], es
2663 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2665 status = inb(iobase1 + ATA_CB_STAT);
2667 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2668 != ATA_CB_STAT_RDY ) {
2669 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2675 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2676 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2677 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2683 // Enable interrupts
2684 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2688 // ---------------------------------------------------------------------------
2689 // ATA/ATAPI driver : execute a data-out command
2690 // ---------------------------------------------------------------------------
2695 // 3 : expected DRQ=1
2696 // 4 : no sectors left to read/verify
2697 // 5 : more sectors to read/verify
2698 // 6 : no sectors left to write
2699 // 7 : more sectors to write
2700 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2701 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2704 Bit16u ebda_seg=read_word(0x0040,0x000E);
2705 Bit16u iobase1, iobase2, blksize;
2706 Bit8u channel, slave;
2707 Bit8u status, current, mode;
2709 channel = device / 2;
2712 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2713 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2714 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2715 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2716 if (mode == ATA_MODE_PIO32) blksize>>=2;
2719 // sector will be 0 only on lba access. Convert to lba-chs
2721 sector = (Bit16u) (lba & 0x000000ffL);
2723 cylinder = (Bit16u) (lba & 0x0000ffffL);
2725 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2728 // Reset count of transferred data
2729 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2730 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2733 status = inb(iobase1 + ATA_CB_STAT);
2734 if (status & ATA_CB_STAT_BSY) return 1;
2736 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2737 outb(iobase1 + ATA_CB_FR, 0x00);
2738 outb(iobase1 + ATA_CB_SC, count);
2739 outb(iobase1 + ATA_CB_SN, sector);
2740 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2741 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2742 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2743 outb(iobase1 + ATA_CB_CMD, command);
2746 status = inb(iobase1 + ATA_CB_STAT);
2747 if ( !(status & ATA_CB_STAT_BSY) ) break;
2750 if (status & ATA_CB_STAT_ERR) {
2751 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2753 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2754 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2758 // FIXME : move seg/off translation here
2761 sti ;; enable higher priority interrupts
2769 mov si, _ata_cmd_data_out.offset + 2[bp]
2770 mov ax, _ata_cmd_data_out.segment + 2[bp]
2771 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2773 ;; adjust if there will be an overrun. 2K max sector size
2775 jbe ata_out_no_adjust
2778 sub si, #0x0800 ;; sub 2 kbytes from offset
2779 add ax, #0x0080 ;; add 2 Kbytes to segment
2782 mov es, ax ;; segment in es
2784 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2786 mov ah, _ata_cmd_data_out.mode + 2[bp]
2787 cmp ah, #ATA_MODE_PIO32
2793 outsw ;; CX words transfered from port(DX) to ES:[SI]
2799 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2802 mov _ata_cmd_data_out.offset + 2[bp], si
2803 mov _ata_cmd_data_out.segment + 2[bp], es
2808 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2810 status = inb(iobase1 + ATA_CB_STAT);
2812 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2813 != ATA_CB_STAT_RDY ) {
2814 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2820 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2821 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2822 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2828 // Enable interrupts
2829 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2833 // ---------------------------------------------------------------------------
2834 // ATA/ATAPI driver : execute a packet command
2835 // ---------------------------------------------------------------------------
2838 // 1 : error in parameters
2842 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2844 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2848 Bit16u ebda_seg=read_word(0x0040,0x000E);
2849 Bit16u iobase1, iobase2;
2850 Bit16u lcount, lbefore, lafter, count;
2851 Bit8u channel, slave;
2852 Bit8u status, mode, lmode;
2853 Bit32u total, transfer;
2855 channel = device / 2;
2858 // Data out is not supported yet
2859 if (inout == ATA_DATA_OUT) {
2860 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2864 // The header length must be even
2866 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2870 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2871 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2872 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2875 if (cmdlen < 12) cmdlen=12;
2876 if (cmdlen > 12) cmdlen=16;
2879 // Reset count of transferred data
2880 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2881 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2883 // Device should not be busy yet
2888 // wait for device to be ready
2890 status = inb(iobase1 + ATA_CB_STAT);
2891 // BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2892 } while (status & ATA_CB_STAT_BSY);
2894 status = inb(iobase1 + ATA_CB_STAT);
2895 if (status & ATA_CB_STAT_BSY) return 2;
2899 // set "noninterruptable"
2900 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2902 //outb(iobase1 + ATA_CB_FR, 0x00);
2903 //outb(iobase1 + ATA_CB_SC, 0x00);
2904 //outb(iobase1 + ATA_CB_SN, 0x00);
2906 // Set cylinders ?? - Why? And why not sector
2907 // This is all embedded in cmd_packet, anyway...
2908 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2909 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2911 // select master or slave
2912 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2914 // Tell it we are sending a command packet
2915 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2918 // Now wait for 400 ns
2921 for (i=0;i<0xffff; i++)
2926 // Device should ok to receive command
2927 // wait until we get
2930 status = inb(iobase1 + ATA_CB_STAT);
2933 if (!(status & ATA_CB_STAT_BSY)) break;
2935 // Shouldn't this be ATA_CB_STAT_RDY? -PAD - NO, it's OK
2936 if ( !(status & ATA_CB_STAT_BSY) ) break;
2941 if (status & ATA_CB_STAT_ERR) {
2942 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2944 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2945 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2949 // Normalize address
2950 cmdseg += (cmdoff / 16);
2953 // Send command to device
2955 sti ;; enable higher priority interrupts
2960 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2961 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2962 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2963 mov es, ax ;; segment in es
2965 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2969 outsw ;; CX words transfered from port(DX) to ES:[SI]
2974 // issue read of alternative status - claimed to be in spec
2975 //inb(iobase2+ATA_CB_ASTAT);
2978 if (inout == ATA_DATA_NO) {
2979 status = inb(iobase1 + ATA_CB_STAT);
2982 // Wait for completion
2985 status=inb(iobase1+ATA_CB_STAT);
2986 BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2987 } while ((status & ATA_CB_STAT_BSY));
2991 status = inb(iobase1 + ATA_CB_STAT);
2993 // Check if command completed
2994 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2996 if (status & ATA_CB_STAT_ERR) {
2997 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3001 // If we get here, we are ready and should have DRQ
3002 // and so data is available
3003 // Device must be ready to send data
3004 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3005 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3006 BX_DEBUG_ATA("ata_cmd_packet 1: not ready (status %02x)\n", status);
3010 // Normalize address
3011 bufseg += (bufoff / 16);
3014 // Get the byte count
3015 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3017 // adjust to read what we want
3030 lafter=lcount-length;
3042 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3043 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3045 // If counts not dividable by 4, use 16bits mode
3047 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3048 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3049 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3051 // adds an extra byte if count are odd. before is always even
3052 if (lcount & 0x01) {
3054 if ((lafter > 0) && (lafter & 0x01)) {
3059 if (lmode == ATA_MODE_PIO32) {
3060 lcount>>=2; lbefore>>=2; lafter>>=2;
3063 lcount>>=1; lbefore>>=1; lafter>>=1;
3072 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3074 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3075 jcxz ata_packet_no_before
3077 mov ah, _ata_cmd_packet.lmode + 2[bp]
3078 cmp ah, #ATA_MODE_PIO32
3079 je ata_packet_in_before_32
3081 ata_packet_in_before_16:
3083 loop ata_packet_in_before_16
3084 jmp ata_packet_no_before
3086 ata_packet_in_before_32:
3088 ata_packet_in_before_32_loop:
3090 loop ata_packet_in_before_32_loop
3093 ata_packet_no_before:
3094 mov cx, _ata_cmd_packet.lcount + 2[bp]
3095 jcxz ata_packet_after
3097 mov di, _ata_cmd_packet.bufoff + 2[bp]
3098 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3101 mov ah, _ata_cmd_packet.lmode + 2[bp]
3102 cmp ah, #ATA_MODE_PIO32
3107 insw ;; CX words transfered tp port(DX) to ES:[DI]
3108 jmp ata_packet_after
3112 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3115 mov cx, _ata_cmd_packet.lafter + 2[bp]
3116 jcxz ata_packet_done
3118 mov ah, _ata_cmd_packet.lmode + 2[bp]
3119 cmp ah, #ATA_MODE_PIO32
3120 je ata_packet_in_after_32
3122 ata_packet_in_after_16:
3124 loop ata_packet_in_after_16
3127 ata_packet_in_after_32:
3129 ata_packet_in_after_32_loop:
3131 loop ata_packet_in_after_32_loop
3138 // Compute new buffer address
3141 // Save transferred bytes count
3143 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3147 // Final check, device must be ready
3148 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3149 != ATA_CB_STAT_RDY ) {
3150 BX_DEBUG_ATA("ata_cmd_packet 2 : not ready (status %02x)\n", (unsigned) status);
3154 // Enable interrupts
3155 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3159 // ---------------------------------------------------------------------------
3160 // End of ATA/ATAPI Driver
3161 // ---------------------------------------------------------------------------
3164 // ---------------------------------------------------------------------------
3165 // Start of ATA/ATAPI generic functions
3166 // ---------------------------------------------------------------------------
3169 atapi_get_sense(device)
3176 memsetb(get_SS(),atacmd,0,12);
3181 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3184 if ((buffer[0] & 0x7e) == 0x70) {
3185 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3192 atapi_is_ready(device)
3198 memsetb(get_SS(),atacmd,0,12);
3201 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3204 if (atapi_get_sense(device) !=0 ) {
3205 memsetb(get_SS(),atacmd,0,12);
3207 // try to send Test Unit Ready again
3208 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3211 return atapi_get_sense(device);
3217 atapi_is_cdrom(device)
3220 Bit16u ebda_seg=read_word(0x0040,0x000E);
3222 if (device >= BX_MAX_ATA_DEVICES)
3225 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3228 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3234 // ---------------------------------------------------------------------------
3235 // End of ATA/ATAPI generic functions
3236 // ---------------------------------------------------------------------------
3238 #endif // BX_USE_ATADRV
3240 #if BX_ELTORITO_BOOT
3242 // ---------------------------------------------------------------------------
3243 // Start of El-Torito boot functions
3244 // ---------------------------------------------------------------------------
3249 Bit16u ebda_seg=read_word(0x0040,0x000E);
3251 //BX_DEBUG("rombios: cdemu_init\n");
3253 // the only important data is this one for now
3254 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3260 Bit16u ebda_seg=read_word(0x0040,0x000E);
3262 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3266 cdemu_emulated_drive()
3268 Bit16u ebda_seg=read_word(0x0040,0x000E);
3270 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3273 static char isotag[6]="CD001";
3274 static char eltorito[24]="EL TORITO SPECIFICATION";
3276 // Returns ah: emulated drive, al: error code
3281 Bit16u ebda_seg=read_word(0x0040,0x000E);
3282 Bit8u atacmd[12], buffer[2048];
3284 Bit16u boot_segment, nbsectors, i, error;
3288 // Find out the first cdrom
3289 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3290 if (atapi_is_cdrom(device)) break;
3294 if(device >= BX_MAX_ATA_DEVICES) return 2;
3296 // Read the Boot Record Volume Descriptor
3297 memsetb(get_SS(),atacmd,0,12);
3298 atacmd[0]=0x28; // READ command
3299 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3300 atacmd[8]=(0x01 & 0x00ff); // Sectors
3301 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3302 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3303 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3304 atacmd[5]=(0x11 & 0x000000ff);
3305 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3310 if(buffer[0]!=0)return 4;
3312 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3315 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3317 // ok, now we calculate the Boot catalog address
3318 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3320 // And we read the Boot Catalog
3321 memsetb(get_SS(),atacmd,0,12);
3322 atacmd[0]=0x28; // READ command
3323 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3324 atacmd[8]=(0x01 & 0x00ff); // Sectors
3325 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3326 atacmd[3]=(lba & 0x00ff0000) >> 16;
3327 atacmd[4]=(lba & 0x0000ff00) >> 8;
3328 atacmd[5]=(lba & 0x000000ff);
3329 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3335 if(buffer[0x00]!=0x01)return 8; // Header
3336 if(buffer[0x01]!=0x00)return 9; // Platform
3337 if(buffer[0x1E]!=0x55)return 10; // key 1
3338 if(buffer[0x1F]!=0xAA)return 10; // key 2
3340 // Initial/Default Entry
3341 if(buffer[0x20]!=0x88)return 11; // Bootable
3343 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3344 if(buffer[0x21]==0){
3345 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3346 // Win2000 cd boot needs to know it booted from cd
3347 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3349 else if(buffer[0x21]<4)
3350 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3352 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3354 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3355 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3357 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3358 if(boot_segment==0x0000)boot_segment=0x07C0;
3360 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3361 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3363 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3364 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3366 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3367 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3369 // And we read the image in memory
3370 memsetb(get_SS(),atacmd,0,12);
3371 atacmd[0]=0x28; // READ command
3372 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3373 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3374 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3375 atacmd[3]=(lba & 0x00ff0000) >> 16;
3376 atacmd[4]=(lba & 0x0000ff00) >> 8;
3377 atacmd[5]=(lba & 0x000000ff);
3378 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3382 // Remember the media type
3383 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3384 case 0x01: // 1.2M floppy
3385 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3386 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3387 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3389 case 0x02: // 1.44M floppy
3390 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3391 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3392 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3394 case 0x03: // 2.88M floppy
3395 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3396 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3397 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3399 case 0x04: // Harddrive
3400 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3401 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3402 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3403 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3407 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3408 // Increase bios installed hardware number of devices
3409 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3410 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3412 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3416 // everything is ok, so from now on, the emulation is active
3417 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3418 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3420 // return the boot drive + no error
3421 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3424 // ---------------------------------------------------------------------------
3425 // End of El-Torito boot functions
3426 // ---------------------------------------------------------------------------
3427 #endif // BX_ELTORITO_BOOT
3430 int14_function(regs, ds, iret_addr)
3431 pusha_regs_t regs; // regs pushed from PUSHA instruction
3432 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3433 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3435 Bit16u addr,timer,val16;
3442 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3443 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3444 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3445 switch (regs.u.r8.ah) {
3447 outb(addr+3, inb(addr+3) | 0x80);
3448 if (regs.u.r8.al & 0xE0 == 0) {
3452 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3453 outb(addr, val16 & 0xFF);
3454 outb(addr+1, val16 >> 8);
3456 outb(addr+3, regs.u.r8.al & 0x1F);
3457 regs.u.r8.ah = inb(addr+5);
3458 regs.u.r8.al = inb(addr+6);
3459 ClearCF(iret_addr.flags);
3462 timer = read_word(0x0040, 0x006C);
3463 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3464 val16 = read_word(0x0040, 0x006C);
3465 if (val16 != timer) {
3470 if (timeout) outb(addr, regs.u.r8.al);
3471 regs.u.r8.ah = inb(addr+5);
3472 if (!timeout) regs.u.r8.ah |= 0x80;
3473 ClearCF(iret_addr.flags);
3476 timer = read_word(0x0040, 0x006C);
3477 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3478 val16 = read_word(0x0040, 0x006C);
3479 if (val16 != timer) {
3486 regs.u.r8.al = inb(addr);
3488 regs.u.r8.ah = inb(addr+5);
3490 ClearCF(iret_addr.flags);
3493 regs.u.r8.ah = inb(addr+5);
3494 regs.u.r8.al = inb(addr+6);
3495 ClearCF(iret_addr.flags);
3498 SetCF(iret_addr.flags); // Unsupported
3501 SetCF(iret_addr.flags); // Unsupported
3506 int15_function(regs, ES, DS, FLAGS)
3507 pusha_regs_t regs; // REGS pushed via pusha
3508 Bit16u ES, DS, FLAGS;
3510 Bit16u ebda_seg=read_word(0x0040,0x000E);
3511 bx_bool prev_a20_enable;
3520 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3522 switch (regs.u.r8.ah) {
3523 case 0x24: /* A20 Control */
3524 switch (regs.u.r8.al) {
3536 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3546 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3548 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3554 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3558 /* keyboard intercept */
3560 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3567 case 0x52: // removable media eject
3569 regs.u.r8.ah = 0; // "ok ejection may proceed"
3573 if( regs.u.r8.al == 0 ) {
3574 // Set Interval requested.
3575 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3576 // Interval not already set.
3577 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3578 write_word( 0x40, 0x98, ES ); // Byte location, segment
3579 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3580 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3581 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3583 irqDisable = inb( 0xA1 );
3584 outb( 0xA1, irqDisable & 0xFE );
3585 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3586 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3588 // Interval already set.
3589 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3591 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3593 } else if( regs.u.r8.al == 1 ) {
3594 // Clear Interval requested
3595 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3597 bRegister = inb_cmos( 0xB );
3598 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3600 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3602 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3611 # error "Int15 function 87h not supported on < 80386"
3613 // +++ should probably have descriptor checks
3614 // +++ should have exception handlers
3616 // turn off interrupts
3621 prev_a20_enable = set_enable_a20(1); // enable A20 line
3623 // 128K max of transfer on 386+ ???
3624 // source == destination ???
3626 // ES:SI points to descriptor table
3627 // offset use initially comments
3628 // ==============================================
3629 // 00..07 Unused zeros Null descriptor
3630 // 08..0f GDT zeros filled in by BIOS
3631 // 10..17 source ssssssss source of data
3632 // 18..1f dest dddddddd destination of data
3633 // 20..27 CS zeros filled in by BIOS
3634 // 28..2f SS zeros filled in by BIOS
3641 // check for access rights of source & dest here
3643 // Initialize GDT descriptor
3644 base15_00 = (ES << 4) + regs.u.r16.si;
3645 base23_16 = ES >> 12;
3646 if (base15_00 < (ES<<4))
3648 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3649 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3650 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3651 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3652 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3654 // Initialize CS descriptor
3655 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3656 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3657 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3658 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3659 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3661 // Initialize SS descriptor
3663 base15_00 = ss << 4;
3664 base23_16 = ss >> 12;
3665 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3666 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3667 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3668 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3669 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3673 // Compile generates locals offset info relative to SP.
3674 // Get CX (word count) from stack.
3677 mov cx, _int15_function.CX [bx]
3679 // since we need to set SS:SP, save them to the BDA
3680 // for future restore
3690 lidt [pmode_IDT_info]
3691 ;; perhaps do something with IDT here
3693 ;; set PE bit in CR0
3697 ;; far jump to flush CPU queue after transition to protected mode
3698 JMP_AP(0x0020, protected_mode)
3701 ;; GDT points to valid descriptor table, now load SS, DS, ES
3702 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3704 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3706 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3712 movsw ;; move CX words from DS:SI to ES:DI
3714 ;; make sure DS and ES limits are 64KB
3719 ;; reset PG bit in CR0 ???
3724 ;; far jump to flush CPU queue after transition to real mode
3725 JMP_AP(0xf000, real_mode)
3728 ;; restore IDT to normal real-mode defaults
3730 lidt [rmode_IDT_info]
3732 // restore SS:SP from the BDA
3740 set_enable_a20(prev_a20_enable);
3742 // turn back on interrupts
3753 // Get the amount of extended memory (above 1M)
3755 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3758 regs.u.r8.al = inb_cmos(0x30);
3759 regs.u.r8.ah = inb_cmos(0x31);
3762 if(regs.u.r16.ax > 0x3c00)
3763 regs.u.r16.ax = 0x3c00;
3770 /* Device busy interrupt. Called by Int 16h when no key available */
3774 /* Interrupt complete. Called by Int 16h when key becomes available */
3778 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3780 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3786 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3791 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3801 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3803 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3807 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3808 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3810 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3815 #if BX_USE_PS2_MOUSE
3817 int15_function_mouse(regs, ES, DS, FLAGS)
3818 pusha_regs_t regs; // REGS pushed via pusha
3819 Bit16u ES, DS, FLAGS;
3821 Bit16u ebda_seg=read_word(0x0040,0x000E);
3822 Bit8u mouse_flags_1, mouse_flags_2;
3823 Bit16u mouse_driver_seg;
3824 Bit16u mouse_driver_offset;
3825 Bit8u comm_byte, prev_command_byte;
3826 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3828 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3830 switch (regs.u.r8.ah) {
3832 // Return Codes status in AH
3833 // =========================
3835 // 01: invalid subfunction (AL > 7)
3836 // 02: invalid input value (out of allowable range)
3837 // 03: interface error
3838 // 04: resend command received from mouse controller,
3839 // device driver should attempt command again
3840 // 05: cannot enable mouse, since no far call has been installed
3841 // 80/86: mouse service not implemented
3843 switch (regs.u.r8.al) {
3844 case 0: // Disable/Enable Mouse
3845 BX_DEBUG_INT15("case 0:\n");
3846 switch (regs.u.r8.bh) {
3847 case 0: // Disable Mouse
3848 BX_DEBUG_INT15("case 0: disable mouse\n");
3849 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3850 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3852 ret = get_mouse_data(&mouse_data1);
3853 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3866 case 1: // Enable Mouse
3867 BX_DEBUG_INT15("case 1: enable mouse\n");
3868 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3869 if ( (mouse_flags_2 & 0x80) == 0 ) {
3870 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3872 regs.u.r8.ah = 5; // no far call installed
3875 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3876 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3878 ret = get_mouse_data(&mouse_data1);
3879 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3880 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3890 default: // invalid subfunction
3891 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3893 regs.u.r8.ah = 1; // invalid subfunction
3898 case 1: // Reset Mouse
3899 case 5: // Initialize Mouse
3900 BX_DEBUG_INT15("case 1 or 5:\n");
3901 if (regs.u.r8.al == 5) {
3902 if (regs.u.r8.bh != 3) {
3904 regs.u.r8.ah = 0x02; // invalid input
3907 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3908 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3909 mouse_flags_1 = 0x00;
3910 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3911 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3914 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3915 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3917 ret = get_mouse_data(&mouse_data3);
3918 // if no mouse attached, it will return RESEND
3919 if (mouse_data3 == 0xfe) {
3923 if (mouse_data3 != 0xfa)
3924 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3926 ret = get_mouse_data(&mouse_data1);
3928 ret = get_mouse_data(&mouse_data2);
3930 // turn IRQ12 and packet generation on
3931 enable_mouse_int_and_events();
3934 regs.u.r8.bl = mouse_data1;
3935 regs.u.r8.bh = mouse_data2;
3947 case 2: // Set Sample Rate
3948 BX_DEBUG_INT15("case 2:\n");
3949 switch (regs.u.r8.bh) {
3950 case 0: mouse_data1 = 10; break; // 10 reports/sec
3951 case 1: mouse_data1 = 20; break; // 20 reports/sec
3952 case 2: mouse_data1 = 40; break; // 40 reports/sec
3953 case 3: mouse_data1 = 60; break; // 60 reports/sec
3954 case 4: mouse_data1 = 80; break; // 80 reports/sec
3955 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3956 case 6: mouse_data1 = 200; break; // 200 reports/sec
3957 default: mouse_data1 = 0;
3959 if (mouse_data1 > 0) {
3960 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3962 ret = get_mouse_data(&mouse_data2);
3963 ret = send_to_mouse_ctrl(mouse_data1);
3964 ret = get_mouse_data(&mouse_data2);
3970 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3975 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3979 case 3: // Set Resolution
3980 BX_DEBUG_INT15("case 3:\n");
3982 // 0 = 25 dpi, 1 count per millimeter
3983 // 1 = 50 dpi, 2 counts per millimeter
3984 // 2 = 100 dpi, 4 counts per millimeter
3985 // 3 = 200 dpi, 8 counts per millimeter
3990 case 4: // Get Device ID
3991 BX_DEBUG_INT15("case 4:\n");
3992 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3993 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3995 ret = get_mouse_data(&mouse_data1);
3996 ret = get_mouse_data(&mouse_data2);
3999 regs.u.r8.bh = mouse_data2;
4003 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4007 case 6: // Return Status & Set Scaling Factor...
4008 BX_DEBUG_INT15("case 6:\n");
4009 switch (regs.u.r8.bh) {
4010 case 0: // Return Status
4011 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4012 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4014 ret = get_mouse_data(&mouse_data1);
4015 if (mouse_data1 != 0xfa)
4016 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4018 ret = get_mouse_data(&mouse_data1);
4020 ret = get_mouse_data(&mouse_data2);
4022 ret = get_mouse_data(&mouse_data3);
4026 regs.u.r8.bl = mouse_data1;
4027 regs.u.r8.cl = mouse_data2;
4028 regs.u.r8.dl = mouse_data3;
4029 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4040 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4043 case 1: // Set Scaling Factor to 1:1
4044 case 2: // Set Scaling Factor to 2:1
4045 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4046 if (regs.u.r8.bh == 1) {
4047 ret = send_to_mouse_ctrl(0xE6);
4049 ret = send_to_mouse_ctrl(0xE7);
4052 get_mouse_data(&mouse_data1);
4053 ret = (mouse_data1 != 0xFA);
4061 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4063 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4067 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4071 case 7: // Set Mouse Handler Address
4072 BX_DEBUG_INT15("case 7:\n");
4073 mouse_driver_seg = ES;
4074 mouse_driver_offset = regs.u.r16.bx;
4075 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4076 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4077 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4078 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4079 /* remove handler */
4080 if ( (mouse_flags_2 & 0x80) != 0 ) {
4081 mouse_flags_2 &= ~0x80;
4082 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4086 /* install handler */
4087 mouse_flags_2 |= 0x80;
4089 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4095 BX_DEBUG_INT15("case default:\n");
4096 regs.u.r8.ah = 1; // invalid function
4102 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4103 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4105 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4112 int15_function32(regs, ES, DS, FLAGS)
4113 pushad_regs_t regs; // REGS pushed via pushad
4114 Bit16u ES, DS, FLAGS;
4116 Bit32u extended_memory_size=0; // 64bits long
4119 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4121 switch (regs.u.r8.ah) {
4123 // Wait for CX:DX microseconds. currently using the
4124 // refresh request port 0x61 bit4, toggling every 15usec
4132 ;; Get the count in eax
4135 mov ax, _int15_function.CX [bx]
4138 mov ax, _int15_function.DX [bx]
4140 ;; convert to numbers of 15usec ticks
4146 ;; wait for ecx number of refresh requests
4167 switch(regs.u.r8.al)
4169 case 0x20: // coded by osmaker aka K.J.
4170 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4172 #if defined(HVMASSIST) && 0
4173 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4175 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4177 BX_DEBUG_INT15("OK bx=%x\n",regs.u.r16.bx);
4179 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4180 memcpyb(ES, regs.u.r16.di,
4181 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4183 regs.u.r32.ebx += 0x14;
4184 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4186 regs.u.r32.eax = 0x534D4150;
4187 regs.u.r32.ecx = 0x14;
4190 } else if (regs.u.r16.bx == 1) {
4191 extended_memory_size = inb_cmos(0x35);
4192 extended_memory_size <<= 8;
4193 extended_memory_size |= inb_cmos(0x34);
4194 extended_memory_size *= 64;
4195 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4197 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4199 extended_memory_size *= 1024;
4200 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4202 if (extended_memory_size <= 15728640)
4204 extended_memory_size = inb_cmos(0x31);
4205 extended_memory_size <<= 8;
4206 extended_memory_size |= inb_cmos(0x30);
4207 extended_memory_size *= 1024;
4210 write_word(ES, regs.u.r16.di, 0x0000);
4211 write_word(ES, regs.u.r16.di+2, 0x0010);
4212 write_word(ES, regs.u.r16.di+4, 0x0000);
4213 write_word(ES, regs.u.r16.di+6, 0x0000);
4215 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4216 extended_memory_size >>= 16;
4217 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4218 extended_memory_size >>= 16;
4219 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4220 extended_memory_size >>= 16;
4221 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4223 write_word(ES, regs.u.r16.di+16, 0x1);
4224 write_word(ES, regs.u.r16.di+18, 0x0);
4227 regs.u.r32.eax = 0x534D4150;
4228 regs.u.r32.ecx = 0x14;
4231 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4232 goto int15_unimplemented;
4235 switch(regs.u.r16.bx)
4238 write_word(ES, regs.u.r16.di, 0x00);
4239 write_word(ES, regs.u.r16.di+2, 0x00);
4240 write_word(ES, regs.u.r16.di+4, 0x00);
4241 write_word(ES, regs.u.r16.di+6, 0x00);
4243 write_word(ES, regs.u.r16.di+8, 0xFC00);
4244 write_word(ES, regs.u.r16.di+10, 0x0009);
4245 write_word(ES, regs.u.r16.di+12, 0x0000);
4246 write_word(ES, regs.u.r16.di+14, 0x0000);
4248 write_word(ES, regs.u.r16.di+16, 0x1);
4249 write_word(ES, regs.u.r16.di+18, 0x0);
4253 regs.u.r32.eax = 0x534D4150;
4254 regs.u.r32.ecx = 0x14;
4259 extended_memory_size = inb_cmos(0x35);
4260 extended_memory_size <<= 8;
4261 extended_memory_size |= inb_cmos(0x34);
4262 extended_memory_size *= 64;
4263 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4265 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4267 extended_memory_size *= 1024;
4268 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4270 if(extended_memory_size <= 15728640)
4272 extended_memory_size = inb_cmos(0x31);
4273 extended_memory_size <<= 8;
4274 extended_memory_size |= inb_cmos(0x30);
4275 extended_memory_size *= 1024;
4278 write_word(ES, regs.u.r16.di, 0x0000);
4279 write_word(ES, regs.u.r16.di+2, 0x0010);
4280 write_word(ES, regs.u.r16.di+4, 0x0000);
4281 write_word(ES, regs.u.r16.di+6, 0x0000);
4283 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4284 extended_memory_size >>= 16;
4285 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4286 extended_memory_size >>= 16;
4287 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4288 extended_memory_size >>= 16;
4289 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4291 write_word(ES, regs.u.r16.di+16, 0x1);
4292 write_word(ES, regs.u.r16.di+18, 0x0);
4295 regs.u.r32.eax = 0x534D4150;
4296 regs.u.r32.ecx = 0x14;
4300 default: /* AX=E820, DX=534D4150, BX unrecognized */
4301 goto int15_unimplemented;
4306 // if DX != 0x534D4150)
4307 goto int15_unimplemented;
4312 // do we have any reason to fail here ?
4315 // my real system sets ax and bx to 0
4316 // this is confirmed by Ralph Brown list
4317 // but syslinux v1.48 is known to behave
4318 // strangely if ax is set to 0
4319 // regs.u.r16.ax = 0;
4320 // regs.u.r16.bx = 0;
4322 // Get the amount of extended memory (above 1M)
4323 regs.u.r8.cl = inb_cmos(0x30);
4324 regs.u.r8.ch = inb_cmos(0x31);
4327 if(regs.u.r16.cx > 0x3c00)
4329 regs.u.r16.cx = 0x3c00;
4332 // Get the amount of extended memory above 16M in 64k blocs
4333 regs.u.r8.dl = inb_cmos(0x34);
4334 regs.u.r8.dh = inb_cmos(0x35);
4336 // Set configured memory equal to extended memory
4337 regs.u.r16.ax = regs.u.r16.cx;
4338 regs.u.r16.bx = regs.u.r16.dx;
4340 default: /* AH=0xE8?? but not implemented */
4341 goto int15_unimplemented;
4344 int15_unimplemented:
4345 // fall into the default
4347 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4348 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4350 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4356 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4357 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4359 Bit8u scan_code, ascii_code, shift_flags, count;
4360 Bit16u kbd_code, max;
4362 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4365 case 0x00: /* read keyboard input */
4367 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4368 BX_PANIC("KBD: int16h: out of keyboard input\n");
4370 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4371 else if (ascii_code == 0xE0) ascii_code = 0;
4372 AX = (scan_code << 8) | ascii_code;
4375 case 0x01: /* check keyboard status */
4376 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4380 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4381 else if (ascii_code == 0xE0) ascii_code = 0;
4382 AX = (scan_code << 8) | ascii_code;
4386 case 0x02: /* get shift flag status */
4387 shift_flags = read_byte(0x0040, 0x17);
4388 SET_AL(shift_flags);
4391 case 0x05: /* store key-stroke into buffer */
4392 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4400 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4401 // bit Bochs Description
4403 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4404 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4405 // 4 1 INT 16/AH=0Ah supported
4406 // 3 0 INT 16/AX=0306h supported
4407 // 2 0 INT 16/AX=0305h supported
4408 // 1 0 INT 16/AX=0304h supported
4409 // 0 0 INT 16/AX=0300h supported
4414 case 0x0A: /* GET KEYBOARD ID */
4420 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4422 if ((inb(0x60) == 0xfa)) {
4425 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4428 kbd_code |= (inb(0x60) << 8);
4430 } while (--count>0);
4436 case 0x10: /* read MF-II keyboard input */
4438 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4439 BX_PANIC("KBD: int16h: out of keyboard input\n");
4441 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4442 AX = (scan_code << 8) | ascii_code;
4445 case 0x11: /* check MF-II keyboard status */
4446 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4450 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4451 AX = (scan_code << 8) | ascii_code;
4455 case 0x12: /* get extended keyboard status */
4456 shift_flags = read_byte(0x0040, 0x17);
4457 SET_AL(shift_flags);
4458 shift_flags = read_byte(0x0040, 0x18);
4459 SET_AH(shift_flags);
4460 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4463 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4464 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4467 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4468 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4472 if (GET_AL() == 0x08)
4473 SET_AH(0x02); // unsupported, aka normal keyboard
4476 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4481 dequeue_key(scan_code, ascii_code, incr)
4486 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4491 buffer_start = 0x001E;
4492 buffer_end = 0x003E;
4494 buffer_start = read_word(0x0040, 0x0080);
4495 buffer_end = read_word(0x0040, 0x0082);
4498 buffer_head = read_word(0x0040, 0x001a);
4499 buffer_tail = read_word(0x0040, 0x001c);
4501 if (buffer_head != buffer_tail) {
4503 acode = read_byte(0x0040, buffer_head);
4504 scode = read_byte(0x0040, buffer_head+1);
4505 write_byte(ss, ascii_code, acode);
4506 write_byte(ss, scan_code, scode);
4510 if (buffer_head >= buffer_end)
4511 buffer_head = buffer_start;
4512 write_word(0x0040, 0x001a, buffer_head);
4521 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4524 inhibit_mouse_int_and_events()
4526 Bit8u command_byte, prev_command_byte;
4528 // Turn off IRQ generation and aux data line
4529 if ( inb(0x64) & 0x02 )
4530 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4531 outb(0x64, 0x20); // get command byte
4532 while ( (inb(0x64) & 0x01) != 0x01 );
4533 prev_command_byte = inb(0x60);
4534 command_byte = prev_command_byte;
4535 //while ( (inb(0x64) & 0x02) );
4536 if ( inb(0x64) & 0x02 )
4537 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4538 command_byte &= 0xfd; // turn off IRQ 12 generation
4539 command_byte |= 0x20; // disable mouse serial clock line
4540 outb(0x64, 0x60); // write command byte
4541 outb(0x60, command_byte);
4542 return(prev_command_byte);
4546 enable_mouse_int_and_events()
4550 // Turn on IRQ generation and aux data line
4551 if ( inb(0x64) & 0x02 )
4552 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4553 outb(0x64, 0x20); // get command byte
4554 while ( (inb(0x64) & 0x01) != 0x01 );
4555 command_byte = inb(0x60);
4556 //while ( (inb(0x64) & 0x02) );
4557 if ( inb(0x64) & 0x02 )
4558 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4559 command_byte |= 0x02; // turn on IRQ 12 generation
4560 command_byte &= 0xdf; // enable mouse serial clock line
4561 outb(0x64, 0x60); // write command byte
4562 outb(0x60, command_byte);
4566 send_to_mouse_ctrl(sendbyte)
4571 // wait for chance to write to ctrl
4572 if ( inb(0x64) & 0x02 )
4573 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4575 outb(0x60, sendbyte);
4581 get_mouse_data(data)
4587 while ( (inb(0x64) & 0x21) != 0x21 ) {
4590 response = inb(0x60);
4593 write_byte(ss, data, response);
4598 set_kbd_command_byte(command_byte)
4601 if ( inb(0x64) & 0x02 )
4602 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4605 outb(0x64, 0x60); // write command byte
4606 outb(0x60, command_byte);
4610 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4611 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4613 Bit8u scancode, asciicode, shift_flags;
4614 Bit8u mf2_flags, mf2_state, led_flags;
4617 // DS has been set to F000 before call
4621 scancode = GET_AL();
4623 if (scancode == 0) {
4624 BX_INFO("KBD: int09 handler: AL=0\n");
4629 shift_flags = read_byte(0x0040, 0x17);
4630 mf2_flags = read_byte(0x0040, 0x18);
4631 mf2_state = read_byte(0x0040, 0x96);
4632 led_flags = read_byte(0x0040, 0x97);
4636 case 0x3a: /* Caps Lock press */
4637 shift_flags ^= 0x40;
4638 write_byte(0x0040, 0x17, shift_flags);
4640 write_byte(0x0040, 0x18, mf2_flags);
4642 write_byte(0x0040, 0x97, led_flags);
4644 case 0xba: /* Caps Lock release */
4646 write_byte(0x0040, 0x18, mf2_flags);
4649 case 0x2a: /* L Shift press */
4650 /*shift_flags &= ~0x40;*/
4651 shift_flags |= 0x02;
4652 write_byte(0x0040, 0x17, shift_flags);
4654 write_byte(0x0040, 0x97, led_flags);
4656 case 0xaa: /* L Shift release */
4657 shift_flags &= ~0x02;
4658 write_byte(0x0040, 0x17, shift_flags);
4661 case 0x36: /* R Shift press */
4662 /*shift_flags &= ~0x40;*/
4663 shift_flags |= 0x01;
4664 write_byte(0x0040, 0x17, shift_flags);
4666 write_byte(0x0040, 0x97, led_flags);
4668 case 0xb6: /* R Shift release */
4669 shift_flags &= ~0x01;
4670 write_byte(0x0040, 0x17, shift_flags);
4673 case 0x1d: /* Ctrl press */
4674 shift_flags |= 0x04;
4675 write_byte(0x0040, 0x17, shift_flags);
4676 if (mf2_state & 0x01) {
4681 write_byte(0x0040, 0x18, mf2_flags);
4683 case 0x9d: /* Ctrl release */
4684 shift_flags &= ~0x04;
4685 write_byte(0x0040, 0x17, shift_flags);
4686 if (mf2_state & 0x01) {
4691 write_byte(0x0040, 0x18, mf2_flags);
4694 case 0x38: /* Alt press */
4695 shift_flags |= 0x08;
4696 write_byte(0x0040, 0x17, shift_flags);
4697 if (mf2_state & 0x01) {
4702 write_byte(0x0040, 0x18, mf2_flags);
4704 case 0xb8: /* Alt release */
4705 shift_flags &= ~0x08;
4706 write_byte(0x0040, 0x17, shift_flags);
4707 if (mf2_state & 0x01) {
4712 write_byte(0x0040, 0x18, mf2_flags);
4715 case 0x45: /* Num Lock press */
4716 if ((mf2_state & 0x01) == 0) {
4718 write_byte(0x0040, 0x18, mf2_flags);
4719 shift_flags ^= 0x20;
4721 write_byte(0x0040, 0x17, shift_flags);
4722 write_byte(0x0040, 0x97, led_flags);
4725 case 0xc5: /* Num Lock release */
4726 if ((mf2_state & 0x01) == 0) {
4728 write_byte(0x0040, 0x18, mf2_flags);
4732 case 0x46: /* Scroll Lock press */
4734 write_byte(0x0040, 0x18, mf2_flags);
4735 shift_flags ^= 0x10;
4737 write_byte(0x0040, 0x17, shift_flags);
4738 write_byte(0x0040, 0x97, led_flags);
4741 case 0xc6: /* Scroll Lock release */
4743 write_byte(0x0040, 0x18, mf2_flags);
4747 if (scancode & 0x80) return; /* toss key releases ... */
4748 if (scancode > MAX_SCAN_CODE) {
4749 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4752 if (shift_flags & 0x08) { /* ALT */
4753 asciicode = scan_to_scanascii[scancode].alt;
4754 scancode = scan_to_scanascii[scancode].alt >> 8;
4756 else if (shift_flags & 0x04) { /* CONTROL */
4757 asciicode = scan_to_scanascii[scancode].control;
4758 scancode = scan_to_scanascii[scancode].control >> 8;
4760 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4761 /* check if lock state should be ignored
4762 * because a SHIFT key are pressed */
4764 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4765 asciicode = scan_to_scanascii[scancode].normal;
4766 scancode = scan_to_scanascii[scancode].normal >> 8;
4769 asciicode = scan_to_scanascii[scancode].shift;
4770 scancode = scan_to_scanascii[scancode].shift >> 8;
4774 /* check if lock is on */
4775 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4776 asciicode = scan_to_scanascii[scancode].shift;
4777 scancode = scan_to_scanascii[scancode].shift >> 8;
4780 asciicode = scan_to_scanascii[scancode].normal;
4781 scancode = scan_to_scanascii[scancode].normal >> 8;
4784 if (scancode==0 && asciicode==0) {
4785 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4787 enqueue_key(scancode, asciicode);
4794 enqueue_key(scan_code, ascii_code)
4795 Bit8u scan_code, ascii_code;
4797 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4799 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4800 // scan_code, ascii_code);
4803 buffer_start = 0x001E;
4804 buffer_end = 0x003E;
4806 buffer_start = read_word(0x0040, 0x0080);
4807 buffer_end = read_word(0x0040, 0x0082);
4810 buffer_head = read_word(0x0040, 0x001A);
4811 buffer_tail = read_word(0x0040, 0x001C);
4813 temp_tail = buffer_tail;
4815 if (buffer_tail >= buffer_end)
4816 buffer_tail = buffer_start;
4818 if (buffer_tail == buffer_head) {
4822 write_byte(0x0040, temp_tail, ascii_code);
4823 write_byte(0x0040, temp_tail+1, scan_code);
4824 write_word(0x0040, 0x001C, buffer_tail);
4830 int74_function(make_farcall, Z, Y, X, status)
4831 Bit16u make_farcall, Z, Y, X, status;
4833 Bit16u ebda_seg=read_word(0x0040,0x000E);
4834 Bit8u in_byte, index, package_count;
4835 Bit8u mouse_flags_1, mouse_flags_2;
4837 BX_DEBUG_INT74("entering int74_function\n");
4840 in_byte = inb(0x64);
4841 if ( (in_byte & 0x21) != 0x21 ) {
4844 in_byte = inb(0x60);
4845 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4847 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4848 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4850 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4851 // BX_PANIC("int74_function:\n");
4855 package_count = mouse_flags_2 & 0x07;
4856 index = mouse_flags_1 & 0x07;
4857 write_byte(ebda_seg, 0x28 + index, in_byte);
4859 if ( (index+1) >= package_count ) {
4860 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4861 status = read_byte(ebda_seg, 0x0028 + 0);
4862 X = read_byte(ebda_seg, 0x0028 + 1);
4863 Y = read_byte(ebda_seg, 0x0028 + 2);
4866 // check if far call handler installed
4867 if (mouse_flags_2 & 0x80)
4873 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4876 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4881 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4882 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4885 Bit16u ebda_seg=read_word(0x0040,0x000E);
4886 Bit16u cylinder, head, sector;
4887 Bit16u segment, offset;
4888 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4890 Bit8u device, status;
4892 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4894 write_byte(0x0040, 0x008e, 0); // clear completion flag
4896 // basic check : device has to be defined
4897 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4898 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4902 // Get the ata channel
4903 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4905 // basic check : device has to be valid
4906 if (device >= BX_MAX_ATA_DEVICES) {
4907 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4913 case 0x00: /* disk controller reset */
4918 case 0x01: /* read disk status */
4919 status = read_byte(0x0040, 0x0074);
4921 SET_DISK_RET_STATUS(0);
4922 /* set CF if error status read */
4923 if (status) goto int13_fail_nostatus;
4924 else goto int13_success_noah;
4927 case 0x02: // read disk sectors
4928 case 0x03: // write disk sectors
4929 case 0x04: // verify disk sectors
4932 cylinder = GET_CH();
4933 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4934 sector = (GET_CL() & 0x3f);
4940 if ( (count > 128) || (count == 0) ) {
4941 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4945 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4946 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4947 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4949 // sanity check on cyl heads, sec
4950 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4951 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4956 if ( GET_AH() == 0x04 ) goto int13_success;
4958 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4959 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4961 // if needed, translate lchs to lba, and execute command
4962 if ( (nph != nlh) || (npspt != nlspt)) {
4963 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4964 sector = 0; // this forces the command to be lba
4967 if ( GET_AH() == 0x02 )
4968 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4970 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4972 // Set nb of sector transferred
4973 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4976 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4978 goto int13_fail_noah;
4984 case 0x05: /* format disk track */
4985 BX_INFO("format disk track called\n");
4990 case 0x08: /* read disk drive parameters */
4992 // Get logical geometry from table
4993 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4994 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4995 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4996 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4998 nlc = nlc - 2; /* 0 based , last sector not used */
5001 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5003 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5005 // FIXME should set ES & DI
5010 case 0x10: /* check drive ready */
5011 // should look at 40:8E also???
5013 // Read the status from controller
5014 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5015 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5020 goto int13_fail_noah;
5024 case 0x15: /* read disk drive size */
5026 // Get physical geometry from table
5027 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5028 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5029 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5031 // Compute sector count seen by int13
5032 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5036 SET_AH(3); // hard disk accessible
5037 goto int13_success_noah;
5040 case 0x41: // IBM/MS installation check
5041 BX=0xaa55; // install check
5042 SET_AH(0x30); // EDD 3.0
5043 CX=0x0007; // ext disk access and edd, removable supported
5044 goto int13_success_noah;
5047 case 0x42: // IBM/MS extended read
5048 case 0x43: // IBM/MS extended write
5049 case 0x44: // IBM/MS verify
5050 case 0x47: // IBM/MS extended seek
5052 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5053 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5054 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5056 // Can't use 64 bits lba
5057 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5059 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5063 // Get 32 bits lba and check
5064 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5065 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5066 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5070 // If verify or seek
5071 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5074 // Execute the command
5075 if ( GET_AH() == 0x42 )
5076 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5078 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5080 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5081 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5084 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5086 goto int13_fail_noah;
5092 case 0x45: // IBM/MS lock/unlock drive
5093 case 0x49: // IBM/MS extended media change
5094 goto int13_success; // Always success for HD
5097 case 0x46: // IBM/MS eject media
5098 SET_AH(0xb2); // Volume Not Removable
5099 goto int13_fail_noah; // Always fail for HD
5102 case 0x48: // IBM/MS get drive parameters
5103 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5105 // Buffer is too small
5113 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5114 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5115 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5116 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5117 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5119 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5120 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5121 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5122 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5123 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5124 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5125 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5126 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5131 Bit8u channel, dev, irq, mode, checksum, i, translation;
5132 Bit16u iobase1, iobase2, options;
5134 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5136 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5137 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5140 channel = device / 2;
5141 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5142 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5143 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5144 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5145 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5147 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5148 options |= (1<<4); // lba translation
5149 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5150 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5151 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5153 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5154 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5155 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5156 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5157 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5158 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5159 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5160 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5161 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5162 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5163 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5166 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5167 checksum = ~checksum;
5168 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5173 Bit8u channel, iface, checksum, i;
5176 channel = device / 2;
5177 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5178 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5180 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5181 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5182 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5183 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5184 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5186 if (iface==ATA_IFACE_ISA) {
5187 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5188 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5189 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5190 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5195 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5196 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5197 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5198 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5200 if (iface==ATA_IFACE_ISA) {
5201 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5202 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5203 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5208 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5209 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5210 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5211 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5214 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5215 checksum = ~checksum;
5216 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5222 case 0x4e: // // IBM/MS set hardware configuration
5223 // DMA, prefetch, PIO maximum not supported
5236 case 0x09: /* initialize drive parameters */
5237 case 0x0c: /* seek to specified cylinder */
5238 case 0x0d: /* alternate disk reset */
5239 case 0x11: /* recalibrate */
5240 case 0x14: /* controller internal diagnostic */
5241 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5245 case 0x0a: /* read disk sectors with ECC */
5246 case 0x0b: /* write disk sectors with ECC */
5247 case 0x18: // set media type for format
5248 case 0x50: // IBM/MS send packet command
5250 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5256 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5258 SET_DISK_RET_STATUS(GET_AH());
5259 int13_fail_nostatus:
5260 SET_CF(); // error occurred
5264 SET_AH(0x00); // no error
5266 SET_DISK_RET_STATUS(0x00);
5267 CLEAR_CF(); // no error
5271 // ---------------------------------------------------------------------------
5272 // Start of int13 for cdrom
5273 // ---------------------------------------------------------------------------
5276 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5277 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5279 Bit16u ebda_seg=read_word(0x0040,0x000E);
5280 Bit8u device, status, locks;
5283 Bit16u count, segment, offset, i, size;
5285 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5286 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5288 SET_DISK_RET_STATUS(0x00);
5290 /* basic check : device should be 0xE0+ */
5291 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5292 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5296 // Get the ata channel
5297 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5299 /* basic check : device has to be valid */
5300 if (device >= BX_MAX_ATA_DEVICES) {
5301 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5307 // all those functions return SUCCESS
5308 case 0x00: /* disk controller reset */
5309 case 0x09: /* initialize drive parameters */
5310 case 0x0c: /* seek to specified cylinder */
5311 case 0x0d: /* alternate disk reset */
5312 case 0x10: /* check drive ready */
5313 case 0x11: /* recalibrate */
5314 case 0x14: /* controller internal diagnostic */
5315 case 0x16: /* detect disk change */
5319 // all those functions return disk write-protected
5320 case 0x03: /* write disk sectors */
5321 case 0x05: /* format disk track */
5322 case 0x43: // IBM/MS extended write
5324 goto int13_fail_noah;
5327 case 0x01: /* read disk status */
5328 status = read_byte(0x0040, 0x0074);
5330 SET_DISK_RET_STATUS(0);
5332 /* set CF if error status read */
5333 if (status) goto int13_fail_nostatus;
5334 else goto int13_success_noah;
5337 case 0x15: /* read disk drive size */
5339 goto int13_fail_noah;
5342 case 0x41: // IBM/MS installation check
5343 BX=0xaa55; // install check
5344 SET_AH(0x30); // EDD 2.1
5345 CX=0x0007; // ext disk access, removable and edd
5346 goto int13_success_noah;
5349 case 0x42: // IBM/MS extended read
5350 case 0x44: // IBM/MS verify sectors
5351 case 0x47: // IBM/MS extended seek
5353 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5354 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5355 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5357 // Can't use 64 bits lba
5358 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5360 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5365 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5367 // If verify or seek
5368 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5371 memsetb(get_SS(),atacmd,0,12);
5372 atacmd[0]=0x28; // READ command
5373 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5374 atacmd[8]=(count & 0x00ff); // Sectors
5375 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5376 atacmd[3]=(lba & 0x00ff0000) >> 16;
5377 atacmd[4]=(lba & 0x0000ff00) >> 8;
5378 atacmd[5]=(lba & 0x000000ff);
5379 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5381 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5382 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5385 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5387 goto int13_fail_noah;
5393 case 0x45: // IBM/MS lock/unlock drive
5394 if (GET_AL() > 2) goto int13_fail;
5396 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5400 if (locks == 0xff) {
5403 goto int13_fail_noah;
5405 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5409 if (locks == 0x00) {
5412 goto int13_fail_noah;
5414 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5415 SET_AL(locks==0?0:1);
5418 SET_AL(locks==0?0:1);
5424 case 0x46: // IBM/MS eject media
5425 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5428 SET_AH(0xb1); // media locked
5429 goto int13_fail_noah;
5431 // FIXME should handle 0x31 no media in device
5432 // FIXME should handle 0xb5 valid request failed
5434 // Call removable media eject
5441 mov _int13_cdrom.status + 2[bp], ah
5442 jnc int13_cdrom_rme_end
5443 mov _int13_cdrom.status, #1
5444 int13_cdrom_rme_end:
5449 SET_AH(0xb1); // media locked
5450 goto int13_fail_noah;
5456 case 0x48: // IBM/MS get drive parameters
5457 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5459 // Buffer is too small
5465 Bit16u cylinders, heads, spt, blksize;
5467 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5469 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5470 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5471 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5472 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5473 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5474 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5475 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5476 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5481 Bit8u channel, dev, irq, mode, checksum, i;
5482 Bit16u iobase1, iobase2, options;
5484 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5486 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5487 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5490 channel = device / 2;
5491 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5492 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5493 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5494 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5496 // FIXME atapi device
5497 options = (1<<4); // lba translation
5498 options |= (1<<5); // removable device
5499 options |= (1<<6); // atapi device
5500 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5502 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5503 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5504 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5505 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5506 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5507 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5508 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5509 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5510 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5511 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5512 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5515 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5516 checksum = ~checksum;
5517 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5522 Bit8u channel, iface, checksum, i;
5525 channel = device / 2;
5526 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5527 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5529 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5530 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5531 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5532 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5533 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5535 if (iface==ATA_IFACE_ISA) {
5536 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5537 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5538 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5539 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5544 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5545 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5546 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5547 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5549 if (iface==ATA_IFACE_ISA) {
5550 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5551 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5552 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5557 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5558 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5559 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5560 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5563 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5564 checksum = ~checksum;
5565 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5571 case 0x49: // IBM/MS extended media change
5572 // always send changed ??
5574 goto int13_fail_nostatus;
5577 case 0x4e: // // IBM/MS set hardware configuration
5578 // DMA, prefetch, PIO maximum not supported
5591 // all those functions return unimplemented
5592 case 0x02: /* read sectors */
5593 case 0x04: /* verify sectors */
5594 case 0x08: /* read disk drive parameters */
5595 case 0x0a: /* read disk sectors with ECC */
5596 case 0x0b: /* write disk sectors with ECC */
5597 case 0x18: /* set media type for format */
5598 case 0x50: // ? - send packet command
5600 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5606 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5608 SET_DISK_RET_STATUS(GET_AH());
5609 int13_fail_nostatus:
5610 SET_CF(); // error occurred
5614 SET_AH(0x00); // no error
5616 SET_DISK_RET_STATUS(0x00);
5617 CLEAR_CF(); // no error
5621 // ---------------------------------------------------------------------------
5622 // End of int13 for cdrom
5623 // ---------------------------------------------------------------------------
5625 #if BX_ELTORITO_BOOT
5626 // ---------------------------------------------------------------------------
5627 // Start of int13 for eltorito functions
5628 // ---------------------------------------------------------------------------
5631 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5632 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5634 Bit16u ebda_seg=read_word(0x0040,0x000E);
5636 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5637 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5641 // FIXME ElTorito Various. Should be implemented
5642 case 0x4a: // ElTorito - Initiate disk emu
5643 case 0x4c: // ElTorito - Initiate disk emu and boot
5644 case 0x4d: // ElTorito - Return Boot catalog
5645 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5649 case 0x4b: // ElTorito - Terminate disk emu
5650 // FIXME ElTorito Hardcoded
5651 write_byte(DS,SI+0x00,0x13);
5652 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5653 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5654 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5655 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5656 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5657 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5658 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5659 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5660 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5661 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5662 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5664 // If we have to terminate emulation
5665 if(GET_AL() == 0x00) {
5666 // FIXME ElTorito Various. Should be handled accordingly to spec
5667 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5674 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5680 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5681 SET_DISK_RET_STATUS(GET_AH());
5682 SET_CF(); // error occurred
5686 SET_AH(0x00); // no error
5687 SET_DISK_RET_STATUS(0x00);
5688 CLEAR_CF(); // no error
5692 // ---------------------------------------------------------------------------
5693 // End of int13 for eltorito functions
5694 // ---------------------------------------------------------------------------
5696 // ---------------------------------------------------------------------------
5697 // Start of int13 when emulating a device from the cd
5698 // ---------------------------------------------------------------------------
5701 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5702 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5704 Bit16u ebda_seg=read_word(0x0040,0x000E);
5705 Bit8u device, status;
5706 Bit16u vheads, vspt, vcylinders;
5707 Bit16u head, sector, cylinder, nbsectors;
5708 Bit32u vlba, ilba, slba, elba;
5709 Bit16u before, segment, offset;
5712 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5713 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5715 /* at this point, we are emulating a floppy/harddisk */
5717 // Recompute the device number
5718 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5719 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5721 SET_DISK_RET_STATUS(0x00);
5723 /* basic checks : emulation should be active, dl should equal the emulated drive */
5724 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5725 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5726 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5732 // all those functions return SUCCESS
5733 case 0x00: /* disk controller reset */
5734 case 0x09: /* initialize drive parameters */
5735 case 0x0c: /* seek to specified cylinder */
5736 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5737 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5738 case 0x11: /* recalibrate */
5739 case 0x14: /* controller internal diagnostic */
5740 case 0x16: /* detect disk change */
5744 // all those functions return disk write-protected
5745 case 0x03: /* write disk sectors */
5746 case 0x05: /* format disk track */
5748 goto int13_fail_noah;
5751 case 0x01: /* read disk status */
5752 status=read_byte(0x0040, 0x0074);
5754 SET_DISK_RET_STATUS(0);
5756 /* set CF if error status read */
5757 if (status) goto int13_fail_nostatus;
5758 else goto int13_success_noah;
5761 case 0x02: // read disk sectors
5762 case 0x04: // verify disk sectors
5763 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5764 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5765 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5767 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5769 sector = GET_CL() & 0x003f;
5770 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5772 nbsectors = GET_AL();
5776 // no sector to read ?
5777 if(nbsectors==0) goto int13_success;
5779 // sanity checks sco openserver needs this!
5781 || (cylinder >= vcylinders)
5782 || (head >= vheads)) {
5786 // After controls, verify do nothing
5787 if (GET_AH() == 0x04) goto int13_success;
5789 segment = ES+(BX / 16);
5792 // calculate the virtual lba inside the image
5793 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5795 // In advance so we don't loose the count
5799 slba = (Bit32u)vlba/4;
5800 before= (Bit16u)vlba%4;
5803 elba = (Bit32u)(vlba+nbsectors-1)/4;
5805 memsetb(get_SS(),atacmd,0,12);
5806 atacmd[0]=0x28; // READ command
5807 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5808 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5809 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5810 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5811 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5812 atacmd[5]=(ilba+slba & 0x000000ff);
5813 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5814 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5817 goto int13_fail_noah;
5823 case 0x08: /* read disk drive parameters */
5824 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5825 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5826 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5830 SET_CH( vcylinders & 0xff );
5831 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5833 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5834 // FIXME ElTorito Harddisk. should send the HD count
5836 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5837 case 0x01: SET_BL( 0x02 ); break;
5838 case 0x02: SET_BL( 0x04 ); break;
5839 case 0x03: SET_BL( 0x06 ); break;
5845 mov ax, #diskette_param_table2
5846 mov _int13_cdemu.DI+2[bp], ax
5847 mov _int13_cdemu.ES+2[bp], cs
5853 case 0x15: /* read disk drive size */
5854 // FIXME ElTorito Harddisk. What geometry to send ?
5856 goto int13_success_noah;
5859 // all those functions return unimplemented
5860 case 0x0a: /* read disk sectors with ECC */
5861 case 0x0b: /* write disk sectors with ECC */
5862 case 0x18: /* set media type for format */
5863 case 0x41: // IBM/MS installation check
5864 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5865 case 0x42: // IBM/MS extended read
5866 case 0x43: // IBM/MS extended write
5867 case 0x44: // IBM/MS verify sectors
5868 case 0x45: // IBM/MS lock/unlock drive
5869 case 0x46: // IBM/MS eject media
5870 case 0x47: // IBM/MS extended seek
5871 case 0x48: // IBM/MS get drive parameters
5872 case 0x49: // IBM/MS extended media change
5873 case 0x4e: // ? - set hardware configuration
5874 case 0x50: // ? - send packet command
5876 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5882 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5884 SET_DISK_RET_STATUS(GET_AH());
5885 int13_fail_nostatus:
5886 SET_CF(); // error occurred
5890 SET_AH(0x00); // no error
5892 SET_DISK_RET_STATUS(0x00);
5893 CLEAR_CF(); // no error
5897 // ---------------------------------------------------------------------------
5898 // End of int13 when emulating a device from the cd
5899 // ---------------------------------------------------------------------------
5901 #endif // BX_ELTORITO_BOOT
5903 #else //BX_USE_ATADRV
5906 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5921 mov ax,4[bp] // cylinder
5923 mov bl,6[bp] // hd_heads
5926 mov bl,8[bp] // head
5928 mov bl,10[bp] // hd_sectors
5930 mov bl,12[bp] // sector
5959 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5960 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5962 Bit8u drive, num_sectors, sector, head, status, mod;
5966 Bit16u max_cylinder, cylinder, total_sectors;
5967 Bit16u hd_cylinders;
5968 Bit8u hd_heads, hd_sectors;
5975 Bit16u count, segment, offset;
5979 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5981 write_byte(0x0040, 0x008e, 0); // clear completion flag
5983 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5985 /* check how many disks first (cmos reg 0x12), return an error if
5986 drive not present */
5987 drive_map = inb_cmos(0x12);
5988 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5989 (((drive_map & 0x0f)==0) ? 0 : 2);
5990 n_drives = (drive_map==0) ? 0 :
5991 ((drive_map==3) ? 2 : 1);
5993 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5995 SET_DISK_RET_STATUS(0x01);
5996 SET_CF(); /* error occurred */
6002 case 0x00: /* disk controller reset */
6003 BX_DEBUG_INT13_HD("int13_f00\n");
6006 SET_DISK_RET_STATUS(0);
6007 set_diskette_ret_status(0);
6008 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6009 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6010 CLEAR_CF(); /* successful */
6014 case 0x01: /* read disk status */
6015 BX_DEBUG_INT13_HD("int13_f01\n");
6016 status = read_byte(0x0040, 0x0074);
6018 SET_DISK_RET_STATUS(0);
6019 /* set CF if error status read */
6020 if (status) SET_CF();
6025 case 0x04: // verify disk sectors
6026 case 0x02: // read disk sectors
6028 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6030 num_sectors = GET_AL();
6031 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6032 sector = (GET_CL() & 0x3f);
6036 if (hd_cylinders > 1024) {
6037 if (hd_cylinders <= 2048) {
6040 else if (hd_cylinders <= 4096) {
6043 else if (hd_cylinders <= 8192) {
6046 else { // hd_cylinders <= 16384
6050 ax = head / hd_heads;
6051 cyl_mod = ax & 0xff;
6053 cylinder |= cyl_mod;
6056 if ( (cylinder >= hd_cylinders) ||
6057 (sector > hd_sectors) ||
6058 (head >= hd_heads) ) {
6060 SET_DISK_RET_STATUS(1);
6061 SET_CF(); /* error occurred */
6065 if ( (num_sectors > 128) || (num_sectors == 0) )
6066 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6069 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6071 if ( GET_AH() == 0x04 ) {
6073 SET_DISK_RET_STATUS(0);
6078 status = inb(0x1f7);
6079 if (status & 0x80) {
6080 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6082 outb(0x01f2, num_sectors);
6083 /* activate LBA? (tomv) */
6084 if (hd_heads > 16) {
6085 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6086 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6089 outb(0x01f3, sector);
6090 outb(0x01f4, cylinder & 0x00ff);
6091 outb(0x01f5, cylinder >> 8);
6092 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6097 status = inb(0x1f7);
6098 if ( !(status & 0x80) ) break;
6101 if (status & 0x01) {
6102 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6103 } else if ( !(status & 0x08) ) {
6104 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6105 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6112 sti ;; enable higher priority interrupts
6117 ;; store temp bx in real DI register
6120 mov di, _int13_harddisk.tempbx + 2 [bp]
6123 ;; adjust if there will be an overrun
6125 jbe i13_f02_no_adjust
6127 sub di, #0x0200 ; sub 512 bytes from offset
6129 add ax, #0x0020 ; add 512 to segment
6133 mov cx, #0x0100 ;; counter (256 words = 512b)
6134 mov dx, #0x01f0 ;; AT data read port
6137 insw ;; CX words transfered from port(DX) to ES:[DI]
6140 ;; store real DI register back to temp bx
6143 mov _int13_harddisk.tempbx + 2 [bp], di
6149 if (num_sectors == 0) {
6150 status = inb(0x1f7);
6151 if ( (status & 0xc9) != 0x40 )
6152 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6156 status = inb(0x1f7);
6157 if ( (status & 0xc9) != 0x48 )
6158 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6164 SET_DISK_RET_STATUS(0);
6165 SET_AL(sector_count);
6166 CLEAR_CF(); /* successful */
6171 case 0x03: /* write disk sectors */
6172 BX_DEBUG_INT13_HD("int13_f03\n");
6173 drive = GET_ELDL ();
6174 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6176 num_sectors = GET_AL();
6177 cylinder = GET_CH();
6178 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6179 sector = (GET_CL() & 0x3f);
6182 if (hd_cylinders > 1024) {
6183 if (hd_cylinders <= 2048) {
6186 else if (hd_cylinders <= 4096) {
6189 else if (hd_cylinders <= 8192) {
6192 else { // hd_cylinders <= 16384
6196 ax = head / hd_heads;
6197 cyl_mod = ax & 0xff;
6199 cylinder |= cyl_mod;
6202 if ( (cylinder >= hd_cylinders) ||
6203 (sector > hd_sectors) ||
6204 (head >= hd_heads) ) {
6206 SET_DISK_RET_STATUS(1);
6207 SET_CF(); /* error occurred */
6211 if ( (num_sectors > 128) || (num_sectors == 0) )
6212 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6215 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6217 status = inb(0x1f7);
6218 if (status & 0x80) {
6219 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6221 // should check for Drive Ready Bit also in status reg
6222 outb(0x01f2, num_sectors);
6224 /* activate LBA? (tomv) */
6225 if (hd_heads > 16) {
6226 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6227 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6230 outb(0x01f3, sector);
6231 outb(0x01f4, cylinder & 0x00ff);
6232 outb(0x01f5, cylinder >> 8);
6233 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6237 // wait for busy bit to turn off after seeking
6239 status = inb(0x1f7);
6240 if ( !(status & 0x80) ) break;
6243 if ( !(status & 0x08) ) {
6244 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6245 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6252 sti ;; enable higher priority interrupts
6257 ;; store temp bx in real SI register
6260 mov si, _int13_harddisk.tempbx + 2 [bp]
6263 ;; adjust if there will be an overrun
6265 jbe i13_f03_no_adjust
6267 sub si, #0x0200 ; sub 512 bytes from offset
6269 add ax, #0x0020 ; add 512 to segment
6273 mov cx, #0x0100 ;; counter (256 words = 512b)
6274 mov dx, #0x01f0 ;; AT data read port
6278 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6280 ;; store real SI register back to temp bx
6283 mov _int13_harddisk.tempbx + 2 [bp], si
6289 if (num_sectors == 0) {
6290 status = inb(0x1f7);
6291 if ( (status & 0xe9) != 0x40 )
6292 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6296 status = inb(0x1f7);
6297 if ( (status & 0xc9) != 0x48 )
6298 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6304 SET_DISK_RET_STATUS(0);
6305 SET_AL(sector_count);
6306 CLEAR_CF(); /* successful */
6310 case 0x05: /* format disk track */
6311 BX_DEBUG_INT13_HD("int13_f05\n");
6312 BX_PANIC("format disk track called\n");
6315 SET_DISK_RET_STATUS(0);
6316 CLEAR_CF(); /* successful */
6320 case 0x08: /* read disk drive parameters */
6321 BX_DEBUG_INT13_HD("int13_f08\n");
6323 drive = GET_ELDL ();
6324 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6328 if (hd_cylinders <= 1024) {
6329 // hd_cylinders >>= 0;
6332 else if (hd_cylinders <= 2048) {
6336 else if (hd_cylinders <= 4096) {
6340 else if (hd_cylinders <= 8192) {
6344 else { // hd_cylinders <= 16384
6349 max_cylinder = hd_cylinders - 2; /* 0 based */
6351 SET_CH(max_cylinder & 0xff);
6352 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6353 SET_DH(hd_heads - 1);
6354 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6356 SET_DISK_RET_STATUS(0);
6357 CLEAR_CF(); /* successful */
6362 case 0x09: /* initialize drive parameters */
6363 BX_DEBUG_INT13_HD("int13_f09\n");
6365 SET_DISK_RET_STATUS(0);
6366 CLEAR_CF(); /* successful */
6370 case 0x0a: /* read disk sectors with ECC */
6371 BX_DEBUG_INT13_HD("int13_f0a\n");
6372 case 0x0b: /* write disk sectors with ECC */
6373 BX_DEBUG_INT13_HD("int13_f0b\n");
6374 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6378 case 0x0c: /* seek to specified cylinder */
6379 BX_DEBUG_INT13_HD("int13_f0c\n");
6380 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6382 SET_DISK_RET_STATUS(0);
6383 CLEAR_CF(); /* successful */
6387 case 0x0d: /* alternate disk reset */
6388 BX_DEBUG_INT13_HD("int13_f0d\n");
6390 SET_DISK_RET_STATUS(0);
6391 CLEAR_CF(); /* successful */
6395 case 0x10: /* check drive ready */
6396 BX_DEBUG_INT13_HD("int13_f10\n");
6398 //SET_DISK_RET_STATUS(0);
6399 //CLEAR_CF(); /* successful */
6403 // should look at 40:8E also???
6404 status = inb(0x01f7);
6405 if ( (status & 0xc0) == 0x40 ) {
6407 SET_DISK_RET_STATUS(0);
6408 CLEAR_CF(); // drive ready
6413 SET_DISK_RET_STATUS(0xAA);
6414 SET_CF(); // not ready
6419 case 0x11: /* recalibrate */
6420 BX_DEBUG_INT13_HD("int13_f11\n");
6422 SET_DISK_RET_STATUS(0);
6423 CLEAR_CF(); /* successful */
6427 case 0x14: /* controller internal diagnostic */
6428 BX_DEBUG_INT13_HD("int13_f14\n");
6430 SET_DISK_RET_STATUS(0);
6431 CLEAR_CF(); /* successful */
6436 case 0x15: /* read disk drive size */
6438 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6442 mov al, _int13_harddisk.hd_heads + 2 [bp]
6443 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6444 mul al, ah ;; ax = heads * sectors
6445 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6446 dec bx ;; use (cylinders - 1) ???
6447 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6448 ;; now we need to move the 32bit result dx:ax to what the
6449 ;; BIOS wants which is cx:dx.
6450 ;; and then into CX:DX on the stack
6451 mov _int13_harddisk.CX + 2 [bp], dx
6452 mov _int13_harddisk.DX + 2 [bp], ax
6455 SET_AH(3); // hard disk accessible
6456 SET_DISK_RET_STATUS(0); // ??? should this be 0
6457 CLEAR_CF(); // successful
6461 case 0x18: // set media type for format
6462 case 0x41: // IBM/MS
6463 case 0x42: // IBM/MS
6464 case 0x43: // IBM/MS
6465 case 0x44: // IBM/MS
6466 case 0x45: // IBM/MS lock/unlock drive
6467 case 0x46: // IBM/MS eject media
6468 case 0x47: // IBM/MS extended seek
6469 case 0x49: // IBM/MS extended media change
6470 case 0x50: // IBM/MS send packet command
6472 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6474 SET_AH(1); // code=invalid function in AH or invalid parameter
6475 SET_DISK_RET_STATUS(1);
6476 SET_CF(); /* unsuccessful */
6482 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6483 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6486 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6488 Bit16u *hd_cylinders;
6498 if (drive == 0x80) {
6499 hd_type = inb_cmos(0x12) & 0xf0;
6500 if (hd_type != 0xf0)
6501 BX_INFO(panic_msg_reg12h,0);
6502 hd_type = inb_cmos(0x19); // HD0: extended type
6504 BX_INFO(panic_msg_reg19h,0,0x19);
6507 hd_type = inb_cmos(0x12) & 0x0f;
6508 if (hd_type != 0x0f)
6509 BX_INFO(panic_msg_reg12h,1);
6510 hd_type = inb_cmos(0x1a); // HD0: extended type
6512 BX_INFO(panic_msg_reg19h,0,0x1a);
6517 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6518 write_word(ss, hd_cylinders, cylinders);
6521 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6523 // sectors per track
6524 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6527 #endif //else BX_USE_ATADRV
6530 //////////////////////
6531 // FLOPPY functions //
6532 //////////////////////
6535 floppy_media_known(drive)
6539 Bit16u media_state_offset;
6541 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6548 media_state_offset = 0x0090;
6550 media_state_offset += 1;
6552 val8 = read_byte(0x0040, media_state_offset);
6553 val8 = (val8 >> 4) & 0x01;
6557 // check pass, return KNOWN
6562 floppy_media_sense(drive)
6566 Bit16u media_state_offset;
6567 Bit8u drive_type, config_data, media_state;
6569 if (floppy_drive_recal(drive) == 0) {
6573 // for now cheat and get drive type from CMOS,
6574 // assume media is same as drive type
6576 // ** config_data **
6577 // Bitfields for diskette media control:
6578 // Bit(s) Description (Table M0028)
6579 // 7-6 last data rate set by controller
6580 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6581 // 5-4 last diskette drive step rate selected
6582 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6583 // 3-2 {data rate at start of operation}
6586 // ** media_state **
6587 // Bitfields for diskette drive media state:
6588 // Bit(s) Description (Table M0030)
6590 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6591 // 5 double stepping required (e.g. 360kB in 1.2MB)
6592 // 4 media type established
6593 // 3 drive capable of supporting 4MB media
6594 // 2-0 on exit from BIOS, contains
6595 // 000 trying 360kB in 360kB
6596 // 001 trying 360kB in 1.2MB
6597 // 010 trying 1.2MB in 1.2MB
6598 // 011 360kB in 360kB established
6599 // 100 360kB in 1.2MB established
6600 // 101 1.2MB in 1.2MB established
6602 // 111 all other formats/drives
6604 drive_type = inb_cmos(0x10);
6609 if ( drive_type == 1 ) {
6611 config_data = 0x00; // 0000 0000
6612 media_state = 0x25; // 0010 0101
6615 else if ( drive_type == 2 ) {
6616 // 1.2 MB 5.25" drive
6617 config_data = 0x00; // 0000 0000
6618 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6621 else if ( drive_type == 3 ) {
6623 config_data = 0x00; // 0000 0000 ???
6624 media_state = 0x17; // 0001 0111
6627 else if ( drive_type == 4 ) {
6628 // 1.44 MB 3.5" drive
6629 config_data = 0x00; // 0000 0000
6630 media_state = 0x17; // 0001 0111
6633 else if ( drive_type == 5 ) {
6634 // 2.88 MB 3.5" drive
6635 config_data = 0xCC; // 1100 1100
6636 media_state = 0xD7; // 1101 0111
6640 // Extended floppy size uses special cmos setting
6641 else if ( drive_type == 6 ) {
6643 config_data = 0x00; // 0000 0000
6644 media_state = 0x27; // 0010 0111
6647 else if ( drive_type == 7 ) {
6649 config_data = 0x00; // 0000 0000
6650 media_state = 0x27; // 0010 0111
6653 else if ( drive_type == 8 ) {
6655 config_data = 0x00; // 0000 0000
6656 media_state = 0x27; // 0010 0111
6662 config_data = 0x00; // 0000 0000
6663 media_state = 0x00; // 0000 0000
6668 media_state_offset = 0x90;
6670 media_state_offset = 0x91;
6671 write_byte(0x0040, 0x008B, config_data);
6672 write_byte(0x0040, media_state_offset, media_state);
6678 floppy_drive_recal(drive)
6682 Bit16u curr_cyl_offset;
6684 // set 40:3e bit 7 to 0
6685 val8 = read_byte(0x0000, 0x043e);
6687 write_byte(0x0000, 0x043e, val8);
6689 // turn on motor of selected drive, DMA & int enabled, normal operation
6698 // reset the disk motor timeout value of INT 08
6699 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6701 // check port 3f4 for drive readiness
6703 if ( (val8 & 0xf0) != 0x80 )
6704 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6706 // send Recalibrate command (2 bytes) to controller
6707 outb(0x03f5, 0x07); // 07: Recalibrate
6708 outb(0x03f5, drive); // 0=drive0, 1=drive1
6710 // turn on interrupts
6715 // wait on 40:3e bit 7 to become 1
6716 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6717 while ( val8 == 0 ) {
6718 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6721 val8 = 0; // separate asm from while() loop
6722 // turn off interrupts
6727 // set 40:3e bit 7 to 0, and calibrated bit
6728 val8 = read_byte(0x0000, 0x043e);
6731 val8 |= 0x02; // Drive 1 calibrated
6732 curr_cyl_offset = 0x0095;
6735 val8 |= 0x01; // Drive 0 calibrated
6736 curr_cyl_offset = 0x0094;
6738 write_byte(0x0040, 0x003e, val8);
6739 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6747 floppy_drive_exists(drive)
6752 // just tell it both drives exist - PAD
6755 // check CMOS to see if drive exists
6756 drive_type = inb_cmos(0x10);
6761 if ( drive_type == 0 )
6767 #if BX_SUPPORT_FLOPPY
6769 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6770 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6772 Bit8u drive, num_sectors, track, sector, head, status;
6773 Bit16u base_address, base_count, base_es;
6774 Bit8u page, mode_register, val8, dor;
6775 Bit8u return_status[7];
6776 Bit8u drive_type, num_floppies, ah;
6777 Bit16u es, last_addr;
6780 //printf("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6781 BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(),get_DS(), ES, DI, SI);
6786 case 0x00: // diskette controller reset
6787 BX_DEBUG_INT13_FL("floppy f00\n");
6790 SET_AH(1); // invalid param
6791 set_diskette_ret_status(1);
6795 drive_type = inb_cmos(0x10);
6801 if (drive_type == 0) {
6802 SET_AH(0x80); // drive not responding
6803 set_diskette_ret_status(0x80);
6808 set_diskette_ret_status(0);
6809 CLEAR_CF(); // successful
6810 set_diskette_current_cyl(drive, 0); // current cylinder
6813 case 0x01: // Read Diskette Status
6815 val8 = read_byte(0x0000, 0x0441);
6822 case 0x02: // Read Diskette Sectors
6823 case 0x03: // Write Diskette Sectors
6824 case 0x04: // Verify Diskette Sectors
6825 num_sectors = GET_AL();
6831 if ( (drive > 1) || (head > 1) ||
6832 (num_sectors == 0) || (num_sectors > 72) ) {
6833 BX_INFO("floppy: drive>1 || head>1 ...\n");
6835 set_diskette_ret_status(1);
6836 SET_AL(0); // no sectors read
6837 SET_CF(); // error occurred
6841 // see if drive exists
6842 if (floppy_drive_exists(drive) == 0) {
6843 SET_AH(0x80); // not responding
6844 set_diskette_ret_status(0x80);
6845 SET_AL(0); // no sectors read
6846 SET_CF(); // error occurred
6850 // see if media in drive, and type is known
6851 if (floppy_media_known(drive) == 0) {
6852 if (floppy_media_sense(drive) == 0) {
6853 SET_AH(0x0C); // Media type not found
6854 set_diskette_ret_status(0x0C);
6855 SET_AL(0); // no sectors read
6856 SET_CF(); // error occurred
6862 // Read Diskette Sectors
6864 //-----------------------------------
6865 // set up DMA controller for transfer
6866 //-----------------------------------
6868 // es:bx = pointer to where to place information from diskette
6869 // port 04: DMA-1 base and current address, channel 2
6870 // port 05: DMA-1 base and current count, channel 2
6871 page = (ES >> 12); // upper 4 bits
6872 base_es = (ES << 4); // lower 16bits contributed by ES
6873 base_address = base_es + BX; // lower 16 bits of address
6874 // contributed by ES:BX
6875 if ( base_address < base_es ) {
6876 // in case of carry, adjust page by 1
6879 base_count = (num_sectors * 512) - 1;
6881 // check for 64K boundary overrun
6882 last_addr = base_address + base_count;
6883 if (last_addr < base_address) {
6885 set_diskette_ret_status(0x09);
6886 SET_AL(0); // no sectors read
6887 SET_CF(); // error occurred
6891 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6894 BX_DEBUG_INT13_FL("clear flip-flop\n");
6895 outb(0x000c, 0x00); // clear flip-flop
6896 outb(0x0004, base_address);
6897 outb(0x0004, base_address>>8);
6898 BX_DEBUG_INT13_FL("clear flip-flop\n");
6899 outb(0x000c, 0x00); // clear flip-flop
6900 outb(0x0005, base_count);
6901 outb(0x0005, base_count>>8);
6903 // port 0b: DMA-1 Mode Register
6904 mode_register = 0x46; // single mode, increment, autoinit disable,
6905 // transfer type=write, channel 2
6906 BX_DEBUG_INT13_FL("setting mode register\n");
6907 outb(0x000b, mode_register);
6909 BX_DEBUG_INT13_FL("setting page register\n");
6910 // port 81: DMA-1 Page Register, channel 2
6913 BX_DEBUG_INT13_FL("unmask chan 2\n");
6914 outb(0x000a, 0x02); // unmask channel 2
6916 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6919 //--------------------------------------
6920 // set up floppy controller for transfer
6921 //--------------------------------------
6923 // set 40:3e bit 7 to 0
6924 val8 = read_byte(0x0000, 0x043e);
6926 write_byte(0x0000, 0x043e, val8);
6928 // turn on motor of selected drive, DMA & int enabled, normal operation
6937 // reset the disk motor timeout value of INT 08
6938 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6940 // check port 3f4 for drive readiness
6942 if ( (val8 & 0xf0) != 0x80 )
6943 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6945 // send read-normal-data command (9 bytes) to controller
6946 outb(0x03f5, 0xe6); // e6: read normal data
6947 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6948 outb(0x03f5, track);
6950 outb(0x03f5, sector);
6951 outb(0x03f5, 2); // 512 byte sector size
6952 outb(0x03f5, 0); // last sector number possible on track
6953 outb(0x03f5, 0); // Gap length
6954 outb(0x03f5, 0xff); // Gap length
6956 // turn on interrupts
6961 // wait on 40:3e bit 7 to become 1
6962 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6963 while ( val8 == 0 ) {
6964 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6967 val8 = 0; // separate asm from while() loop
6968 // turn off interrupts
6973 // set 40:3e bit 7 to 0
6974 val8 = read_byte(0x0000, 0x043e);
6976 write_byte(0x0000, 0x043e, val8);
6978 // check port 3f4 for accessibility to status bytes
6980 if ( (val8 & 0xc0) != 0xc0 )
6981 BX_PANIC("int13_diskette: ctrl not ready\n");
6983 // read 7 return status bytes from controller
6984 // using loop index broken, have to unroll...
6985 return_status[0] = inb(0x3f5);
6986 return_status[1] = inb(0x3f5);
6987 return_status[2] = inb(0x3f5);
6988 return_status[3] = inb(0x3f5);
6989 return_status[4] = inb(0x3f5);
6990 return_status[5] = inb(0x3f5);
6991 return_status[6] = inb(0x3f5);
6992 // record in BIOS Data Area
6993 write_byte(0x0040, 0x0042, return_status[0]);
6994 write_byte(0x0040, 0x0043, return_status[1]);
6995 write_byte(0x0040, 0x0044, return_status[2]);
6996 write_byte(0x0040, 0x0045, return_status[3]);
6997 write_byte(0x0040, 0x0046, return_status[4]);
6998 write_byte(0x0040, 0x0047, return_status[5]);
6999 write_byte(0x0040, 0x0048, return_status[6]);
7001 if ( (return_status[0] & 0xc0) != 0 ) {
7003 set_diskette_ret_status(0x20);
7004 SET_AL(0); // no sectors read
7005 SET_CF(); // error occurred
7009 // ??? should track be new val from return_status[3] ?
7010 set_diskette_current_cyl(drive, track);
7011 // AL = number of sectors read (same value as passed)
7012 SET_AH(0x00); // success
7013 CLEAR_CF(); // success
7016 else if (ah == 0x03) {
7017 // Write Diskette Sectors
7019 //-----------------------------------
7020 // set up DMA controller for transfer
7021 //-----------------------------------
7023 // es:bx = pointer to where to place information from diskette
7024 // port 04: DMA-1 base and current address, channel 2
7025 // port 05: DMA-1 base and current count, channel 2
7026 page = (ES >> 12); // upper 4 bits
7027 base_es = (ES << 4); // lower 16bits contributed by ES
7028 base_address = base_es + BX; // lower 16 bits of address
7029 // contributed by ES:BX
7030 if ( base_address < base_es ) {
7031 // in case of carry, adjust page by 1
7034 base_count = (num_sectors * 512) - 1;
7036 // check for 64K boundary overrun
7037 last_addr = base_address + base_count;
7038 if (last_addr < base_address) {
7040 set_diskette_ret_status(0x09);
7041 SET_AL(0); // no sectors read
7042 SET_CF(); // error occurred
7046 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7049 outb(0x000c, 0x00); // clear flip-flop
7050 outb(0x0004, base_address);
7051 outb(0x0004, base_address>>8);
7052 outb(0x000c, 0x00); // clear flip-flop
7053 outb(0x0005, base_count);
7054 outb(0x0005, base_count>>8);
7056 // port 0b: DMA-1 Mode Register
7057 mode_register = 0x4a; // single mode, increment, autoinit disable,
7058 // transfer type=read, channel 2
7059 outb(0x000b, mode_register);
7061 // port 81: DMA-1 Page Register, channel 2
7064 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7067 //--------------------------------------
7068 // set up floppy controller for transfer
7069 //--------------------------------------
7071 // set 40:3e bit 7 to 0
7072 val8 = read_byte(0x0000, 0x043e);
7074 write_byte(0x0000, 0x043e, val8);
7076 // turn on motor of selected drive, DMA & int enabled, normal operation
7085 // reset the disk motor timeout value of INT 08
7086 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7088 // check port 3f4 for drive readiness
7090 if ( (val8 & 0xf0) != 0x80 )
7091 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7093 // send read-normal-data command (9 bytes) to controller
7094 outb(0x03f5, 0xc5); // c5: write normal data
7095 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7096 outb(0x03f5, track);
7098 outb(0x03f5, sector);
7099 outb(0x03f5, 2); // 512 byte sector size
7100 outb(0x03f5, 0); // last sector number possible on track
7101 outb(0x03f5, 0); // Gap length
7102 outb(0x03f5, 0xff); // Gap length
7104 // turn on interrupts
7109 // wait on 40:3e bit 7 to become 1
7110 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7111 while ( val8 == 0 ) {
7112 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7115 val8 = 0; // separate asm from while() loop
7116 // turn off interrupts
7121 // set 40:3e bit 7 to 0
7122 val8 = read_byte(0x0000, 0x043e);
7124 write_byte(0x0000, 0x043e, val8);
7126 // check port 3f4 for accessibility to status bytes
7128 if ( (val8 & 0xc0) != 0xc0 )
7129 BX_PANIC("int13_diskette: ctrl not ready\n");
7131 // read 7 return status bytes from controller
7132 // using loop index broken, have to unroll...
7133 return_status[0] = inb(0x3f5);
7134 return_status[1] = inb(0x3f5);
7135 return_status[2] = inb(0x3f5);
7136 return_status[3] = inb(0x3f5);
7137 return_status[4] = inb(0x3f5);
7138 return_status[5] = inb(0x3f5);
7139 return_status[6] = inb(0x3f5);
7140 // record in BIOS Data Area
7141 write_byte(0x0040, 0x0042, return_status[0]);
7142 write_byte(0x0040, 0x0043, return_status[1]);
7143 write_byte(0x0040, 0x0044, return_status[2]);
7144 write_byte(0x0040, 0x0045, return_status[3]);
7145 write_byte(0x0040, 0x0046, return_status[4]);
7146 write_byte(0x0040, 0x0047, return_status[5]);
7147 write_byte(0x0040, 0x0048, return_status[6]);
7149 if ( (return_status[0] & 0xc0) != 0 ) {
7150 if ( (return_status[1] & 0x02) != 0 ) {
7151 // diskette not writable.
7152 // AH=status code=0x03 (tried to write on write-protected disk)
7153 // AL=number of sectors written=0
7158 BX_PANIC("int13_diskette_function: read error\n");
7162 // ??? should track be new val from return_status[3] ?
7163 set_diskette_current_cyl(drive, track);
7164 // AL = number of sectors read (same value as passed)
7165 SET_AH(0x00); // success
7166 CLEAR_CF(); // success
7169 else { // if (ah == 0x04)
7170 // Verify Diskette Sectors
7172 // ??? should track be new val from return_status[3] ?
7173 set_diskette_current_cyl(drive, track);
7174 // AL = number of sectors verified (same value as passed)
7175 CLEAR_CF(); // success
7176 SET_AH(0x00); // success
7181 case 0x05: // format diskette track
7182 BX_DEBUG_INT13_FL("floppy f05\n");
7184 num_sectors = GET_AL();
7189 if ((drive > 1) || (head > 1) || (track > 79) ||
7190 (num_sectors == 0) || (num_sectors > 18)) {
7192 set_diskette_ret_status(1);
7193 SET_CF(); // error occurred
7196 // see if drive exists
7197 if (floppy_drive_exists(drive) == 0) {
7198 SET_AH(0x80); // drive not responding
7199 set_diskette_ret_status(0x80);
7200 SET_CF(); // error occurred
7204 // see if media in drive, and type is known
7205 if (floppy_media_known(drive) == 0) {
7206 if (floppy_media_sense(drive) == 0) {
7207 SET_AH(0x0C); // Media type not found
7208 set_diskette_ret_status(0x0C);
7209 SET_AL(0); // no sectors read
7210 SET_CF(); // error occurred
7215 // set up DMA controller for transfer
7216 page = (ES >> 12); // upper 4 bits
7217 base_es = (ES << 4); // lower 16bits contributed by ES
7218 base_address = base_es + BX; // lower 16 bits of address
7219 // contributed by ES:BX
7220 if ( base_address < base_es ) {
7221 // in case of carry, adjust page by 1
7224 base_count = (num_sectors * 4) - 1;
7226 // check for 64K boundary overrun
7227 last_addr = base_address + base_count;
7228 if (last_addr < base_address) {
7230 set_diskette_ret_status(0x09);
7231 SET_AL(0); // no sectors read
7232 SET_CF(); // error occurred
7237 outb(0x000c, 0x00); // clear flip-flop
7238 outb(0x0004, base_address);
7239 outb(0x0004, base_address>>8);
7240 outb(0x000c, 0x00); // clear flip-flop
7241 outb(0x0005, base_count);
7242 outb(0x0005, base_count>>8);
7243 mode_register = 0x4a; // single mode, increment, autoinit disable,
7244 // transfer type=read, channel 2
7245 outb(0x000b, mode_register);
7246 // port 81: DMA-1 Page Register, channel 2
7250 // set up floppy controller for transfer
7251 val8 = read_byte(0x0000, 0x043e);
7253 write_byte(0x0000, 0x043e, val8);
7254 // turn on motor of selected drive, DMA & int enabled, normal operation
7263 // reset the disk motor timeout value of INT 08
7264 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7266 // check port 3f4 for drive readiness
7268 if ( (val8 & 0xf0) != 0x80 )
7269 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7271 // send read-normal-data command (6 bytes) to controller
7272 outb(0x03f5, 0x4d); // 4d: format track
7273 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7274 outb(0x03f5, 2); // 512 byte sector size
7275 outb(0x03f5, num_sectors); // number of sectors per track
7276 outb(0x03f5, 0); // Gap length
7277 outb(0x03f5, 0xf6); // Fill byte
7278 // turn on interrupts
7282 // wait on 40:3e bit 7 to become 1
7283 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7284 while ( val8 == 0 ) {
7285 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7287 val8 = 0; // separate asm from while() loop
7288 // turn off interrupts
7292 // set 40:3e bit 7 to 0
7293 val8 = read_byte(0x0000, 0x043e);
7295 write_byte(0x0000, 0x043e, val8);
7296 // check port 3f4 for accessibility to status bytes
7298 if ( (val8 & 0xc0) != 0xc0 )
7299 BX_PANIC("int13_diskette: ctrl not ready\n");
7301 // read 7 return status bytes from controller
7302 // using loop index broken, have to unroll...
7303 return_status[0] = inb(0x3f5);
7304 return_status[1] = inb(0x3f5);
7305 return_status[2] = inb(0x3f5);
7306 return_status[3] = inb(0x3f5);
7307 return_status[4] = inb(0x3f5);
7308 return_status[5] = inb(0x3f5);
7309 return_status[6] = inb(0x3f5);
7310 // record in BIOS Data Area
7311 write_byte(0x0040, 0x0042, return_status[0]);
7312 write_byte(0x0040, 0x0043, return_status[1]);
7313 write_byte(0x0040, 0x0044, return_status[2]);
7314 write_byte(0x0040, 0x0045, return_status[3]);
7315 write_byte(0x0040, 0x0046, return_status[4]);
7316 write_byte(0x0040, 0x0047, return_status[5]);
7317 write_byte(0x0040, 0x0048, return_status[6]);
7319 if ( (return_status[0] & 0xc0) != 0 ) {
7320 if ( (return_status[1] & 0x02) != 0 ) {
7321 // diskette not writable.
7322 // AH=status code=0x03 (tried to write on write-protected disk)
7323 // AL=number of sectors written=0
7328 BX_PANIC("int13_diskette_function: write error\n");
7333 set_diskette_ret_status(0);
7334 set_diskette_current_cyl(drive, 0);
7335 CLEAR_CF(); // successful
7339 case 0x08: // read diskette drive parameters
7340 BX_DEBUG_INT13_FL("floppy f08\n");
7350 SET_DL(num_floppies);
7355 drive_type = inb_cmos(0x10);
7357 if (drive_type & 0xf0)
7359 if (drive_type & 0x0f)
7371 SET_DL(num_floppies);
7373 switch (drive_type) {
7376 SET_DH(0); // max head #
7379 case 1: // 360KB, 5.25"
7380 CX = 0x2709; // 40 tracks, 9 sectors
7381 SET_DH(1); // max head #
7384 case 2: // 1.2MB, 5.25"
7385 CX = 0x4f0f; // 80 tracks, 15 sectors
7386 SET_DH(1); // max head #
7389 case 3: // 720KB, 3.5"
7390 CX = 0x4f09; // 80 tracks, 9 sectors
7391 SET_DH(1); // max head #
7394 case 4: // 1.44MB, 3.5"
7395 CX = 0x4f12; // 80 tracks, 18 sectors
7396 SET_DH(1); // max head #
7399 case 5: // 2.88MB, 3.5"
7400 CX = 0x4f24; // 80 tracks, 36 sectors
7401 SET_DH(1); // max head #
7404 case 6: // 160k, 5.25"
7405 CX = 0x2708; // 40 tracks, 8 sectors
7406 SET_DH(0); // max head #
7409 case 7: // 180k, 5.25"
7410 CX = 0x2709; // 40 tracks, 9 sectors
7411 SET_DH(0); // max head #
7414 case 8: // 320k, 5.25"
7415 CX = 0x2708; // 40 tracks, 8 sectors
7416 SET_DH(1); // max head #
7420 BX_PANIC("floppy: int13: bad floppy type\n");
7423 /* set es & di to point to 11 byte diskette param table in ROM */
7427 mov ax, #diskette_param_table2
7428 mov _int13_diskette_function.DI+2[bp], ax
7429 mov _int13_diskette_function.ES+2[bp], cs
7432 CLEAR_CF(); // success
7433 /* disk status not changed upon success */
7437 case 0x15: // read diskette drive type
7438 BX_DEBUG_INT13_FL("floppy f15\n");
7441 SET_AH(0); // only 2 drives supported
7442 // set_diskette_ret_status here ???
7446 drive_type = inb_cmos(0x10);
7452 CLEAR_CF(); // successful, not present
7453 if (drive_type==0) {
7454 SET_AH(0); // drive not present
7457 SET_AH(1); // drive present, does not support change line
7462 case 0x16: // get diskette change line status
7463 BX_DEBUG_INT13_FL("floppy f16\n");
7466 SET_AH(0x01); // invalid drive
7467 set_diskette_ret_status(0x01);
7472 SET_AH(0x06); // change line not supported
7473 set_diskette_ret_status(0x06);
7477 case 0x17: // set diskette type for format(old)
7478 BX_DEBUG_INT13_FL("floppy f17\n");
7479 /* not used for 1.44M floppies */
7480 SET_AH(0x01); // not supported
7481 set_diskette_ret_status(1); /* not supported */
7485 case 0x18: // set diskette type for format(new)
7486 BX_DEBUG_INT13_FL("floppy f18\n");
7487 SET_AH(0x01); // do later
7488 set_diskette_ret_status(1);
7493 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7495 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7496 SET_AH(0x01); // ???
7497 set_diskette_ret_status(1);
7503 #else // #if BX_SUPPORT_FLOPPY
7505 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7506 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7510 switch ( GET_AH() ) {
7512 case 0x01: // Read Diskette Status
7514 val8 = read_byte(0x0000, 0x0441);
7523 write_byte(0x0000, 0x0441, 0x01);
7527 #endif // #if BX_SUPPORT_FLOPPY
7530 set_diskette_ret_status(value)
7533 write_byte(0x0040, 0x0041, value);
7537 set_diskette_current_cyl(drive, cyl)
7542 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7543 write_byte(0x0040, 0x0094+drive, cyl);
7547 determine_floppy_media(drive)
7551 Bit8u val8, DOR, ctrl_info;
7553 ctrl_info = read_byte(0x0040, 0x008F);
7561 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7564 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7568 if ( (ctrl_info & 0x04) != 0x04 ) {
7569 // Drive not determined means no drive exists, done.
7574 // check Main Status Register for readiness
7575 val8 = inb(0x03f4) & 0x80; // Main Status Register
7577 BX_PANIC("d_f_m: MRQ bit not set\n");
7581 // existing BDA values
7583 // turn on drive motor
7584 outb(0x03f2, DOR); // Digital Output Register
7587 BX_PANIC("d_f_m: OK so far\n");
7592 int17_function(regs, ds, iret_addr)
7593 pusha_regs_t regs; // regs pushed from PUSHA instruction
7594 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7595 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7597 Bit16u addr,timeout;
7604 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7605 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7606 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7607 if (regs.u.r8.ah == 0) {
7608 outb(addr, regs.u.r8.al);
7610 outb(addr+2, val8 | 0x01); // send strobe
7614 outb(addr+2, val8 & ~0x01);
7615 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7619 if (regs.u.r8.ah == 1) {
7621 outb(addr+2, val8 & ~0x04); // send init
7625 outb(addr+2, val8 | 0x04);
7628 regs.u.r8.ah = (val8 ^ 0x48);
7629 if (!timeout) regs.u.r8.ah |= 0x01;
7630 ClearCF(iret_addr.flags);
7632 SetCF(iret_addr.flags); // Unsupported
7636 // returns bootsegment in ax, drive in bl
7638 int19_function(bseqnr)
7641 Bit16u ebda_seg=read_word(0x0040,0x000E);
7650 // BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7652 // if BX_ELTORITO_BOOT is not defined, old behavior
7653 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7654 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7655 // 0: system boot sequence, first drive C: then A:
7656 // 1: system boot sequence, first drive A: then C:
7657 // else BX_ELTORITO_BOOT is defined
7658 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7659 // CMOS reg 0x3D & 0x0f : 1st boot device
7660 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7661 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7662 // boot device codes:
7663 // 0x00 : not defined
7664 // 0x01 : first floppy
7665 // 0x02 : first harddrive
7666 // 0x03 : first cdrom
7667 // else : boot failure
7669 // Get the boot sequence
7670 #if BX_ELTORITO_BOOT
7671 bootseq=inb_cmos(0x3d);
7672 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7674 if (bseqnr==2) bootseq >>= 4;
7675 if (bseqnr==3) bootseq >>= 8;
7676 if (bootseq<0x10) lastdrive = 1;
7677 bootdrv=0x00; bootcd=0;
7678 switch(bootseq & 0x0f) {
7679 case 0x01: bootdrv=0x00; bootcd=0; break;
7680 case 0x02: bootdrv=0x80; bootcd=0; break;
7681 case 0x03: bootdrv=0x00; bootcd=1; break;
7682 default: return 0x00000000;
7685 bootseq=inb_cmos(0x2d);
7691 bootdrv=0x00; bootcd=0;
7692 if((bootseq&0x20)==0) bootdrv=0x80;
7693 #endif // BX_ELTORITO_BOOT
7695 #if BX_ELTORITO_BOOT
7696 // We have to boot from cd
7698 status = cdrom_boot();
7700 BX_DEBUG("CDBoot:%x\n",status);
7704 if ( (status & 0x00ff) !=0 ) {
7705 print_cdromboot_failure(status);
7706 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7710 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7711 bootdrv = (Bit8u)(status>>8);
7714 #endif // BX_ELTORITO_BOOT
7716 // We have to boot from harddisk or floppy
7727 mov _int19_function.status + 2[bp], ax
7728 mov dl, _int19_function.bootdrv + 2[bp]
7729 mov ax, _int19_function.bootseg + 2[bp]
7730 mov es, ax ;; segment
7731 mov bx, #0x0000 ;; offset
7732 mov ah, #0x02 ;; function 2, read diskette sector
7733 mov al, #0x01 ;; read 1 sector
7734 mov ch, #0x00 ;; track 0
7735 mov cl, #0x01 ;; sector 1
7736 mov dh, #0x00 ;; head 0
7737 int #0x13 ;; read sector
7740 mov _int19_function.status + 2[bp], ax
7748 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7753 // check signature if instructed by cmos reg 0x38, only for floppy
7754 // bootchk = 1 : signature check disabled
7755 // bootchk = 0 : signature check enabled
7756 if (bootdrv != 0) bootchk = 0;
7757 else bootchk = inb_cmos(0x38) & 0x01;
7759 #if BX_ELTORITO_BOOT
7760 // if boot from cd, no signature check
7763 #endif // BX_ELTORITO_BOOT
7766 if (read_word(bootseg,0x1fe) != 0xaa55) {
7767 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7772 #if BX_ELTORITO_BOOT
7773 // Print out the boot string
7774 BX_DEBUG("cdrom_boot: %x\n",status);
7775 print_boot_device(bootcd, bootdrv);
7776 #else // BX_ELTORITO_BOOT
7777 print_boot_device(0, bootdrv);
7778 #endif // BX_ELTORITO_BOOT
7780 BX_DEBUG("boot to %x\n", (((Bit32u)bootdrv) << 16) + bootseg);
7782 // return the boot segment
7783 return (((Bit32u)bootdrv) << 16) + bootseg;
7787 int1a_function(regs, ds, iret_addr)
7788 pusha_regs_t regs; // regs pushed from PUSHA instruction
7789 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7790 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7794 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);
7800 switch (regs.u.r8.ah) {
7801 case 0: // get current clock count
7805 regs.u.r16.cx = BiosData->ticks_high;
7806 regs.u.r16.dx = BiosData->ticks_low;
7807 regs.u.r8.al = BiosData->midnight_flag;
7808 BiosData->midnight_flag = 0; // reset flag
7813 ClearCF(iret_addr.flags); // OK
7816 case 1: // Set Current Clock Count
7820 BiosData->ticks_high = regs.u.r16.cx;
7821 BiosData->ticks_low = regs.u.r16.dx;
7822 BiosData->midnight_flag = 0; // reset flag
7827 ClearCF(iret_addr.flags); // OK
7831 case 2: // Read CMOS Time
7832 if (rtc_updating()) {
7833 SetCF(iret_addr.flags);
7837 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7838 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7839 regs.u.r8.ch = inb_cmos(0x04); // Hours
7840 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7842 regs.u.r8.al = regs.u.r8.ch;
7843 ClearCF(iret_addr.flags); // OK
7846 case 3: // Set CMOS Time
7847 // Using a debugger, I notice the following masking/setting
7848 // of bits in Status Register B, by setting Reg B to
7849 // a few values and getting its value after INT 1A was called.
7851 // try#1 try#2 try#3
7852 // before 1111 1101 0111 1101 0000 0000
7853 // after 0110 0010 0110 0010 0000 0010
7855 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7856 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7857 if (rtc_updating()) {
7859 // fall through as if an update were not in progress
7861 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7862 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7863 outb_cmos(0x04, regs.u.r8.ch); // Hours
7864 // Set Daylight Savings time enabled bit to requested value
7865 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7866 // (reg B already selected)
7867 outb_cmos(0x0b, val8);
7869 regs.u.r8.al = val8; // val last written to Reg B
7870 ClearCF(iret_addr.flags); // OK
7873 case 4: // Read CMOS Date
7875 if (rtc_updating()) {
7876 SetCF(iret_addr.flags);
7879 regs.u.r8.cl = inb_cmos(0x09); // Year
7880 regs.u.r8.dh = inb_cmos(0x08); // Month
7881 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7882 regs.u.r8.ch = inb_cmos(0x32); // Century
7883 regs.u.r8.al = regs.u.r8.ch;
7884 ClearCF(iret_addr.flags); // OK
7887 case 5: // Set CMOS Date
7888 // Using a debugger, I notice the following masking/setting
7889 // of bits in Status Register B, by setting Reg B to
7890 // a few values and getting its value after INT 1A was called.
7892 // try#1 try#2 try#3 try#4
7893 // before 1111 1101 0111 1101 0000 0010 0000 0000
7894 // after 0110 1101 0111 1101 0000 0010 0000 0000
7896 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7897 // My assumption: RegB = (RegB & 01111111b)
7898 if (rtc_updating()) {
7900 SetCF(iret_addr.flags);
7903 outb_cmos(0x09, regs.u.r8.cl); // Year
7904 outb_cmos(0x08, regs.u.r8.dh); // Month
7905 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7906 outb_cmos(0x32, regs.u.r8.ch); // Century
7907 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7908 outb_cmos(0x0b, val8);
7910 regs.u.r8.al = val8; // AL = val last written to Reg B
7911 ClearCF(iret_addr.flags); // OK
7914 case 6: // Set Alarm Time in CMOS
7915 // Using a debugger, I notice the following masking/setting
7916 // of bits in Status Register B, by setting Reg B to
7917 // a few values and getting its value after INT 1A was called.
7919 // try#1 try#2 try#3
7920 // before 1101 1111 0101 1111 0000 0000
7921 // after 0110 1111 0111 1111 0010 0000
7923 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7924 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7925 val8 = inb_cmos(0x0b); // Get Status Reg B
7928 // Alarm interrupt enabled already
7929 SetCF(iret_addr.flags); // Error: alarm in use
7932 if (rtc_updating()) {
7934 // fall through as if an update were not in progress
7936 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7937 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7938 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7939 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7940 // enable Status Reg B alarm bit, clear halt clock bit
7941 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7942 ClearCF(iret_addr.flags); // OK
7945 case 7: // Turn off Alarm
7946 // Using a debugger, I notice the following masking/setting
7947 // of bits in Status Register B, by setting Reg B to
7948 // a few values and getting its value after INT 1A was called.
7950 // try#1 try#2 try#3 try#4
7951 // before 1111 1101 0111 1101 0010 0000 0010 0010
7952 // after 0100 0101 0101 0101 0000 0000 0000 0010
7954 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7955 // My assumption: RegB = (RegB & 01010111b)
7956 val8 = inb_cmos(0x0b); // Get Status Reg B
7957 // clear clock-halt bit, disable alarm bit
7958 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7960 regs.u.r8.al = val8; // val last written to Reg B
7961 ClearCF(iret_addr.flags); // OK
7965 // real mode PCI BIOS functions now handled in assembler code
7966 // this C code handles the error code for information only
7967 if (regs.u.r8.bl == 0xff) {
7968 BX_INFO("PCI BIOS: PCI not present\n");
7969 } else if (regs.u.r8.bl == 0x81) {
7970 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7971 } else if (regs.u.r8.bl == 0x83) {
7972 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7973 } else if (regs.u.r8.bl == 0x86) {
7974 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7976 regs.u.r8.ah = regs.u.r8.bl;
7977 SetCF(iret_addr.flags);
7982 SetCF(iret_addr.flags); // Unsupported
7987 int70_function(regs, ds, iret_addr)
7988 pusha_regs_t regs; // regs pushed from PUSHA instruction
7989 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7990 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7992 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7993 Bit8u registerB = 0, registerC = 0;
7995 // Check which modes are enabled and have occurred.
7996 registerB = inb_cmos( 0xB );
7997 registerC = inb_cmos( 0xC );
7999 if( ( registerB & 0x60 ) != 0 ) {
8000 if( ( registerC & 0x20 ) != 0 ) {
8001 // Handle Alarm Interrupt.
8008 if( ( registerC & 0x40 ) != 0 ) {
8009 // Handle Periodic Interrupt.
8011 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8012 // Wait Interval (Int 15, AH=83) active.
8013 Bit32u time, toggle;
8015 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8016 if( time < 0x3D1 ) {
8018 Bit16u segment, offset;
8020 offset = read_word( 0x40, 0x98 );
8021 segment = read_word( 0x40, 0x9A );
8022 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8023 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8024 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8026 // Continue waiting.
8028 write_dword( 0x40, 0x9C, time );
8041 ;------------------------------------------
8042 ;- INT74h : PS/2 mouse hardware interrupt -
8043 ;------------------------------------------
8048 push #0x00 ;; placeholder for status
8049 push #0x00 ;; placeholder for X
8050 push #0x00 ;; placeholder for Y
8051 push #0x00 ;; placeholder for Z
8052 push #0x00 ;; placeholder for make_far_call boolean
8053 call _int74_function
8054 pop cx ;; remove make_far_call from stack
8057 ;; make far call to EBDA:0022
8060 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8062 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8067 add sp, #8 ;; pop status, x, y, z
8069 pop ds ;; restore DS
8074 ;; This will perform an IRET, but will retain value of current CF
8075 ;; by altering flags on stack. Better than RETF #02.
8080 and BYTE [bp + 0x06], #0xfe
8086 or BYTE [bp + 0x06], #0x01
8091 ;----------------------
8092 ;- INT13h (relocated) -
8093 ;----------------------
8095 ; int13_relocated is a little bit messed up since I played with it
8096 ; I have to rewrite it:
8097 ; - call a function that detect which function to call
8098 ; - make all called C function get the same parameters list
8102 #if BX_ELTORITO_BOOT
8103 ;; check for an eltorito function
8105 jb int13_not_eltorito
8107 ja int13_not_eltorito
8116 jmp _int13_eltorito ;; ELDX not used
8124 ;; check if emulation active
8125 call _cdemu_isactive
8127 je int13_cdemu_inactive
8129 ;; check if access to the emulated drive
8130 call _cdemu_emulated_drive
8133 cmp al,dl ;; int13 on emulated drive
8148 jmp _int13_cdemu ;; ELDX not used
8151 and dl,#0xE0 ;; mask to get device class, including cdroms
8152 cmp al,dl ;; al is 0x00 or 0x80
8153 jne int13_cdemu_inactive ;; inactive for device class
8165 dec dl ;; real drive is dl - 1
8168 int13_cdemu_inactive:
8174 #endif // BX_ELTORITO_BOOT
8185 push dx ;; push eltorito value of dx instead of sp
8196 ;; now the 16-bit registers can be restored with:
8197 ;; pop ds; pop es; popa; iret
8198 ;; arguments passed to functions should be
8199 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8205 jmp _int13_diskette_function
8214 // ebx is modified: BSD 5.2.1 boot loader problem
8215 // someone should figure out which 32 bit register that actually are used
8232 call _int13_harddisk
8244 int18_handler: ;; Boot Failure routing
8245 call _int18_panic_msg
8252 int19_relocated: ;; Boot function, relocated
8254 ;; int19 was beginning to be really complex, so now it
8255 ;; just calls an C function, that does the work
8256 ;; it returns in BL the boot drive, and in AX the boot segment
8257 ;; the boot segment will be 0x0000 if something has failed
8269 call _int19_function
8272 ;; bl contains the boot drive
8273 ;; ax contains the boot segment or 0 if failure
8275 test ax, ax ;; if ax is 0 try next boot device
8281 call _int19_function
8284 test ax, ax ;; if ax is 0 try next boot device
8290 call _int19_function
8293 test ax, ax ;; if ax is 0 call int18
8297 mov dl, bl ;; set drive so guest os find it
8298 shl eax, #0x04 ;; convert seg to ip
8299 mov 2[bp], ax ;; set ip
8301 shr eax, #0x04 ;; get cs back
8302 and ax, #0xF000 ;; remove what went in ip
8303 mov 4[bp], ax ;; set cs
8305 mov es, ax ;; set es to zero fixes [ 549815 ]
8306 mov [bp], ax ;; set bp to zero
8307 mov ax, #0xaa55 ;; set ok flag
8312 iret ;; Beam me up Scotty
8317 int1c_handler: ;; User Timer Tick
8321 ;----------------------
8322 ;- POST: Floppy Drive -
8323 ;----------------------
8329 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8331 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8333 mov 0x0440, al ;; diskette motor timeout counter: not active
8334 mov 0x0441, al ;; diskette controller status return code
8336 mov 0x0442, al ;; disk & diskette controller status register 0
8337 mov 0x0443, al ;; diskette controller status register 1
8338 mov 0x0444, al ;; diskette controller status register 2
8339 mov 0x0445, al ;; diskette controller cylinder number
8340 mov 0x0446, al ;; diskette controller head number
8341 mov 0x0447, al ;; diskette controller sector number
8342 mov 0x0448, al ;; diskette controller bytes written
8344 mov 0x048b, al ;; diskette configuration data
8346 ;; -----------------------------------------------------------------
8347 ;; (048F) diskette controller information
8349 mov al, #0x10 ;; get CMOS diskette drive type
8352 mov ah, al ;; save byte to AH
8355 shr al, #4 ;; look at top 4 bits for drive 0
8356 jz f0_missing ;; jump if no drive0
8357 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8360 mov bl, #0x00 ;; no drive0
8363 mov al, ah ;; restore from AH
8364 and al, #0x0f ;; look at bottom 4 bits for drive 1
8365 jz f1_missing ;; jump if no drive1
8366 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8368 ;; leave high bits in BL zerod
8369 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8370 ;; -----------------------------------------------------------------
8373 mov 0x0490, al ;; diskette 0 media state
8374 mov 0x0491, al ;; diskette 1 media state
8376 ;; diskette 0,1 operational starting state
8377 ;; drive type has not been determined,
8378 ;; has no changed detection line
8382 mov 0x0494, al ;; diskette 0 current cylinder
8383 mov 0x0495, al ;; diskette 1 current cylinder
8386 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8388 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8389 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8390 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8395 ;--------------------
8396 ;- POST: HARD DRIVE -
8397 ;--------------------
8398 ; relocated here because the primary POST area isnt big enough.
8401 // INT 76h calls INT 15h function ax=9100
8403 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8409 mov 0x0474, al /* hard disk status of last operation */
8410 mov 0x0477, al /* hard disk port offset (XT only ???) */
8411 mov 0x048c, al /* hard disk status register */
8412 mov 0x048d, al /* hard disk error register */
8413 mov 0x048e, al /* hard disk task complete flag */
8415 mov 0x0475, al /* hard disk number attached */
8417 mov 0x0476, al /* hard disk control byte */
8418 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8419 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8420 ;; INT 41h: hard disk 0 configuration pointer
8421 ;; INT 46h: hard disk 1 configuration pointer
8422 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8423 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8425 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8437 cmp al, #47 ;; decimal 47 - user definable
8441 ;; CMOS purpose param table offset
8442 ;; 1b cylinders low 0
8443 ;; 1c cylinders high 1
8445 ;; 1e write pre-comp low 5
8446 ;; 1f write pre-comp high 6
8447 ;; 20 retries/bad map/heads>8 8
8448 ;; 21 landing zone low C
8449 ;; 22 landing zone high D
8450 ;; 23 sectors/track E
8455 ;;; Filling EBDA table for hard disk 0.
8463 mov (0x003d + 0x05), ax ;; write precomp word
8468 mov (0x003d + 0x08), al ;; drive control byte
8477 mov (0x003d + 0x0C), ax ;; landing zone word
8479 mov al, #0x1c ;; get cylinders word in AX
8481 in al, #0x71 ;; high byte
8485 in al, #0x71 ;; low byte
8486 mov bx, ax ;; BX = cylinders
8491 mov cl, al ;; CL = heads
8496 mov dl, al ;; DL = sectors
8499 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8501 hd0_post_physical_chs:
8502 ;; no logical CHS mapping used, just physical CHS
8503 ;; use Standard Fixed Disk Parameter Table (FDPT)
8504 mov (0x003d + 0x00), bx ;; number of physical cylinders
8505 mov (0x003d + 0x02), cl ;; number of physical heads
8506 mov (0x003d + 0x0E), dl ;; number of physical sectors
8509 hd0_post_logical_chs:
8510 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8511 mov (0x003d + 0x09), bx ;; number of physical cylinders
8512 mov (0x003d + 0x0b), cl ;; number of physical heads
8513 mov (0x003d + 0x04), dl ;; number of physical sectors
8514 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8516 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8519 jnbe hd0_post_above_2048
8520 ;; 1024 < c <= 2048 cylinders
8523 jmp hd0_post_store_logical
8525 hd0_post_above_2048:
8527 jnbe hd0_post_above_4096
8528 ;; 2048 < c <= 4096 cylinders
8531 jmp hd0_post_store_logical
8533 hd0_post_above_4096:
8535 jnbe hd0_post_above_8192
8536 ;; 4096 < c <= 8192 cylinders
8539 jmp hd0_post_store_logical
8541 hd0_post_above_8192:
8542 ;; 8192 < c <= 16384 cylinders
8546 hd0_post_store_logical:
8547 mov (0x003d + 0x00), bx ;; number of physical cylinders
8548 mov (0x003d + 0x02), cl ;; number of physical heads
8550 mov cl, #0x0f ;; repeat count
8551 mov si, #0x003d ;; offset to disk0 FDPT
8552 mov al, #0x00 ;; sum
8553 hd0_post_checksum_loop:
8557 jnz hd0_post_checksum_loop
8558 not al ;; now take 2s complement
8561 ;;; Done filling EBDA table for hard disk 0.
8565 ;; is there really a second hard disk? if not, return now
8573 ;; check that the hd type is really 0x0f.
8578 ;; check that the extended type is 47 - user definable
8582 cmp al, #47 ;; decimal 47 - user definable
8587 ;; CMOS purpose param table offset
8588 ;; 0x24 cylinders low 0
8589 ;; 0x25 cylinders high 1
8591 ;; 0x27 write pre-comp low 5
8592 ;; 0x28 write pre-comp high 6
8594 ;; 0x2a landing zone low C
8595 ;; 0x2b landing zone high D
8596 ;; 0x2c sectors/track E
8597 ;;; Fill EBDA table for hard disk 1.
8607 mov (0x004d + 0x05), ax ;; write precomp word
8612 mov (0x004d + 0x08), al ;; drive control byte
8621 mov (0x004d + 0x0C), ax ;; landing zone word
8623 mov al, #0x25 ;; get cylinders word in AX
8625 in al, #0x71 ;; high byte
8629 in al, #0x71 ;; low byte
8630 mov bx, ax ;; BX = cylinders
8635 mov cl, al ;; CL = heads
8640 mov dl, al ;; DL = sectors
8643 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8645 hd1_post_physical_chs:
8646 ;; no logical CHS mapping used, just physical CHS
8647 ;; use Standard Fixed Disk Parameter Table (FDPT)
8648 mov (0x004d + 0x00), bx ;; number of physical cylinders
8649 mov (0x004d + 0x02), cl ;; number of physical heads
8650 mov (0x004d + 0x0E), dl ;; number of physical sectors
8653 hd1_post_logical_chs:
8654 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8655 mov (0x004d + 0x09), bx ;; number of physical cylinders
8656 mov (0x004d + 0x0b), cl ;; number of physical heads
8657 mov (0x004d + 0x04), dl ;; number of physical sectors
8658 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8660 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8663 jnbe hd1_post_above_2048
8664 ;; 1024 < c <= 2048 cylinders
8667 jmp hd1_post_store_logical
8669 hd1_post_above_2048:
8671 jnbe hd1_post_above_4096
8672 ;; 2048 < c <= 4096 cylinders
8675 jmp hd1_post_store_logical
8677 hd1_post_above_4096:
8679 jnbe hd1_post_above_8192
8680 ;; 4096 < c <= 8192 cylinders
8683 jmp hd1_post_store_logical
8685 hd1_post_above_8192:
8686 ;; 8192 < c <= 16384 cylinders
8690 hd1_post_store_logical:
8691 mov (0x004d + 0x00), bx ;; number of physical cylinders
8692 mov (0x004d + 0x02), cl ;; number of physical heads
8694 mov cl, #0x0f ;; repeat count
8695 mov si, #0x004d ;; offset to disk0 FDPT
8696 mov al, #0x00 ;; sum
8697 hd1_post_checksum_loop:
8701 jnz hd1_post_checksum_loop
8702 not al ;; now take 2s complement
8705 ;;; Done filling EBDA table for hard disk 1.
8709 ;--------------------
8710 ;- POST: EBDA segment
8711 ;--------------------
8712 ; relocated here because the primary POST area isnt big enough.
8717 mov byte ptr [0x0], #EBDA_SIZE
8719 xor ax, ax ; mov EBDA seg into 40E
8721 mov word ptr [0x40E], #EBDA_SEG
8724 ;--------------------
8725 ;- POST: EOI + jmp via [0x40:67)
8726 ;--------------------
8727 ; relocated here because the primary POST area isnt big enough.
8737 ;--------------------
8740 out #0xA0, al ;; slave PIC EOI
8743 out #0x20, al ;; master PIC EOI
8746 ;--------------------
8748 ;; in: AL in BCD format
8749 ;; out: AL in binary format, AH will always be 0
8752 and bl, #0x0f ;; bl has low digit
8753 shr al, #4 ;; al has high digit
8755 mul al, bh ;; multiply high digit by 10 (result in AX)
8756 add al, bl ;; then add low digit
8759 ;--------------------
8761 ;; Setup the Timer Ticks Count (0x46C:dword) and
8762 ;; Timer Ticks Roller Flag (0x470:byte)
8763 ;; The Timer Ticks Count needs to be set according to
8764 ;; the current CMOS time, as if ticks have been occurring
8765 ;; at 18.2hz since midnight up to this point. Calculating
8766 ;; this is a little complicated. Here are the factors I gather
8767 ;; regarding this. 14,318,180 hz was the original clock speed,
8768 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8769 ;; at the time, or 4 to drive the CGA video adapter. The div3
8770 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8771 ;; the timer. With a maximum 16bit timer count, this is again
8772 ;; divided down by 65536 to 18.2hz.
8774 ;; 14,318,180 Hz clock
8775 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8776 ;; /4 = 1,193,181 Hz fed to timer
8777 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8778 ;; 1 second = 18.20650736 ticks
8779 ;; 1 minute = 1092.390442 ticks
8780 ;; 1 hour = 65543.42651 ticks
8782 ;; Given the values in the CMOS clock, one could calculate
8783 ;; the number of ticks by the following:
8784 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8785 ;; (BcdToBin(minutes) * 1092.3904)
8786 ;; (BcdToBin(hours) * 65543.427)
8787 ;; To get a little more accuracy, since Im using integer
8788 ;; arithmatic, I use:
8789 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8790 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8791 ;; (BcdToBin(hours) * 65543427) / 1000
8796 xor eax, eax ;; clear EAX
8799 in al, #0x71 ;; AL has CMOS seconds in BCD
8800 call BcdToBin ;; EAX now has seconds in binary
8806 mov ecx, eax ;; ECX will accumulate total ticks
8809 xor eax, eax ;; clear EAX
8812 in al, #0x71 ;; AL has CMOS minutes in BCD
8813 call BcdToBin ;; EAX now has minutes in binary
8819 add ecx, eax ;; add to total ticks
8822 xor eax, eax ;; clear EAX
8825 in al, #0x71 ;; AL has CMOS hours in BCD
8826 call BcdToBin ;; EAX now has hours in binary
8832 add ecx, eax ;; add to total ticks
8834 mov 0x46C, ecx ;; Timer Ticks Count
8836 mov 0x470, al ;; Timer Ticks Rollover Flag
8839 ;--------------------
8841 ;; record completion in BIOS task complete flag
8853 ;--------------------
8858 #include "apmbios.S"
8862 #include "apmbios.S"
8865 #include "apmbios.S"
8869 ;--------------------
8874 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8875 dw bios32_entry_point, 0xf ;; 32 bit physical address
8876 db 0 ;; revision level
8877 ;; length in paragraphs and checksum stored in a word to prevent errors
8878 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8879 & 0xff) << 8) + 0x01
8880 db 0,0,0,0,0 ;; reserved
8885 cmp eax, #0x49435024
8887 mov eax, #0x80000000
8892 cmp eax, #0x12378086
8894 mov ebx, #0x000f0000
8896 mov edx, #pcibios_protected
8911 cmp al, #0x01 ;; installation check
8915 mov edx, #0x20494350
8918 pci_pro_f02: ;; find pci device
8926 call pci_pro_select_reg
8940 pci_pro_f08: ;; read configuration byte
8943 call pci_pro_select_reg
8952 pci_pro_f09: ;; read configuration word
8955 call pci_pro_select_reg
8964 pci_pro_f0a: ;; read configuration dword
8967 call pci_pro_select_reg
8974 pci_pro_f0b: ;; write configuration byte
8977 call pci_pro_select_reg
8986 pci_pro_f0c: ;; write configuration word
8989 call pci_pro_select_reg
8998 pci_pro_f0d: ;; write configuration dword
9001 call pci_pro_select_reg
9044 mov eax, #0x80000000
9049 cmp eax, #0x12378086
9059 cmp al, #0x01 ;; installation check
9064 mov edx, #0x20494350
9066 mov di, #pcibios_protected
9069 pci_real_f02: ;; find pci device
9079 call pci_real_select_reg
9083 jne pci_real_nextdev
9090 jne pci_real_devloop
9095 pci_real_f08: ;; read configuration byte
9098 call pci_real_select_reg
9107 pci_real_f09: ;; read configuration word
9110 call pci_real_select_reg
9119 pci_real_f0a: ;; read configuration dword
9122 call pci_real_select_reg
9129 pci_real_f0b: ;; write configuration byte
9132 call pci_real_select_reg
9141 pci_real_f0c: ;; write configuration word
9144 call pci_real_select_reg
9153 pci_real_f0d: ;; write configuration dword
9155 jne pci_real_unknown
9156 call pci_real_select_reg
9177 pci_real_select_reg:
9191 pci_routing_table_structure:
9192 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9194 dw 32 + (6 * 16) ;; table size
9195 db 0 ;; PCI interrupt router bus
9196 db 0x08 ;; PCI interrupt router DevFunc
9197 dw 0x0000 ;; PCI exclusive IRQs
9198 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9199 dw 0x7000 ;; compatible PCI interrupt router device ID
9200 dw 0,0 ;; Miniport data
9201 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9203 ;; first slot entry PCI-to-ISA (embedded)
9204 db 0 ;; pci bus number
9205 db 0x08 ;; pci device number (bit 7-3)
9206 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9207 dw 0xdef8 ;; IRQ bitmap INTA#
9208 db 0x61 ;; link value INTB#
9209 dw 0xdef8 ;; IRQ bitmap INTB#
9210 db 0x62 ;; link value INTC#
9211 dw 0xdef8 ;; IRQ bitmap INTC#
9212 db 0x63 ;; link value INTD#
9213 dw 0xdef8 ;; IRQ bitmap INTD#
9214 db 0 ;; physical slot (0 = embedded)
9216 ;; second slot entry: 1st PCI slot
9217 db 0 ;; pci bus number
9218 db 0x10 ;; pci device number (bit 7-3)
9219 db 0x61 ;; link value INTA#
9220 dw 0xdef8 ;; IRQ bitmap INTA#
9221 db 0x62 ;; link value INTB#
9222 dw 0xdef8 ;; IRQ bitmap INTB#
9223 db 0x63 ;; link value INTC#
9224 dw 0xdef8 ;; IRQ bitmap INTC#
9225 db 0x60 ;; link value INTD#
9226 dw 0xdef8 ;; IRQ bitmap INTD#
9227 db 1 ;; physical slot (0 = embedded)
9229 ;; third slot entry: 2nd PCI slot
9230 db 0 ;; pci bus number
9231 db 0x18 ;; pci device number (bit 7-3)
9232 db 0x62 ;; link value INTA#
9233 dw 0xdef8 ;; IRQ bitmap INTA#
9234 db 0x63 ;; link value INTB#
9235 dw 0xdef8 ;; IRQ bitmap INTB#
9236 db 0x60 ;; link value INTC#
9237 dw 0xdef8 ;; IRQ bitmap INTC#
9238 db 0x61 ;; link value INTD#
9239 dw 0xdef8 ;; IRQ bitmap INTD#
9240 db 2 ;; physical slot (0 = embedded)
9242 ;; 4th slot entry: 3rd PCI slot
9243 db 0 ;; pci bus number
9244 db 0x20 ;; pci device number (bit 7-3)
9245 db 0x63 ;; link value INTA#
9246 dw 0xdef8 ;; IRQ bitmap INTA#
9247 db 0x60 ;; link value INTB#
9248 dw 0xdef8 ;; IRQ bitmap INTB#
9249 db 0x61 ;; link value INTC#
9250 dw 0xdef8 ;; IRQ bitmap INTC#
9251 db 0x62 ;; link value INTD#
9252 dw 0xdef8 ;; IRQ bitmap INTD#
9253 db 3 ;; physical slot (0 = embedded)
9255 ;; 5th slot entry: 4rd PCI slot
9256 db 0 ;; pci bus number
9257 db 0x28 ;; pci device number (bit 7-3)
9258 db 0x60 ;; link value INTA#
9259 dw 0xdef8 ;; IRQ bitmap INTA#
9260 db 0x61 ;; link value INTB#
9261 dw 0xdef8 ;; IRQ bitmap INTB#
9262 db 0x62 ;; link value INTC#
9263 dw 0xdef8 ;; IRQ bitmap INTC#
9264 db 0x63 ;; link value INTD#
9265 dw 0xdef8 ;; IRQ bitmap INTD#
9266 db 4 ;; physical slot (0 = embedded)
9268 ;; 6th slot entry: 5rd PCI slot
9269 db 0 ;; pci bus number
9270 db 0x30 ;; pci device number (bit 7-3)
9271 db 0x61 ;; link value INTA#
9272 dw 0xdef8 ;; IRQ bitmap INTA#
9273 db 0x62 ;; link value INTB#
9274 dw 0xdef8 ;; IRQ bitmap INTB#
9275 db 0x63 ;; link value INTC#
9276 dw 0xdef8 ;; IRQ bitmap INTC#
9277 db 0x60 ;; link value INTD#
9278 dw 0xdef8 ;; IRQ bitmap INTD#
9279 db 5 ;; physical slot (0 = embedded)
9285 pcibios_init_sel_reg:
9297 pcibios_init_set_elcr:
9321 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9326 mov si, #pci_routing_table_structure
9330 call pcibios_init_sel_reg
9333 cmp eax, [si+12] ;; check irq router
9336 call pcibios_init_sel_reg
9337 push bx ;; save irq router bus + devfunc
9340 out dx, ax ;; reset PIRQ route control
9348 add si, #0x20 ;; set pointer to 1st entry
9350 mov ax, #pci_irq_list
9359 call pcibios_init_sel_reg
9363 jnz pci_test_int_pin
9369 call pcibios_init_sel_reg
9374 dec al ;; determine pirq reg
9383 call pcibios_init_sel_reg
9390 mov bx, [bp-2] ;; pci irq list pointer
9395 call pcibios_init_set_elcr
9399 add bl, [bp-3] ;; pci function number
9401 call pcibios_init_sel_reg
9411 mov byte ptr[bp-3], #0x00
9419 #endif // BX_PCIBIOS
9421 ; parallel port detection: base address in DX, index in BX, timeout in CL
9426 and al, #0xdf ; clear input mode
9436 mov [bx+0x408], dx ; Parallel I/O address
9438 mov [bx+0x478], cl ; Parallel printer timeout
9443 ; serial port detection: base address in DX, index in BX, timeout in CL
9445 ; no serial port in the VM -PAD
9465 mov [bx+0x400], dx ; Serial I/O address
9467 mov [bx+0x47c], cl ; Serial timeout
9494 ;; Scan for existence of valid expansion ROMS.
9495 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9496 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9497 ;; System ROM: only 0xE0000
9503 ;; 2 ROM length in 512-byte blocks
9504 ;; 3 ROM initialization entry point (FAR CALL)
9509 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9510 cmp [0], #0xAA55 ;; look for signature
9511 jne rom_scan_increment
9513 jnz rom_scan_increment
9515 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9517 ;; We want our increment in 512-byte quantities, rounded to
9518 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9520 jz block_count_rounded
9521 and al, #0xfc ;; needs rounding up
9523 block_count_rounded:
9525 xor bx, bx ;; Restore DS back to 0000:
9528 ;; Push addr of ROM entry point
9530 push #0x0003 ;; Push offset
9531 mov bp, sp ;; Call ROM init routine using seg:off on stack
9532 db 0xff ;; call_far ss:[bp+0]
9535 cli ;; In case expansion ROM BIOS turns IF on
9536 add sp, #2 ;; Pop offset value
9537 pop cx ;; Pop seg value (restore CX)
9538 pop ax ;; Restore AX
9540 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9541 ;; because the segment selector is shifted left 4 bits.
9546 xor ax, ax ;; Restore DS back to 0000:
9552 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9553 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9554 ; but the tables themeselves can be elsewhere.
9563 mov cx, #0x001f ; 0x1f bytes to copy
9565 mov es, ax ; destination segment is 0xf0000
9566 mov di, #smbios_entry_point ; destination offset
9568 mov ds, ax ; source segment is 0x9f000
9569 mov si, #0x0000 ; source offset is 0
9587 ;; for 'C' strings and other data, insert them here with
9588 ;; a the following hack:
9589 ;; DATA_SEG_DEFS_HERE
9595 .org 0xe05b ; POST Entry Point
9600 ;; first reset the DMA controllers
9604 ;; then initialize the DMA controllers
9606 out 0xD6, al ; cascade mode of channel 4 enabled
9608 out 0xD4, al ; unmask channel 4
9610 ;; Examine CMOS shutdown status.
9618 ;; Reset CMOS shutdown status.
9620 out 0x70, AL ; select CMOS register Fh
9622 out 0x71, AL ; set shutdown action to normal
9624 ;; Examine CMOS shutdown status.
9627 ;; 0x00, 0x09, 0x0D+ = normal startup
9635 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9639 ;; Examine CMOS shutdown status.
9640 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9642 call _shutdown_status_panic
9648 ; 0xb0, 0x20, /* mov al, #0x20 */
9649 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9659 ; case 0: normal startup
9668 ;; zero out BIOS data area (40:00..40:ff)
9670 mov cx, #0x0080 ;; 128 words
9676 call _log_bios_start
9678 ;; set all interrupts to default handler
9679 mov bx, #0x0000 ;; offset index
9680 mov cx, #0x0100 ;; counter (256 interrupts)
9681 mov ax, #dummy_iret_handler
9691 loop post_default_ints
9693 ;; set vector 0x79 to zero
9694 ;; this is used by 'gardian angel' protection system
9695 SET_INT_VECTOR(0x79, #0, #0)
9697 ;; base memory in K 40:13 (word)
9698 mov ax, #BASE_MEM_IN_K
9702 ;; Manufacturing Test 40:12
9705 ;; Warm Boot Flag 0040:0072
9706 ;; value of 1234h = skip memory checks
9710 ;; Printer Services vector
9711 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9713 ;; Bootstrap failure vector
9714 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9716 ;; Bootstrap Loader vector
9717 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9719 ;; User Timer Tick vector
9720 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9722 ;; Memory Size Check vector
9723 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9725 ;; Equipment Configuration Check vector
9726 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9729 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9735 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9736 ;; int 1C already points at dummy_iret_handler (above)
9737 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9740 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9745 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9751 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9752 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9756 mov 0x0417, al /* keyboard shift flags, set 1 */
9757 mov 0x0418, al /* keyboard shift flags, set 2 */
9758 mov 0x0419, al /* keyboard alt-numpad work area */
9759 mov 0x0471, al /* keyboard ctrl-break flag */
9760 mov 0x0497, al /* keyboard status flags 4 */
9762 mov 0x0496, al /* keyboard status flags 3 */
9765 /* keyboard head of buffer pointer */
9769 /* keyboard end of buffer pointer */
9772 /* keyboard pointer to start of buffer */
9776 /* keyboard pointer to end of buffer */
9780 /* init the keyboard */
9783 ;; mov CMOS Equipment Byte to BDA Equipment Word
9792 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9796 mov cl, #0x14 ; timeout value
9797 mov dx, #0x378 ; Parallel I/O address, port 1
9799 mov dx, #0x278 ; Parallel I/O address, port 2
9802 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9804 or ax, bx ; set number of parallel ports
9808 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9809 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9811 mov cl, #0x0a ; timeout value
9812 mov dx, #0x03f8 ; Serial I/O address, port 1
9814 mov dx, #0x02f8 ; Serial I/O address, port 2
9816 mov dx, #0x03e8 ; Serial I/O address, port 3
9818 mov dx, #0x02e8 ; Serial I/O address, port 4
9821 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9823 or ax, bx ; set number of serial port
9827 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9828 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9829 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9830 ;; BIOS DATA AREA 0x4CE ???
9831 call timer_tick_post
9834 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9836 ;; IRQ13 (FPU exception) setup
9837 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9840 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9845 mov al, #0x11 ; send initialisation commands
9860 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9861 #if BX_USE_PS2_MOUSE
9866 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9869 call _copy_e820_table
9888 call _print_bios_banner
9893 call floppy_drive_post
9900 call hard_drive_post
9903 ;; ATA/ATAPI driver setup
9908 #else // BX_USE_ATADRV
9913 call hard_drive_post
9915 #endif // BX_USE_ATADRV
9917 #if BX_ELTORITO_BOOT
9919 ;; eltorito floppy/harddisk emulation from cd
9923 #endif // BX_ELTORITO_BOOT
9926 //JMP_EP(0x0064) ; INT 19h location
9929 .org 0xe2c3 ; NMI Handler Entry Point
9931 ;; FIXME the NMI handler should not panic
9932 ;; but iret when called from int75 (fpu exception)
9933 call _nmi_handler_msg
9937 out 0xf0, al // clear irq13
9938 call eoi_both_pics // clear interrupt
9939 int 2 // legacy nmi call
9942 ;-------------------------------------------
9943 ;- INT 13h Fixed Disk Services Entry Point -
9944 ;-------------------------------------------
9945 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9947 //JMPL(int13_relocated)
9950 .org 0xe401 ; Fixed Disk Parameter Table
9955 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9959 ;-------------------------------------------
9960 ;- System BIOS Configuration Data Table
9961 ;-------------------------------------------
9962 .org BIOS_CONFIG_TABLE
9963 db 0x08 ; Table size (bytes) -Lo
9964 db 0x00 ; Table size (bytes) -Hi
9969 ; b7: 1=DMA channel 3 used by hard disk
9970 ; b6: 1=2 interrupt controllers present
9972 ; b4: 1=BIOS calls int 15h/4Fh every key
9973 ; b3: 1=wait for extern event supported (Int 15h/41h)
9974 ; b2: 1=extended BIOS data area used
9975 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9976 ; b0: 1=Dual bus (MicroChannel + ISA)
9980 (BX_CALL_INT15_4F << 4) | \
9982 (BX_USE_EBDA << 2) | \
9986 ; b7: 1=32-bit DMA supported
9987 ; b6: 1=int16h, function 9 supported
9988 ; b5: 1=int15h/C6h (get POS data) supported
9989 ; b4: 1=int15h/C7h (get mem map info) supported
9990 ; b3: 1=int15h/C8h (en/dis CPU) supported
9991 ; b2: 1=non-8042 kb controller
9992 ; b1: 1=data streaming supported
10006 ; b4: POST supports ROM-to-RAM enable/disable
10007 ; b3: SCSI on system board
10008 ; b2: info panel installed
10009 ; b1: Initial Machine Load (IML) system - BIOS on disk
10010 ; b0: SCSI supported in IML
10014 ; b6: EEPROM present
10015 ; b5-3: ABIOS presence (011 = not supported)
10017 ; b1: memory split above 16Mb supported
10018 ; b0: POSTEXT directly supported by POST
10020 ; Feature byte 5 (IBM)
10021 ; b1: enhanced mouse
10027 .org 0xe729 ; Baud Rate Generator Table
10032 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10038 call _int14_function
10044 ;----------------------------------------
10045 ;- INT 16h Keyboard Service Entry Point -
10046 ;----------------------------------------
10062 call _int16_function
10072 and BYTE [bp + 0x06], #0xbf
10080 or BYTE [bp + 0x06], #0x40
10088 int16_wait_for_key:
10092 jne int16_key_found
10096 /* no key yet, call int 15h, function AX=9002 */
10097 0x50, /* push AX */
10098 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10099 0xcd, 0x15, /* int 15h */
10101 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10103 jmp int16_wait_for_key
10108 call _int16_function
10113 /* notify int16 complete w/ int 15h, function AX=9102 */
10114 0x50, /* push AX */
10115 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10116 0xcd, 0x15, /* int 15h */
10123 ;-------------------------------------------------
10124 ;- INT09h : Keyboard Hardware Service Entry Point -
10125 ;-------------------------------------------------
10131 mov al, #0xAD ;;disable keyboard
10140 in al, #0x60 ;;read key from keyboard controller
10141 //test al, #0x80 ;;look for key release
10142 //jnz int09_process_key ;; dont pass releases to intercept?
10144 ;; check for extended key
10146 jne int09_call_int15_4f
10151 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10153 mov BYTE [0x496], al
10156 in al, #0x60 ;;read another key from keyboard controller
10160 int09_call_int15_4f:
10163 #ifdef BX_CALL_INT15_4F
10164 mov ah, #0x4f ;; allow for keyboard intercept
10171 //int09_process_key:
10174 call _int09_function
10180 call eoi_master_pic
10183 mov al, #0xAE ;;enable keyboard
10191 ;----------------------------------------
10192 ;- INT 13h Diskette Service Entry Point -
10193 ;----------------------------------------
10196 jmp int13_noeltorito
10198 ;---------------------------------------------
10199 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10200 ;---------------------------------------------
10201 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10211 mov al, #0x08 ; sense interrupt status
10229 mov ax, #0x0000 ;; segment 0000
10231 call eoi_master_pic
10233 or al, #0x80 ;; diskette interrupt has occurred
10241 .org 0xefc7 ; Diskette Controller Parameter Table
10242 diskette_param_table:
10243 ;; Since no provisions are made for multiple drive types, most
10244 ;; values in this table are ignored. I set parameters for 1.44M
10247 db 0x02 ;; head load time 0000001, DMA used
10259 ;----------------------------------------
10260 ;- INT17h : Printer Service Entry Point -
10261 ;----------------------------------------
10268 call _int17_function
10273 diskette_param_table2:
10274 ;; New diskette parameter table adding 3 parameters from IBM
10275 ;; Since no provisions are made for multiple drive types, most
10276 ;; values in this table are ignored. I set parameters for 1.44M
10279 db 0x02 ;; head load time 0000001, DMA used
10289 db 79 ;; maximum track
10290 db 0 ;; data transfer rate
10291 db 4 ;; drive type in cmos
10293 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10300 .org 0xf065 ; INT 10h Video Support Service Entry Point
10302 ;; dont do anything, since the VGA BIOS handles int10h requests
10305 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10310 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10311 ; ??? different for Pentium (machine check)?
10323 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10335 .org 0xf859 ; INT 15h System Services Entry Point
10349 #if BX_USE_PS2_MOUSE
10351 je int15_handler_mouse
10353 call _int15_function
10354 int15_handler_mouse_ret:
10356 int15_handler32_ret:
10366 #if BX_USE_PS2_MOUSE
10367 int15_handler_mouse:
10368 call _int15_function_mouse
10369 jmp int15_handler_mouse_ret
10374 call _int15_function32
10376 jmp int15_handler32_ret
10378 ;; Protected mode IDT descriptor
10380 ;; I just make the limit 0, so the machine will shutdown
10381 ;; if an exception occurs during protected mode memory
10384 ;; Set base to f0000 to correspond to beginning of BIOS,
10385 ;; in case I actually define an IDT later
10389 dw 0x0000 ;; limit 15:00
10390 dw 0x0000 ;; base 15:00
10391 db 0x0f ;; base 23:16
10393 ;; Real mode IDT descriptor
10395 ;; Set to typical real-mode values.
10400 dw 0x03ff ;; limit 15:00
10401 dw 0x0000 ;; base 15:00
10402 db 0x00 ;; base 23:16
10408 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10421 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10422 mov ds, ax ; on 16bit protected mode.
10423 jmp int1a_callfunction
10430 int1a_callfunction:
10431 call _int1a_function
10437 ;; int70h: IRQ8 - CMOS RTC
10444 call _int70_function
10452 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10460 ;; time to turn off drive(s)?
10463 jz int08_floppy_off
10466 jnz int08_floppy_off
10467 ;; turn motor(s) off
10476 mov eax, 0x046c ;; get ticks dword
10479 ;; compare eax to one days worth of timer ticks at 18.2 hz
10480 cmp eax, #0x001800B0
10481 jb int08_store_ticks
10482 ;; there has been a midnight rollover at this point
10483 xor eax, eax ;; zero out counter
10484 inc BYTE 0x0470 ;; increment rollover flag
10487 mov 0x046c, eax ;; store new ticks dword
10488 ;; chain to user timer tick INT #0x1c
10490 //;; call_ep [ds:loc]
10491 //CALL_EP( 0x1c << 2 )
10494 call eoi_master_pic
10499 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10503 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10505 ;------------------------------------------------
10506 ;- IRET Instruction for Dummy Interrupt Handler -
10507 ;------------------------------------------------
10508 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10509 dummy_iret_handler:
10512 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10521 .org 0xfff0 ; Power-up Entry Point
10528 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10529 .ascii BIOS_BUILD_DATE
10531 .org 0xfffe ; System Model ID
10535 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10538 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10539 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10540 * This font is public domain
10542 static Bit8u vgafont8[128*8]=
10544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10545 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10546 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10547 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10548 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10549 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10550 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10551 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10552 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10553 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10554 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10555 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10556 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10557 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10558 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10559 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10560 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10561 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10562 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10563 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10564 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10565 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10566 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10567 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10568 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10569 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10570 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10571 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10572 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10573 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10574 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10575 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10577 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10578 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10579 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10580 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10581 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10582 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10583 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10584 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10585 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10586 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10587 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10588 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10589 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10590 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10591 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10592 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10593 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10594 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10595 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10596 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10597 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10598 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10599 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10600 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10601 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10602 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10603 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10604 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10605 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10606 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10607 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10608 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10609 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10610 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10611 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10612 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10613 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10614 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10615 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10616 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10617 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10618 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10619 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10620 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10621 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10622 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10623 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10624 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10625 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10626 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10627 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10628 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10629 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10630 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10631 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10632 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10633 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10634 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10635 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10636 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10637 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10638 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10640 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10641 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10642 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10643 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10644 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10645 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10646 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10647 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10648 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10649 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10650 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10651 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10652 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10653 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10654 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10655 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10656 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10657 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10658 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10659 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10660 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10661 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10662 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10663 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10664 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10665 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10666 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10667 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10668 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10669 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10670 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10671 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10677 // just carve out some blank space for HVMLOADER to write the MP tables to
10679 // NOTE: There should be enough space for a 32 processor entry MP table
10683 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10684 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
10685 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
10686 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
10687 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
10688 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
10689 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
10690 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
10691 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
10692 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
10693 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
10694 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
10695 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
10696 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
10697 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
10700 smbios_entry_point:
10701 db 0,0,0,0,0,0,0,0 ; 8 bytes
10702 db 0,0,0,0,0,0,0,0 ; 16 bytes
10703 db 0,0,0,0,0,0,0,0 ; 24 bytes
10704 db 0,0,0,0,0,0,0 ; 31 bytes
10707 #else // !HVMASSIST
10711 // bcc-generated data will be placed here
10713 // For documentation of this config structure, look on developer.intel.com and
10714 // search for multiprocessor specification. Note that when you change anything
10715 // you must update the checksum (a pain!). It would be better to construct this
10716 // with C structures, or at least fill in the checksum automatically.
10718 // Maybe this structs could be moved elsewhere than d000
10720 #if (BX_SMP_PROCESSORS==1)
10721 // no structure necessary.
10722 #elif (BX_SMP_PROCESSORS==2)
10723 // define the Intel MP Configuration Structure for 2 processors at
10724 // APIC ID 0,1. I/O APIC at ID=2.
10727 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10728 dw (mp_config_end-mp_config_table) ;; table length
10730 db 0x65 ;; checksum
10731 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10732 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10733 db 0x20, 0x20, 0x20, 0x20
10734 db 0x20, 0x20, 0x20, 0x20
10735 dw 0,0 ;; oem table ptr
10736 dw 0 ;; oem table size
10737 dw 20 ;; entry count
10738 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10739 dw 0 ;; extended table length
10740 db 0 ;; extended table checksum
10743 db 0 ;; entry type=processor
10744 db 0 ;; local APIC id
10745 db 0x11 ;; local APIC version number
10746 db 3 ;; cpu flags: enabled, bootstrap processor
10747 db 0,6,0,0 ;; cpu signature
10748 dw 0x201,0 ;; feature flags
10752 db 0 ;; entry type=processor
10753 db 1 ;; local APIC id
10754 db 0x11 ;; local APIC version number
10755 db 1 ;; cpu flags: enabled
10756 db 0,6,0,0 ;; cpu signature
10757 dw 0x201,0 ;; feature flags
10761 db 1 ;; entry type=bus
10763 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10765 db 2 ;; entry type=I/O APIC
10766 db 2 ;; apic id=2. linux will set.
10767 db 0x11 ;; I/O APIC version number
10768 db 1 ;; flags=1=enabled
10769 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10771 db 3 ;; entry type=I/O interrupt
10772 db 0 ;; interrupt type=vectored interrupt
10773 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10774 db 0 ;; source bus ID is ISA
10775 db 0 ;; source bus IRQ
10776 db 2 ;; destination I/O APIC ID
10777 db 0 ;; destination I/O APIC interrrupt in
10778 ;; repeat pattern for interrupts 0-15
10788 db 3,0,0,0,0,10,2,10
10789 db 3,0,0,0,0,11,2,11
10790 db 3,0,0,0,0,12,2,12
10791 db 3,0,0,0,0,13,2,13
10792 db 3,0,0,0,0,14,2,14
10793 db 3,0,0,0,0,15,2,15
10794 #elif (BX_SMP_PROCESSORS==4)
10795 // define the Intel MP Configuration Structure for 4 processors at
10796 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10799 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10800 dw (mp_config_end-mp_config_table) ;; table length
10802 db 0xdd ;; checksum
10803 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10804 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10805 db 0x20, 0x20, 0x20, 0x20
10806 db 0x20, 0x20, 0x20, 0x20
10807 dw 0,0 ;; oem table ptr
10808 dw 0 ;; oem table size
10809 dw 22 ;; entry count
10810 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10811 dw 0 ;; extended table length
10812 db 0 ;; extended table checksum
10815 db 0 ;; entry type=processor
10816 db 0 ;; local APIC id
10817 db 0x11 ;; local APIC version number
10818 db 3 ;; cpu flags: enabled, bootstrap processor
10819 db 0,6,0,0 ;; cpu signature
10820 dw 0x201,0 ;; feature flags
10824 db 0 ;; entry type=processor
10825 db 1 ;; local APIC id
10826 db 0x11 ;; local APIC version number
10827 db 1 ;; cpu flags: enabled
10828 db 0,6,0,0 ;; cpu signature
10829 dw 0x201,0 ;; feature flags
10833 db 0 ;; entry type=processor
10834 db 2 ;; local APIC id
10835 db 0x11 ;; local APIC version number
10836 db 1 ;; cpu flags: enabled
10837 db 0,6,0,0 ;; cpu signature
10838 dw 0x201,0 ;; feature flags
10842 db 0 ;; entry type=processor
10843 db 3 ;; local APIC id
10844 db 0x11 ;; local APIC version number
10845 db 1 ;; cpu flags: enabled
10846 db 0,6,0,0 ;; cpu signature
10847 dw 0x201,0 ;; feature flags
10851 db 1 ;; entry type=bus
10853 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10855 db 2 ;; entry type=I/O APIC
10856 db 4 ;; apic id=4. linux will set.
10857 db 0x11 ;; I/O APIC version number
10858 db 1 ;; flags=1=enabled
10859 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10861 db 3 ;; entry type=I/O interrupt
10862 db 0 ;; interrupt type=vectored interrupt
10863 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10864 db 0 ;; source bus ID is ISA
10865 db 0 ;; source bus IRQ
10866 db 4 ;; destination I/O APIC ID
10867 db 0 ;; destination I/O APIC interrrupt in
10868 ;; repeat pattern for interrupts 0-15
10878 db 3,0,0,0,0,10,4,10
10879 db 3,0,0,0,0,11,4,11
10880 db 3,0,0,0,0,12,4,12
10881 db 3,0,0,0,0,13,4,13
10882 db 3,0,0,0,0,14,4,14
10883 db 3,0,0,0,0,15,4,15
10884 #elif (BX_SMP_PROCESSORS==8)
10885 // define the Intel MP Configuration Structure for 8 processors at
10886 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10889 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10890 dw (mp_config_end-mp_config_table) ;; table length
10892 db 0xc3 ;; checksum
10893 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10894 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10895 db 0x20, 0x20, 0x20, 0x20
10896 db 0x20, 0x20, 0x20, 0x20
10897 dw 0,0 ;; oem table ptr
10898 dw 0 ;; oem table size
10899 dw 26 ;; entry count
10900 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10901 dw 0 ;; extended table length
10902 db 0 ;; extended table checksum
10905 db 0 ;; entry type=processor
10906 db 0 ;; local APIC id
10907 db 0x11 ;; local APIC version number
10908 db 3 ;; cpu flags: enabled, bootstrap processor
10909 db 0,6,0,0 ;; cpu signature
10910 dw 0x201,0 ;; feature flags
10914 db 0 ;; entry type=processor
10915 db 1 ;; local APIC id
10916 db 0x11 ;; local APIC version number
10917 db 1 ;; cpu flags: enabled
10918 db 0,6,0,0 ;; cpu signature
10919 dw 0x201,0 ;; feature flags
10923 db 0 ;; entry type=processor
10924 db 2 ;; local APIC id
10925 db 0x11 ;; local APIC version number
10926 db 1 ;; cpu flags: enabled
10927 db 0,6,0,0 ;; cpu signature
10928 dw 0x201,0 ;; feature flags
10932 db 0 ;; entry type=processor
10933 db 3 ;; local APIC id
10934 db 0x11 ;; local APIC version number
10935 db 1 ;; cpu flags: enabled
10936 db 0,6,0,0 ;; cpu signature
10937 dw 0x201,0 ;; feature flags
10941 db 0 ;; entry type=processor
10942 db 4 ;; local APIC id
10943 db 0x11 ;; local APIC version number
10944 db 1 ;; cpu flags: enabled
10945 db 0,6,0,0 ;; cpu signature
10946 dw 0x201,0 ;; feature flags
10950 db 0 ;; entry type=processor
10951 db 5 ;; local APIC id
10952 db 0x11 ;; local APIC version number
10953 db 1 ;; cpu flags: enabled
10954 db 0,6,0,0 ;; cpu signature
10955 dw 0x201,0 ;; feature flags
10959 db 0 ;; entry type=processor
10960 db 6 ;; local APIC id
10961 db 0x11 ;; local APIC version number
10962 db 1 ;; cpu flags: enabled
10963 db 0,6,0,0 ;; cpu signature
10964 dw 0x201,0 ;; feature flags
10968 db 0 ;; entry type=processor
10969 db 7 ;; local APIC id
10970 db 0x11 ;; local APIC version number
10971 db 1 ;; cpu flags: enabled
10972 db 0,6,0,0 ;; cpu signature
10973 dw 0x201,0 ;; feature flags
10977 db 1 ;; entry type=bus
10979 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10981 db 2 ;; entry type=I/O APIC
10983 db 0x11 ;; I/O APIC version number
10984 db 1 ;; flags=1=enabled
10985 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10987 db 3 ;; entry type=I/O interrupt
10988 db 0 ;; interrupt type=vectored interrupt
10989 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10990 db 0 ;; source bus ID is ISA
10991 db 0 ;; source bus IRQ
10992 db 8 ;; destination I/O APIC ID
10993 db 0 ;; destination I/O APIC interrrupt in
10994 ;; repeat pattern for interrupts 0-15
11004 db 3,0,0,0,0,10,8,10
11005 db 3,0,0,0,0,11,8,11
11006 db 3,0,0,0,0,12,8,12
11007 db 3,0,0,0,0,13,8,13
11008 db 3,0,0,0,0,14,8,14
11009 db 3,0,0,0,0,15,8,15
11011 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11012 #endif // if (BX_SMP_PROCESSORS==...)
11014 mp_config_end: // this label used to find length of mp structure
11017 #if (BX_SMP_PROCESSORS>1)
11019 mp_floating_pointer_structure:
11020 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
11021 dw mp_config_table, 0xf ;; pointer to MP configuration table
11022 db 1 ;; length of this struct in 16-bit byte chunks
11023 db 4 ;; MP spec revision
11024 db 0xc1 ;; checksum
11025 db 0 ;; MP feature byte 1. value 0 means look at the config table
11026 db 0,0,0,0 ;; MP feature bytes 2-5.
11031 #endif // HVMASSIST