2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.6 2008/05/30 00:46:55 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.6 $";
949 static char bios_date_string[] = "$Date: 2008/05/30 00:46:55 $";
951 static char CVSID[] = "$Id: rombios.c,v 1.6 2008/05/30 00:46:55 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
1411 //set_DS(ds_selector)
1412 // Bit16u ds_selector;
1419 // mov ax, 4[bp] ; ds_selector
1439 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1440 if (nr_entries > 32)
1442 write_word(0xe000, 0x8, nr_entries);
1443 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1445 #endif /* HVMASSIST */
1448 /* serial debug port*/
1449 #define BX_DEBUG_PORT 0x03f8
1452 #define UART_RBR 0x00
1453 #define UART_THR 0x00
1456 #define UART_IER 0x01
1457 #define UART_IIR 0x02
1458 #define UART_FCR 0x02
1459 #define UART_LCR 0x03
1460 #define UART_MCR 0x04
1461 #define UART_DLL 0x00
1462 #define UART_DLM 0x01
1465 #define UART_LSR 0x05
1466 #define UART_MSR 0x06
1467 #define UART_SCR 0x07
1469 int uart_can_tx_byte(base_port)
1472 return inb(base_port + UART_LSR) & 0x20;
1475 void uart_wait_to_tx_byte(base_port)
1478 while (!uart_can_tx_byte(base_port));
1481 void uart_wait_until_sent(base_port)
1484 while (!(inb(base_port + UART_LSR) & 0x40));
1487 void uart_tx_byte(base_port, data)
1491 uart_wait_to_tx_byte(base_port);
1492 outb(base_port + UART_THR, data);
1493 uart_wait_until_sent(base_port);
1522 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1523 uart_tx_byte(BX_DEBUG_PORT, c);
1528 #if BX_VIRTUAL_PORTS
1529 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1530 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1532 if (action & BIOS_PRINTF_SCREEN) {
1533 if (c == '\n') wrch('\r');
1539 put_int(action, val, width, neg)
1544 short nval = val / 10;
1546 put_int(action, nval, width - 1, neg);
1548 while (--width > 0) send(action, ' ');
1549 if (neg) send(action, '-');
1551 send(action, val - (nval * 10) + '0');
1555 put_uint(action, val, width, neg)
1561 unsigned short nval = val / 10;
1563 put_uint(action, nval, width - 1, neg);
1565 while (--width > 0) send(action, ' ');
1566 if (neg) send(action, '-');
1568 send(action, val - (nval * 10) + '0');
1571 //--------------------------------------------------------------------------
1573 // A compact variable argument printf function which prints its output via
1574 // an I/O port so that it can be logged by Bochs/Plex.
1575 // Currently, only %x is supported (or %02x, %04x, etc).
1577 // Supports %[format_width][format]
1578 // where format can be d,x,c,s
1579 //--------------------------------------------------------------------------
1581 bios_printf(action, s)
1585 Bit8u c, format_char;
1589 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1597 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1598 #if BX_VIRTUAL_PORTS
1599 outb(PANIC_PORT2, 0x00);
1601 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1604 while (c = read_byte(get_CS(), s)) {
1609 else if (in_format) {
1610 if ( (c>='0') && (c<='9') ) {
1611 format_width = (format_width * 10) + (c - '0');
1614 arg_ptr++; // increment to next arg
1615 arg = read_word(arg_seg, arg_ptr);
1617 if (format_width == 0)
1619 for (i=format_width-1; i>=0; i--) {
1620 nibble = (arg >> (4 * i)) & 0x000f;
1621 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1624 else if (c == 'u') {
1625 put_uint(action, arg, format_width, 0);
1627 else if (c == 'd') {
1629 put_int(action, -arg, format_width - 1, 1);
1631 put_int(action, arg, format_width, 0);
1633 else if (c == 's') {
1634 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1636 else if (c == 'c') {
1640 BX_PANIC("bios_printf: unknown format\n");
1650 if (action & BIOS_PRINTF_HALT) {
1651 // freeze in a busy loop.
1661 //--------------------------------------------------------------------------
1663 //--------------------------------------------------------------------------
1664 // this file is based on LinuxBIOS implementation of keyboard.c
1665 // could convert to #asm to gain space
1672 BX_DEBUG("rombios: keyboard_init\n");
1674 /* printf("Assuming keyboard already inited and returning\n");
1677 /* ------------------- Flush buffers ------------------------*/
1678 /* Wait until buffer is empty */
1680 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1682 /* flush incoming keys */
1683 // temporarily chaged for debug -PAD
1688 if (inb(0x64) & 0x01) {
1694 // Due to timer issues, and if the IPS setting is > 15000000,
1695 // the incoming keys might not be flushed here. That will
1696 // cause a panic a few lines below. See sourceforge bug report :
1697 // [ 642031 ] FATAL: Keyboard RESET error:993
1699 /* ------------------- controller side ----------------------*/
1700 /* send cmd = 0xAA, self test 8042 */
1703 /* Wait until buffer is empty */
1705 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x02);
1706 if (max==0x0) keyboard_panic(00);
1710 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x03);
1711 if (max==0x0) keyboard_panic(01);
1713 /* read self-test result, 0x55 should be returned from 0x60 */
1714 if ((inb(0x60) != 0x55)){
1715 keyboard_panic(991);
1718 /* send cmd = 0xAB, keyboard interface test */
1721 /* Wait until buffer is empty */
1723 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1724 if (max==0x0) keyboard_panic(10);
1728 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1729 if (max==0x0) keyboard_panic(11);
1731 /* read keyboard interface test result, */
1732 /* 0x00 should be returned form 0x60 */
1733 if ((inb(0x60) != 0x00)) {
1734 keyboard_panic(992);
1737 /* Enable Keyboard clock */
1741 /* ------------------- keyboard side ------------------------*/
1742 /* reset kerboard and self test (keyboard side) */
1745 /* Wait until buffer is empty */
1747 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1748 if (max==0x0) keyboard_panic(20);
1752 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1753 if (max==0x0) keyboard_panic(21);
1755 /* keyboard should return ACK */
1756 if ((inb(0x60) != 0xfa)) {
1757 keyboard_panic(993);
1762 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1763 if (max==0x0) keyboard_panic(31);
1765 if ((inb(0x60) != 0xaa)) {
1766 keyboard_panic(994);
1769 /* Disable keyboard */
1772 /* Wait until buffer is empty */
1774 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1775 if (max==0x0) keyboard_panic(40);
1779 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1780 if (max==0x0) keyboard_panic(41);
1782 /* keyboard should return ACK */
1785 printf("rc=0x%x\n",rc);
1786 keyboard_panic(995);
1789 /* Write Keyboard Mode */
1792 /* Wait until buffer is empty */
1794 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1795 if (max==0x0) keyboard_panic(50);
1797 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1800 /* Wait until buffer is empty */
1802 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1803 if (max==0x0) keyboard_panic(60);
1805 /* Enable keyboard */
1808 /* Wait until buffer is empty */
1810 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1811 if (max==0x0) keyboard_panic(70);
1815 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1816 if (max==0x0) keyboard_panic(70);
1818 /* keyboard should return ACK */
1819 if ((inb(0x60) != 0xfa)) {
1820 keyboard_panic(996);
1824 printf("keyboard init done.\n");
1827 //--------------------------------------------------------------------------
1829 //--------------------------------------------------------------------------
1831 keyboard_panic(status)
1834 // If you're getting a 993 keyboard panic here,
1835 // please see the comment in keyboard_init
1836 printf("Keyboard error:%u CONTINUING\n",status); return;
1837 BX_PANIC("Keyboard error:%u\n",status);
1840 //--------------------------------------------------------------------------
1841 // shutdown_status_panic
1842 // called when the shutdown statsu is not implemented, displays the status
1843 //--------------------------------------------------------------------------
1845 shutdown_status_panic(status)
1848 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1851 //--------------------------------------------------------------------------
1852 // print_bios_banner
1853 // displays a the bios version
1854 //--------------------------------------------------------------------------
1858 printf("Hi from peter's modified bios\n");
1859 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1860 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1864 //--------------------------------------------------------------------------
1865 // print_boot_device
1866 // displays the boot device
1867 //--------------------------------------------------------------------------
1869 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1872 print_boot_device(cdboot, drive)
1873 Bit8u cdboot; Bit16u drive;
1877 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1878 // drive contains real/emulated boot drive
1880 if(cdboot)i=2; // CD-Rom
1881 else if((drive&0x0080)==0x00)i=0; // Floppy
1882 else if((drive&0x0080)==0x80)i=1; // Hard drive
1885 printf("Booting from %s...\n",drivetypes[i]);
1888 //--------------------------------------------------------------------------
1889 // print_boot_failure
1890 // displays the reason why boot failed
1891 //--------------------------------------------------------------------------
1893 print_boot_failure(cdboot, drive, reason, lastdrive)
1894 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1896 Bit16u drivenum = drive&0x7f;
1898 // cdboot: 1 if boot from cd, 0 otherwise
1899 // drive : drive number
1900 // reason: 0 signature check failed, 1 read error
1901 // lastdrive: 1 boot drive is the last one in boot sequence
1904 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1905 else if (drive & 0x80)
1906 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1908 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1912 BX_PANIC("Not a bootable disk\n");
1914 BX_PANIC("Could not read the boot disk\n");
1918 //--------------------------------------------------------------------------
1919 // print_cdromboot_failure
1920 // displays the reason why boot failed
1921 //--------------------------------------------------------------------------
1923 print_cdromboot_failure( code )
1926 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1934 BX_PANIC("NMI Handler called\n");
1940 BX_PANIC("INT18: BOOT FAILURE\n");
1947 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1949 BX_INFO("%s\n", bios_version_string);
1958 // Use PS2 System Control port A to set A20 enable
1960 // get current setting first
1963 // change A20 status
1965 outb(0x92, oldval | 0x02);
1967 outb(0x92, oldval & 0xfd);
1969 return((oldval & 0x02) != 0);
1986 // ---------------------------------------------------------------------------
1987 // Start of ATA/ATAPI Driver
1988 // ---------------------------------------------------------------------------
1990 // Global defines -- ATA register and register bits.
1991 // command block & control block regs
1992 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1993 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1994 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1995 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1996 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1997 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1998 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1999 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2000 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2001 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2002 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2003 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2004 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2006 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2007 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2008 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2009 #define ATA_CB_ER_MC 0x20 // ATA media change
2010 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2011 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2012 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2013 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2014 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2016 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2017 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2018 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2019 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2020 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2022 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2023 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2024 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2025 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2026 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2028 // bits 7-4 of the device/head (CB_DH) reg
2029 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2030 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2032 // status reg (CB_STAT and CB_ASTAT) bits
2033 #define ATA_CB_STAT_BSY 0x80 // busy
2034 #define ATA_CB_STAT_RDY 0x40 // ready
2035 #define ATA_CB_STAT_DF 0x20 // device fault
2036 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2037 #define ATA_CB_STAT_SKC 0x10 // seek complete
2038 #define ATA_CB_STAT_SERV 0x10 // service
2039 #define ATA_CB_STAT_DRQ 0x08 // data request
2040 #define ATA_CB_STAT_CORR 0x04 // corrected
2041 #define ATA_CB_STAT_IDX 0x02 // index
2042 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2043 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2045 // device control reg (CB_DC) bits
2046 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2047 #define ATA_CB_DC_SRST 0x04 // soft reset
2048 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2050 // Most mandtory and optional ATA commands (from ATA-3),
2051 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2052 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2053 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2054 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2055 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2056 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2057 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2058 #define ATA_CMD_DEVICE_RESET 0x08
2059 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2060 #define ATA_CMD_FLUSH_CACHE 0xE7
2061 #define ATA_CMD_FORMAT_TRACK 0x50
2062 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2063 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2064 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2065 #define ATA_CMD_IDLE1 0xE3
2066 #define ATA_CMD_IDLE2 0x97
2067 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2068 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2069 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2070 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2071 #define ATA_CMD_NOP 0x00
2072 #define ATA_CMD_PACKET 0xA0
2073 #define ATA_CMD_READ_BUFFER 0xE4
2074 #define ATA_CMD_READ_DMA 0xC8
2075 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2076 #define ATA_CMD_READ_MULTIPLE 0xC4
2077 #define ATA_CMD_READ_SECTORS 0x20
2078 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2079 #define ATA_CMD_RECALIBRATE 0x10
2080 #define ATA_CMD_SEEK 0x70
2081 #define ATA_CMD_SET_FEATURES 0xEF
2082 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2083 #define ATA_CMD_SLEEP1 0xE6
2084 #define ATA_CMD_SLEEP2 0x99
2085 #define ATA_CMD_STANDBY1 0xE2
2086 #define ATA_CMD_STANDBY2 0x96
2087 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2088 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2089 #define ATA_CMD_WRITE_BUFFER 0xE8
2090 #define ATA_CMD_WRITE_DMA 0xCA
2091 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2092 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2093 #define ATA_CMD_WRITE_SECTORS 0x30
2094 #define ATA_CMD_WRITE_VERIFY 0x3C
2096 #define ATA_IFACE_NONE 0x00
2097 #define ATA_IFACE_ISA 0x00
2098 #define ATA_IFACE_PCI 0x01
2100 #define ATA_TYPE_NONE 0x00
2101 #define ATA_TYPE_UNKNOWN 0x01
2102 #define ATA_TYPE_ATA 0x02
2103 #define ATA_TYPE_ATAPI 0x03
2105 #define ATA_DEVICE_NONE 0x00
2106 #define ATA_DEVICE_HD 0xFF
2107 #define ATA_DEVICE_CDROM 0x05
2109 #define ATA_MODE_NONE 0x00
2110 #define ATA_MODE_PIO16 0x00
2111 #define ATA_MODE_PIO32 0x01
2112 #define ATA_MODE_ISADMA 0x02
2113 #define ATA_MODE_PCIDMA 0x03
2114 #define ATA_MODE_USEIRQ 0x10
2116 #define ATA_TRANSLATION_NONE 0
2117 #define ATA_TRANSLATION_LBA 1
2118 #define ATA_TRANSLATION_LARGE 2
2119 #define ATA_TRANSLATION_RECHS 3
2121 #define ATA_DATA_NO 0x00
2122 #define ATA_DATA_IN 0x01
2123 #define ATA_DATA_OUT 0x02
2125 // ---------------------------------------------------------------------------
2126 // ATA/ATAPI driver : initialization
2127 // ---------------------------------------------------------------------------
2130 Bit16u ebda_seg=read_word(0x0040,0x000E);
2131 Bit8u channel, device;
2133 //BX_DEBUG("rombios: ata_init\n");
2135 // Channels info init.
2136 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2137 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2138 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2139 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2140 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2143 // Devices info init.
2144 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2145 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2146 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2147 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2148 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2149 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2150 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2151 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2152 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2153 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2154 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2155 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2156 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2157 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2159 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2162 // hdidmap and cdidmap init.
2163 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2164 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2165 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2168 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2169 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2172 // ---------------------------------------------------------------------------
2173 // ATA/ATAPI driver : device detection
2174 // ---------------------------------------------------------------------------
2178 Bit16u ebda_seg=read_word(0x0040,0x000E);
2179 Bit8u hdcount, cdcount, device, type;
2180 Bit8u buffer[0x0200];
2182 //BX_DEBUG("rombios: ata_detect\n");
2184 #if BX_MAX_ATA_INTERFACES > 0
2185 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2186 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2187 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2188 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2190 #if BX_MAX_ATA_INTERFACES > 1
2191 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2192 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2193 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2194 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2196 #if BX_MAX_ATA_INTERFACES > 2
2197 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2198 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2199 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2200 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2202 #if BX_MAX_ATA_INTERFACES > 3
2203 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2204 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2205 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2206 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2208 #if BX_MAX_ATA_INTERFACES > 4
2209 #error Please fill the ATA interface informations
2215 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2216 Bit16u iobase1, iobase2;
2217 Bit8u channel, slave, shift;
2218 Bit8u sc, sn, cl, ch, st;
2220 channel = device / 2;
2223 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2224 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2226 // Disable interrupts
2227 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2230 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2231 outb(iobase1+ATA_CB_SC, 0x55);
2232 outb(iobase1+ATA_CB_SN, 0xaa);
2233 outb(iobase1+ATA_CB_SC, 0xaa);
2234 outb(iobase1+ATA_CB_SN, 0x55);
2235 outb(iobase1+ATA_CB_SC, 0x55);
2236 outb(iobase1+ATA_CB_SN, 0xaa);
2238 // If we found something
2239 sc = inb(iobase1+ATA_CB_SC);
2240 sn = inb(iobase1+ATA_CB_SN);
2242 if ( (sc == 0x55) && (sn == 0xaa) ) {
2243 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2245 // reset the channel
2248 // check for ATA or ATAPI
2249 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2250 sc = inb(iobase1+ATA_CB_SC);
2251 sn = inb(iobase1+ATA_CB_SN);
2252 if ( (sc==0x01) && (sn==0x01) ) {
2253 cl = inb(iobase1+ATA_CB_CL);
2254 ch = inb(iobase1+ATA_CB_CH);
2255 st = inb(iobase1+ATA_CB_STAT);
2257 if ( (cl==0x14) && (ch==0xeb) ) {
2258 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2260 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2261 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2266 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2268 // Now we send a IDENTIFY command to ATA device
2269 if(type == ATA_TYPE_ATA) {
2271 Bit16u cylinders, heads, spt, blksize;
2272 Bit8u translation, removable, mode;
2274 // default mode to PIO16
2275 mode = ATA_MODE_PIO16;
2277 //Temporary values to do the transfer
2278 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2279 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2281 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2282 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2284 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2286 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2289 blksize = read_word(get_SS(),buffer+10);
2291 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2292 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2293 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2295 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2297 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2298 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2299 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2300 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2301 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2302 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2303 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2304 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2305 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2307 translation = inb_cmos(0x39 + channel/2);
2308 for (shift=device%4; shift>0; shift--) translation >>= 2;
2309 translation &= 0x03;
2311 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2313 switch (translation) {
2314 case ATA_TRANSLATION_NONE:
2317 case ATA_TRANSLATION_LBA:
2320 case ATA_TRANSLATION_LARGE:
2323 case ATA_TRANSLATION_RECHS:
2327 switch (translation) {
2328 case ATA_TRANSLATION_NONE:
2330 case ATA_TRANSLATION_LBA:
2333 heads = sectors / 1024;
2334 if (heads>128) heads = 255;
2335 else if (heads>64) heads = 128;
2336 else if (heads>32) heads = 64;
2337 else if (heads>16) heads = 32;
2339 cylinders = sectors / heads;
2341 case ATA_TRANSLATION_RECHS:
2342 // Take care not to overflow
2344 if(cylinders>61439) cylinders=61439;
2346 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2348 // then go through the large bitshift process
2349 case ATA_TRANSLATION_LARGE:
2350 while(cylinders > 1024) {
2354 // If we max out the head count
2355 if (heads > 127) break;
2359 // clip to 1024 cylinders in lchs
2360 if (cylinders > 1024) cylinders=1024;
2361 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2363 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2364 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2365 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2368 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2372 // Now we send a IDENTIFY command to ATAPI device
2373 if(type == ATA_TYPE_ATAPI) {
2375 Bit8u type, removable, mode;
2378 // default mode to PIO16
2379 mode = ATA_MODE_PIO16;
2381 //Temporary values to do the transfer
2382 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2383 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2385 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2386 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2388 type = read_byte(get_SS(),buffer+1) & 0x1f;
2389 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2391 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2395 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2396 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2397 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2398 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2401 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2408 Bit8u c, i, version, model[41];
2412 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2414 case ATA_TYPE_ATAPI:
2415 // Read ATA/ATAPI version
2416 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2417 for(version=15;version>0;version--) {
2418 if((ataversion&(1<<version))!=0)
2424 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2425 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2429 write_byte(get_SS(),model+40,0x00);
2431 if(read_byte(get_SS(),model+i)==0x20)
2432 write_byte(get_SS(),model+i,0x00);
2440 printf("ata%d %s: ",channel,slave?" slave":"master");
2441 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2442 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2444 case ATA_TYPE_ATAPI:
2445 printf("ata%d %s: ",channel,slave?" slave":"master");
2446 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2447 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2448 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2450 printf(" ATAPI-%d Device\n",version);
2452 case ATA_TYPE_UNKNOWN:
2453 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2459 // Store the devices counts
2460 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2461 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2462 write_byte(0x40,0x75, hdcount);
2466 // FIXME : should use bios=cmos|auto|disable bits
2467 // FIXME : should know about translation bits
2468 // FIXME : move hard_drive_post here
2472 // ---------------------------------------------------------------------------
2473 // ATA/ATAPI driver : software reset
2474 // ---------------------------------------------------------------------------
2476 // 8.2.1 Software reset - Device 0
2478 void ata_reset(device)
2481 Bit16u ebda_seg=read_word(0x0040,0x000E);
2482 Bit16u iobase1, iobase2;
2483 Bit8u channel, slave, sn, sc;
2486 channel = device / 2;
2489 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2490 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2494 // 8.2.1 (a) -- set SRST in DC
2495 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2497 // 8.2.1 (b) -- wait for BSY
2500 Bit8u status = inb(iobase1+ATA_CB_STAT);
2501 if ((status & ATA_CB_STAT_BSY) != 0) break;
2504 // 8.2.1 (f) -- clear SRST
2505 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2507 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2509 // 8.2.1 (g) -- check for sc==sn==0x01
2511 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2512 sc = inb(iobase1+ATA_CB_SC);
2513 sn = inb(iobase1+ATA_CB_SN);
2515 if ( (sc==0x01) && (sn==0x01) ) {
2517 // 8.2.1 (h) -- wait for not BSY
2520 Bit8u status = inb(iobase1+ATA_CB_STAT);
2521 if ((status & ATA_CB_STAT_BSY) == 0) break;
2526 // 8.2.1 (i) -- wait for DRDY
2529 Bit8u status = inb(iobase1+ATA_CB_STAT);
2530 if ((status & ATA_CB_STAT_RDY) != 0) break;
2533 // Enable interrupts
2534 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2537 // ---------------------------------------------------------------------------
2538 // ATA/ATAPI driver : execute a non data command
2539 // ---------------------------------------------------------------------------
2541 Bit16u ata_cmd_non_data()
2544 // ---------------------------------------------------------------------------
2545 // ATA/ATAPI driver : execute a data-in command
2546 // ---------------------------------------------------------------------------
2551 // 3 : expected DRQ=1
2552 // 4 : no sectors left to read/verify
2553 // 5 : more sectors to read/verify
2554 // 6 : no sectors left to write
2555 // 7 : more sectors to write
2556 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2557 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2560 Bit16u ebda_seg=read_word(0x0040,0x000E);
2561 Bit16u iobase1, iobase2, blksize;
2562 Bit8u channel, slave;
2563 Bit8u status, current, mode;
2565 channel = device / 2;
2568 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2569 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2570 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2571 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2572 if (mode == ATA_MODE_PIO32) blksize>>=2;
2575 // sector will be 0 only on lba access. Convert to lba-chs
2577 sector = (Bit16u) (lba & 0x000000ffL);
2579 cylinder = (Bit16u) (lba & 0x0000ffffL);
2581 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2584 // Reset count of transferred data
2585 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2586 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2589 status = inb(iobase1 + ATA_CB_STAT);
2590 if (status & ATA_CB_STAT_BSY) return 1;
2592 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2593 outb(iobase1 + ATA_CB_FR, 0x00);
2594 outb(iobase1 + ATA_CB_SC, count);
2595 outb(iobase1 + ATA_CB_SN, sector);
2596 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2597 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2598 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2599 outb(iobase1 + ATA_CB_CMD, command);
2602 status = inb(iobase1 + ATA_CB_STAT);
2603 if ( !(status & ATA_CB_STAT_BSY) ) break;
2606 if (status & ATA_CB_STAT_ERR) {
2607 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2609 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2610 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2614 // FIXME : move seg/off translation here
2617 sti ;; enable higher priority interrupts
2625 mov di, _ata_cmd_data_in.offset + 2[bp]
2626 mov ax, _ata_cmd_data_in.segment + 2[bp]
2627 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2629 ;; adjust if there will be an overrun. 2K max sector size
2631 jbe ata_in_no_adjust
2634 sub di, #0x0800 ;; sub 2 kbytes from offset
2635 add ax, #0x0080 ;; add 2 Kbytes to segment
2638 mov es, ax ;; segment in es
2640 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2642 mov ah, _ata_cmd_data_in.mode + 2[bp]
2643 cmp ah, #ATA_MODE_PIO32
2648 insw ;; CX words transfered from port(DX) to ES:[DI]
2653 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2656 mov _ata_cmd_data_in.offset + 2[bp], di
2657 mov _ata_cmd_data_in.segment + 2[bp], es
2662 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2664 status = inb(iobase1 + ATA_CB_STAT);
2666 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2667 != ATA_CB_STAT_RDY ) {
2668 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2674 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2675 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2676 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2682 // Enable interrupts
2683 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2687 // ---------------------------------------------------------------------------
2688 // ATA/ATAPI driver : execute a data-out command
2689 // ---------------------------------------------------------------------------
2694 // 3 : expected DRQ=1
2695 // 4 : no sectors left to read/verify
2696 // 5 : more sectors to read/verify
2697 // 6 : no sectors left to write
2698 // 7 : more sectors to write
2699 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2700 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2703 Bit16u ebda_seg=read_word(0x0040,0x000E);
2704 Bit16u iobase1, iobase2, blksize;
2705 Bit8u channel, slave;
2706 Bit8u status, current, mode;
2708 channel = device / 2;
2711 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2712 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2713 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2714 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2715 if (mode == ATA_MODE_PIO32) blksize>>=2;
2718 // sector will be 0 only on lba access. Convert to lba-chs
2720 sector = (Bit16u) (lba & 0x000000ffL);
2722 cylinder = (Bit16u) (lba & 0x0000ffffL);
2724 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2727 // Reset count of transferred data
2728 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2729 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2732 status = inb(iobase1 + ATA_CB_STAT);
2733 if (status & ATA_CB_STAT_BSY) return 1;
2735 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2736 outb(iobase1 + ATA_CB_FR, 0x00);
2737 outb(iobase1 + ATA_CB_SC, count);
2738 outb(iobase1 + ATA_CB_SN, sector);
2739 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2740 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2741 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2742 outb(iobase1 + ATA_CB_CMD, command);
2745 status = inb(iobase1 + ATA_CB_STAT);
2746 if ( !(status & ATA_CB_STAT_BSY) ) break;
2749 if (status & ATA_CB_STAT_ERR) {
2750 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2752 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2753 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2757 // FIXME : move seg/off translation here
2760 sti ;; enable higher priority interrupts
2768 mov si, _ata_cmd_data_out.offset + 2[bp]
2769 mov ax, _ata_cmd_data_out.segment + 2[bp]
2770 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2772 ;; adjust if there will be an overrun. 2K max sector size
2774 jbe ata_out_no_adjust
2777 sub si, #0x0800 ;; sub 2 kbytes from offset
2778 add ax, #0x0080 ;; add 2 Kbytes to segment
2781 mov es, ax ;; segment in es
2783 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2785 mov ah, _ata_cmd_data_out.mode + 2[bp]
2786 cmp ah, #ATA_MODE_PIO32
2792 outsw ;; CX words transfered from port(DX) to ES:[SI]
2798 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2801 mov _ata_cmd_data_out.offset + 2[bp], si
2802 mov _ata_cmd_data_out.segment + 2[bp], es
2807 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2809 status = inb(iobase1 + ATA_CB_STAT);
2811 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2812 != ATA_CB_STAT_RDY ) {
2813 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2819 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2820 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2821 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2827 // Enable interrupts
2828 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2832 // ---------------------------------------------------------------------------
2833 // ATA/ATAPI driver : execute a packet command
2834 // ---------------------------------------------------------------------------
2837 // 1 : error in parameters
2841 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2843 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2847 Bit16u ebda_seg=read_word(0x0040,0x000E);
2848 Bit16u iobase1, iobase2;
2849 Bit16u lcount, lbefore, lafter, count;
2850 Bit8u channel, slave;
2851 Bit8u status, mode, lmode;
2852 Bit32u total, transfer;
2854 channel = device / 2;
2857 // Data out is not supported yet
2858 if (inout == ATA_DATA_OUT) {
2859 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2863 // The header length must be even
2865 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2869 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2870 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2871 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2874 if (cmdlen < 12) cmdlen=12;
2875 if (cmdlen > 12) cmdlen=16;
2878 // Reset count of transferred data
2879 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2880 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2882 // Device should not be busy yet
2887 // wait for device to be ready
2889 status = inb(iobase1 + ATA_CB_STAT);
2890 // BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2891 } while (status & ATA_CB_STAT_BSY);
2893 status = inb(iobase1 + ATA_CB_STAT);
2894 if (status & ATA_CB_STAT_BSY) return 2;
2898 // set "noninterruptable"
2899 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2901 //outb(iobase1 + ATA_CB_FR, 0x00);
2902 //outb(iobase1 + ATA_CB_SC, 0x00);
2903 //outb(iobase1 + ATA_CB_SN, 0x00);
2905 // Set cylinders ?? - Why? And why not sector
2906 // This is all embedded in cmd_packet, anyway...
2907 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2908 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2910 // select master or slave
2911 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2913 // Tell it we are sending a command packet
2914 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2917 // Now wait for 400 ns
2920 for (i=0;i<0xffff; i++)
2925 // Device should ok to receive command
2926 // wait until we get
2929 status = inb(iobase1 + ATA_CB_STAT);
2932 if (!(status & ATA_CB_STAT_BSY)) break;
2934 // Shouldn't this be ATA_CB_STAT_RDY? -PAD - NO, it's OK
2935 if ( !(status & ATA_CB_STAT_BSY) ) break;
2940 if (status & ATA_CB_STAT_ERR) {
2941 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2943 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2944 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2948 // Normalize address
2949 cmdseg += (cmdoff / 16);
2952 // Send command to device
2954 sti ;; enable higher priority interrupts
2959 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2960 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2961 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2962 mov es, ax ;; segment in es
2964 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2968 outsw ;; CX words transfered from port(DX) to ES:[SI]
2973 // issue read of alternative status - claimed to be in spec
2974 //inb(iobase2+ATA_CB_ASTAT);
2977 if (inout == ATA_DATA_NO) {
2978 status = inb(iobase1 + ATA_CB_STAT);
2981 // Wait for completion
2984 status=inb(iobase1+ATA_CB_STAT);
2985 BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2986 } while ((status & ATA_CB_STAT_BSY));
2990 status = inb(iobase1 + ATA_CB_STAT);
2992 // Check if command completed
2993 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2995 if (status & ATA_CB_STAT_ERR) {
2996 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3000 // If we get here, we are ready and should have DRQ
3001 // and so data is available
3002 // Device must be ready to send data
3003 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3004 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3005 BX_DEBUG_ATA("ata_cmd_packet 1: not ready (status %02x)\n", status);
3009 // Normalize address
3010 bufseg += (bufoff / 16);
3013 // Get the byte count
3014 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3016 // adjust to read what we want
3029 lafter=lcount-length;
3041 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3042 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3044 // If counts not dividable by 4, use 16bits mode
3046 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3047 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3048 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3050 // adds an extra byte if count are odd. before is always even
3051 if (lcount & 0x01) {
3053 if ((lafter > 0) && (lafter & 0x01)) {
3058 if (lmode == ATA_MODE_PIO32) {
3059 lcount>>=2; lbefore>>=2; lafter>>=2;
3062 lcount>>=1; lbefore>>=1; lafter>>=1;
3071 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3073 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3074 jcxz ata_packet_no_before
3076 mov ah, _ata_cmd_packet.lmode + 2[bp]
3077 cmp ah, #ATA_MODE_PIO32
3078 je ata_packet_in_before_32
3080 ata_packet_in_before_16:
3082 loop ata_packet_in_before_16
3083 jmp ata_packet_no_before
3085 ata_packet_in_before_32:
3087 ata_packet_in_before_32_loop:
3089 loop ata_packet_in_before_32_loop
3092 ata_packet_no_before:
3093 mov cx, _ata_cmd_packet.lcount + 2[bp]
3094 jcxz ata_packet_after
3096 mov di, _ata_cmd_packet.bufoff + 2[bp]
3097 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3100 mov ah, _ata_cmd_packet.lmode + 2[bp]
3101 cmp ah, #ATA_MODE_PIO32
3106 insw ;; CX words transfered tp port(DX) to ES:[DI]
3107 jmp ata_packet_after
3111 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3114 mov cx, _ata_cmd_packet.lafter + 2[bp]
3115 jcxz ata_packet_done
3117 mov ah, _ata_cmd_packet.lmode + 2[bp]
3118 cmp ah, #ATA_MODE_PIO32
3119 je ata_packet_in_after_32
3121 ata_packet_in_after_16:
3123 loop ata_packet_in_after_16
3126 ata_packet_in_after_32:
3128 ata_packet_in_after_32_loop:
3130 loop ata_packet_in_after_32_loop
3137 // Compute new buffer address
3140 // Save transferred bytes count
3142 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3146 // Final check, device must be ready
3147 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3148 != ATA_CB_STAT_RDY ) {
3149 BX_DEBUG_ATA("ata_cmd_packet 2 : not ready (status %02x)\n", (unsigned) status);
3153 // Enable interrupts
3154 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3158 // ---------------------------------------------------------------------------
3159 // End of ATA/ATAPI Driver
3160 // ---------------------------------------------------------------------------
3163 // ---------------------------------------------------------------------------
3164 // Start of ATA/ATAPI generic functions
3165 // ---------------------------------------------------------------------------
3168 atapi_get_sense(device)
3175 memsetb(get_SS(),atacmd,0,12);
3180 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3183 if ((buffer[0] & 0x7e) == 0x70) {
3184 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3191 atapi_is_ready(device)
3197 memsetb(get_SS(),atacmd,0,12);
3200 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3203 if (atapi_get_sense(device) !=0 ) {
3204 memsetb(get_SS(),atacmd,0,12);
3206 // try to send Test Unit Ready again
3207 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3210 return atapi_get_sense(device);
3216 atapi_is_cdrom(device)
3219 Bit16u ebda_seg=read_word(0x0040,0x000E);
3221 if (device >= BX_MAX_ATA_DEVICES)
3224 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3227 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3233 // ---------------------------------------------------------------------------
3234 // End of ATA/ATAPI generic functions
3235 // ---------------------------------------------------------------------------
3237 #endif // BX_USE_ATADRV
3239 #if BX_ELTORITO_BOOT
3241 // ---------------------------------------------------------------------------
3242 // Start of El-Torito boot functions
3243 // ---------------------------------------------------------------------------
3248 Bit16u ebda_seg=read_word(0x0040,0x000E);
3250 //BX_DEBUG("rombios: cdemu_init\n");
3252 // the only important data is this one for now
3253 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3259 Bit16u ebda_seg=read_word(0x0040,0x000E);
3261 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3265 cdemu_emulated_drive()
3267 Bit16u ebda_seg=read_word(0x0040,0x000E);
3269 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3272 static char isotag[6]="CD001";
3273 static char eltorito[24]="EL TORITO SPECIFICATION";
3275 // Returns ah: emulated drive, al: error code
3280 Bit16u ebda_seg=read_word(0x0040,0x000E);
3281 Bit8u atacmd[12], buffer[2048];
3283 Bit16u boot_segment, nbsectors, i, error;
3287 // Find out the first cdrom
3288 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3289 if (atapi_is_cdrom(device)) break;
3293 if(device >= BX_MAX_ATA_DEVICES) return 2;
3295 // Read the Boot Record Volume Descriptor
3296 memsetb(get_SS(),atacmd,0,12);
3297 atacmd[0]=0x28; // READ command
3298 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3299 atacmd[8]=(0x01 & 0x00ff); // Sectors
3300 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3301 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3302 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3303 atacmd[5]=(0x11 & 0x000000ff);
3304 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3309 if(buffer[0]!=0)return 4;
3311 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3314 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3316 // ok, now we calculate the Boot catalog address
3317 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3319 // And we read the Boot Catalog
3320 memsetb(get_SS(),atacmd,0,12);
3321 atacmd[0]=0x28; // READ command
3322 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3323 atacmd[8]=(0x01 & 0x00ff); // Sectors
3324 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3325 atacmd[3]=(lba & 0x00ff0000) >> 16;
3326 atacmd[4]=(lba & 0x0000ff00) >> 8;
3327 atacmd[5]=(lba & 0x000000ff);
3328 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3334 if(buffer[0x00]!=0x01)return 8; // Header
3335 if(buffer[0x01]!=0x00)return 9; // Platform
3336 if(buffer[0x1E]!=0x55)return 10; // key 1
3337 if(buffer[0x1F]!=0xAA)return 10; // key 2
3339 // Initial/Default Entry
3340 if(buffer[0x20]!=0x88)return 11; // Bootable
3342 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3343 if(buffer[0x21]==0){
3344 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3345 // Win2000 cd boot needs to know it booted from cd
3346 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3348 else if(buffer[0x21]<4)
3349 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3351 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3353 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3354 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3356 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3357 if(boot_segment==0x0000)boot_segment=0x07C0;
3359 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3360 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3362 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3363 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3365 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3366 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3368 // And we read the image in memory
3369 memsetb(get_SS(),atacmd,0,12);
3370 atacmd[0]=0x28; // READ command
3371 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3372 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3373 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3374 atacmd[3]=(lba & 0x00ff0000) >> 16;
3375 atacmd[4]=(lba & 0x0000ff00) >> 8;
3376 atacmd[5]=(lba & 0x000000ff);
3377 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3381 // Remember the media type
3382 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3383 case 0x01: // 1.2M floppy
3384 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3385 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3386 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3388 case 0x02: // 1.44M floppy
3389 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3390 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3391 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3393 case 0x03: // 2.88M floppy
3394 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3395 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3396 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3398 case 0x04: // Harddrive
3399 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3400 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3401 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3402 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3406 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3407 // Increase bios installed hardware number of devices
3408 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3409 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3411 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3415 // everything is ok, so from now on, the emulation is active
3416 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3417 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3419 // return the boot drive + no error
3420 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3423 // ---------------------------------------------------------------------------
3424 // End of El-Torito boot functions
3425 // ---------------------------------------------------------------------------
3426 #endif // BX_ELTORITO_BOOT
3429 int14_function(regs, ds, iret_addr)
3430 pusha_regs_t regs; // regs pushed from PUSHA instruction
3431 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3432 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3434 Bit16u addr,timer,val16;
3441 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3442 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3443 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3444 switch (regs.u.r8.ah) {
3446 outb(addr+3, inb(addr+3) | 0x80);
3447 if (regs.u.r8.al & 0xE0 == 0) {
3451 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3452 outb(addr, val16 & 0xFF);
3453 outb(addr+1, val16 >> 8);
3455 outb(addr+3, regs.u.r8.al & 0x1F);
3456 regs.u.r8.ah = inb(addr+5);
3457 regs.u.r8.al = inb(addr+6);
3458 ClearCF(iret_addr.flags);
3461 timer = read_word(0x0040, 0x006C);
3462 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3463 val16 = read_word(0x0040, 0x006C);
3464 if (val16 != timer) {
3469 if (timeout) outb(addr, regs.u.r8.al);
3470 regs.u.r8.ah = inb(addr+5);
3471 if (!timeout) regs.u.r8.ah |= 0x80;
3472 ClearCF(iret_addr.flags);
3475 timer = read_word(0x0040, 0x006C);
3476 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3477 val16 = read_word(0x0040, 0x006C);
3478 if (val16 != timer) {
3485 regs.u.r8.al = inb(addr);
3487 regs.u.r8.ah = inb(addr+5);
3489 ClearCF(iret_addr.flags);
3492 regs.u.r8.ah = inb(addr+5);
3493 regs.u.r8.al = inb(addr+6);
3494 ClearCF(iret_addr.flags);
3497 SetCF(iret_addr.flags); // Unsupported
3500 SetCF(iret_addr.flags); // Unsupported
3505 int15_function(regs, ES, DS, FLAGS)
3506 pusha_regs_t regs; // REGS pushed via pusha
3507 Bit16u ES, DS, FLAGS;
3509 Bit16u ebda_seg=read_word(0x0040,0x000E);
3510 bx_bool prev_a20_enable;
3519 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3521 switch (regs.u.r8.ah) {
3522 case 0x24: /* A20 Control */
3523 switch (regs.u.r8.al) {
3535 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3545 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3547 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3553 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3557 /* keyboard intercept */
3559 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3566 case 0x52: // removable media eject
3568 regs.u.r8.ah = 0; // "ok ejection may proceed"
3572 if( regs.u.r8.al == 0 ) {
3573 // Set Interval requested.
3574 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3575 // Interval not already set.
3576 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3577 write_word( 0x40, 0x98, ES ); // Byte location, segment
3578 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3579 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3580 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3582 irqDisable = inb( 0xA1 );
3583 outb( 0xA1, irqDisable & 0xFE );
3584 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3585 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3587 // Interval already set.
3588 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3590 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3592 } else if( regs.u.r8.al == 1 ) {
3593 // Clear Interval requested
3594 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3596 bRegister = inb_cmos( 0xB );
3597 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3599 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3601 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3610 # error "Int15 function 87h not supported on < 80386"
3612 // +++ should probably have descriptor checks
3613 // +++ should have exception handlers
3615 // turn off interrupts
3620 prev_a20_enable = set_enable_a20(1); // enable A20 line
3622 // 128K max of transfer on 386+ ???
3623 // source == destination ???
3625 // ES:SI points to descriptor table
3626 // offset use initially comments
3627 // ==============================================
3628 // 00..07 Unused zeros Null descriptor
3629 // 08..0f GDT zeros filled in by BIOS
3630 // 10..17 source ssssssss source of data
3631 // 18..1f dest dddddddd destination of data
3632 // 20..27 CS zeros filled in by BIOS
3633 // 28..2f SS zeros filled in by BIOS
3640 // check for access rights of source & dest here
3642 // Initialize GDT descriptor
3643 base15_00 = (ES << 4) + regs.u.r16.si;
3644 base23_16 = ES >> 12;
3645 if (base15_00 < (ES<<4))
3647 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3648 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3649 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3650 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3651 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3653 // Initialize CS descriptor
3654 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3655 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3656 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3657 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3658 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3660 // Initialize SS descriptor
3662 base15_00 = ss << 4;
3663 base23_16 = ss >> 12;
3664 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3665 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3666 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3667 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3668 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3672 // Compile generates locals offset info relative to SP.
3673 // Get CX (word count) from stack.
3676 mov cx, _int15_function.CX [bx]
3678 // since we need to set SS:SP, save them to the BDA
3679 // for future restore
3689 lidt [pmode_IDT_info]
3690 ;; perhaps do something with IDT here
3692 ;; set PE bit in CR0
3696 ;; far jump to flush CPU queue after transition to protected mode
3697 JMP_AP(0x0020, protected_mode)
3700 ;; GDT points to valid descriptor table, now load SS, DS, ES
3701 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3703 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3705 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3711 movsw ;; move CX words from DS:SI to ES:DI
3713 ;; make sure DS and ES limits are 64KB
3718 ;; reset PG bit in CR0 ???
3723 ;; far jump to flush CPU queue after transition to real mode
3724 JMP_AP(0xf000, real_mode)
3727 ;; restore IDT to normal real-mode defaults
3729 lidt [rmode_IDT_info]
3731 // restore SS:SP from the BDA
3739 set_enable_a20(prev_a20_enable);
3741 // turn back on interrupts
3752 // Get the amount of extended memory (above 1M)
3754 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3757 regs.u.r8.al = inb_cmos(0x30);
3758 regs.u.r8.ah = inb_cmos(0x31);
3761 if(regs.u.r16.ax > 0x3c00)
3762 regs.u.r16.ax = 0x3c00;
3769 /* Device busy interrupt. Called by Int 16h when no key available */
3773 /* Interrupt complete. Called by Int 16h when key becomes available */
3777 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3779 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3785 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3790 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3800 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3802 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3806 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3807 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3809 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3814 #if BX_USE_PS2_MOUSE
3816 int15_function_mouse(regs, ES, DS, FLAGS)
3817 pusha_regs_t regs; // REGS pushed via pusha
3818 Bit16u ES, DS, FLAGS;
3820 Bit16u ebda_seg=read_word(0x0040,0x000E);
3821 Bit8u mouse_flags_1, mouse_flags_2;
3822 Bit16u mouse_driver_seg;
3823 Bit16u mouse_driver_offset;
3824 Bit8u comm_byte, prev_command_byte;
3825 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3827 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3829 switch (regs.u.r8.ah) {
3831 // Return Codes status in AH
3832 // =========================
3834 // 01: invalid subfunction (AL > 7)
3835 // 02: invalid input value (out of allowable range)
3836 // 03: interface error
3837 // 04: resend command received from mouse controller,
3838 // device driver should attempt command again
3839 // 05: cannot enable mouse, since no far call has been installed
3840 // 80/86: mouse service not implemented
3842 switch (regs.u.r8.al) {
3843 case 0: // Disable/Enable Mouse
3844 BX_DEBUG_INT15("case 0:\n");
3845 switch (regs.u.r8.bh) {
3846 case 0: // Disable Mouse
3847 BX_DEBUG_INT15("case 0: disable mouse\n");
3848 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3849 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3851 ret = get_mouse_data(&mouse_data1);
3852 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3865 case 1: // Enable Mouse
3866 BX_DEBUG_INT15("case 1: enable mouse\n");
3867 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3868 if ( (mouse_flags_2 & 0x80) == 0 ) {
3869 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3871 regs.u.r8.ah = 5; // no far call installed
3874 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3875 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3877 ret = get_mouse_data(&mouse_data1);
3878 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3879 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3889 default: // invalid subfunction
3890 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3892 regs.u.r8.ah = 1; // invalid subfunction
3897 case 1: // Reset Mouse
3898 case 5: // Initialize Mouse
3899 BX_DEBUG_INT15("case 1 or 5:\n");
3900 if (regs.u.r8.al == 5) {
3901 if (regs.u.r8.bh != 3) {
3903 regs.u.r8.ah = 0x02; // invalid input
3906 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3907 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3908 mouse_flags_1 = 0x00;
3909 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3910 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3913 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3914 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3916 ret = get_mouse_data(&mouse_data3);
3917 // if no mouse attached, it will return RESEND
3918 if (mouse_data3 == 0xfe) {
3922 if (mouse_data3 != 0xfa)
3923 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3925 ret = get_mouse_data(&mouse_data1);
3927 ret = get_mouse_data(&mouse_data2);
3929 // turn IRQ12 and packet generation on
3930 enable_mouse_int_and_events();
3933 regs.u.r8.bl = mouse_data1;
3934 regs.u.r8.bh = mouse_data2;
3946 case 2: // Set Sample Rate
3947 BX_DEBUG_INT15("case 2:\n");
3948 switch (regs.u.r8.bh) {
3949 case 0: mouse_data1 = 10; break; // 10 reports/sec
3950 case 1: mouse_data1 = 20; break; // 20 reports/sec
3951 case 2: mouse_data1 = 40; break; // 40 reports/sec
3952 case 3: mouse_data1 = 60; break; // 60 reports/sec
3953 case 4: mouse_data1 = 80; break; // 80 reports/sec
3954 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3955 case 6: mouse_data1 = 200; break; // 200 reports/sec
3956 default: mouse_data1 = 0;
3958 if (mouse_data1 > 0) {
3959 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3961 ret = get_mouse_data(&mouse_data2);
3962 ret = send_to_mouse_ctrl(mouse_data1);
3963 ret = get_mouse_data(&mouse_data2);
3969 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3974 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3978 case 3: // Set Resolution
3979 BX_DEBUG_INT15("case 3:\n");
3981 // 0 = 25 dpi, 1 count per millimeter
3982 // 1 = 50 dpi, 2 counts per millimeter
3983 // 2 = 100 dpi, 4 counts per millimeter
3984 // 3 = 200 dpi, 8 counts per millimeter
3989 case 4: // Get Device ID
3990 BX_DEBUG_INT15("case 4:\n");
3991 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3992 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3994 ret = get_mouse_data(&mouse_data1);
3995 ret = get_mouse_data(&mouse_data2);
3998 regs.u.r8.bh = mouse_data2;
4002 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4006 case 6: // Return Status & Set Scaling Factor...
4007 BX_DEBUG_INT15("case 6:\n");
4008 switch (regs.u.r8.bh) {
4009 case 0: // Return Status
4010 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4011 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4013 ret = get_mouse_data(&mouse_data1);
4014 if (mouse_data1 != 0xfa)
4015 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4017 ret = get_mouse_data(&mouse_data1);
4019 ret = get_mouse_data(&mouse_data2);
4021 ret = get_mouse_data(&mouse_data3);
4025 regs.u.r8.bl = mouse_data1;
4026 regs.u.r8.cl = mouse_data2;
4027 regs.u.r8.dl = mouse_data3;
4028 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4039 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4042 case 1: // Set Scaling Factor to 1:1
4043 case 2: // Set Scaling Factor to 2:1
4044 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4045 if (regs.u.r8.bh == 1) {
4046 ret = send_to_mouse_ctrl(0xE6);
4048 ret = send_to_mouse_ctrl(0xE7);
4051 get_mouse_data(&mouse_data1);
4052 ret = (mouse_data1 != 0xFA);
4060 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4062 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4066 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4070 case 7: // Set Mouse Handler Address
4071 BX_DEBUG_INT15("case 7:\n");
4072 mouse_driver_seg = ES;
4073 mouse_driver_offset = regs.u.r16.bx;
4074 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4075 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4076 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4077 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4078 /* remove handler */
4079 if ( (mouse_flags_2 & 0x80) != 0 ) {
4080 mouse_flags_2 &= ~0x80;
4081 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4085 /* install handler */
4086 mouse_flags_2 |= 0x80;
4088 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4094 BX_DEBUG_INT15("case default:\n");
4095 regs.u.r8.ah = 1; // invalid function
4101 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4102 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4104 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4111 int15_function32(regs, ES, DS, FLAGS)
4112 pushad_regs_t regs; // REGS pushed via pushad
4113 Bit16u ES, DS, FLAGS;
4115 Bit32u extended_memory_size=0; // 64bits long
4118 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4120 switch (regs.u.r8.ah) {
4122 // Wait for CX:DX microseconds. currently using the
4123 // refresh request port 0x61 bit4, toggling every 15usec
4131 ;; Get the count in eax
4134 mov ax, _int15_function.CX [bx]
4137 mov ax, _int15_function.DX [bx]
4139 ;; convert to numbers of 15usec ticks
4145 ;; wait for ecx number of refresh requests
4166 switch(regs.u.r8.al)
4168 case 0x20: // coded by osmaker aka K.J.
4169 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4172 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4173 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4175 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4176 memcpyb(ES, regs.u.r16.di,
4177 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4179 regs.u.r32.ebx += 0x14;
4180 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4182 regs.u.r32.eax = 0x534D4150;
4183 regs.u.r32.ecx = 0x14;
4186 } else if (regs.u.r16.bx == 1) {
4187 extended_memory_size = inb_cmos(0x35);
4188 extended_memory_size <<= 8;
4189 extended_memory_size |= inb_cmos(0x34);
4190 extended_memory_size *= 64;
4191 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4193 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4195 extended_memory_size *= 1024;
4196 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4198 if (extended_memory_size <= 15728640)
4200 extended_memory_size = inb_cmos(0x31);
4201 extended_memory_size <<= 8;
4202 extended_memory_size |= inb_cmos(0x30);
4203 extended_memory_size *= 1024;
4206 write_word(ES, regs.u.r16.di, 0x0000);
4207 write_word(ES, regs.u.r16.di+2, 0x0010);
4208 write_word(ES, regs.u.r16.di+4, 0x0000);
4209 write_word(ES, regs.u.r16.di+6, 0x0000);
4211 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4212 extended_memory_size >>= 16;
4213 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4214 extended_memory_size >>= 16;
4215 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4216 extended_memory_size >>= 16;
4217 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4219 write_word(ES, regs.u.r16.di+16, 0x1);
4220 write_word(ES, regs.u.r16.di+18, 0x0);
4223 regs.u.r32.eax = 0x534D4150;
4224 regs.u.r32.ecx = 0x14;
4227 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4228 goto int15_unimplemented;
4231 switch(regs.u.r16.bx)
4234 write_word(ES, regs.u.r16.di, 0x00);
4235 write_word(ES, regs.u.r16.di+2, 0x00);
4236 write_word(ES, regs.u.r16.di+4, 0x00);
4237 write_word(ES, regs.u.r16.di+6, 0x00);
4239 write_word(ES, regs.u.r16.di+8, 0xFC00);
4240 write_word(ES, regs.u.r16.di+10, 0x0009);
4241 write_word(ES, regs.u.r16.di+12, 0x0000);
4242 write_word(ES, regs.u.r16.di+14, 0x0000);
4244 write_word(ES, regs.u.r16.di+16, 0x1);
4245 write_word(ES, regs.u.r16.di+18, 0x0);
4249 regs.u.r32.eax = 0x534D4150;
4250 regs.u.r32.ecx = 0x14;
4255 extended_memory_size = inb_cmos(0x35);
4256 extended_memory_size <<= 8;
4257 extended_memory_size |= inb_cmos(0x34);
4258 extended_memory_size *= 64;
4259 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4261 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4263 extended_memory_size *= 1024;
4264 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4266 if(extended_memory_size <= 15728640)
4268 extended_memory_size = inb_cmos(0x31);
4269 extended_memory_size <<= 8;
4270 extended_memory_size |= inb_cmos(0x30);
4271 extended_memory_size *= 1024;
4274 write_word(ES, regs.u.r16.di, 0x0000);
4275 write_word(ES, regs.u.r16.di+2, 0x0010);
4276 write_word(ES, regs.u.r16.di+4, 0x0000);
4277 write_word(ES, regs.u.r16.di+6, 0x0000);
4279 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4280 extended_memory_size >>= 16;
4281 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4282 extended_memory_size >>= 16;
4283 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4284 extended_memory_size >>= 16;
4285 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4287 write_word(ES, regs.u.r16.di+16, 0x1);
4288 write_word(ES, regs.u.r16.di+18, 0x0);
4291 regs.u.r32.eax = 0x534D4150;
4292 regs.u.r32.ecx = 0x14;
4296 default: /* AX=E820, DX=534D4150, BX unrecognized */
4297 goto int15_unimplemented;
4302 // if DX != 0x534D4150)
4303 goto int15_unimplemented;
4308 // do we have any reason to fail here ?
4311 // my real system sets ax and bx to 0
4312 // this is confirmed by Ralph Brown list
4313 // but syslinux v1.48 is known to behave
4314 // strangely if ax is set to 0
4315 // regs.u.r16.ax = 0;
4316 // regs.u.r16.bx = 0;
4318 // Get the amount of extended memory (above 1M)
4319 regs.u.r8.cl = inb_cmos(0x30);
4320 regs.u.r8.ch = inb_cmos(0x31);
4323 if(regs.u.r16.cx > 0x3c00)
4325 regs.u.r16.cx = 0x3c00;
4328 // Get the amount of extended memory above 16M in 64k blocs
4329 regs.u.r8.dl = inb_cmos(0x34);
4330 regs.u.r8.dh = inb_cmos(0x35);
4332 // Set configured memory equal to extended memory
4333 regs.u.r16.ax = regs.u.r16.cx;
4334 regs.u.r16.bx = regs.u.r16.dx;
4336 default: /* AH=0xE8?? but not implemented */
4337 goto int15_unimplemented;
4340 int15_unimplemented:
4341 // fall into the default
4343 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4344 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4346 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4352 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4353 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4355 Bit8u scan_code, ascii_code, shift_flags, count;
4356 Bit16u kbd_code, max;
4358 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4361 case 0x00: /* read keyboard input */
4363 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4364 BX_PANIC("KBD: int16h: out of keyboard input\n");
4366 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4367 else if (ascii_code == 0xE0) ascii_code = 0;
4368 AX = (scan_code << 8) | ascii_code;
4371 case 0x01: /* check keyboard status */
4372 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4376 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4377 else if (ascii_code == 0xE0) ascii_code = 0;
4378 AX = (scan_code << 8) | ascii_code;
4382 case 0x02: /* get shift flag status */
4383 shift_flags = read_byte(0x0040, 0x17);
4384 SET_AL(shift_flags);
4387 case 0x05: /* store key-stroke into buffer */
4388 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4396 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4397 // bit Bochs Description
4399 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4400 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4401 // 4 1 INT 16/AH=0Ah supported
4402 // 3 0 INT 16/AX=0306h supported
4403 // 2 0 INT 16/AX=0305h supported
4404 // 1 0 INT 16/AX=0304h supported
4405 // 0 0 INT 16/AX=0300h supported
4410 case 0x0A: /* GET KEYBOARD ID */
4416 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4418 if ((inb(0x60) == 0xfa)) {
4421 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4424 kbd_code |= (inb(0x60) << 8);
4426 } while (--count>0);
4432 case 0x10: /* read MF-II keyboard input */
4434 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4435 BX_PANIC("KBD: int16h: out of keyboard input\n");
4437 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4438 AX = (scan_code << 8) | ascii_code;
4441 case 0x11: /* check MF-II keyboard status */
4442 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4446 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4447 AX = (scan_code << 8) | ascii_code;
4451 case 0x12: /* get extended keyboard status */
4452 shift_flags = read_byte(0x0040, 0x17);
4453 SET_AL(shift_flags);
4454 shift_flags = read_byte(0x0040, 0x18);
4455 SET_AH(shift_flags);
4456 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4459 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4460 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4463 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4464 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4468 if (GET_AL() == 0x08)
4469 SET_AH(0x02); // unsupported, aka normal keyboard
4472 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4477 dequeue_key(scan_code, ascii_code, incr)
4482 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4487 buffer_start = 0x001E;
4488 buffer_end = 0x003E;
4490 buffer_start = read_word(0x0040, 0x0080);
4491 buffer_end = read_word(0x0040, 0x0082);
4494 buffer_head = read_word(0x0040, 0x001a);
4495 buffer_tail = read_word(0x0040, 0x001c);
4497 if (buffer_head != buffer_tail) {
4499 acode = read_byte(0x0040, buffer_head);
4500 scode = read_byte(0x0040, buffer_head+1);
4501 write_byte(ss, ascii_code, acode);
4502 write_byte(ss, scan_code, scode);
4506 if (buffer_head >= buffer_end)
4507 buffer_head = buffer_start;
4508 write_word(0x0040, 0x001a, buffer_head);
4517 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4520 inhibit_mouse_int_and_events()
4522 Bit8u command_byte, prev_command_byte;
4524 // Turn off IRQ generation and aux data line
4525 if ( inb(0x64) & 0x02 )
4526 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4527 outb(0x64, 0x20); // get command byte
4528 while ( (inb(0x64) & 0x01) != 0x01 );
4529 prev_command_byte = inb(0x60);
4530 command_byte = prev_command_byte;
4531 //while ( (inb(0x64) & 0x02) );
4532 if ( inb(0x64) & 0x02 )
4533 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4534 command_byte &= 0xfd; // turn off IRQ 12 generation
4535 command_byte |= 0x20; // disable mouse serial clock line
4536 outb(0x64, 0x60); // write command byte
4537 outb(0x60, command_byte);
4538 return(prev_command_byte);
4542 enable_mouse_int_and_events()
4546 // Turn on IRQ generation and aux data line
4547 if ( inb(0x64) & 0x02 )
4548 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4549 outb(0x64, 0x20); // get command byte
4550 while ( (inb(0x64) & 0x01) != 0x01 );
4551 command_byte = inb(0x60);
4552 //while ( (inb(0x64) & 0x02) );
4553 if ( inb(0x64) & 0x02 )
4554 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4555 command_byte |= 0x02; // turn on IRQ 12 generation
4556 command_byte &= 0xdf; // enable mouse serial clock line
4557 outb(0x64, 0x60); // write command byte
4558 outb(0x60, command_byte);
4562 send_to_mouse_ctrl(sendbyte)
4567 // wait for chance to write to ctrl
4568 if ( inb(0x64) & 0x02 )
4569 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4571 outb(0x60, sendbyte);
4577 get_mouse_data(data)
4583 while ( (inb(0x64) & 0x21) != 0x21 ) {
4586 response = inb(0x60);
4589 write_byte(ss, data, response);
4594 set_kbd_command_byte(command_byte)
4597 if ( inb(0x64) & 0x02 )
4598 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4601 outb(0x64, 0x60); // write command byte
4602 outb(0x60, command_byte);
4606 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4607 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4609 Bit8u scancode, asciicode, shift_flags;
4610 Bit8u mf2_flags, mf2_state, led_flags;
4613 // DS has been set to F000 before call
4617 scancode = GET_AL();
4619 if (scancode == 0) {
4620 BX_INFO("KBD: int09 handler: AL=0\n");
4625 shift_flags = read_byte(0x0040, 0x17);
4626 mf2_flags = read_byte(0x0040, 0x18);
4627 mf2_state = read_byte(0x0040, 0x96);
4628 led_flags = read_byte(0x0040, 0x97);
4632 case 0x3a: /* Caps Lock press */
4633 shift_flags ^= 0x40;
4634 write_byte(0x0040, 0x17, shift_flags);
4636 write_byte(0x0040, 0x18, mf2_flags);
4638 write_byte(0x0040, 0x97, led_flags);
4640 case 0xba: /* Caps Lock release */
4642 write_byte(0x0040, 0x18, mf2_flags);
4645 case 0x2a: /* L Shift press */
4646 /*shift_flags &= ~0x40;*/
4647 shift_flags |= 0x02;
4648 write_byte(0x0040, 0x17, shift_flags);
4650 write_byte(0x0040, 0x97, led_flags);
4652 case 0xaa: /* L Shift release */
4653 shift_flags &= ~0x02;
4654 write_byte(0x0040, 0x17, shift_flags);
4657 case 0x36: /* R Shift press */
4658 /*shift_flags &= ~0x40;*/
4659 shift_flags |= 0x01;
4660 write_byte(0x0040, 0x17, shift_flags);
4662 write_byte(0x0040, 0x97, led_flags);
4664 case 0xb6: /* R Shift release */
4665 shift_flags &= ~0x01;
4666 write_byte(0x0040, 0x17, shift_flags);
4669 case 0x1d: /* Ctrl press */
4670 shift_flags |= 0x04;
4671 write_byte(0x0040, 0x17, shift_flags);
4672 if (mf2_state & 0x01) {
4677 write_byte(0x0040, 0x18, mf2_flags);
4679 case 0x9d: /* Ctrl release */
4680 shift_flags &= ~0x04;
4681 write_byte(0x0040, 0x17, shift_flags);
4682 if (mf2_state & 0x01) {
4687 write_byte(0x0040, 0x18, mf2_flags);
4690 case 0x38: /* Alt press */
4691 shift_flags |= 0x08;
4692 write_byte(0x0040, 0x17, shift_flags);
4693 if (mf2_state & 0x01) {
4698 write_byte(0x0040, 0x18, mf2_flags);
4700 case 0xb8: /* Alt release */
4701 shift_flags &= ~0x08;
4702 write_byte(0x0040, 0x17, shift_flags);
4703 if (mf2_state & 0x01) {
4708 write_byte(0x0040, 0x18, mf2_flags);
4711 case 0x45: /* Num Lock press */
4712 if ((mf2_state & 0x01) == 0) {
4714 write_byte(0x0040, 0x18, mf2_flags);
4715 shift_flags ^= 0x20;
4717 write_byte(0x0040, 0x17, shift_flags);
4718 write_byte(0x0040, 0x97, led_flags);
4721 case 0xc5: /* Num Lock release */
4722 if ((mf2_state & 0x01) == 0) {
4724 write_byte(0x0040, 0x18, mf2_flags);
4728 case 0x46: /* Scroll Lock press */
4730 write_byte(0x0040, 0x18, mf2_flags);
4731 shift_flags ^= 0x10;
4733 write_byte(0x0040, 0x17, shift_flags);
4734 write_byte(0x0040, 0x97, led_flags);
4737 case 0xc6: /* Scroll Lock release */
4739 write_byte(0x0040, 0x18, mf2_flags);
4743 if (scancode & 0x80) return; /* toss key releases ... */
4744 if (scancode > MAX_SCAN_CODE) {
4745 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4748 if (shift_flags & 0x08) { /* ALT */
4749 asciicode = scan_to_scanascii[scancode].alt;
4750 scancode = scan_to_scanascii[scancode].alt >> 8;
4752 else if (shift_flags & 0x04) { /* CONTROL */
4753 asciicode = scan_to_scanascii[scancode].control;
4754 scancode = scan_to_scanascii[scancode].control >> 8;
4756 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4757 /* check if lock state should be ignored
4758 * because a SHIFT key are pressed */
4760 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4761 asciicode = scan_to_scanascii[scancode].normal;
4762 scancode = scan_to_scanascii[scancode].normal >> 8;
4765 asciicode = scan_to_scanascii[scancode].shift;
4766 scancode = scan_to_scanascii[scancode].shift >> 8;
4770 /* check if lock is on */
4771 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4772 asciicode = scan_to_scanascii[scancode].shift;
4773 scancode = scan_to_scanascii[scancode].shift >> 8;
4776 asciicode = scan_to_scanascii[scancode].normal;
4777 scancode = scan_to_scanascii[scancode].normal >> 8;
4780 if (scancode==0 && asciicode==0) {
4781 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4783 enqueue_key(scancode, asciicode);
4790 enqueue_key(scan_code, ascii_code)
4791 Bit8u scan_code, ascii_code;
4793 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4795 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4796 // scan_code, ascii_code);
4799 buffer_start = 0x001E;
4800 buffer_end = 0x003E;
4802 buffer_start = read_word(0x0040, 0x0080);
4803 buffer_end = read_word(0x0040, 0x0082);
4806 buffer_head = read_word(0x0040, 0x001A);
4807 buffer_tail = read_word(0x0040, 0x001C);
4809 temp_tail = buffer_tail;
4811 if (buffer_tail >= buffer_end)
4812 buffer_tail = buffer_start;
4814 if (buffer_tail == buffer_head) {
4818 write_byte(0x0040, temp_tail, ascii_code);
4819 write_byte(0x0040, temp_tail+1, scan_code);
4820 write_word(0x0040, 0x001C, buffer_tail);
4826 int74_function(make_farcall, Z, Y, X, status)
4827 Bit16u make_farcall, Z, Y, X, status;
4829 Bit16u ebda_seg=read_word(0x0040,0x000E);
4830 Bit8u in_byte, index, package_count;
4831 Bit8u mouse_flags_1, mouse_flags_2;
4833 BX_DEBUG_INT74("entering int74_function\n");
4836 in_byte = inb(0x64);
4837 if ( (in_byte & 0x21) != 0x21 ) {
4840 in_byte = inb(0x60);
4841 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4843 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4844 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4846 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4847 // BX_PANIC("int74_function:\n");
4851 package_count = mouse_flags_2 & 0x07;
4852 index = mouse_flags_1 & 0x07;
4853 write_byte(ebda_seg, 0x28 + index, in_byte);
4855 if ( (index+1) >= package_count ) {
4856 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4857 status = read_byte(ebda_seg, 0x0028 + 0);
4858 X = read_byte(ebda_seg, 0x0028 + 1);
4859 Y = read_byte(ebda_seg, 0x0028 + 2);
4862 // check if far call handler installed
4863 if (mouse_flags_2 & 0x80)
4869 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4872 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4877 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4878 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4881 Bit16u ebda_seg=read_word(0x0040,0x000E);
4882 Bit16u cylinder, head, sector;
4883 Bit16u segment, offset;
4884 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4886 Bit8u device, status;
4888 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4890 write_byte(0x0040, 0x008e, 0); // clear completion flag
4892 // basic check : device has to be defined
4893 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4894 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4898 // Get the ata channel
4899 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4901 // basic check : device has to be valid
4902 if (device >= BX_MAX_ATA_DEVICES) {
4903 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4909 case 0x00: /* disk controller reset */
4914 case 0x01: /* read disk status */
4915 status = read_byte(0x0040, 0x0074);
4917 SET_DISK_RET_STATUS(0);
4918 /* set CF if error status read */
4919 if (status) goto int13_fail_nostatus;
4920 else goto int13_success_noah;
4923 case 0x02: // read disk sectors
4924 case 0x03: // write disk sectors
4925 case 0x04: // verify disk sectors
4928 cylinder = GET_CH();
4929 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4930 sector = (GET_CL() & 0x3f);
4936 if ( (count > 128) || (count == 0) ) {
4937 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4941 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4942 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4943 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4945 // sanity check on cyl heads, sec
4946 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4947 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4952 if ( GET_AH() == 0x04 ) goto int13_success;
4954 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4955 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4957 // if needed, translate lchs to lba, and execute command
4958 if ( (nph != nlh) || (npspt != nlspt)) {
4959 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4960 sector = 0; // this forces the command to be lba
4963 if ( GET_AH() == 0x02 )
4964 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4966 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4968 // Set nb of sector transferred
4969 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4972 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4974 goto int13_fail_noah;
4980 case 0x05: /* format disk track */
4981 BX_INFO("format disk track called\n");
4986 case 0x08: /* read disk drive parameters */
4988 // Get logical geometry from table
4989 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4990 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4991 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4992 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4994 nlc = nlc - 2; /* 0 based , last sector not used */
4997 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4999 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5001 // FIXME should set ES & DI
5006 case 0x10: /* check drive ready */
5007 // should look at 40:8E also???
5009 // Read the status from controller
5010 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5011 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5016 goto int13_fail_noah;
5020 case 0x15: /* read disk drive size */
5022 // Get physical geometry from table
5023 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5024 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5025 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5027 // Compute sector count seen by int13
5028 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5032 SET_AH(3); // hard disk accessible
5033 goto int13_success_noah;
5036 case 0x41: // IBM/MS installation check
5037 BX=0xaa55; // install check
5038 SET_AH(0x30); // EDD 3.0
5039 CX=0x0007; // ext disk access and edd, removable supported
5040 goto int13_success_noah;
5043 case 0x42: // IBM/MS extended read
5044 case 0x43: // IBM/MS extended write
5045 case 0x44: // IBM/MS verify
5046 case 0x47: // IBM/MS extended seek
5048 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5049 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5050 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5052 // Can't use 64 bits lba
5053 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5055 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5059 // Get 32 bits lba and check
5060 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5061 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5062 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5066 // If verify or seek
5067 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5070 // Execute the command
5071 if ( GET_AH() == 0x42 )
5072 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5074 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5076 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5077 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5080 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5082 goto int13_fail_noah;
5088 case 0x45: // IBM/MS lock/unlock drive
5089 case 0x49: // IBM/MS extended media change
5090 goto int13_success; // Always success for HD
5093 case 0x46: // IBM/MS eject media
5094 SET_AH(0xb2); // Volume Not Removable
5095 goto int13_fail_noah; // Always fail for HD
5098 case 0x48: // IBM/MS get drive parameters
5099 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5101 // Buffer is too small
5109 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5110 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5111 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5112 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5113 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5115 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5116 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5117 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5118 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5119 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5120 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5121 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5122 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5127 Bit8u channel, dev, irq, mode, checksum, i, translation;
5128 Bit16u iobase1, iobase2, options;
5130 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5132 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5133 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5136 channel = device / 2;
5137 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5138 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5139 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5140 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5141 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5143 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5144 options |= (1<<4); // lba translation
5145 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5146 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5147 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5149 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5150 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5151 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5152 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5153 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5154 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5155 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5156 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5157 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5158 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5159 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5162 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5163 checksum = ~checksum;
5164 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5169 Bit8u channel, iface, checksum, i;
5172 channel = device / 2;
5173 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5174 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5176 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5177 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5178 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5179 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5180 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5182 if (iface==ATA_IFACE_ISA) {
5183 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5184 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5185 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5186 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5191 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5192 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5193 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5194 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5196 if (iface==ATA_IFACE_ISA) {
5197 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5198 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5199 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5204 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5205 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5206 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5207 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5210 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5211 checksum = ~checksum;
5212 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5218 case 0x4e: // // IBM/MS set hardware configuration
5219 // DMA, prefetch, PIO maximum not supported
5232 case 0x09: /* initialize drive parameters */
5233 case 0x0c: /* seek to specified cylinder */
5234 case 0x0d: /* alternate disk reset */
5235 case 0x11: /* recalibrate */
5236 case 0x14: /* controller internal diagnostic */
5237 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5241 case 0x0a: /* read disk sectors with ECC */
5242 case 0x0b: /* write disk sectors with ECC */
5243 case 0x18: // set media type for format
5244 case 0x50: // IBM/MS send packet command
5246 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5252 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5254 SET_DISK_RET_STATUS(GET_AH());
5255 int13_fail_nostatus:
5256 SET_CF(); // error occurred
5260 SET_AH(0x00); // no error
5262 SET_DISK_RET_STATUS(0x00);
5263 CLEAR_CF(); // no error
5267 // ---------------------------------------------------------------------------
5268 // Start of int13 for cdrom
5269 // ---------------------------------------------------------------------------
5272 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5273 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5275 Bit16u ebda_seg=read_word(0x0040,0x000E);
5276 Bit8u device, status, locks;
5279 Bit16u count, segment, offset, i, size;
5281 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5282 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5284 SET_DISK_RET_STATUS(0x00);
5286 /* basic check : device should be 0xE0+ */
5287 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5288 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5292 // Get the ata channel
5293 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5295 /* basic check : device has to be valid */
5296 if (device >= BX_MAX_ATA_DEVICES) {
5297 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5303 // all those functions return SUCCESS
5304 case 0x00: /* disk controller reset */
5305 case 0x09: /* initialize drive parameters */
5306 case 0x0c: /* seek to specified cylinder */
5307 case 0x0d: /* alternate disk reset */
5308 case 0x10: /* check drive ready */
5309 case 0x11: /* recalibrate */
5310 case 0x14: /* controller internal diagnostic */
5311 case 0x16: /* detect disk change */
5315 // all those functions return disk write-protected
5316 case 0x03: /* write disk sectors */
5317 case 0x05: /* format disk track */
5318 case 0x43: // IBM/MS extended write
5320 goto int13_fail_noah;
5323 case 0x01: /* read disk status */
5324 status = read_byte(0x0040, 0x0074);
5326 SET_DISK_RET_STATUS(0);
5328 /* set CF if error status read */
5329 if (status) goto int13_fail_nostatus;
5330 else goto int13_success_noah;
5333 case 0x15: /* read disk drive size */
5335 goto int13_fail_noah;
5338 case 0x41: // IBM/MS installation check
5339 BX=0xaa55; // install check
5340 SET_AH(0x30); // EDD 2.1
5341 CX=0x0007; // ext disk access, removable and edd
5342 goto int13_success_noah;
5345 case 0x42: // IBM/MS extended read
5346 case 0x44: // IBM/MS verify sectors
5347 case 0x47: // IBM/MS extended seek
5349 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5350 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5351 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5353 // Can't use 64 bits lba
5354 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5356 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5361 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5363 // If verify or seek
5364 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5367 memsetb(get_SS(),atacmd,0,12);
5368 atacmd[0]=0x28; // READ command
5369 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5370 atacmd[8]=(count & 0x00ff); // Sectors
5371 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5372 atacmd[3]=(lba & 0x00ff0000) >> 16;
5373 atacmd[4]=(lba & 0x0000ff00) >> 8;
5374 atacmd[5]=(lba & 0x000000ff);
5375 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5377 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5378 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5381 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5383 goto int13_fail_noah;
5389 case 0x45: // IBM/MS lock/unlock drive
5390 if (GET_AL() > 2) goto int13_fail;
5392 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5396 if (locks == 0xff) {
5399 goto int13_fail_noah;
5401 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5405 if (locks == 0x00) {
5408 goto int13_fail_noah;
5410 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5411 SET_AL(locks==0?0:1);
5414 SET_AL(locks==0?0:1);
5420 case 0x46: // IBM/MS eject media
5421 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5424 SET_AH(0xb1); // media locked
5425 goto int13_fail_noah;
5427 // FIXME should handle 0x31 no media in device
5428 // FIXME should handle 0xb5 valid request failed
5430 // Call removable media eject
5437 mov _int13_cdrom.status + 2[bp], ah
5438 jnc int13_cdrom_rme_end
5439 mov _int13_cdrom.status, #1
5440 int13_cdrom_rme_end:
5445 SET_AH(0xb1); // media locked
5446 goto int13_fail_noah;
5452 case 0x48: // IBM/MS get drive parameters
5453 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5455 // Buffer is too small
5461 Bit16u cylinders, heads, spt, blksize;
5463 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5465 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5466 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5467 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5468 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5469 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5470 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5471 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5472 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5477 Bit8u channel, dev, irq, mode, checksum, i;
5478 Bit16u iobase1, iobase2, options;
5480 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5482 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5483 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5486 channel = device / 2;
5487 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5488 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5489 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5490 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5492 // FIXME atapi device
5493 options = (1<<4); // lba translation
5494 options |= (1<<5); // removable device
5495 options |= (1<<6); // atapi device
5496 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5498 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5499 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5500 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5501 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5502 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5503 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5504 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5505 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5506 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5507 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5508 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5511 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5512 checksum = ~checksum;
5513 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5518 Bit8u channel, iface, checksum, i;
5521 channel = device / 2;
5522 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5523 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5525 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5526 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5527 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5528 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5529 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5531 if (iface==ATA_IFACE_ISA) {
5532 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5533 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5534 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5535 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5540 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5541 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5542 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5543 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5545 if (iface==ATA_IFACE_ISA) {
5546 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5547 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5548 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5553 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5554 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5555 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5556 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5559 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5560 checksum = ~checksum;
5561 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5567 case 0x49: // IBM/MS extended media change
5568 // always send changed ??
5570 goto int13_fail_nostatus;
5573 case 0x4e: // // IBM/MS set hardware configuration
5574 // DMA, prefetch, PIO maximum not supported
5587 // all those functions return unimplemented
5588 case 0x02: /* read sectors */
5589 case 0x04: /* verify sectors */
5590 case 0x08: /* read disk drive parameters */
5591 case 0x0a: /* read disk sectors with ECC */
5592 case 0x0b: /* write disk sectors with ECC */
5593 case 0x18: /* set media type for format */
5594 case 0x50: // ? - send packet command
5596 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5602 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5604 SET_DISK_RET_STATUS(GET_AH());
5605 int13_fail_nostatus:
5606 SET_CF(); // error occurred
5610 SET_AH(0x00); // no error
5612 SET_DISK_RET_STATUS(0x00);
5613 CLEAR_CF(); // no error
5617 // ---------------------------------------------------------------------------
5618 // End of int13 for cdrom
5619 // ---------------------------------------------------------------------------
5621 #if BX_ELTORITO_BOOT
5622 // ---------------------------------------------------------------------------
5623 // Start of int13 for eltorito functions
5624 // ---------------------------------------------------------------------------
5627 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5628 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5630 Bit16u ebda_seg=read_word(0x0040,0x000E);
5632 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5633 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5637 // FIXME ElTorito Various. Should be implemented
5638 case 0x4a: // ElTorito - Initiate disk emu
5639 case 0x4c: // ElTorito - Initiate disk emu and boot
5640 case 0x4d: // ElTorito - Return Boot catalog
5641 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5645 case 0x4b: // ElTorito - Terminate disk emu
5646 // FIXME ElTorito Hardcoded
5647 write_byte(DS,SI+0x00,0x13);
5648 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5649 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5650 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5651 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5652 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5653 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5654 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5655 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5656 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5657 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5658 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5660 // If we have to terminate emulation
5661 if(GET_AL() == 0x00) {
5662 // FIXME ElTorito Various. Should be handled accordingly to spec
5663 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5670 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5676 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5677 SET_DISK_RET_STATUS(GET_AH());
5678 SET_CF(); // error occurred
5682 SET_AH(0x00); // no error
5683 SET_DISK_RET_STATUS(0x00);
5684 CLEAR_CF(); // no error
5688 // ---------------------------------------------------------------------------
5689 // End of int13 for eltorito functions
5690 // ---------------------------------------------------------------------------
5692 // ---------------------------------------------------------------------------
5693 // Start of int13 when emulating a device from the cd
5694 // ---------------------------------------------------------------------------
5697 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5698 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5700 Bit16u ebda_seg=read_word(0x0040,0x000E);
5701 Bit8u device, status;
5702 Bit16u vheads, vspt, vcylinders;
5703 Bit16u head, sector, cylinder, nbsectors;
5704 Bit32u vlba, ilba, slba, elba;
5705 Bit16u before, segment, offset;
5708 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5709 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5711 /* at this point, we are emulating a floppy/harddisk */
5713 // Recompute the device number
5714 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5715 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5717 SET_DISK_RET_STATUS(0x00);
5719 /* basic checks : emulation should be active, dl should equal the emulated drive */
5720 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5721 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5722 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5728 // all those functions return SUCCESS
5729 case 0x00: /* disk controller reset */
5730 case 0x09: /* initialize drive parameters */
5731 case 0x0c: /* seek to specified cylinder */
5732 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5733 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5734 case 0x11: /* recalibrate */
5735 case 0x14: /* controller internal diagnostic */
5736 case 0x16: /* detect disk change */
5740 // all those functions return disk write-protected
5741 case 0x03: /* write disk sectors */
5742 case 0x05: /* format disk track */
5744 goto int13_fail_noah;
5747 case 0x01: /* read disk status */
5748 status=read_byte(0x0040, 0x0074);
5750 SET_DISK_RET_STATUS(0);
5752 /* set CF if error status read */
5753 if (status) goto int13_fail_nostatus;
5754 else goto int13_success_noah;
5757 case 0x02: // read disk sectors
5758 case 0x04: // verify disk sectors
5759 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5760 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5761 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5763 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5765 sector = GET_CL() & 0x003f;
5766 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5768 nbsectors = GET_AL();
5772 // no sector to read ?
5773 if(nbsectors==0) goto int13_success;
5775 // sanity checks sco openserver needs this!
5777 || (cylinder >= vcylinders)
5778 || (head >= vheads)) {
5782 // After controls, verify do nothing
5783 if (GET_AH() == 0x04) goto int13_success;
5785 segment = ES+(BX / 16);
5788 // calculate the virtual lba inside the image
5789 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5791 // In advance so we don't loose the count
5795 slba = (Bit32u)vlba/4;
5796 before= (Bit16u)vlba%4;
5799 elba = (Bit32u)(vlba+nbsectors-1)/4;
5801 memsetb(get_SS(),atacmd,0,12);
5802 atacmd[0]=0x28; // READ command
5803 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5804 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5805 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5806 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5807 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5808 atacmd[5]=(ilba+slba & 0x000000ff);
5809 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5810 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5813 goto int13_fail_noah;
5819 case 0x08: /* read disk drive parameters */
5820 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5821 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5822 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5826 SET_CH( vcylinders & 0xff );
5827 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5829 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5830 // FIXME ElTorito Harddisk. should send the HD count
5832 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5833 case 0x01: SET_BL( 0x02 ); break;
5834 case 0x02: SET_BL( 0x04 ); break;
5835 case 0x03: SET_BL( 0x06 ); break;
5841 mov ax, #diskette_param_table2
5842 mov _int13_cdemu.DI+2[bp], ax
5843 mov _int13_cdemu.ES+2[bp], cs
5849 case 0x15: /* read disk drive size */
5850 // FIXME ElTorito Harddisk. What geometry to send ?
5852 goto int13_success_noah;
5855 // all those functions return unimplemented
5856 case 0x0a: /* read disk sectors with ECC */
5857 case 0x0b: /* write disk sectors with ECC */
5858 case 0x18: /* set media type for format */
5859 case 0x41: // IBM/MS installation check
5860 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5861 case 0x42: // IBM/MS extended read
5862 case 0x43: // IBM/MS extended write
5863 case 0x44: // IBM/MS verify sectors
5864 case 0x45: // IBM/MS lock/unlock drive
5865 case 0x46: // IBM/MS eject media
5866 case 0x47: // IBM/MS extended seek
5867 case 0x48: // IBM/MS get drive parameters
5868 case 0x49: // IBM/MS extended media change
5869 case 0x4e: // ? - set hardware configuration
5870 case 0x50: // ? - send packet command
5872 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5878 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5880 SET_DISK_RET_STATUS(GET_AH());
5881 int13_fail_nostatus:
5882 SET_CF(); // error occurred
5886 SET_AH(0x00); // no error
5888 SET_DISK_RET_STATUS(0x00);
5889 CLEAR_CF(); // no error
5893 // ---------------------------------------------------------------------------
5894 // End of int13 when emulating a device from the cd
5895 // ---------------------------------------------------------------------------
5897 #endif // BX_ELTORITO_BOOT
5899 #else //BX_USE_ATADRV
5902 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5917 mov ax,4[bp] // cylinder
5919 mov bl,6[bp] // hd_heads
5922 mov bl,8[bp] // head
5924 mov bl,10[bp] // hd_sectors
5926 mov bl,12[bp] // sector
5955 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5956 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5958 Bit8u drive, num_sectors, sector, head, status, mod;
5962 Bit16u max_cylinder, cylinder, total_sectors;
5963 Bit16u hd_cylinders;
5964 Bit8u hd_heads, hd_sectors;
5971 Bit16u count, segment, offset;
5975 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5977 write_byte(0x0040, 0x008e, 0); // clear completion flag
5979 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5981 /* check how many disks first (cmos reg 0x12), return an error if
5982 drive not present */
5983 drive_map = inb_cmos(0x12);
5984 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5985 (((drive_map & 0x0f)==0) ? 0 : 2);
5986 n_drives = (drive_map==0) ? 0 :
5987 ((drive_map==3) ? 2 : 1);
5989 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5991 SET_DISK_RET_STATUS(0x01);
5992 SET_CF(); /* error occurred */
5998 case 0x00: /* disk controller reset */
5999 BX_DEBUG_INT13_HD("int13_f00\n");
6002 SET_DISK_RET_STATUS(0);
6003 set_diskette_ret_status(0);
6004 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6005 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6006 CLEAR_CF(); /* successful */
6010 case 0x01: /* read disk status */
6011 BX_DEBUG_INT13_HD("int13_f01\n");
6012 status = read_byte(0x0040, 0x0074);
6014 SET_DISK_RET_STATUS(0);
6015 /* set CF if error status read */
6016 if (status) SET_CF();
6021 case 0x04: // verify disk sectors
6022 case 0x02: // read disk sectors
6024 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6026 num_sectors = GET_AL();
6027 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6028 sector = (GET_CL() & 0x3f);
6032 if (hd_cylinders > 1024) {
6033 if (hd_cylinders <= 2048) {
6036 else if (hd_cylinders <= 4096) {
6039 else if (hd_cylinders <= 8192) {
6042 else { // hd_cylinders <= 16384
6046 ax = head / hd_heads;
6047 cyl_mod = ax & 0xff;
6049 cylinder |= cyl_mod;
6052 if ( (cylinder >= hd_cylinders) ||
6053 (sector > hd_sectors) ||
6054 (head >= hd_heads) ) {
6056 SET_DISK_RET_STATUS(1);
6057 SET_CF(); /* error occurred */
6061 if ( (num_sectors > 128) || (num_sectors == 0) )
6062 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6065 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6067 if ( GET_AH() == 0x04 ) {
6069 SET_DISK_RET_STATUS(0);
6074 status = inb(0x1f7);
6075 if (status & 0x80) {
6076 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6078 outb(0x01f2, num_sectors);
6079 /* activate LBA? (tomv) */
6080 if (hd_heads > 16) {
6081 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6082 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6085 outb(0x01f3, sector);
6086 outb(0x01f4, cylinder & 0x00ff);
6087 outb(0x01f5, cylinder >> 8);
6088 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6093 status = inb(0x1f7);
6094 if ( !(status & 0x80) ) break;
6097 if (status & 0x01) {
6098 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6099 } else if ( !(status & 0x08) ) {
6100 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6101 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6108 sti ;; enable higher priority interrupts
6113 ;; store temp bx in real DI register
6116 mov di, _int13_harddisk.tempbx + 2 [bp]
6119 ;; adjust if there will be an overrun
6121 jbe i13_f02_no_adjust
6123 sub di, #0x0200 ; sub 512 bytes from offset
6125 add ax, #0x0020 ; add 512 to segment
6129 mov cx, #0x0100 ;; counter (256 words = 512b)
6130 mov dx, #0x01f0 ;; AT data read port
6133 insw ;; CX words transfered from port(DX) to ES:[DI]
6136 ;; store real DI register back to temp bx
6139 mov _int13_harddisk.tempbx + 2 [bp], di
6145 if (num_sectors == 0) {
6146 status = inb(0x1f7);
6147 if ( (status & 0xc9) != 0x40 )
6148 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6152 status = inb(0x1f7);
6153 if ( (status & 0xc9) != 0x48 )
6154 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6160 SET_DISK_RET_STATUS(0);
6161 SET_AL(sector_count);
6162 CLEAR_CF(); /* successful */
6167 case 0x03: /* write disk sectors */
6168 BX_DEBUG_INT13_HD("int13_f03\n");
6169 drive = GET_ELDL ();
6170 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6172 num_sectors = GET_AL();
6173 cylinder = GET_CH();
6174 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6175 sector = (GET_CL() & 0x3f);
6178 if (hd_cylinders > 1024) {
6179 if (hd_cylinders <= 2048) {
6182 else if (hd_cylinders <= 4096) {
6185 else if (hd_cylinders <= 8192) {
6188 else { // hd_cylinders <= 16384
6192 ax = head / hd_heads;
6193 cyl_mod = ax & 0xff;
6195 cylinder |= cyl_mod;
6198 if ( (cylinder >= hd_cylinders) ||
6199 (sector > hd_sectors) ||
6200 (head >= hd_heads) ) {
6202 SET_DISK_RET_STATUS(1);
6203 SET_CF(); /* error occurred */
6207 if ( (num_sectors > 128) || (num_sectors == 0) )
6208 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6211 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6213 status = inb(0x1f7);
6214 if (status & 0x80) {
6215 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6217 // should check for Drive Ready Bit also in status reg
6218 outb(0x01f2, num_sectors);
6220 /* activate LBA? (tomv) */
6221 if (hd_heads > 16) {
6222 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6223 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6226 outb(0x01f3, sector);
6227 outb(0x01f4, cylinder & 0x00ff);
6228 outb(0x01f5, cylinder >> 8);
6229 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6233 // wait for busy bit to turn off after seeking
6235 status = inb(0x1f7);
6236 if ( !(status & 0x80) ) break;
6239 if ( !(status & 0x08) ) {
6240 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6241 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6248 sti ;; enable higher priority interrupts
6253 ;; store temp bx in real SI register
6256 mov si, _int13_harddisk.tempbx + 2 [bp]
6259 ;; adjust if there will be an overrun
6261 jbe i13_f03_no_adjust
6263 sub si, #0x0200 ; sub 512 bytes from offset
6265 add ax, #0x0020 ; add 512 to segment
6269 mov cx, #0x0100 ;; counter (256 words = 512b)
6270 mov dx, #0x01f0 ;; AT data read port
6274 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6276 ;; store real SI register back to temp bx
6279 mov _int13_harddisk.tempbx + 2 [bp], si
6285 if (num_sectors == 0) {
6286 status = inb(0x1f7);
6287 if ( (status & 0xe9) != 0x40 )
6288 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6292 status = inb(0x1f7);
6293 if ( (status & 0xc9) != 0x48 )
6294 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6300 SET_DISK_RET_STATUS(0);
6301 SET_AL(sector_count);
6302 CLEAR_CF(); /* successful */
6306 case 0x05: /* format disk track */
6307 BX_DEBUG_INT13_HD("int13_f05\n");
6308 BX_PANIC("format disk track called\n");
6311 SET_DISK_RET_STATUS(0);
6312 CLEAR_CF(); /* successful */
6316 case 0x08: /* read disk drive parameters */
6317 BX_DEBUG_INT13_HD("int13_f08\n");
6319 drive = GET_ELDL ();
6320 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6324 if (hd_cylinders <= 1024) {
6325 // hd_cylinders >>= 0;
6328 else if (hd_cylinders <= 2048) {
6332 else if (hd_cylinders <= 4096) {
6336 else if (hd_cylinders <= 8192) {
6340 else { // hd_cylinders <= 16384
6345 max_cylinder = hd_cylinders - 2; /* 0 based */
6347 SET_CH(max_cylinder & 0xff);
6348 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6349 SET_DH(hd_heads - 1);
6350 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6352 SET_DISK_RET_STATUS(0);
6353 CLEAR_CF(); /* successful */
6358 case 0x09: /* initialize drive parameters */
6359 BX_DEBUG_INT13_HD("int13_f09\n");
6361 SET_DISK_RET_STATUS(0);
6362 CLEAR_CF(); /* successful */
6366 case 0x0a: /* read disk sectors with ECC */
6367 BX_DEBUG_INT13_HD("int13_f0a\n");
6368 case 0x0b: /* write disk sectors with ECC */
6369 BX_DEBUG_INT13_HD("int13_f0b\n");
6370 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6374 case 0x0c: /* seek to specified cylinder */
6375 BX_DEBUG_INT13_HD("int13_f0c\n");
6376 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6378 SET_DISK_RET_STATUS(0);
6379 CLEAR_CF(); /* successful */
6383 case 0x0d: /* alternate disk reset */
6384 BX_DEBUG_INT13_HD("int13_f0d\n");
6386 SET_DISK_RET_STATUS(0);
6387 CLEAR_CF(); /* successful */
6391 case 0x10: /* check drive ready */
6392 BX_DEBUG_INT13_HD("int13_f10\n");
6394 //SET_DISK_RET_STATUS(0);
6395 //CLEAR_CF(); /* successful */
6399 // should look at 40:8E also???
6400 status = inb(0x01f7);
6401 if ( (status & 0xc0) == 0x40 ) {
6403 SET_DISK_RET_STATUS(0);
6404 CLEAR_CF(); // drive ready
6409 SET_DISK_RET_STATUS(0xAA);
6410 SET_CF(); // not ready
6415 case 0x11: /* recalibrate */
6416 BX_DEBUG_INT13_HD("int13_f11\n");
6418 SET_DISK_RET_STATUS(0);
6419 CLEAR_CF(); /* successful */
6423 case 0x14: /* controller internal diagnostic */
6424 BX_DEBUG_INT13_HD("int13_f14\n");
6426 SET_DISK_RET_STATUS(0);
6427 CLEAR_CF(); /* successful */
6432 case 0x15: /* read disk drive size */
6434 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6438 mov al, _int13_harddisk.hd_heads + 2 [bp]
6439 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6440 mul al, ah ;; ax = heads * sectors
6441 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6442 dec bx ;; use (cylinders - 1) ???
6443 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6444 ;; now we need to move the 32bit result dx:ax to what the
6445 ;; BIOS wants which is cx:dx.
6446 ;; and then into CX:DX on the stack
6447 mov _int13_harddisk.CX + 2 [bp], dx
6448 mov _int13_harddisk.DX + 2 [bp], ax
6451 SET_AH(3); // hard disk accessible
6452 SET_DISK_RET_STATUS(0); // ??? should this be 0
6453 CLEAR_CF(); // successful
6457 case 0x18: // set media type for format
6458 case 0x41: // IBM/MS
6459 case 0x42: // IBM/MS
6460 case 0x43: // IBM/MS
6461 case 0x44: // IBM/MS
6462 case 0x45: // IBM/MS lock/unlock drive
6463 case 0x46: // IBM/MS eject media
6464 case 0x47: // IBM/MS extended seek
6465 case 0x49: // IBM/MS extended media change
6466 case 0x50: // IBM/MS send packet command
6468 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6470 SET_AH(1); // code=invalid function in AH or invalid parameter
6471 SET_DISK_RET_STATUS(1);
6472 SET_CF(); /* unsuccessful */
6478 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6479 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6482 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6484 Bit16u *hd_cylinders;
6494 if (drive == 0x80) {
6495 hd_type = inb_cmos(0x12) & 0xf0;
6496 if (hd_type != 0xf0)
6497 BX_INFO(panic_msg_reg12h,0);
6498 hd_type = inb_cmos(0x19); // HD0: extended type
6500 BX_INFO(panic_msg_reg19h,0,0x19);
6503 hd_type = inb_cmos(0x12) & 0x0f;
6504 if (hd_type != 0x0f)
6505 BX_INFO(panic_msg_reg12h,1);
6506 hd_type = inb_cmos(0x1a); // HD0: extended type
6508 BX_INFO(panic_msg_reg19h,0,0x1a);
6513 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6514 write_word(ss, hd_cylinders, cylinders);
6517 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6519 // sectors per track
6520 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6523 #endif //else BX_USE_ATADRV
6526 //////////////////////
6527 // FLOPPY functions //
6528 //////////////////////
6531 floppy_media_known(drive)
6535 Bit16u media_state_offset;
6537 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6544 media_state_offset = 0x0090;
6546 media_state_offset += 1;
6548 val8 = read_byte(0x0040, media_state_offset);
6549 val8 = (val8 >> 4) & 0x01;
6553 // check pass, return KNOWN
6558 floppy_media_sense(drive)
6562 Bit16u media_state_offset;
6563 Bit8u drive_type, config_data, media_state;
6565 if (floppy_drive_recal(drive) == 0) {
6569 // for now cheat and get drive type from CMOS,
6570 // assume media is same as drive type
6572 // ** config_data **
6573 // Bitfields for diskette media control:
6574 // Bit(s) Description (Table M0028)
6575 // 7-6 last data rate set by controller
6576 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6577 // 5-4 last diskette drive step rate selected
6578 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6579 // 3-2 {data rate at start of operation}
6582 // ** media_state **
6583 // Bitfields for diskette drive media state:
6584 // Bit(s) Description (Table M0030)
6586 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6587 // 5 double stepping required (e.g. 360kB in 1.2MB)
6588 // 4 media type established
6589 // 3 drive capable of supporting 4MB media
6590 // 2-0 on exit from BIOS, contains
6591 // 000 trying 360kB in 360kB
6592 // 001 trying 360kB in 1.2MB
6593 // 010 trying 1.2MB in 1.2MB
6594 // 011 360kB in 360kB established
6595 // 100 360kB in 1.2MB established
6596 // 101 1.2MB in 1.2MB established
6598 // 111 all other formats/drives
6600 drive_type = inb_cmos(0x10);
6605 if ( drive_type == 1 ) {
6607 config_data = 0x00; // 0000 0000
6608 media_state = 0x25; // 0010 0101
6611 else if ( drive_type == 2 ) {
6612 // 1.2 MB 5.25" drive
6613 config_data = 0x00; // 0000 0000
6614 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6617 else if ( drive_type == 3 ) {
6619 config_data = 0x00; // 0000 0000 ???
6620 media_state = 0x17; // 0001 0111
6623 else if ( drive_type == 4 ) {
6624 // 1.44 MB 3.5" drive
6625 config_data = 0x00; // 0000 0000
6626 media_state = 0x17; // 0001 0111
6629 else if ( drive_type == 5 ) {
6630 // 2.88 MB 3.5" drive
6631 config_data = 0xCC; // 1100 1100
6632 media_state = 0xD7; // 1101 0111
6636 // Extended floppy size uses special cmos setting
6637 else if ( drive_type == 6 ) {
6639 config_data = 0x00; // 0000 0000
6640 media_state = 0x27; // 0010 0111
6643 else if ( drive_type == 7 ) {
6645 config_data = 0x00; // 0000 0000
6646 media_state = 0x27; // 0010 0111
6649 else if ( drive_type == 8 ) {
6651 config_data = 0x00; // 0000 0000
6652 media_state = 0x27; // 0010 0111
6658 config_data = 0x00; // 0000 0000
6659 media_state = 0x00; // 0000 0000
6664 media_state_offset = 0x90;
6666 media_state_offset = 0x91;
6667 write_byte(0x0040, 0x008B, config_data);
6668 write_byte(0x0040, media_state_offset, media_state);
6674 floppy_drive_recal(drive)
6678 Bit16u curr_cyl_offset;
6680 // set 40:3e bit 7 to 0
6681 val8 = read_byte(0x0000, 0x043e);
6683 write_byte(0x0000, 0x043e, val8);
6685 // turn on motor of selected drive, DMA & int enabled, normal operation
6694 // reset the disk motor timeout value of INT 08
6695 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6697 // check port 3f4 for drive readiness
6699 if ( (val8 & 0xf0) != 0x80 )
6700 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6702 // send Recalibrate command (2 bytes) to controller
6703 outb(0x03f5, 0x07); // 07: Recalibrate
6704 outb(0x03f5, drive); // 0=drive0, 1=drive1
6706 // turn on interrupts
6711 // wait on 40:3e bit 7 to become 1
6712 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6713 while ( val8 == 0 ) {
6714 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6717 val8 = 0; // separate asm from while() loop
6718 // turn off interrupts
6723 // set 40:3e bit 7 to 0, and calibrated bit
6724 val8 = read_byte(0x0000, 0x043e);
6727 val8 |= 0x02; // Drive 1 calibrated
6728 curr_cyl_offset = 0x0095;
6731 val8 |= 0x01; // Drive 0 calibrated
6732 curr_cyl_offset = 0x0094;
6734 write_byte(0x0040, 0x003e, val8);
6735 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6743 floppy_drive_exists(drive)
6748 // just tell it both drives exist - PAD
6751 // check CMOS to see if drive exists
6752 drive_type = inb_cmos(0x10);
6757 if ( drive_type == 0 )
6763 #if BX_SUPPORT_FLOPPY
6765 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6766 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6768 Bit8u drive, num_sectors, track, sector, head, status;
6769 Bit16u base_address, base_count, base_es;
6770 Bit8u page, mode_register, val8, dor;
6771 Bit8u return_status[7];
6772 Bit8u drive_type, num_floppies, ah;
6773 Bit16u es, last_addr;
6775 printf("In int13_diskette\n");
6777 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6778 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6783 case 0x00: // diskette controller reset
6784 BX_DEBUG_INT13_FL("floppy f00\n");
6787 SET_AH(1); // invalid param
6788 set_diskette_ret_status(1);
6792 drive_type = inb_cmos(0x10);
6798 if (drive_type == 0) {
6799 SET_AH(0x80); // drive not responding
6800 set_diskette_ret_status(0x80);
6805 set_diskette_ret_status(0);
6806 CLEAR_CF(); // successful
6807 set_diskette_current_cyl(drive, 0); // current cylinder
6810 case 0x01: // Read Diskette Status
6812 val8 = read_byte(0x0000, 0x0441);
6819 case 0x02: // Read Diskette Sectors
6820 case 0x03: // Write Diskette Sectors
6821 case 0x04: // Verify Diskette Sectors
6822 num_sectors = GET_AL();
6828 if ( (drive > 1) || (head > 1) ||
6829 (num_sectors == 0) || (num_sectors > 72) ) {
6830 BX_INFO("floppy: drive>1 || head>1 ...\n");
6832 set_diskette_ret_status(1);
6833 SET_AL(0); // no sectors read
6834 SET_CF(); // error occurred
6838 // see if drive exists
6839 if (floppy_drive_exists(drive) == 0) {
6840 SET_AH(0x80); // not responding
6841 set_diskette_ret_status(0x80);
6842 SET_AL(0); // no sectors read
6843 SET_CF(); // error occurred
6847 // see if media in drive, and type is known
6848 if (floppy_media_known(drive) == 0) {
6849 if (floppy_media_sense(drive) == 0) {
6850 SET_AH(0x0C); // Media type not found
6851 set_diskette_ret_status(0x0C);
6852 SET_AL(0); // no sectors read
6853 SET_CF(); // error occurred
6859 // Read Diskette Sectors
6861 //-----------------------------------
6862 // set up DMA controller for transfer
6863 //-----------------------------------
6865 // es:bx = pointer to where to place information from diskette
6866 // port 04: DMA-1 base and current address, channel 2
6867 // port 05: DMA-1 base and current count, channel 2
6868 page = (ES >> 12); // upper 4 bits
6869 base_es = (ES << 4); // lower 16bits contributed by ES
6870 base_address = base_es + BX; // lower 16 bits of address
6871 // contributed by ES:BX
6872 if ( base_address < base_es ) {
6873 // in case of carry, adjust page by 1
6876 base_count = (num_sectors * 512) - 1;
6878 // check for 64K boundary overrun
6879 last_addr = base_address + base_count;
6880 if (last_addr < base_address) {
6882 set_diskette_ret_status(0x09);
6883 SET_AL(0); // no sectors read
6884 SET_CF(); // error occurred
6888 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6891 BX_DEBUG_INT13_FL("clear flip-flop\n");
6892 outb(0x000c, 0x00); // clear flip-flop
6893 outb(0x0004, base_address);
6894 outb(0x0004, base_address>>8);
6895 BX_DEBUG_INT13_FL("clear flip-flop\n");
6896 outb(0x000c, 0x00); // clear flip-flop
6897 outb(0x0005, base_count);
6898 outb(0x0005, base_count>>8);
6900 // port 0b: DMA-1 Mode Register
6901 mode_register = 0x46; // single mode, increment, autoinit disable,
6902 // transfer type=write, channel 2
6903 BX_DEBUG_INT13_FL("setting mode register\n");
6904 outb(0x000b, mode_register);
6906 BX_DEBUG_INT13_FL("setting page register\n");
6907 // port 81: DMA-1 Page Register, channel 2
6910 BX_DEBUG_INT13_FL("unmask chan 2\n");
6911 outb(0x000a, 0x02); // unmask channel 2
6913 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6916 //--------------------------------------
6917 // set up floppy controller for transfer
6918 //--------------------------------------
6920 // set 40:3e bit 7 to 0
6921 val8 = read_byte(0x0000, 0x043e);
6923 write_byte(0x0000, 0x043e, val8);
6925 // turn on motor of selected drive, DMA & int enabled, normal operation
6934 // reset the disk motor timeout value of INT 08
6935 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6937 // check port 3f4 for drive readiness
6939 if ( (val8 & 0xf0) != 0x80 )
6940 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6942 // send read-normal-data command (9 bytes) to controller
6943 outb(0x03f5, 0xe6); // e6: read normal data
6944 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6945 outb(0x03f5, track);
6947 outb(0x03f5, sector);
6948 outb(0x03f5, 2); // 512 byte sector size
6949 outb(0x03f5, 0); // last sector number possible on track
6950 outb(0x03f5, 0); // Gap length
6951 outb(0x03f5, 0xff); // Gap length
6953 // turn on interrupts
6958 // wait on 40:3e bit 7 to become 1
6959 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6960 while ( val8 == 0 ) {
6961 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6964 val8 = 0; // separate asm from while() loop
6965 // turn off interrupts
6970 // set 40:3e bit 7 to 0
6971 val8 = read_byte(0x0000, 0x043e);
6973 write_byte(0x0000, 0x043e, val8);
6975 // check port 3f4 for accessibility to status bytes
6977 if ( (val8 & 0xc0) != 0xc0 )
6978 BX_PANIC("int13_diskette: ctrl not ready\n");
6980 // read 7 return status bytes from controller
6981 // using loop index broken, have to unroll...
6982 return_status[0] = inb(0x3f5);
6983 return_status[1] = inb(0x3f5);
6984 return_status[2] = inb(0x3f5);
6985 return_status[3] = inb(0x3f5);
6986 return_status[4] = inb(0x3f5);
6987 return_status[5] = inb(0x3f5);
6988 return_status[6] = inb(0x3f5);
6989 // record in BIOS Data Area
6990 write_byte(0x0040, 0x0042, return_status[0]);
6991 write_byte(0x0040, 0x0043, return_status[1]);
6992 write_byte(0x0040, 0x0044, return_status[2]);
6993 write_byte(0x0040, 0x0045, return_status[3]);
6994 write_byte(0x0040, 0x0046, return_status[4]);
6995 write_byte(0x0040, 0x0047, return_status[5]);
6996 write_byte(0x0040, 0x0048, return_status[6]);
6998 if ( (return_status[0] & 0xc0) != 0 ) {
7000 set_diskette_ret_status(0x20);
7001 SET_AL(0); // no sectors read
7002 SET_CF(); // error occurred
7006 // ??? should track be new val from return_status[3] ?
7007 set_diskette_current_cyl(drive, track);
7008 // AL = number of sectors read (same value as passed)
7009 SET_AH(0x00); // success
7010 CLEAR_CF(); // success
7013 else if (ah == 0x03) {
7014 // Write Diskette Sectors
7016 //-----------------------------------
7017 // set up DMA controller for transfer
7018 //-----------------------------------
7020 // es:bx = pointer to where to place information from diskette
7021 // port 04: DMA-1 base and current address, channel 2
7022 // port 05: DMA-1 base and current count, channel 2
7023 page = (ES >> 12); // upper 4 bits
7024 base_es = (ES << 4); // lower 16bits contributed by ES
7025 base_address = base_es + BX; // lower 16 bits of address
7026 // contributed by ES:BX
7027 if ( base_address < base_es ) {
7028 // in case of carry, adjust page by 1
7031 base_count = (num_sectors * 512) - 1;
7033 // check for 64K boundary overrun
7034 last_addr = base_address + base_count;
7035 if (last_addr < base_address) {
7037 set_diskette_ret_status(0x09);
7038 SET_AL(0); // no sectors read
7039 SET_CF(); // error occurred
7043 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7046 outb(0x000c, 0x00); // clear flip-flop
7047 outb(0x0004, base_address);
7048 outb(0x0004, base_address>>8);
7049 outb(0x000c, 0x00); // clear flip-flop
7050 outb(0x0005, base_count);
7051 outb(0x0005, base_count>>8);
7053 // port 0b: DMA-1 Mode Register
7054 mode_register = 0x4a; // single mode, increment, autoinit disable,
7055 // transfer type=read, channel 2
7056 outb(0x000b, mode_register);
7058 // port 81: DMA-1 Page Register, channel 2
7061 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7064 //--------------------------------------
7065 // set up floppy controller for transfer
7066 //--------------------------------------
7068 // set 40:3e bit 7 to 0
7069 val8 = read_byte(0x0000, 0x043e);
7071 write_byte(0x0000, 0x043e, val8);
7073 // turn on motor of selected drive, DMA & int enabled, normal operation
7082 // reset the disk motor timeout value of INT 08
7083 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7085 // check port 3f4 for drive readiness
7087 if ( (val8 & 0xf0) != 0x80 )
7088 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7090 // send read-normal-data command (9 bytes) to controller
7091 outb(0x03f5, 0xc5); // c5: write normal data
7092 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7093 outb(0x03f5, track);
7095 outb(0x03f5, sector);
7096 outb(0x03f5, 2); // 512 byte sector size
7097 outb(0x03f5, 0); // last sector number possible on track
7098 outb(0x03f5, 0); // Gap length
7099 outb(0x03f5, 0xff); // Gap length
7101 // turn on interrupts
7106 // wait on 40:3e bit 7 to become 1
7107 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7108 while ( val8 == 0 ) {
7109 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7112 val8 = 0; // separate asm from while() loop
7113 // turn off interrupts
7118 // set 40:3e bit 7 to 0
7119 val8 = read_byte(0x0000, 0x043e);
7121 write_byte(0x0000, 0x043e, val8);
7123 // check port 3f4 for accessibility to status bytes
7125 if ( (val8 & 0xc0) != 0xc0 )
7126 BX_PANIC("int13_diskette: ctrl not ready\n");
7128 // read 7 return status bytes from controller
7129 // using loop index broken, have to unroll...
7130 return_status[0] = inb(0x3f5);
7131 return_status[1] = inb(0x3f5);
7132 return_status[2] = inb(0x3f5);
7133 return_status[3] = inb(0x3f5);
7134 return_status[4] = inb(0x3f5);
7135 return_status[5] = inb(0x3f5);
7136 return_status[6] = inb(0x3f5);
7137 // record in BIOS Data Area
7138 write_byte(0x0040, 0x0042, return_status[0]);
7139 write_byte(0x0040, 0x0043, return_status[1]);
7140 write_byte(0x0040, 0x0044, return_status[2]);
7141 write_byte(0x0040, 0x0045, return_status[3]);
7142 write_byte(0x0040, 0x0046, return_status[4]);
7143 write_byte(0x0040, 0x0047, return_status[5]);
7144 write_byte(0x0040, 0x0048, return_status[6]);
7146 if ( (return_status[0] & 0xc0) != 0 ) {
7147 if ( (return_status[1] & 0x02) != 0 ) {
7148 // diskette not writable.
7149 // AH=status code=0x03 (tried to write on write-protected disk)
7150 // AL=number of sectors written=0
7155 BX_PANIC("int13_diskette_function: read error\n");
7159 // ??? should track be new val from return_status[3] ?
7160 set_diskette_current_cyl(drive, track);
7161 // AL = number of sectors read (same value as passed)
7162 SET_AH(0x00); // success
7163 CLEAR_CF(); // success
7166 else { // if (ah == 0x04)
7167 // Verify Diskette Sectors
7169 // ??? should track be new val from return_status[3] ?
7170 set_diskette_current_cyl(drive, track);
7171 // AL = number of sectors verified (same value as passed)
7172 CLEAR_CF(); // success
7173 SET_AH(0x00); // success
7178 case 0x05: // format diskette track
7179 BX_DEBUG_INT13_FL("floppy f05\n");
7181 num_sectors = GET_AL();
7186 if ((drive > 1) || (head > 1) || (track > 79) ||
7187 (num_sectors == 0) || (num_sectors > 18)) {
7189 set_diskette_ret_status(1);
7190 SET_CF(); // error occurred
7193 // see if drive exists
7194 if (floppy_drive_exists(drive) == 0) {
7195 SET_AH(0x80); // drive not responding
7196 set_diskette_ret_status(0x80);
7197 SET_CF(); // error occurred
7201 // see if media in drive, and type is known
7202 if (floppy_media_known(drive) == 0) {
7203 if (floppy_media_sense(drive) == 0) {
7204 SET_AH(0x0C); // Media type not found
7205 set_diskette_ret_status(0x0C);
7206 SET_AL(0); // no sectors read
7207 SET_CF(); // error occurred
7212 // set up DMA controller for transfer
7213 page = (ES >> 12); // upper 4 bits
7214 base_es = (ES << 4); // lower 16bits contributed by ES
7215 base_address = base_es + BX; // lower 16 bits of address
7216 // contributed by ES:BX
7217 if ( base_address < base_es ) {
7218 // in case of carry, adjust page by 1
7221 base_count = (num_sectors * 4) - 1;
7223 // check for 64K boundary overrun
7224 last_addr = base_address + base_count;
7225 if (last_addr < base_address) {
7227 set_diskette_ret_status(0x09);
7228 SET_AL(0); // no sectors read
7229 SET_CF(); // error occurred
7234 outb(0x000c, 0x00); // clear flip-flop
7235 outb(0x0004, base_address);
7236 outb(0x0004, base_address>>8);
7237 outb(0x000c, 0x00); // clear flip-flop
7238 outb(0x0005, base_count);
7239 outb(0x0005, base_count>>8);
7240 mode_register = 0x4a; // single mode, increment, autoinit disable,
7241 // transfer type=read, channel 2
7242 outb(0x000b, mode_register);
7243 // port 81: DMA-1 Page Register, channel 2
7247 // set up floppy controller for transfer
7248 val8 = read_byte(0x0000, 0x043e);
7250 write_byte(0x0000, 0x043e, val8);
7251 // turn on motor of selected drive, DMA & int enabled, normal operation
7260 // reset the disk motor timeout value of INT 08
7261 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7263 // check port 3f4 for drive readiness
7265 if ( (val8 & 0xf0) != 0x80 )
7266 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7268 // send read-normal-data command (6 bytes) to controller
7269 outb(0x03f5, 0x4d); // 4d: format track
7270 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7271 outb(0x03f5, 2); // 512 byte sector size
7272 outb(0x03f5, num_sectors); // number of sectors per track
7273 outb(0x03f5, 0); // Gap length
7274 outb(0x03f5, 0xf6); // Fill byte
7275 // turn on interrupts
7279 // wait on 40:3e bit 7 to become 1
7280 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7281 while ( val8 == 0 ) {
7282 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7284 val8 = 0; // separate asm from while() loop
7285 // turn off interrupts
7289 // set 40:3e bit 7 to 0
7290 val8 = read_byte(0x0000, 0x043e);
7292 write_byte(0x0000, 0x043e, val8);
7293 // check port 3f4 for accessibility to status bytes
7295 if ( (val8 & 0xc0) != 0xc0 )
7296 BX_PANIC("int13_diskette: ctrl not ready\n");
7298 // read 7 return status bytes from controller
7299 // using loop index broken, have to unroll...
7300 return_status[0] = inb(0x3f5);
7301 return_status[1] = inb(0x3f5);
7302 return_status[2] = inb(0x3f5);
7303 return_status[3] = inb(0x3f5);
7304 return_status[4] = inb(0x3f5);
7305 return_status[5] = inb(0x3f5);
7306 return_status[6] = inb(0x3f5);
7307 // record in BIOS Data Area
7308 write_byte(0x0040, 0x0042, return_status[0]);
7309 write_byte(0x0040, 0x0043, return_status[1]);
7310 write_byte(0x0040, 0x0044, return_status[2]);
7311 write_byte(0x0040, 0x0045, return_status[3]);
7312 write_byte(0x0040, 0x0046, return_status[4]);
7313 write_byte(0x0040, 0x0047, return_status[5]);
7314 write_byte(0x0040, 0x0048, return_status[6]);
7316 if ( (return_status[0] & 0xc0) != 0 ) {
7317 if ( (return_status[1] & 0x02) != 0 ) {
7318 // diskette not writable.
7319 // AH=status code=0x03 (tried to write on write-protected disk)
7320 // AL=number of sectors written=0
7325 BX_PANIC("int13_diskette_function: write error\n");
7330 set_diskette_ret_status(0);
7331 set_diskette_current_cyl(drive, 0);
7332 CLEAR_CF(); // successful
7336 case 0x08: // read diskette drive parameters
7337 BX_DEBUG_INT13_FL("floppy f08\n");
7347 SET_DL(num_floppies);
7352 drive_type = inb_cmos(0x10);
7354 if (drive_type & 0xf0)
7356 if (drive_type & 0x0f)
7368 SET_DL(num_floppies);
7370 switch (drive_type) {
7373 SET_DH(0); // max head #
7376 case 1: // 360KB, 5.25"
7377 CX = 0x2709; // 40 tracks, 9 sectors
7378 SET_DH(1); // max head #
7381 case 2: // 1.2MB, 5.25"
7382 CX = 0x4f0f; // 80 tracks, 15 sectors
7383 SET_DH(1); // max head #
7386 case 3: // 720KB, 3.5"
7387 CX = 0x4f09; // 80 tracks, 9 sectors
7388 SET_DH(1); // max head #
7391 case 4: // 1.44MB, 3.5"
7392 CX = 0x4f12; // 80 tracks, 18 sectors
7393 SET_DH(1); // max head #
7396 case 5: // 2.88MB, 3.5"
7397 CX = 0x4f24; // 80 tracks, 36 sectors
7398 SET_DH(1); // max head #
7401 case 6: // 160k, 5.25"
7402 CX = 0x2708; // 40 tracks, 8 sectors
7403 SET_DH(0); // max head #
7406 case 7: // 180k, 5.25"
7407 CX = 0x2709; // 40 tracks, 9 sectors
7408 SET_DH(0); // max head #
7411 case 8: // 320k, 5.25"
7412 CX = 0x2708; // 40 tracks, 8 sectors
7413 SET_DH(1); // max head #
7417 BX_PANIC("floppy: int13: bad floppy type\n");
7420 /* set es & di to point to 11 byte diskette param table in ROM */
7424 mov ax, #diskette_param_table2
7425 mov _int13_diskette_function.DI+2[bp], ax
7426 mov _int13_diskette_function.ES+2[bp], cs
7429 CLEAR_CF(); // success
7430 /* disk status not changed upon success */
7434 case 0x15: // read diskette drive type
7435 BX_DEBUG_INT13_FL("floppy f15\n");
7438 SET_AH(0); // only 2 drives supported
7439 // set_diskette_ret_status here ???
7443 drive_type = inb_cmos(0x10);
7449 CLEAR_CF(); // successful, not present
7450 if (drive_type==0) {
7451 SET_AH(0); // drive not present
7454 SET_AH(1); // drive present, does not support change line
7459 case 0x16: // get diskette change line status
7460 BX_DEBUG_INT13_FL("floppy f16\n");
7463 SET_AH(0x01); // invalid drive
7464 set_diskette_ret_status(0x01);
7469 SET_AH(0x06); // change line not supported
7470 set_diskette_ret_status(0x06);
7474 case 0x17: // set diskette type for format(old)
7475 BX_DEBUG_INT13_FL("floppy f17\n");
7476 /* not used for 1.44M floppies */
7477 SET_AH(0x01); // not supported
7478 set_diskette_ret_status(1); /* not supported */
7482 case 0x18: // set diskette type for format(new)
7483 BX_DEBUG_INT13_FL("floppy f18\n");
7484 SET_AH(0x01); // do later
7485 set_diskette_ret_status(1);
7490 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7492 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7493 SET_AH(0x01); // ???
7494 set_diskette_ret_status(1);
7500 #else // #if BX_SUPPORT_FLOPPY
7502 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7503 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7507 switch ( GET_AH() ) {
7509 case 0x01: // Read Diskette Status
7511 val8 = read_byte(0x0000, 0x0441);
7520 write_byte(0x0000, 0x0441, 0x01);
7524 #endif // #if BX_SUPPORT_FLOPPY
7527 set_diskette_ret_status(value)
7530 write_byte(0x0040, 0x0041, value);
7534 set_diskette_current_cyl(drive, cyl)
7539 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7540 write_byte(0x0040, 0x0094+drive, cyl);
7544 determine_floppy_media(drive)
7548 Bit8u val8, DOR, ctrl_info;
7550 ctrl_info = read_byte(0x0040, 0x008F);
7558 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7561 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7565 if ( (ctrl_info & 0x04) != 0x04 ) {
7566 // Drive not determined means no drive exists, done.
7571 // check Main Status Register for readiness
7572 val8 = inb(0x03f4) & 0x80; // Main Status Register
7574 BX_PANIC("d_f_m: MRQ bit not set\n");
7578 // existing BDA values
7580 // turn on drive motor
7581 outb(0x03f2, DOR); // Digital Output Register
7584 BX_PANIC("d_f_m: OK so far\n");
7589 int17_function(regs, ds, iret_addr)
7590 pusha_regs_t regs; // regs pushed from PUSHA instruction
7591 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7592 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7594 Bit16u addr,timeout;
7601 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7602 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7603 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7604 if (regs.u.r8.ah == 0) {
7605 outb(addr, regs.u.r8.al);
7607 outb(addr+2, val8 | 0x01); // send strobe
7611 outb(addr+2, val8 & ~0x01);
7612 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7616 if (regs.u.r8.ah == 1) {
7618 outb(addr+2, val8 & ~0x04); // send init
7622 outb(addr+2, val8 | 0x04);
7625 regs.u.r8.ah = (val8 ^ 0x48);
7626 if (!timeout) regs.u.r8.ah |= 0x01;
7627 ClearCF(iret_addr.flags);
7629 SetCF(iret_addr.flags); // Unsupported
7633 // returns bootsegment in ax, drive in bl
7635 int19_function(bseqnr)
7638 Bit16u ebda_seg=read_word(0x0040,0x000E);
7647 // BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7649 // if BX_ELTORITO_BOOT is not defined, old behavior
7650 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7651 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7652 // 0: system boot sequence, first drive C: then A:
7653 // 1: system boot sequence, first drive A: then C:
7654 // else BX_ELTORITO_BOOT is defined
7655 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7656 // CMOS reg 0x3D & 0x0f : 1st boot device
7657 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7658 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7659 // boot device codes:
7660 // 0x00 : not defined
7661 // 0x01 : first floppy
7662 // 0x02 : first harddrive
7663 // 0x03 : first cdrom
7664 // else : boot failure
7666 // Get the boot sequence
7667 #if BX_ELTORITO_BOOT
7668 bootseq=inb_cmos(0x3d);
7669 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7671 if (bseqnr==2) bootseq >>= 4;
7672 if (bseqnr==3) bootseq >>= 8;
7673 if (bootseq<0x10) lastdrive = 1;
7674 bootdrv=0x00; bootcd=0;
7675 switch(bootseq & 0x0f) {
7676 case 0x01: bootdrv=0x00; bootcd=0; break;
7677 case 0x02: bootdrv=0x80; bootcd=0; break;
7678 case 0x03: bootdrv=0x00; bootcd=1; break;
7679 default: return 0x00000000;
7682 bootseq=inb_cmos(0x2d);
7688 bootdrv=0x00; bootcd=0;
7689 if((bootseq&0x20)==0) bootdrv=0x80;
7690 #endif // BX_ELTORITO_BOOT
7692 #if BX_ELTORITO_BOOT
7693 // We have to boot from cd
7695 status = cdrom_boot();
7697 BX_DEBUG("CDBoot:%x\n",status);
7701 if ( (status & 0x00ff) !=0 ) {
7702 print_cdromboot_failure(status);
7703 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7707 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7708 bootdrv = (Bit8u)(status>>8);
7711 #endif // BX_ELTORITO_BOOT
7713 // We have to boot from harddisk or floppy
7724 mov _int19_function.status + 2[bp], ax
7725 mov dl, _int19_function.bootdrv + 2[bp]
7726 mov ax, _int19_function.bootseg + 2[bp]
7727 mov es, ax ;; segment
7728 mov bx, #0x0000 ;; offset
7729 mov ah, #0x02 ;; function 2, read diskette sector
7730 mov al, #0x01 ;; read 1 sector
7731 mov ch, #0x00 ;; track 0
7732 mov cl, #0x01 ;; sector 1
7733 mov dh, #0x00 ;; head 0
7734 int #0x13 ;; read sector
7737 mov _int19_function.status + 2[bp], ax
7745 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7750 // check signature if instructed by cmos reg 0x38, only for floppy
7751 // bootchk = 1 : signature check disabled
7752 // bootchk = 0 : signature check enabled
7753 if (bootdrv != 0) bootchk = 0;
7754 else bootchk = inb_cmos(0x38) & 0x01;
7756 #if BX_ELTORITO_BOOT
7757 // if boot from cd, no signature check
7760 #endif // BX_ELTORITO_BOOT
7763 if (read_word(bootseg,0x1fe) != 0xaa55) {
7764 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7769 #if BX_ELTORITO_BOOT
7770 // Print out the boot string
7771 BX_DEBUG("cdrom_boot: %x\n",status);
7772 print_boot_device(bootcd, bootdrv);
7773 #else // BX_ELTORITO_BOOT
7774 print_boot_device(0, bootdrv);
7775 #endif // BX_ELTORITO_BOOT
7777 // return the boot segment
7778 return (((Bit32u)bootdrv) << 16) + bootseg;
7782 int1a_function(regs, ds, iret_addr)
7783 pusha_regs_t regs; // regs pushed from PUSHA instruction
7784 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7785 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7789 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);
7795 switch (regs.u.r8.ah) {
7796 case 0: // get current clock count
7800 regs.u.r16.cx = BiosData->ticks_high;
7801 regs.u.r16.dx = BiosData->ticks_low;
7802 regs.u.r8.al = BiosData->midnight_flag;
7803 BiosData->midnight_flag = 0; // reset flag
7808 ClearCF(iret_addr.flags); // OK
7811 case 1: // Set Current Clock Count
7815 BiosData->ticks_high = regs.u.r16.cx;
7816 BiosData->ticks_low = regs.u.r16.dx;
7817 BiosData->midnight_flag = 0; // reset flag
7822 ClearCF(iret_addr.flags); // OK
7826 case 2: // Read CMOS Time
7827 if (rtc_updating()) {
7828 SetCF(iret_addr.flags);
7832 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7833 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7834 regs.u.r8.ch = inb_cmos(0x04); // Hours
7835 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7837 regs.u.r8.al = regs.u.r8.ch;
7838 ClearCF(iret_addr.flags); // OK
7841 case 3: // Set CMOS Time
7842 // Using a debugger, I notice the following masking/setting
7843 // of bits in Status Register B, by setting Reg B to
7844 // a few values and getting its value after INT 1A was called.
7846 // try#1 try#2 try#3
7847 // before 1111 1101 0111 1101 0000 0000
7848 // after 0110 0010 0110 0010 0000 0010
7850 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7851 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7852 if (rtc_updating()) {
7854 // fall through as if an update were not in progress
7856 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7857 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7858 outb_cmos(0x04, regs.u.r8.ch); // Hours
7859 // Set Daylight Savings time enabled bit to requested value
7860 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7861 // (reg B already selected)
7862 outb_cmos(0x0b, val8);
7864 regs.u.r8.al = val8; // val last written to Reg B
7865 ClearCF(iret_addr.flags); // OK
7868 case 4: // Read CMOS Date
7870 if (rtc_updating()) {
7871 SetCF(iret_addr.flags);
7874 regs.u.r8.cl = inb_cmos(0x09); // Year
7875 regs.u.r8.dh = inb_cmos(0x08); // Month
7876 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7877 regs.u.r8.ch = inb_cmos(0x32); // Century
7878 regs.u.r8.al = regs.u.r8.ch;
7879 ClearCF(iret_addr.flags); // OK
7882 case 5: // Set CMOS Date
7883 // Using a debugger, I notice the following masking/setting
7884 // of bits in Status Register B, by setting Reg B to
7885 // a few values and getting its value after INT 1A was called.
7887 // try#1 try#2 try#3 try#4
7888 // before 1111 1101 0111 1101 0000 0010 0000 0000
7889 // after 0110 1101 0111 1101 0000 0010 0000 0000
7891 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7892 // My assumption: RegB = (RegB & 01111111b)
7893 if (rtc_updating()) {
7895 SetCF(iret_addr.flags);
7898 outb_cmos(0x09, regs.u.r8.cl); // Year
7899 outb_cmos(0x08, regs.u.r8.dh); // Month
7900 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7901 outb_cmos(0x32, regs.u.r8.ch); // Century
7902 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7903 outb_cmos(0x0b, val8);
7905 regs.u.r8.al = val8; // AL = val last written to Reg B
7906 ClearCF(iret_addr.flags); // OK
7909 case 6: // Set Alarm Time in CMOS
7910 // Using a debugger, I notice the following masking/setting
7911 // of bits in Status Register B, by setting Reg B to
7912 // a few values and getting its value after INT 1A was called.
7914 // try#1 try#2 try#3
7915 // before 1101 1111 0101 1111 0000 0000
7916 // after 0110 1111 0111 1111 0010 0000
7918 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7919 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7920 val8 = inb_cmos(0x0b); // Get Status Reg B
7923 // Alarm interrupt enabled already
7924 SetCF(iret_addr.flags); // Error: alarm in use
7927 if (rtc_updating()) {
7929 // fall through as if an update were not in progress
7931 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7932 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7933 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7934 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7935 // enable Status Reg B alarm bit, clear halt clock bit
7936 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7937 ClearCF(iret_addr.flags); // OK
7940 case 7: // Turn off Alarm
7941 // Using a debugger, I notice the following masking/setting
7942 // of bits in Status Register B, by setting Reg B to
7943 // a few values and getting its value after INT 1A was called.
7945 // try#1 try#2 try#3 try#4
7946 // before 1111 1101 0111 1101 0010 0000 0010 0010
7947 // after 0100 0101 0101 0101 0000 0000 0000 0010
7949 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7950 // My assumption: RegB = (RegB & 01010111b)
7951 val8 = inb_cmos(0x0b); // Get Status Reg B
7952 // clear clock-halt bit, disable alarm bit
7953 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7955 regs.u.r8.al = val8; // val last written to Reg B
7956 ClearCF(iret_addr.flags); // OK
7960 // real mode PCI BIOS functions now handled in assembler code
7961 // this C code handles the error code for information only
7962 if (regs.u.r8.bl == 0xff) {
7963 BX_INFO("PCI BIOS: PCI not present\n");
7964 } else if (regs.u.r8.bl == 0x81) {
7965 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7966 } else if (regs.u.r8.bl == 0x83) {
7967 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7968 } else if (regs.u.r8.bl == 0x86) {
7969 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7971 regs.u.r8.ah = regs.u.r8.bl;
7972 SetCF(iret_addr.flags);
7977 SetCF(iret_addr.flags); // Unsupported
7982 int70_function(regs, ds, iret_addr)
7983 pusha_regs_t regs; // regs pushed from PUSHA instruction
7984 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7985 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7987 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7988 Bit8u registerB = 0, registerC = 0;
7990 // Check which modes are enabled and have occurred.
7991 registerB = inb_cmos( 0xB );
7992 registerC = inb_cmos( 0xC );
7994 if( ( registerB & 0x60 ) != 0 ) {
7995 if( ( registerC & 0x20 ) != 0 ) {
7996 // Handle Alarm Interrupt.
8003 if( ( registerC & 0x40 ) != 0 ) {
8004 // Handle Periodic Interrupt.
8006 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8007 // Wait Interval (Int 15, AH=83) active.
8008 Bit32u time, toggle;
8010 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8011 if( time < 0x3D1 ) {
8013 Bit16u segment, offset;
8015 offset = read_word( 0x40, 0x98 );
8016 segment = read_word( 0x40, 0x9A );
8017 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8018 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8019 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8021 // Continue waiting.
8023 write_dword( 0x40, 0x9C, time );
8036 ;------------------------------------------
8037 ;- INT74h : PS/2 mouse hardware interrupt -
8038 ;------------------------------------------
8043 push #0x00 ;; placeholder for status
8044 push #0x00 ;; placeholder for X
8045 push #0x00 ;; placeholder for Y
8046 push #0x00 ;; placeholder for Z
8047 push #0x00 ;; placeholder for make_far_call boolean
8048 call _int74_function
8049 pop cx ;; remove make_far_call from stack
8052 ;; make far call to EBDA:0022
8055 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8057 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8062 add sp, #8 ;; pop status, x, y, z
8064 pop ds ;; restore DS
8069 ;; This will perform an IRET, but will retain value of current CF
8070 ;; by altering flags on stack. Better than RETF #02.
8075 and BYTE [bp + 0x06], #0xfe
8081 or BYTE [bp + 0x06], #0x01
8086 ;----------------------
8087 ;- INT13h (relocated) -
8088 ;----------------------
8090 ; int13_relocated is a little bit messed up since I played with it
8091 ; I have to rewrite it:
8092 ; - call a function that detect which function to call
8093 ; - make all called C function get the same parameters list
8097 #if BX_ELTORITO_BOOT
8098 ;; check for an eltorito function
8100 jb int13_not_eltorito
8102 ja int13_not_eltorito
8111 jmp _int13_eltorito ;; ELDX not used
8119 ;; check if emulation active
8120 call _cdemu_isactive
8122 je int13_cdemu_inactive
8124 ;; check if access to the emulated drive
8125 call _cdemu_emulated_drive
8128 cmp al,dl ;; int13 on emulated drive
8143 jmp _int13_cdemu ;; ELDX not used
8146 and dl,#0xE0 ;; mask to get device class, including cdroms
8147 cmp al,dl ;; al is 0x00 or 0x80
8148 jne int13_cdemu_inactive ;; inactive for device class
8160 dec dl ;; real drive is dl - 1
8163 int13_cdemu_inactive:
8169 #endif // BX_ELTORITO_BOOT
8180 push dx ;; push eltorito value of dx instead of sp
8191 ;; now the 16-bit registers can be restored with:
8192 ;; pop ds; pop es; popa; iret
8193 ;; arguments passed to functions should be
8194 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8200 jmp _int13_diskette_function
8209 // ebx is modified: BSD 5.2.1 boot loader problem
8210 // someone should figure out which 32 bit register that actually are used
8227 call _int13_harddisk
8239 int18_handler: ;; Boot Failure routing
8240 call _int18_panic_msg
8247 int19_relocated: ;; Boot function, relocated
8249 ;; int19 was beginning to be really complex, so now it
8250 ;; just calls an C function, that does the work
8251 ;; it returns in BL the boot drive, and in AX the boot segment
8252 ;; the boot segment will be 0x0000 if something has failed
8264 call _int19_function
8267 ;; bl contains the boot drive
8268 ;; ax contains the boot segment or 0 if failure
8270 test ax, ax ;; if ax is 0 try next boot device
8276 call _int19_function
8279 test ax, ax ;; if ax is 0 try next boot device
8285 call _int19_function
8288 test ax, ax ;; if ax is 0 call int18
8292 mov dl, bl ;; set drive so guest os find it
8293 shl eax, #0x04 ;; convert seg to ip
8294 mov 2[bp], ax ;; set ip
8296 shr eax, #0x04 ;; get cs back
8297 and ax, #0xF000 ;; remove what went in ip
8298 mov 4[bp], ax ;; set cs
8300 mov es, ax ;; set es to zero fixes [ 549815 ]
8301 mov [bp], ax ;; set bp to zero
8302 mov ax, #0xaa55 ;; set ok flag
8305 iret ;; Beam me up Scotty
8310 int1c_handler: ;; User Timer Tick
8314 ;----------------------
8315 ;- POST: Floppy Drive -
8316 ;----------------------
8322 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8324 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8326 mov 0x0440, al ;; diskette motor timeout counter: not active
8327 mov 0x0441, al ;; diskette controller status return code
8329 mov 0x0442, al ;; disk & diskette controller status register 0
8330 mov 0x0443, al ;; diskette controller status register 1
8331 mov 0x0444, al ;; diskette controller status register 2
8332 mov 0x0445, al ;; diskette controller cylinder number
8333 mov 0x0446, al ;; diskette controller head number
8334 mov 0x0447, al ;; diskette controller sector number
8335 mov 0x0448, al ;; diskette controller bytes written
8337 mov 0x048b, al ;; diskette configuration data
8339 ;; -----------------------------------------------------------------
8340 ;; (048F) diskette controller information
8342 mov al, #0x10 ;; get CMOS diskette drive type
8345 mov ah, al ;; save byte to AH
8348 shr al, #4 ;; look at top 4 bits for drive 0
8349 jz f0_missing ;; jump if no drive0
8350 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8353 mov bl, #0x00 ;; no drive0
8356 mov al, ah ;; restore from AH
8357 and al, #0x0f ;; look at bottom 4 bits for drive 1
8358 jz f1_missing ;; jump if no drive1
8359 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8361 ;; leave high bits in BL zerod
8362 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8363 ;; -----------------------------------------------------------------
8366 mov 0x0490, al ;; diskette 0 media state
8367 mov 0x0491, al ;; diskette 1 media state
8369 ;; diskette 0,1 operational starting state
8370 ;; drive type has not been determined,
8371 ;; has no changed detection line
8375 mov 0x0494, al ;; diskette 0 current cylinder
8376 mov 0x0495, al ;; diskette 1 current cylinder
8379 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8381 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8382 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8383 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8388 ;--------------------
8389 ;- POST: HARD DRIVE -
8390 ;--------------------
8391 ; relocated here because the primary POST area isnt big enough.
8394 // INT 76h calls INT 15h function ax=9100
8396 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8402 mov 0x0474, al /* hard disk status of last operation */
8403 mov 0x0477, al /* hard disk port offset (XT only ???) */
8404 mov 0x048c, al /* hard disk status register */
8405 mov 0x048d, al /* hard disk error register */
8406 mov 0x048e, al /* hard disk task complete flag */
8408 mov 0x0475, al /* hard disk number attached */
8410 mov 0x0476, al /* hard disk control byte */
8411 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8412 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8413 ;; INT 41h: hard disk 0 configuration pointer
8414 ;; INT 46h: hard disk 1 configuration pointer
8415 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8416 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8418 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8430 cmp al, #47 ;; decimal 47 - user definable
8434 ;; CMOS purpose param table offset
8435 ;; 1b cylinders low 0
8436 ;; 1c cylinders high 1
8438 ;; 1e write pre-comp low 5
8439 ;; 1f write pre-comp high 6
8440 ;; 20 retries/bad map/heads>8 8
8441 ;; 21 landing zone low C
8442 ;; 22 landing zone high D
8443 ;; 23 sectors/track E
8448 ;;; Filling EBDA table for hard disk 0.
8456 mov (0x003d + 0x05), ax ;; write precomp word
8461 mov (0x003d + 0x08), al ;; drive control byte
8470 mov (0x003d + 0x0C), ax ;; landing zone word
8472 mov al, #0x1c ;; get cylinders word in AX
8474 in al, #0x71 ;; high byte
8478 in al, #0x71 ;; low byte
8479 mov bx, ax ;; BX = cylinders
8484 mov cl, al ;; CL = heads
8489 mov dl, al ;; DL = sectors
8492 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8494 hd0_post_physical_chs:
8495 ;; no logical CHS mapping used, just physical CHS
8496 ;; use Standard Fixed Disk Parameter Table (FDPT)
8497 mov (0x003d + 0x00), bx ;; number of physical cylinders
8498 mov (0x003d + 0x02), cl ;; number of physical heads
8499 mov (0x003d + 0x0E), dl ;; number of physical sectors
8502 hd0_post_logical_chs:
8503 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8504 mov (0x003d + 0x09), bx ;; number of physical cylinders
8505 mov (0x003d + 0x0b), cl ;; number of physical heads
8506 mov (0x003d + 0x04), dl ;; number of physical sectors
8507 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8509 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8512 jnbe hd0_post_above_2048
8513 ;; 1024 < c <= 2048 cylinders
8516 jmp hd0_post_store_logical
8518 hd0_post_above_2048:
8520 jnbe hd0_post_above_4096
8521 ;; 2048 < c <= 4096 cylinders
8524 jmp hd0_post_store_logical
8526 hd0_post_above_4096:
8528 jnbe hd0_post_above_8192
8529 ;; 4096 < c <= 8192 cylinders
8532 jmp hd0_post_store_logical
8534 hd0_post_above_8192:
8535 ;; 8192 < c <= 16384 cylinders
8539 hd0_post_store_logical:
8540 mov (0x003d + 0x00), bx ;; number of physical cylinders
8541 mov (0x003d + 0x02), cl ;; number of physical heads
8543 mov cl, #0x0f ;; repeat count
8544 mov si, #0x003d ;; offset to disk0 FDPT
8545 mov al, #0x00 ;; sum
8546 hd0_post_checksum_loop:
8550 jnz hd0_post_checksum_loop
8551 not al ;; now take 2s complement
8554 ;;; Done filling EBDA table for hard disk 0.
8558 ;; is there really a second hard disk? if not, return now
8566 ;; check that the hd type is really 0x0f.
8571 ;; check that the extended type is 47 - user definable
8575 cmp al, #47 ;; decimal 47 - user definable
8580 ;; CMOS purpose param table offset
8581 ;; 0x24 cylinders low 0
8582 ;; 0x25 cylinders high 1
8584 ;; 0x27 write pre-comp low 5
8585 ;; 0x28 write pre-comp high 6
8587 ;; 0x2a landing zone low C
8588 ;; 0x2b landing zone high D
8589 ;; 0x2c sectors/track E
8590 ;;; Fill EBDA table for hard disk 1.
8600 mov (0x004d + 0x05), ax ;; write precomp word
8605 mov (0x004d + 0x08), al ;; drive control byte
8614 mov (0x004d + 0x0C), ax ;; landing zone word
8616 mov al, #0x25 ;; get cylinders word in AX
8618 in al, #0x71 ;; high byte
8622 in al, #0x71 ;; low byte
8623 mov bx, ax ;; BX = cylinders
8628 mov cl, al ;; CL = heads
8633 mov dl, al ;; DL = sectors
8636 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8638 hd1_post_physical_chs:
8639 ;; no logical CHS mapping used, just physical CHS
8640 ;; use Standard Fixed Disk Parameter Table (FDPT)
8641 mov (0x004d + 0x00), bx ;; number of physical cylinders
8642 mov (0x004d + 0x02), cl ;; number of physical heads
8643 mov (0x004d + 0x0E), dl ;; number of physical sectors
8646 hd1_post_logical_chs:
8647 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8648 mov (0x004d + 0x09), bx ;; number of physical cylinders
8649 mov (0x004d + 0x0b), cl ;; number of physical heads
8650 mov (0x004d + 0x04), dl ;; number of physical sectors
8651 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8653 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8656 jnbe hd1_post_above_2048
8657 ;; 1024 < c <= 2048 cylinders
8660 jmp hd1_post_store_logical
8662 hd1_post_above_2048:
8664 jnbe hd1_post_above_4096
8665 ;; 2048 < c <= 4096 cylinders
8668 jmp hd1_post_store_logical
8670 hd1_post_above_4096:
8672 jnbe hd1_post_above_8192
8673 ;; 4096 < c <= 8192 cylinders
8676 jmp hd1_post_store_logical
8678 hd1_post_above_8192:
8679 ;; 8192 < c <= 16384 cylinders
8683 hd1_post_store_logical:
8684 mov (0x004d + 0x00), bx ;; number of physical cylinders
8685 mov (0x004d + 0x02), cl ;; number of physical heads
8687 mov cl, #0x0f ;; repeat count
8688 mov si, #0x004d ;; offset to disk0 FDPT
8689 mov al, #0x00 ;; sum
8690 hd1_post_checksum_loop:
8694 jnz hd1_post_checksum_loop
8695 not al ;; now take 2s complement
8698 ;;; Done filling EBDA table for hard disk 1.
8702 ;--------------------
8703 ;- POST: EBDA segment
8704 ;--------------------
8705 ; relocated here because the primary POST area isnt big enough.
8710 mov byte ptr [0x0], #EBDA_SIZE
8712 xor ax, ax ; mov EBDA seg into 40E
8714 mov word ptr [0x40E], #EBDA_SEG
8717 ;--------------------
8718 ;- POST: EOI + jmp via [0x40:67)
8719 ;--------------------
8720 ; relocated here because the primary POST area isnt big enough.
8730 ;--------------------
8733 out #0xA0, al ;; slave PIC EOI
8736 out #0x20, al ;; master PIC EOI
8739 ;--------------------
8741 ;; in: AL in BCD format
8742 ;; out: AL in binary format, AH will always be 0
8745 and bl, #0x0f ;; bl has low digit
8746 shr al, #4 ;; al has high digit
8748 mul al, bh ;; multiply high digit by 10 (result in AX)
8749 add al, bl ;; then add low digit
8752 ;--------------------
8754 ;; Setup the Timer Ticks Count (0x46C:dword) and
8755 ;; Timer Ticks Roller Flag (0x470:byte)
8756 ;; The Timer Ticks Count needs to be set according to
8757 ;; the current CMOS time, as if ticks have been occurring
8758 ;; at 18.2hz since midnight up to this point. Calculating
8759 ;; this is a little complicated. Here are the factors I gather
8760 ;; regarding this. 14,318,180 hz was the original clock speed,
8761 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8762 ;; at the time, or 4 to drive the CGA video adapter. The div3
8763 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8764 ;; the timer. With a maximum 16bit timer count, this is again
8765 ;; divided down by 65536 to 18.2hz.
8767 ;; 14,318,180 Hz clock
8768 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8769 ;; /4 = 1,193,181 Hz fed to timer
8770 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8771 ;; 1 second = 18.20650736 ticks
8772 ;; 1 minute = 1092.390442 ticks
8773 ;; 1 hour = 65543.42651 ticks
8775 ;; Given the values in the CMOS clock, one could calculate
8776 ;; the number of ticks by the following:
8777 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8778 ;; (BcdToBin(minutes) * 1092.3904)
8779 ;; (BcdToBin(hours) * 65543.427)
8780 ;; To get a little more accuracy, since Im using integer
8781 ;; arithmatic, I use:
8782 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8783 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8784 ;; (BcdToBin(hours) * 65543427) / 1000
8789 xor eax, eax ;; clear EAX
8792 in al, #0x71 ;; AL has CMOS seconds in BCD
8793 call BcdToBin ;; EAX now has seconds in binary
8799 mov ecx, eax ;; ECX will accumulate total ticks
8802 xor eax, eax ;; clear EAX
8805 in al, #0x71 ;; AL has CMOS minutes in BCD
8806 call BcdToBin ;; EAX now has minutes in binary
8812 add ecx, eax ;; add to total ticks
8815 xor eax, eax ;; clear EAX
8818 in al, #0x71 ;; AL has CMOS hours in BCD
8819 call BcdToBin ;; EAX now has hours in binary
8825 add ecx, eax ;; add to total ticks
8827 mov 0x46C, ecx ;; Timer Ticks Count
8829 mov 0x470, al ;; Timer Ticks Rollover Flag
8832 ;--------------------
8834 ;; record completion in BIOS task complete flag
8846 ;--------------------
8851 #include "apmbios.S"
8855 #include "apmbios.S"
8858 #include "apmbios.S"
8862 ;--------------------
8867 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8868 dw bios32_entry_point, 0xf ;; 32 bit physical address
8869 db 0 ;; revision level
8870 ;; length in paragraphs and checksum stored in a word to prevent errors
8871 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8872 & 0xff) << 8) + 0x01
8873 db 0,0,0,0,0 ;; reserved
8878 cmp eax, #0x49435024
8880 mov eax, #0x80000000
8885 cmp eax, #0x12378086
8887 mov ebx, #0x000f0000
8889 mov edx, #pcibios_protected
8904 cmp al, #0x01 ;; installation check
8908 mov edx, #0x20494350
8911 pci_pro_f02: ;; find pci device
8919 call pci_pro_select_reg
8933 pci_pro_f08: ;; read configuration byte
8936 call pci_pro_select_reg
8945 pci_pro_f09: ;; read configuration word
8948 call pci_pro_select_reg
8957 pci_pro_f0a: ;; read configuration dword
8960 call pci_pro_select_reg
8967 pci_pro_f0b: ;; write configuration byte
8970 call pci_pro_select_reg
8979 pci_pro_f0c: ;; write configuration word
8982 call pci_pro_select_reg
8991 pci_pro_f0d: ;; write configuration dword
8994 call pci_pro_select_reg
9037 mov eax, #0x80000000
9042 cmp eax, #0x12378086
9052 cmp al, #0x01 ;; installation check
9057 mov edx, #0x20494350
9059 mov di, #pcibios_protected
9062 pci_real_f02: ;; find pci device
9072 call pci_real_select_reg
9076 jne pci_real_nextdev
9083 jne pci_real_devloop
9088 pci_real_f08: ;; read configuration byte
9091 call pci_real_select_reg
9100 pci_real_f09: ;; read configuration word
9103 call pci_real_select_reg
9112 pci_real_f0a: ;; read configuration dword
9115 call pci_real_select_reg
9122 pci_real_f0b: ;; write configuration byte
9125 call pci_real_select_reg
9134 pci_real_f0c: ;; write configuration word
9137 call pci_real_select_reg
9146 pci_real_f0d: ;; write configuration dword
9148 jne pci_real_unknown
9149 call pci_real_select_reg
9170 pci_real_select_reg:
9184 pci_routing_table_structure:
9185 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9187 dw 32 + (6 * 16) ;; table size
9188 db 0 ;; PCI interrupt router bus
9189 db 0x08 ;; PCI interrupt router DevFunc
9190 dw 0x0000 ;; PCI exclusive IRQs
9191 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9192 dw 0x7000 ;; compatible PCI interrupt router device ID
9193 dw 0,0 ;; Miniport data
9194 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9196 ;; first slot entry PCI-to-ISA (embedded)
9197 db 0 ;; pci bus number
9198 db 0x08 ;; pci device number (bit 7-3)
9199 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9200 dw 0xdef8 ;; IRQ bitmap INTA#
9201 db 0x61 ;; link value INTB#
9202 dw 0xdef8 ;; IRQ bitmap INTB#
9203 db 0x62 ;; link value INTC#
9204 dw 0xdef8 ;; IRQ bitmap INTC#
9205 db 0x63 ;; link value INTD#
9206 dw 0xdef8 ;; IRQ bitmap INTD#
9207 db 0 ;; physical slot (0 = embedded)
9209 ;; second slot entry: 1st PCI slot
9210 db 0 ;; pci bus number
9211 db 0x10 ;; pci device number (bit 7-3)
9212 db 0x61 ;; link value INTA#
9213 dw 0xdef8 ;; IRQ bitmap INTA#
9214 db 0x62 ;; link value INTB#
9215 dw 0xdef8 ;; IRQ bitmap INTB#
9216 db 0x63 ;; link value INTC#
9217 dw 0xdef8 ;; IRQ bitmap INTC#
9218 db 0x60 ;; link value INTD#
9219 dw 0xdef8 ;; IRQ bitmap INTD#
9220 db 1 ;; physical slot (0 = embedded)
9222 ;; third slot entry: 2nd PCI slot
9223 db 0 ;; pci bus number
9224 db 0x18 ;; pci device number (bit 7-3)
9225 db 0x62 ;; link value INTA#
9226 dw 0xdef8 ;; IRQ bitmap INTA#
9227 db 0x63 ;; link value INTB#
9228 dw 0xdef8 ;; IRQ bitmap INTB#
9229 db 0x60 ;; link value INTC#
9230 dw 0xdef8 ;; IRQ bitmap INTC#
9231 db 0x61 ;; link value INTD#
9232 dw 0xdef8 ;; IRQ bitmap INTD#
9233 db 2 ;; physical slot (0 = embedded)
9235 ;; 4th slot entry: 3rd PCI slot
9236 db 0 ;; pci bus number
9237 db 0x20 ;; pci device number (bit 7-3)
9238 db 0x63 ;; link value INTA#
9239 dw 0xdef8 ;; IRQ bitmap INTA#
9240 db 0x60 ;; link value INTB#
9241 dw 0xdef8 ;; IRQ bitmap INTB#
9242 db 0x61 ;; link value INTC#
9243 dw 0xdef8 ;; IRQ bitmap INTC#
9244 db 0x62 ;; link value INTD#
9245 dw 0xdef8 ;; IRQ bitmap INTD#
9246 db 3 ;; physical slot (0 = embedded)
9248 ;; 5th slot entry: 4rd PCI slot
9249 db 0 ;; pci bus number
9250 db 0x28 ;; pci device number (bit 7-3)
9251 db 0x60 ;; link value INTA#
9252 dw 0xdef8 ;; IRQ bitmap INTA#
9253 db 0x61 ;; link value INTB#
9254 dw 0xdef8 ;; IRQ bitmap INTB#
9255 db 0x62 ;; link value INTC#
9256 dw 0xdef8 ;; IRQ bitmap INTC#
9257 db 0x63 ;; link value INTD#
9258 dw 0xdef8 ;; IRQ bitmap INTD#
9259 db 4 ;; physical slot (0 = embedded)
9261 ;; 6th slot entry: 5rd PCI slot
9262 db 0 ;; pci bus number
9263 db 0x30 ;; pci device number (bit 7-3)
9264 db 0x61 ;; link value INTA#
9265 dw 0xdef8 ;; IRQ bitmap INTA#
9266 db 0x62 ;; link value INTB#
9267 dw 0xdef8 ;; IRQ bitmap INTB#
9268 db 0x63 ;; link value INTC#
9269 dw 0xdef8 ;; IRQ bitmap INTC#
9270 db 0x60 ;; link value INTD#
9271 dw 0xdef8 ;; IRQ bitmap INTD#
9272 db 5 ;; physical slot (0 = embedded)
9278 pcibios_init_sel_reg:
9290 pcibios_init_set_elcr:
9314 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9319 mov si, #pci_routing_table_structure
9323 call pcibios_init_sel_reg
9326 cmp eax, [si+12] ;; check irq router
9329 call pcibios_init_sel_reg
9330 push bx ;; save irq router bus + devfunc
9333 out dx, ax ;; reset PIRQ route control
9341 add si, #0x20 ;; set pointer to 1st entry
9343 mov ax, #pci_irq_list
9352 call pcibios_init_sel_reg
9356 jnz pci_test_int_pin
9362 call pcibios_init_sel_reg
9367 dec al ;; determine pirq reg
9376 call pcibios_init_sel_reg
9383 mov bx, [bp-2] ;; pci irq list pointer
9388 call pcibios_init_set_elcr
9392 add bl, [bp-3] ;; pci function number
9394 call pcibios_init_sel_reg
9404 mov byte ptr[bp-3], #0x00
9412 #endif // BX_PCIBIOS
9414 ; parallel port detection: base address in DX, index in BX, timeout in CL
9419 and al, #0xdf ; clear input mode
9429 mov [bx+0x408], dx ; Parallel I/O address
9431 mov [bx+0x478], cl ; Parallel printer timeout
9436 ; serial port detection: base address in DX, index in BX, timeout in CL
9438 ; no serial port in the VM -PAD
9458 mov [bx+0x400], dx ; Serial I/O address
9460 mov [bx+0x47c], cl ; Serial timeout
9487 ;; Scan for existence of valid expansion ROMS.
9488 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9489 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9490 ;; System ROM: only 0xE0000
9496 ;; 2 ROM length in 512-byte blocks
9497 ;; 3 ROM initialization entry point (FAR CALL)
9502 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9503 cmp [0], #0xAA55 ;; look for signature
9504 jne rom_scan_increment
9506 jnz rom_scan_increment
9507 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9509 ;; We want our increment in 512-byte quantities, rounded to
9510 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9512 jz block_count_rounded
9513 and al, #0xfc ;; needs rounding up
9515 block_count_rounded:
9517 xor bx, bx ;; Restore DS back to 0000:
9520 ;; Push addr of ROM entry point
9522 push #0x0003 ;; Push offset
9523 mov bp, sp ;; Call ROM init routine using seg:off on stack
9524 db 0xff ;; call_far ss:[bp+0]
9527 cli ;; In case expansion ROM BIOS turns IF on
9528 add sp, #2 ;; Pop offset value
9529 pop cx ;; Pop seg value (restore CX)
9530 pop ax ;; Restore AX
9532 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9533 ;; because the segment selector is shifted left 4 bits.
9538 xor ax, ax ;; Restore DS back to 0000:
9544 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9545 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9546 ; but the tables themeselves can be elsewhere.
9555 mov cx, #0x001f ; 0x1f bytes to copy
9557 mov es, ax ; destination segment is 0xf0000
9558 mov di, #smbios_entry_point ; destination offset
9560 mov ds, ax ; source segment is 0x9f000
9561 mov si, #0x0000 ; source offset is 0
9579 ;; for 'C' strings and other data, insert them here with
9580 ;; a the following hack:
9581 ;; DATA_SEG_DEFS_HERE
9587 .org 0xe05b ; POST Entry Point
9592 ;; first reset the DMA controllers
9596 ;; then initialize the DMA controllers
9598 out 0xD6, al ; cascade mode of channel 4 enabled
9600 out 0xD4, al ; unmask channel 4
9602 ;; Examine CMOS shutdown status.
9610 ;; Reset CMOS shutdown status.
9612 out 0x70, AL ; select CMOS register Fh
9614 out 0x71, AL ; set shutdown action to normal
9616 ;; Examine CMOS shutdown status.
9619 ;; 0x00, 0x09, 0x0D+ = normal startup
9627 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9631 ;; Examine CMOS shutdown status.
9632 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9634 call _shutdown_status_panic
9640 ; 0xb0, 0x20, /* mov al, #0x20 */
9641 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9651 ; case 0: normal startup
9660 ;; zero out BIOS data area (40:00..40:ff)
9662 mov cx, #0x0080 ;; 128 words
9668 call _log_bios_start
9670 ;; set all interrupts to default handler
9671 mov bx, #0x0000 ;; offset index
9672 mov cx, #0x0100 ;; counter (256 interrupts)
9673 mov ax, #dummy_iret_handler
9683 loop post_default_ints
9685 ;; set vector 0x79 to zero
9686 ;; this is used by 'gardian angel' protection system
9687 SET_INT_VECTOR(0x79, #0, #0)
9689 ;; base memory in K 40:13 (word)
9690 mov ax, #BASE_MEM_IN_K
9694 ;; Manufacturing Test 40:12
9697 ;; Warm Boot Flag 0040:0072
9698 ;; value of 1234h = skip memory checks
9702 ;; Printer Services vector
9703 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9705 ;; Bootstrap failure vector
9706 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9708 ;; Bootstrap Loader vector
9709 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9711 ;; User Timer Tick vector
9712 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9714 ;; Memory Size Check vector
9715 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9717 ;; Equipment Configuration Check vector
9718 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9721 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9727 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9728 ;; int 1C already points at dummy_iret_handler (above)
9729 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9732 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9737 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9743 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9744 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9748 mov 0x0417, al /* keyboard shift flags, set 1 */
9749 mov 0x0418, al /* keyboard shift flags, set 2 */
9750 mov 0x0419, al /* keyboard alt-numpad work area */
9751 mov 0x0471, al /* keyboard ctrl-break flag */
9752 mov 0x0497, al /* keyboard status flags 4 */
9754 mov 0x0496, al /* keyboard status flags 3 */
9757 /* keyboard head of buffer pointer */
9761 /* keyboard end of buffer pointer */
9764 /* keyboard pointer to start of buffer */
9768 /* keyboard pointer to end of buffer */
9772 /* init the keyboard */
9775 ;; mov CMOS Equipment Byte to BDA Equipment Word
9784 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9788 mov cl, #0x14 ; timeout value
9789 mov dx, #0x378 ; Parallel I/O address, port 1
9791 mov dx, #0x278 ; Parallel I/O address, port 2
9794 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9796 or ax, bx ; set number of parallel ports
9800 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9801 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9803 mov cl, #0x0a ; timeout value
9804 mov dx, #0x03f8 ; Serial I/O address, port 1
9806 mov dx, #0x02f8 ; Serial I/O address, port 2
9808 mov dx, #0x03e8 ; Serial I/O address, port 3
9810 mov dx, #0x02e8 ; Serial I/O address, port 4
9813 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9815 or ax, bx ; set number of serial port
9819 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9820 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9821 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9822 ;; BIOS DATA AREA 0x4CE ???
9823 call timer_tick_post
9826 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9828 ;; IRQ13 (FPU exception) setup
9829 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9832 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9837 mov al, #0x11 ; send initialisation commands
9852 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9853 #if BX_USE_PS2_MOUSE
9858 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9861 call _copy_e820_table
9880 call _print_bios_banner
9885 call floppy_drive_post
9892 call hard_drive_post
9895 ;; ATA/ATAPI driver setup
9900 #else // BX_USE_ATADRV
9905 call hard_drive_post
9907 #endif // BX_USE_ATADRV
9909 #if BX_ELTORITO_BOOT
9911 ;; eltorito floppy/harddisk emulation from cd
9915 #endif // BX_ELTORITO_BOOT
9918 //JMP_EP(0x0064) ; INT 19h location
9921 .org 0xe2c3 ; NMI Handler Entry Point
9923 ;; FIXME the NMI handler should not panic
9924 ;; but iret when called from int75 (fpu exception)
9925 call _nmi_handler_msg
9929 out 0xf0, al // clear irq13
9930 call eoi_both_pics // clear interrupt
9931 int 2 // legacy nmi call
9934 ;-------------------------------------------
9935 ;- INT 13h Fixed Disk Services Entry Point -
9936 ;-------------------------------------------
9937 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9939 //JMPL(int13_relocated)
9942 .org 0xe401 ; Fixed Disk Parameter Table
9947 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9951 ;-------------------------------------------
9952 ;- System BIOS Configuration Data Table
9953 ;-------------------------------------------
9954 .org BIOS_CONFIG_TABLE
9955 db 0x08 ; Table size (bytes) -Lo
9956 db 0x00 ; Table size (bytes) -Hi
9961 ; b7: 1=DMA channel 3 used by hard disk
9962 ; b6: 1=2 interrupt controllers present
9964 ; b4: 1=BIOS calls int 15h/4Fh every key
9965 ; b3: 1=wait for extern event supported (Int 15h/41h)
9966 ; b2: 1=extended BIOS data area used
9967 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9968 ; b0: 1=Dual bus (MicroChannel + ISA)
9972 (BX_CALL_INT15_4F << 4) | \
9974 (BX_USE_EBDA << 2) | \
9978 ; b7: 1=32-bit DMA supported
9979 ; b6: 1=int16h, function 9 supported
9980 ; b5: 1=int15h/C6h (get POS data) supported
9981 ; b4: 1=int15h/C7h (get mem map info) supported
9982 ; b3: 1=int15h/C8h (en/dis CPU) supported
9983 ; b2: 1=non-8042 kb controller
9984 ; b1: 1=data streaming supported
9998 ; b4: POST supports ROM-to-RAM enable/disable
9999 ; b3: SCSI on system board
10000 ; b2: info panel installed
10001 ; b1: Initial Machine Load (IML) system - BIOS on disk
10002 ; b0: SCSI supported in IML
10006 ; b6: EEPROM present
10007 ; b5-3: ABIOS presence (011 = not supported)
10009 ; b1: memory split above 16Mb supported
10010 ; b0: POSTEXT directly supported by POST
10012 ; Feature byte 5 (IBM)
10013 ; b1: enhanced mouse
10019 .org 0xe729 ; Baud Rate Generator Table
10024 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10030 call _int14_function
10036 ;----------------------------------------
10037 ;- INT 16h Keyboard Service Entry Point -
10038 ;----------------------------------------
10054 call _int16_function
10064 and BYTE [bp + 0x06], #0xbf
10072 or BYTE [bp + 0x06], #0x40
10080 int16_wait_for_key:
10084 jne int16_key_found
10088 /* no key yet, call int 15h, function AX=9002 */
10089 0x50, /* push AX */
10090 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10091 0xcd, 0x15, /* int 15h */
10093 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10095 jmp int16_wait_for_key
10100 call _int16_function
10105 /* notify int16 complete w/ int 15h, function AX=9102 */
10106 0x50, /* push AX */
10107 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10108 0xcd, 0x15, /* int 15h */
10115 ;-------------------------------------------------
10116 ;- INT09h : Keyboard Hardware Service Entry Point -
10117 ;-------------------------------------------------
10123 mov al, #0xAD ;;disable keyboard
10132 in al, #0x60 ;;read key from keyboard controller
10133 //test al, #0x80 ;;look for key release
10134 //jnz int09_process_key ;; dont pass releases to intercept?
10136 ;; check for extended key
10138 jne int09_call_int15_4f
10143 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10145 mov BYTE [0x496], al
10148 in al, #0x60 ;;read another key from keyboard controller
10152 int09_call_int15_4f:
10155 #ifdef BX_CALL_INT15_4F
10156 mov ah, #0x4f ;; allow for keyboard intercept
10163 //int09_process_key:
10166 call _int09_function
10172 call eoi_master_pic
10175 mov al, #0xAE ;;enable keyboard
10183 ;----------------------------------------
10184 ;- INT 13h Diskette Service Entry Point -
10185 ;----------------------------------------
10188 jmp int13_noeltorito
10190 ;---------------------------------------------
10191 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10192 ;---------------------------------------------
10193 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10203 mov al, #0x08 ; sense interrupt status
10221 mov ax, #0x0000 ;; segment 0000
10223 call eoi_master_pic
10225 or al, #0x80 ;; diskette interrupt has occurred
10233 .org 0xefc7 ; Diskette Controller Parameter Table
10234 diskette_param_table:
10235 ;; Since no provisions are made for multiple drive types, most
10236 ;; values in this table are ignored. I set parameters for 1.44M
10239 db 0x02 ;; head load time 0000001, DMA used
10251 ;----------------------------------------
10252 ;- INT17h : Printer Service Entry Point -
10253 ;----------------------------------------
10260 call _int17_function
10265 diskette_param_table2:
10266 ;; New diskette parameter table adding 3 parameters from IBM
10267 ;; Since no provisions are made for multiple drive types, most
10268 ;; values in this table are ignored. I set parameters for 1.44M
10271 db 0x02 ;; head load time 0000001, DMA used
10281 db 79 ;; maximum track
10282 db 0 ;; data transfer rate
10283 db 4 ;; drive type in cmos
10285 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10292 .org 0xf065 ; INT 10h Video Support Service Entry Point
10294 ;; dont do anything, since the VGA BIOS handles int10h requests
10297 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10302 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10303 ; ??? different for Pentium (machine check)?
10315 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10327 .org 0xf859 ; INT 15h System Services Entry Point
10341 #if BX_USE_PS2_MOUSE
10343 je int15_handler_mouse
10345 call _int15_function
10346 int15_handler_mouse_ret:
10348 int15_handler32_ret:
10358 #if BX_USE_PS2_MOUSE
10359 int15_handler_mouse:
10360 call _int15_function_mouse
10361 jmp int15_handler_mouse_ret
10366 call _int15_function32
10368 jmp int15_handler32_ret
10370 ;; Protected mode IDT descriptor
10372 ;; I just make the limit 0, so the machine will shutdown
10373 ;; if an exception occurs during protected mode memory
10376 ;; Set base to f0000 to correspond to beginning of BIOS,
10377 ;; in case I actually define an IDT later
10381 dw 0x0000 ;; limit 15:00
10382 dw 0x0000 ;; base 15:00
10383 db 0x0f ;; base 23:16
10385 ;; Real mode IDT descriptor
10387 ;; Set to typical real-mode values.
10392 dw 0x03ff ;; limit 15:00
10393 dw 0x0000 ;; base 15:00
10394 db 0x00 ;; base 23:16
10400 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10413 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10414 mov ds, ax ; on 16bit protected mode.
10415 jmp int1a_callfunction
10422 int1a_callfunction:
10423 call _int1a_function
10429 ;; int70h: IRQ8 - CMOS RTC
10436 call _int70_function
10444 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10452 ;; time to turn off drive(s)?
10455 jz int08_floppy_off
10458 jnz int08_floppy_off
10459 ;; turn motor(s) off
10468 mov eax, 0x046c ;; get ticks dword
10471 ;; compare eax to one days worth of timer ticks at 18.2 hz
10472 cmp eax, #0x001800B0
10473 jb int08_store_ticks
10474 ;; there has been a midnight rollover at this point
10475 xor eax, eax ;; zero out counter
10476 inc BYTE 0x0470 ;; increment rollover flag
10479 mov 0x046c, eax ;; store new ticks dword
10480 ;; chain to user timer tick INT #0x1c
10482 //;; call_ep [ds:loc]
10483 //CALL_EP( 0x1c << 2 )
10486 call eoi_master_pic
10491 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10495 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10497 ;------------------------------------------------
10498 ;- IRET Instruction for Dummy Interrupt Handler -
10499 ;------------------------------------------------
10500 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10501 dummy_iret_handler:
10504 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10513 .org 0xfff0 ; Power-up Entry Point
10520 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10521 .ascii BIOS_BUILD_DATE
10523 .org 0xfffe ; System Model ID
10527 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10530 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10531 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10532 * This font is public domain
10534 static Bit8u vgafont8[128*8]=
10536 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10537 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10538 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10539 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10540 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10541 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10542 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10543 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10544 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10545 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10546 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10547 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10548 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10549 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10550 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10551 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10552 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10553 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10554 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10555 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10556 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10557 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10558 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10559 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10560 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10561 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10562 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10563 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10564 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10565 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10566 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10567 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10569 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10570 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10571 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10572 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10573 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10574 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10575 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10576 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10577 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10578 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10579 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10580 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10581 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10582 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10583 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10584 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10585 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10586 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10587 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10588 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10589 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10590 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10591 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10592 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10593 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10594 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10595 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10596 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10597 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10598 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10599 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10600 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10601 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10602 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10603 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10604 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10605 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10606 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10607 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10608 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10609 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10610 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10611 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10612 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10613 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10614 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10615 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10616 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10617 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10618 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10619 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10620 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10621 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10622 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10623 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10624 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10625 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10626 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10627 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10628 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10629 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10630 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10632 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10633 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10634 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10635 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10636 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10637 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10638 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10639 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10640 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10641 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10642 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10643 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10644 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10645 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10646 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10647 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10648 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10649 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10650 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10651 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10652 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10653 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10654 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10655 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10656 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10657 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10658 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10659 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10660 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10661 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10662 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10663 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10669 // just carve out some blank space for HVMLOADER to write the MP tables to
10671 // NOTE: There should be enough space for a 32 processor entry MP table
10675 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10676 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
10677 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
10678 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
10679 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
10680 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
10681 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
10682 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
10683 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
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 ;; 576 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 ;; 640 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 ;; 704 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 ;; 768 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 ;; 832 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 ;; 896 bytes
10692 smbios_entry_point:
10693 db 0,0,0,0,0,0,0,0 ; 8 bytes
10694 db 0,0,0,0,0,0,0,0 ; 16 bytes
10695 db 0,0,0,0,0,0,0,0 ; 24 bytes
10696 db 0,0,0,0,0,0,0 ; 31 bytes
10699 #else // !HVMASSIST
10703 // bcc-generated data will be placed here
10705 // For documentation of this config structure, look on developer.intel.com and
10706 // search for multiprocessor specification. Note that when you change anything
10707 // you must update the checksum (a pain!). It would be better to construct this
10708 // with C structures, or at least fill in the checksum automatically.
10710 // Maybe this structs could be moved elsewhere than d000
10712 #if (BX_SMP_PROCESSORS==1)
10713 // no structure necessary.
10714 #elif (BX_SMP_PROCESSORS==2)
10715 // define the Intel MP Configuration Structure for 2 processors at
10716 // APIC ID 0,1. I/O APIC at ID=2.
10719 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10720 dw (mp_config_end-mp_config_table) ;; table length
10722 db 0x65 ;; checksum
10723 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10724 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10725 db 0x20, 0x20, 0x20, 0x20
10726 db 0x20, 0x20, 0x20, 0x20
10727 dw 0,0 ;; oem table ptr
10728 dw 0 ;; oem table size
10729 dw 20 ;; entry count
10730 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10731 dw 0 ;; extended table length
10732 db 0 ;; extended table checksum
10735 db 0 ;; entry type=processor
10736 db 0 ;; local APIC id
10737 db 0x11 ;; local APIC version number
10738 db 3 ;; cpu flags: enabled, bootstrap processor
10739 db 0,6,0,0 ;; cpu signature
10740 dw 0x201,0 ;; feature flags
10744 db 0 ;; entry type=processor
10745 db 1 ;; local APIC id
10746 db 0x11 ;; local APIC version number
10747 db 1 ;; cpu flags: enabled
10748 db 0,6,0,0 ;; cpu signature
10749 dw 0x201,0 ;; feature flags
10753 db 1 ;; entry type=bus
10755 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10757 db 2 ;; entry type=I/O APIC
10758 db 2 ;; apic id=2. linux will set.
10759 db 0x11 ;; I/O APIC version number
10760 db 1 ;; flags=1=enabled
10761 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10763 db 3 ;; entry type=I/O interrupt
10764 db 0 ;; interrupt type=vectored interrupt
10765 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10766 db 0 ;; source bus ID is ISA
10767 db 0 ;; source bus IRQ
10768 db 2 ;; destination I/O APIC ID
10769 db 0 ;; destination I/O APIC interrrupt in
10770 ;; repeat pattern for interrupts 0-15
10780 db 3,0,0,0,0,10,2,10
10781 db 3,0,0,0,0,11,2,11
10782 db 3,0,0,0,0,12,2,12
10783 db 3,0,0,0,0,13,2,13
10784 db 3,0,0,0,0,14,2,14
10785 db 3,0,0,0,0,15,2,15
10786 #elif (BX_SMP_PROCESSORS==4)
10787 // define the Intel MP Configuration Structure for 4 processors at
10788 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10791 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10792 dw (mp_config_end-mp_config_table) ;; table length
10794 db 0xdd ;; checksum
10795 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10796 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10797 db 0x20, 0x20, 0x20, 0x20
10798 db 0x20, 0x20, 0x20, 0x20
10799 dw 0,0 ;; oem table ptr
10800 dw 0 ;; oem table size
10801 dw 22 ;; entry count
10802 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10803 dw 0 ;; extended table length
10804 db 0 ;; extended table checksum
10807 db 0 ;; entry type=processor
10808 db 0 ;; local APIC id
10809 db 0x11 ;; local APIC version number
10810 db 3 ;; cpu flags: enabled, bootstrap processor
10811 db 0,6,0,0 ;; cpu signature
10812 dw 0x201,0 ;; feature flags
10816 db 0 ;; entry type=processor
10817 db 1 ;; local APIC id
10818 db 0x11 ;; local APIC version number
10819 db 1 ;; cpu flags: enabled
10820 db 0,6,0,0 ;; cpu signature
10821 dw 0x201,0 ;; feature flags
10825 db 0 ;; entry type=processor
10826 db 2 ;; local APIC id
10827 db 0x11 ;; local APIC version number
10828 db 1 ;; cpu flags: enabled
10829 db 0,6,0,0 ;; cpu signature
10830 dw 0x201,0 ;; feature flags
10834 db 0 ;; entry type=processor
10835 db 3 ;; local APIC id
10836 db 0x11 ;; local APIC version number
10837 db 1 ;; cpu flags: enabled
10838 db 0,6,0,0 ;; cpu signature
10839 dw 0x201,0 ;; feature flags
10843 db 1 ;; entry type=bus
10845 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10847 db 2 ;; entry type=I/O APIC
10848 db 4 ;; apic id=4. linux will set.
10849 db 0x11 ;; I/O APIC version number
10850 db 1 ;; flags=1=enabled
10851 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10853 db 3 ;; entry type=I/O interrupt
10854 db 0 ;; interrupt type=vectored interrupt
10855 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10856 db 0 ;; source bus ID is ISA
10857 db 0 ;; source bus IRQ
10858 db 4 ;; destination I/O APIC ID
10859 db 0 ;; destination I/O APIC interrrupt in
10860 ;; repeat pattern for interrupts 0-15
10870 db 3,0,0,0,0,10,4,10
10871 db 3,0,0,0,0,11,4,11
10872 db 3,0,0,0,0,12,4,12
10873 db 3,0,0,0,0,13,4,13
10874 db 3,0,0,0,0,14,4,14
10875 db 3,0,0,0,0,15,4,15
10876 #elif (BX_SMP_PROCESSORS==8)
10877 // define the Intel MP Configuration Structure for 8 processors at
10878 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10881 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10882 dw (mp_config_end-mp_config_table) ;; table length
10884 db 0xc3 ;; checksum
10885 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10886 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10887 db 0x20, 0x20, 0x20, 0x20
10888 db 0x20, 0x20, 0x20, 0x20
10889 dw 0,0 ;; oem table ptr
10890 dw 0 ;; oem table size
10891 dw 26 ;; entry count
10892 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10893 dw 0 ;; extended table length
10894 db 0 ;; extended table checksum
10897 db 0 ;; entry type=processor
10898 db 0 ;; local APIC id
10899 db 0x11 ;; local APIC version number
10900 db 3 ;; cpu flags: enabled, bootstrap processor
10901 db 0,6,0,0 ;; cpu signature
10902 dw 0x201,0 ;; feature flags
10906 db 0 ;; entry type=processor
10907 db 1 ;; local APIC id
10908 db 0x11 ;; local APIC version number
10909 db 1 ;; cpu flags: enabled
10910 db 0,6,0,0 ;; cpu signature
10911 dw 0x201,0 ;; feature flags
10915 db 0 ;; entry type=processor
10916 db 2 ;; local APIC id
10917 db 0x11 ;; local APIC version number
10918 db 1 ;; cpu flags: enabled
10919 db 0,6,0,0 ;; cpu signature
10920 dw 0x201,0 ;; feature flags
10924 db 0 ;; entry type=processor
10925 db 3 ;; local APIC id
10926 db 0x11 ;; local APIC version number
10927 db 1 ;; cpu flags: enabled
10928 db 0,6,0,0 ;; cpu signature
10929 dw 0x201,0 ;; feature flags
10933 db 0 ;; entry type=processor
10934 db 4 ;; local APIC id
10935 db 0x11 ;; local APIC version number
10936 db 1 ;; cpu flags: enabled
10937 db 0,6,0,0 ;; cpu signature
10938 dw 0x201,0 ;; feature flags
10942 db 0 ;; entry type=processor
10943 db 5 ;; local APIC id
10944 db 0x11 ;; local APIC version number
10945 db 1 ;; cpu flags: enabled
10946 db 0,6,0,0 ;; cpu signature
10947 dw 0x201,0 ;; feature flags
10951 db 0 ;; entry type=processor
10952 db 6 ;; local APIC id
10953 db 0x11 ;; local APIC version number
10954 db 1 ;; cpu flags: enabled
10955 db 0,6,0,0 ;; cpu signature
10956 dw 0x201,0 ;; feature flags
10960 db 0 ;; entry type=processor
10961 db 7 ;; local APIC id
10962 db 0x11 ;; local APIC version number
10963 db 1 ;; cpu flags: enabled
10964 db 0,6,0,0 ;; cpu signature
10965 dw 0x201,0 ;; feature flags
10969 db 1 ;; entry type=bus
10971 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10973 db 2 ;; entry type=I/O APIC
10975 db 0x11 ;; I/O APIC version number
10976 db 1 ;; flags=1=enabled
10977 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10979 db 3 ;; entry type=I/O interrupt
10980 db 0 ;; interrupt type=vectored interrupt
10981 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10982 db 0 ;; source bus ID is ISA
10983 db 0 ;; source bus IRQ
10984 db 8 ;; destination I/O APIC ID
10985 db 0 ;; destination I/O APIC interrrupt in
10986 ;; repeat pattern for interrupts 0-15
10996 db 3,0,0,0,0,10,8,10
10997 db 3,0,0,0,0,11,8,11
10998 db 3,0,0,0,0,12,8,12
10999 db 3,0,0,0,0,13,8,13
11000 db 3,0,0,0,0,14,8,14
11001 db 3,0,0,0,0,15,8,15
11003 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11004 #endif // if (BX_SMP_PROCESSORS==...)
11006 mp_config_end: // this label used to find length of mp structure
11009 #if (BX_SMP_PROCESSORS>1)
11011 mp_floating_pointer_structure:
11012 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
11013 dw mp_config_table, 0xf ;; pointer to MP configuration table
11014 db 1 ;; length of this struct in 16-bit byte chunks
11015 db 4 ;; MP spec revision
11016 db 0xc1 ;; checksum
11017 db 0 ;; MP feature byte 1. value 0 means look at the config table
11018 db 0,0,0,0 ;; MP feature bytes 2-5.
11023 #endif // HVMASSIST