2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.4 2008/05/11 23:26:05 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.4 $";
949 static char bios_date_string[] = "$Date: 2008/05/11 23:26:05 $";
951 static char CVSID[] = "$Id: rombios.c,v 1.4 2008/05/11 23:26:05 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 */
1686 if (inb(0x64) & 0x01) {
1692 // Due to timer issues, and if the IPS setting is > 15000000,
1693 // the incoming keys might not be flushed here. That will
1694 // cause a panic a few lines below. See sourceforge bug report :
1695 // [ 642031 ] FATAL: Keyboard RESET error:993
1697 /* ------------------- controller side ----------------------*/
1698 /* send cmd = 0xAA, self test 8042 */
1701 /* Wait until buffer is empty */
1703 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1704 if (max==0x0) keyboard_panic(00);
1708 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1709 if (max==0x0) keyboard_panic(01);
1711 /* read self-test result, 0x55 should be returned from 0x60 */
1712 if ((inb(0x60) != 0x55)){
1713 keyboard_panic(991);
1716 /* send cmd = 0xAB, keyboard interface test */
1719 /* Wait until buffer is empty */
1721 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1722 if (max==0x0) keyboard_panic(10);
1726 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1727 if (max==0x0) keyboard_panic(11);
1729 /* read keyboard interface test result, */
1730 /* 0x00 should be returned form 0x60 */
1731 if ((inb(0x60) != 0x00)) {
1732 keyboard_panic(992);
1735 /* Enable Keyboard clock */
1739 /* ------------------- keyboard side ------------------------*/
1740 /* reset kerboard and self test (keyboard side) */
1743 /* Wait until buffer is empty */
1745 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1746 if (max==0x0) keyboard_panic(20);
1750 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1751 if (max==0x0) keyboard_panic(21);
1753 /* keyboard should return ACK */
1754 if ((inb(0x60) != 0xfa)) {
1755 keyboard_panic(993);
1760 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1761 if (max==0x0) keyboard_panic(31);
1763 if ((inb(0x60) != 0xaa)) {
1764 keyboard_panic(994);
1767 /* Disable keyboard */
1770 /* Wait until buffer is empty */
1772 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1773 if (max==0x0) keyboard_panic(40);
1777 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1778 if (max==0x0) keyboard_panic(41);
1780 /* keyboard should return ACK */
1783 printf("rc=0x%x\n",rc);
1784 keyboard_panic(995);
1787 /* Write Keyboard Mode */
1790 /* Wait until buffer is empty */
1792 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1793 if (max==0x0) keyboard_panic(50);
1795 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1798 /* Wait until buffer is empty */
1800 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1801 if (max==0x0) keyboard_panic(60);
1803 /* Enable keyboard */
1806 /* Wait until buffer is empty */
1808 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1809 if (max==0x0) keyboard_panic(70);
1813 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1814 if (max==0x0) keyboard_panic(70);
1816 /* keyboard should return ACK */
1817 if ((inb(0x60) != 0xfa)) {
1818 keyboard_panic(996);
1822 printf("keyboard init done.\n");
1825 //--------------------------------------------------------------------------
1827 //--------------------------------------------------------------------------
1829 keyboard_panic(status)
1832 // If you're getting a 993 keyboard panic here,
1833 // please see the comment in keyboard_init
1834 printf("Keyboard error:%u CONTINUING\n",status); return;
1835 BX_PANIC("Keyboard error:%u\n",status);
1838 //--------------------------------------------------------------------------
1839 // shutdown_status_panic
1840 // called when the shutdown statsu is not implemented, displays the status
1841 //--------------------------------------------------------------------------
1843 shutdown_status_panic(status)
1846 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1849 //--------------------------------------------------------------------------
1850 // print_bios_banner
1851 // displays a the bios version
1852 //--------------------------------------------------------------------------
1856 printf("Hi from peter's modified bios\n");
1857 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1858 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1862 //--------------------------------------------------------------------------
1863 // print_boot_device
1864 // displays the boot device
1865 //--------------------------------------------------------------------------
1867 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1870 print_boot_device(cdboot, drive)
1871 Bit8u cdboot; Bit16u drive;
1875 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1876 // drive contains real/emulated boot drive
1878 if(cdboot)i=2; // CD-Rom
1879 else if((drive&0x0080)==0x00)i=0; // Floppy
1880 else if((drive&0x0080)==0x80)i=1; // Hard drive
1883 printf("Booting from %s...\n",drivetypes[i]);
1886 //--------------------------------------------------------------------------
1887 // print_boot_failure
1888 // displays the reason why boot failed
1889 //--------------------------------------------------------------------------
1891 print_boot_failure(cdboot, drive, reason, lastdrive)
1892 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1894 Bit16u drivenum = drive&0x7f;
1896 // cdboot: 1 if boot from cd, 0 otherwise
1897 // drive : drive number
1898 // reason: 0 signature check failed, 1 read error
1899 // lastdrive: 1 boot drive is the last one in boot sequence
1902 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1903 else if (drive & 0x80)
1904 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1906 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1910 BX_PANIC("Not a bootable disk\n");
1912 BX_PANIC("Could not read the boot disk\n");
1916 //--------------------------------------------------------------------------
1917 // print_cdromboot_failure
1918 // displays the reason why boot failed
1919 //--------------------------------------------------------------------------
1921 print_cdromboot_failure( code )
1924 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1932 BX_PANIC("NMI Handler called\n");
1938 BX_PANIC("INT18: BOOT FAILURE\n");
1945 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1947 BX_INFO("%s\n", bios_version_string);
1956 // Use PS2 System Control port A to set A20 enable
1958 // get current setting first
1961 // change A20 status
1963 outb(0x92, oldval | 0x02);
1965 outb(0x92, oldval & 0xfd);
1967 return((oldval & 0x02) != 0);
1984 // ---------------------------------------------------------------------------
1985 // Start of ATA/ATAPI Driver
1986 // ---------------------------------------------------------------------------
1988 // Global defines -- ATA register and register bits.
1989 // command block & control block regs
1990 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1991 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1992 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1993 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1994 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1995 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1996 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1997 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1998 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1999 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2000 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2001 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2002 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2004 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2005 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2006 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2007 #define ATA_CB_ER_MC 0x20 // ATA media change
2008 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2009 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2010 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2011 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2012 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2014 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2015 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2016 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2017 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2018 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2020 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2021 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2022 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2023 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2024 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2026 // bits 7-4 of the device/head (CB_DH) reg
2027 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2028 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2030 // status reg (CB_STAT and CB_ASTAT) bits
2031 #define ATA_CB_STAT_BSY 0x80 // busy
2032 #define ATA_CB_STAT_RDY 0x40 // ready
2033 #define ATA_CB_STAT_DF 0x20 // device fault
2034 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2035 #define ATA_CB_STAT_SKC 0x10 // seek complete
2036 #define ATA_CB_STAT_SERV 0x10 // service
2037 #define ATA_CB_STAT_DRQ 0x08 // data request
2038 #define ATA_CB_STAT_CORR 0x04 // corrected
2039 #define ATA_CB_STAT_IDX 0x02 // index
2040 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2041 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2043 // device control reg (CB_DC) bits
2044 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2045 #define ATA_CB_DC_SRST 0x04 // soft reset
2046 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2048 // Most mandtory and optional ATA commands (from ATA-3),
2049 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2050 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2051 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2052 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2053 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2054 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2055 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2056 #define ATA_CMD_DEVICE_RESET 0x08
2057 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2058 #define ATA_CMD_FLUSH_CACHE 0xE7
2059 #define ATA_CMD_FORMAT_TRACK 0x50
2060 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2061 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2062 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2063 #define ATA_CMD_IDLE1 0xE3
2064 #define ATA_CMD_IDLE2 0x97
2065 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2066 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2067 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2068 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2069 #define ATA_CMD_NOP 0x00
2070 #define ATA_CMD_PACKET 0xA0
2071 #define ATA_CMD_READ_BUFFER 0xE4
2072 #define ATA_CMD_READ_DMA 0xC8
2073 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2074 #define ATA_CMD_READ_MULTIPLE 0xC4
2075 #define ATA_CMD_READ_SECTORS 0x20
2076 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2077 #define ATA_CMD_RECALIBRATE 0x10
2078 #define ATA_CMD_SEEK 0x70
2079 #define ATA_CMD_SET_FEATURES 0xEF
2080 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2081 #define ATA_CMD_SLEEP1 0xE6
2082 #define ATA_CMD_SLEEP2 0x99
2083 #define ATA_CMD_STANDBY1 0xE2
2084 #define ATA_CMD_STANDBY2 0x96
2085 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2086 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2087 #define ATA_CMD_WRITE_BUFFER 0xE8
2088 #define ATA_CMD_WRITE_DMA 0xCA
2089 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2090 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2091 #define ATA_CMD_WRITE_SECTORS 0x30
2092 #define ATA_CMD_WRITE_VERIFY 0x3C
2094 #define ATA_IFACE_NONE 0x00
2095 #define ATA_IFACE_ISA 0x00
2096 #define ATA_IFACE_PCI 0x01
2098 #define ATA_TYPE_NONE 0x00
2099 #define ATA_TYPE_UNKNOWN 0x01
2100 #define ATA_TYPE_ATA 0x02
2101 #define ATA_TYPE_ATAPI 0x03
2103 #define ATA_DEVICE_NONE 0x00
2104 #define ATA_DEVICE_HD 0xFF
2105 #define ATA_DEVICE_CDROM 0x05
2107 #define ATA_MODE_NONE 0x00
2108 #define ATA_MODE_PIO16 0x00
2109 #define ATA_MODE_PIO32 0x01
2110 #define ATA_MODE_ISADMA 0x02
2111 #define ATA_MODE_PCIDMA 0x03
2112 #define ATA_MODE_USEIRQ 0x10
2114 #define ATA_TRANSLATION_NONE 0
2115 #define ATA_TRANSLATION_LBA 1
2116 #define ATA_TRANSLATION_LARGE 2
2117 #define ATA_TRANSLATION_RECHS 3
2119 #define ATA_DATA_NO 0x00
2120 #define ATA_DATA_IN 0x01
2121 #define ATA_DATA_OUT 0x02
2123 // ---------------------------------------------------------------------------
2124 // ATA/ATAPI driver : initialization
2125 // ---------------------------------------------------------------------------
2128 Bit16u ebda_seg=read_word(0x0040,0x000E);
2129 Bit8u channel, device;
2131 //BX_DEBUG("rombios: ata_init\n");
2133 // Channels info init.
2134 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2135 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2136 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2137 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2138 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2141 // Devices info init.
2142 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2143 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2144 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2145 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2146 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2147 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2148 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2149 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2150 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2151 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2152 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2153 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2154 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2155 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2157 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2160 // hdidmap and cdidmap init.
2161 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2162 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2163 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2166 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2167 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2170 // ---------------------------------------------------------------------------
2171 // ATA/ATAPI driver : device detection
2172 // ---------------------------------------------------------------------------
2176 Bit16u ebda_seg=read_word(0x0040,0x000E);
2177 Bit8u hdcount, cdcount, device, type;
2178 Bit8u buffer[0x0200];
2180 //BX_DEBUG("rombios: ata_detect\n");
2182 #if BX_MAX_ATA_INTERFACES > 0
2183 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2184 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2185 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2186 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2188 #if BX_MAX_ATA_INTERFACES > 1
2189 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2190 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2191 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2192 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2194 #if BX_MAX_ATA_INTERFACES > 2
2195 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2196 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2197 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2198 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2200 #if BX_MAX_ATA_INTERFACES > 3
2201 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2202 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2203 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2204 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2206 #if BX_MAX_ATA_INTERFACES > 4
2207 #error Please fill the ATA interface informations
2213 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2214 Bit16u iobase1, iobase2;
2215 Bit8u channel, slave, shift;
2216 Bit8u sc, sn, cl, ch, st;
2218 channel = device / 2;
2221 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2222 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2224 // Disable interrupts
2225 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2228 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2229 outb(iobase1+ATA_CB_SC, 0x55);
2230 outb(iobase1+ATA_CB_SN, 0xaa);
2231 outb(iobase1+ATA_CB_SC, 0xaa);
2232 outb(iobase1+ATA_CB_SN, 0x55);
2233 outb(iobase1+ATA_CB_SC, 0x55);
2234 outb(iobase1+ATA_CB_SN, 0xaa);
2236 // If we found something
2237 sc = inb(iobase1+ATA_CB_SC);
2238 sn = inb(iobase1+ATA_CB_SN);
2240 if ( (sc == 0x55) && (sn == 0xaa) ) {
2241 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2243 // reset the channel
2246 // check for ATA or ATAPI
2247 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2248 sc = inb(iobase1+ATA_CB_SC);
2249 sn = inb(iobase1+ATA_CB_SN);
2250 if ( (sc==0x01) && (sn==0x01) ) {
2251 cl = inb(iobase1+ATA_CB_CL);
2252 ch = inb(iobase1+ATA_CB_CH);
2253 st = inb(iobase1+ATA_CB_STAT);
2255 if ( (cl==0x14) && (ch==0xeb) ) {
2256 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2258 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2259 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2264 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2266 // Now we send a IDENTIFY command to ATA device
2267 if(type == ATA_TYPE_ATA) {
2269 Bit16u cylinders, heads, spt, blksize;
2270 Bit8u translation, removable, mode;
2272 // default mode to PIO16
2273 mode = ATA_MODE_PIO16;
2275 //Temporary values to do the transfer
2276 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2277 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2279 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2280 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2282 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2284 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2287 blksize = read_word(get_SS(),buffer+10);
2289 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2290 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2291 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2293 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2295 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2296 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2297 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2298 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2299 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2300 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2301 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2302 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2303 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2305 translation = inb_cmos(0x39 + channel/2);
2306 for (shift=device%4; shift>0; shift--) translation >>= 2;
2307 translation &= 0x03;
2309 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2311 switch (translation) {
2312 case ATA_TRANSLATION_NONE:
2315 case ATA_TRANSLATION_LBA:
2318 case ATA_TRANSLATION_LARGE:
2321 case ATA_TRANSLATION_RECHS:
2325 switch (translation) {
2326 case ATA_TRANSLATION_NONE:
2328 case ATA_TRANSLATION_LBA:
2331 heads = sectors / 1024;
2332 if (heads>128) heads = 255;
2333 else if (heads>64) heads = 128;
2334 else if (heads>32) heads = 64;
2335 else if (heads>16) heads = 32;
2337 cylinders = sectors / heads;
2339 case ATA_TRANSLATION_RECHS:
2340 // Take care not to overflow
2342 if(cylinders>61439) cylinders=61439;
2344 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2346 // then go through the large bitshift process
2347 case ATA_TRANSLATION_LARGE:
2348 while(cylinders > 1024) {
2352 // If we max out the head count
2353 if (heads > 127) break;
2357 // clip to 1024 cylinders in lchs
2358 if (cylinders > 1024) cylinders=1024;
2359 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2361 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2362 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2363 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2366 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2370 // Now we send a IDENTIFY command to ATAPI device
2371 if(type == ATA_TYPE_ATAPI) {
2373 Bit8u type, removable, mode;
2376 // default mode to PIO16
2377 mode = ATA_MODE_PIO16;
2379 //Temporary values to do the transfer
2380 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2381 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2383 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2384 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2386 type = read_byte(get_SS(),buffer+1) & 0x1f;
2387 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2389 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2393 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2394 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2395 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2396 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2399 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2406 Bit8u c, i, version, model[41];
2410 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2412 case ATA_TYPE_ATAPI:
2413 // Read ATA/ATAPI version
2414 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2415 for(version=15;version>0;version--) {
2416 if((ataversion&(1<<version))!=0)
2422 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2423 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2427 write_byte(get_SS(),model+40,0x00);
2429 if(read_byte(get_SS(),model+i)==0x20)
2430 write_byte(get_SS(),model+i,0x00);
2438 printf("ata%d %s: ",channel,slave?" slave":"master");
2439 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2440 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2442 case ATA_TYPE_ATAPI:
2443 printf("ata%d %s: ",channel,slave?" slave":"master");
2444 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2445 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2446 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2448 printf(" ATAPI-%d Device\n",version);
2450 case ATA_TYPE_UNKNOWN:
2451 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2457 // Store the devices counts
2458 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2459 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2460 write_byte(0x40,0x75, hdcount);
2464 // FIXME : should use bios=cmos|auto|disable bits
2465 // FIXME : should know about translation bits
2466 // FIXME : move hard_drive_post here
2470 // ---------------------------------------------------------------------------
2471 // ATA/ATAPI driver : software reset
2472 // ---------------------------------------------------------------------------
2474 // 8.2.1 Software reset - Device 0
2476 void ata_reset(device)
2479 Bit16u ebda_seg=read_word(0x0040,0x000E);
2480 Bit16u iobase1, iobase2;
2481 Bit8u channel, slave, sn, sc;
2484 channel = device / 2;
2487 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2488 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2492 // 8.2.1 (a) -- set SRST in DC
2493 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2495 // 8.2.1 (b) -- wait for BSY
2498 Bit8u status = inb(iobase1+ATA_CB_STAT);
2499 if ((status & ATA_CB_STAT_BSY) != 0) break;
2502 // 8.2.1 (f) -- clear SRST
2503 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2505 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2507 // 8.2.1 (g) -- check for sc==sn==0x01
2509 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2510 sc = inb(iobase1+ATA_CB_SC);
2511 sn = inb(iobase1+ATA_CB_SN);
2513 if ( (sc==0x01) && (sn==0x01) ) {
2515 // 8.2.1 (h) -- wait for not BSY
2518 Bit8u status = inb(iobase1+ATA_CB_STAT);
2519 if ((status & ATA_CB_STAT_BSY) == 0) break;
2524 // 8.2.1 (i) -- wait for DRDY
2527 Bit8u status = inb(iobase1+ATA_CB_STAT);
2528 if ((status & ATA_CB_STAT_RDY) != 0) break;
2531 // Enable interrupts
2532 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2535 // ---------------------------------------------------------------------------
2536 // ATA/ATAPI driver : execute a non data command
2537 // ---------------------------------------------------------------------------
2539 Bit16u ata_cmd_non_data()
2542 // ---------------------------------------------------------------------------
2543 // ATA/ATAPI driver : execute a data-in command
2544 // ---------------------------------------------------------------------------
2549 // 3 : expected DRQ=1
2550 // 4 : no sectors left to read/verify
2551 // 5 : more sectors to read/verify
2552 // 6 : no sectors left to write
2553 // 7 : more sectors to write
2554 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2555 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2558 Bit16u ebda_seg=read_word(0x0040,0x000E);
2559 Bit16u iobase1, iobase2, blksize;
2560 Bit8u channel, slave;
2561 Bit8u status, current, mode;
2563 channel = device / 2;
2566 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2567 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2568 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2569 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2570 if (mode == ATA_MODE_PIO32) blksize>>=2;
2573 // sector will be 0 only on lba access. Convert to lba-chs
2575 sector = (Bit16u) (lba & 0x000000ffL);
2577 cylinder = (Bit16u) (lba & 0x0000ffffL);
2579 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2582 // Reset count of transferred data
2583 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2584 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2587 status = inb(iobase1 + ATA_CB_STAT);
2588 if (status & ATA_CB_STAT_BSY) return 1;
2590 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2591 outb(iobase1 + ATA_CB_FR, 0x00);
2592 outb(iobase1 + ATA_CB_SC, count);
2593 outb(iobase1 + ATA_CB_SN, sector);
2594 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2595 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2596 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2597 outb(iobase1 + ATA_CB_CMD, command);
2600 status = inb(iobase1 + ATA_CB_STAT);
2601 if ( !(status & ATA_CB_STAT_BSY) ) break;
2604 if (status & ATA_CB_STAT_ERR) {
2605 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2607 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2608 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2612 // FIXME : move seg/off translation here
2615 sti ;; enable higher priority interrupts
2623 mov di, _ata_cmd_data_in.offset + 2[bp]
2624 mov ax, _ata_cmd_data_in.segment + 2[bp]
2625 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2627 ;; adjust if there will be an overrun. 2K max sector size
2629 jbe ata_in_no_adjust
2632 sub di, #0x0800 ;; sub 2 kbytes from offset
2633 add ax, #0x0080 ;; add 2 Kbytes to segment
2636 mov es, ax ;; segment in es
2638 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2640 mov ah, _ata_cmd_data_in.mode + 2[bp]
2641 cmp ah, #ATA_MODE_PIO32
2646 insw ;; CX words transfered from port(DX) to ES:[DI]
2651 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2654 mov _ata_cmd_data_in.offset + 2[bp], di
2655 mov _ata_cmd_data_in.segment + 2[bp], es
2660 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2662 status = inb(iobase1 + ATA_CB_STAT);
2664 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2665 != ATA_CB_STAT_RDY ) {
2666 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2672 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2673 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2674 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2680 // Enable interrupts
2681 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2685 // ---------------------------------------------------------------------------
2686 // ATA/ATAPI driver : execute a data-out command
2687 // ---------------------------------------------------------------------------
2692 // 3 : expected DRQ=1
2693 // 4 : no sectors left to read/verify
2694 // 5 : more sectors to read/verify
2695 // 6 : no sectors left to write
2696 // 7 : more sectors to write
2697 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2698 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2701 Bit16u ebda_seg=read_word(0x0040,0x000E);
2702 Bit16u iobase1, iobase2, blksize;
2703 Bit8u channel, slave;
2704 Bit8u status, current, mode;
2706 channel = device / 2;
2709 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2710 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2711 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2712 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2713 if (mode == ATA_MODE_PIO32) blksize>>=2;
2716 // sector will be 0 only on lba access. Convert to lba-chs
2718 sector = (Bit16u) (lba & 0x000000ffL);
2720 cylinder = (Bit16u) (lba & 0x0000ffffL);
2722 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2725 // Reset count of transferred data
2726 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2727 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2730 status = inb(iobase1 + ATA_CB_STAT);
2731 if (status & ATA_CB_STAT_BSY) return 1;
2733 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2734 outb(iobase1 + ATA_CB_FR, 0x00);
2735 outb(iobase1 + ATA_CB_SC, count);
2736 outb(iobase1 + ATA_CB_SN, sector);
2737 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2738 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2739 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2740 outb(iobase1 + ATA_CB_CMD, command);
2743 status = inb(iobase1 + ATA_CB_STAT);
2744 if ( !(status & ATA_CB_STAT_BSY) ) break;
2747 if (status & ATA_CB_STAT_ERR) {
2748 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2750 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2751 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2755 // FIXME : move seg/off translation here
2758 sti ;; enable higher priority interrupts
2766 mov si, _ata_cmd_data_out.offset + 2[bp]
2767 mov ax, _ata_cmd_data_out.segment + 2[bp]
2768 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2770 ;; adjust if there will be an overrun. 2K max sector size
2772 jbe ata_out_no_adjust
2775 sub si, #0x0800 ;; sub 2 kbytes from offset
2776 add ax, #0x0080 ;; add 2 Kbytes to segment
2779 mov es, ax ;; segment in es
2781 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2783 mov ah, _ata_cmd_data_out.mode + 2[bp]
2784 cmp ah, #ATA_MODE_PIO32
2790 outsw ;; CX words transfered from port(DX) to ES:[SI]
2796 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2799 mov _ata_cmd_data_out.offset + 2[bp], si
2800 mov _ata_cmd_data_out.segment + 2[bp], es
2805 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2807 status = inb(iobase1 + ATA_CB_STAT);
2809 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2810 != ATA_CB_STAT_RDY ) {
2811 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2817 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2818 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2819 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2825 // Enable interrupts
2826 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2830 // ---------------------------------------------------------------------------
2831 // ATA/ATAPI driver : execute a packet command
2832 // ---------------------------------------------------------------------------
2835 // 1 : error in parameters
2839 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2841 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2845 Bit16u ebda_seg=read_word(0x0040,0x000E);
2846 Bit16u iobase1, iobase2;
2847 Bit16u lcount, lbefore, lafter, count;
2848 Bit8u channel, slave;
2849 Bit8u status, mode, lmode;
2850 Bit32u total, transfer;
2852 channel = device / 2;
2855 // Data out is not supported yet
2856 if (inout == ATA_DATA_OUT) {
2857 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2861 // The header length must be even
2863 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2867 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2868 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2869 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2872 if (cmdlen < 12) cmdlen=12;
2873 if (cmdlen > 12) cmdlen=16;
2876 // Reset count of transferred data
2877 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2878 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2880 // Device should not be busy yet
2885 // wait for device to be ready
2887 status = inb(iobase1 + ATA_CB_STAT);
2888 // BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2889 } while (status & ATA_CB_STAT_BSY);
2891 status = inb(iobase1 + ATA_CB_STAT);
2892 if (status & ATA_CB_STAT_BSY) return 2;
2895 // select master or slave
2896 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
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 // Tell it we are sending a command packet
2911 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2914 // Now wait for 400 ns
2917 for (i=0;i<0xffff; i++)
2922 // Device should ok to receive command
2923 // what until we get
2926 status = inb(iobase1 + ATA_CB_STAT);
2929 if (!(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ)) break;
2931 // Shouldn't this be ATA_CB_STAT_RDY? -PAD - NO, it's OK
2932 if ( !(status & ATA_CB_STAT_BSY) ) break;
2937 if (status & ATA_CB_STAT_ERR) {
2938 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2940 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2941 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2945 // Normalize address
2946 cmdseg += (cmdoff / 16);
2949 // Send command to device
2951 sti ;; enable higher priority interrupts
2956 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2957 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2958 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2959 mov es, ax ;; segment in es
2961 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2965 outsw ;; CX words transfered from port(DX) to ES:[SI]
2970 // issue read of alternative status - claimed to be in spec
2971 inb(iobase2+ATA_CB_ASTAT);
2974 if (inout == ATA_DATA_NO) {
2975 status = inb(iobase1 + ATA_CB_STAT);
2978 // Wait for completion
2981 status=inb(iobase1+ATA_CB_STAT);
2982 BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2983 } while ((status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_RDY));
2987 status = inb(iobase1 + ATA_CB_STAT);
2989 // Check if command completed
2990 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2992 if (status & ATA_CB_STAT_ERR) {
2993 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2997 // If we get here, we are ready and should have DRQ
2998 // and so data is available
2999 // Device must be ready to send data
3000 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3001 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3002 BX_DEBUG_ATA("ata_cmd_packet 1: not ready (status %02x)\n", status);
3006 // Normalize address
3007 bufseg += (bufoff / 16);
3010 // Get the byte count
3011 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3013 // adjust to read what we want
3026 lafter=lcount-length;
3038 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3039 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3041 // If counts not dividable by 4, use 16bits mode
3043 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3044 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3045 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3047 // adds an extra byte if count are odd. before is always even
3048 if (lcount & 0x01) {
3050 if ((lafter > 0) && (lafter & 0x01)) {
3055 if (lmode == ATA_MODE_PIO32) {
3056 lcount>>=2; lbefore>>=2; lafter>>=2;
3059 lcount>>=1; lbefore>>=1; lafter>>=1;
3068 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3070 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3071 jcxz ata_packet_no_before
3073 mov ah, _ata_cmd_packet.lmode + 2[bp]
3074 cmp ah, #ATA_MODE_PIO32
3075 je ata_packet_in_before_32
3077 ata_packet_in_before_16:
3079 loop ata_packet_in_before_16
3080 jmp ata_packet_no_before
3082 ata_packet_in_before_32:
3084 ata_packet_in_before_32_loop:
3086 loop ata_packet_in_before_32_loop
3089 ata_packet_no_before:
3090 mov cx, _ata_cmd_packet.lcount + 2[bp]
3091 jcxz ata_packet_after
3093 mov di, _ata_cmd_packet.bufoff + 2[bp]
3094 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3097 mov ah, _ata_cmd_packet.lmode + 2[bp]
3098 cmp ah, #ATA_MODE_PIO32
3103 insw ;; CX words transfered tp port(DX) to ES:[DI]
3104 jmp ata_packet_after
3108 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3111 mov cx, _ata_cmd_packet.lafter + 2[bp]
3112 jcxz ata_packet_done
3114 mov ah, _ata_cmd_packet.lmode + 2[bp]
3115 cmp ah, #ATA_MODE_PIO32
3116 je ata_packet_in_after_32
3118 ata_packet_in_after_16:
3120 loop ata_packet_in_after_16
3123 ata_packet_in_after_32:
3125 ata_packet_in_after_32_loop:
3127 loop ata_packet_in_after_32_loop
3134 // Compute new buffer address
3137 // Save transferred bytes count
3139 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3143 // Final check, device must be ready
3144 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3145 != ATA_CB_STAT_RDY ) {
3146 BX_DEBUG_ATA("ata_cmd_packet 2 : not ready (status %02x)\n", (unsigned) status);
3150 // Enable interrupts
3151 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3155 // ---------------------------------------------------------------------------
3156 // End of ATA/ATAPI Driver
3157 // ---------------------------------------------------------------------------
3160 // ---------------------------------------------------------------------------
3161 // Start of ATA/ATAPI generic functions
3162 // ---------------------------------------------------------------------------
3165 atapi_get_sense(device)
3172 memsetb(get_SS(),atacmd,0,12);
3177 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3180 if ((buffer[0] & 0x7e) == 0x70) {
3181 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3188 atapi_is_ready(device)
3194 memsetb(get_SS(),atacmd,0,12);
3197 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3200 if (atapi_get_sense(device) !=0 ) {
3201 memsetb(get_SS(),atacmd,0,12);
3203 // try to send Test Unit Ready again
3204 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3207 return atapi_get_sense(device);
3213 atapi_is_cdrom(device)
3216 Bit16u ebda_seg=read_word(0x0040,0x000E);
3218 if (device >= BX_MAX_ATA_DEVICES)
3221 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3224 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3230 // ---------------------------------------------------------------------------
3231 // End of ATA/ATAPI generic functions
3232 // ---------------------------------------------------------------------------
3234 #endif // BX_USE_ATADRV
3236 #if BX_ELTORITO_BOOT
3238 // ---------------------------------------------------------------------------
3239 // Start of El-Torito boot functions
3240 // ---------------------------------------------------------------------------
3245 Bit16u ebda_seg=read_word(0x0040,0x000E);
3247 //BX_DEBUG("rombios: cdemu_init\n");
3249 // the only important data is this one for now
3250 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3256 Bit16u ebda_seg=read_word(0x0040,0x000E);
3258 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3262 cdemu_emulated_drive()
3264 Bit16u ebda_seg=read_word(0x0040,0x000E);
3266 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3269 static char isotag[6]="CD001";
3270 static char eltorito[24]="EL TORITO SPECIFICATION";
3272 // Returns ah: emulated drive, al: error code
3277 Bit16u ebda_seg=read_word(0x0040,0x000E);
3278 Bit8u atacmd[12], buffer[2048];
3280 Bit16u boot_segment, nbsectors, i, error;
3284 // Find out the first cdrom
3285 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3286 if (atapi_is_cdrom(device)) break;
3290 if(device >= BX_MAX_ATA_DEVICES) return 2;
3292 // Read the Boot Record Volume Descriptor
3293 memsetb(get_SS(),atacmd,0,12);
3294 atacmd[0]=0x28; // READ command
3295 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3296 atacmd[8]=(0x01 & 0x00ff); // Sectors
3297 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3298 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3299 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3300 atacmd[5]=(0x11 & 0x000000ff);
3301 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3306 if(buffer[0]!=0)return 4;
3308 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3311 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3313 // ok, now we calculate the Boot catalog address
3314 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3316 // And we read the Boot Catalog
3317 memsetb(get_SS(),atacmd,0,12);
3318 atacmd[0]=0x28; // READ command
3319 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3320 atacmd[8]=(0x01 & 0x00ff); // Sectors
3321 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3322 atacmd[3]=(lba & 0x00ff0000) >> 16;
3323 atacmd[4]=(lba & 0x0000ff00) >> 8;
3324 atacmd[5]=(lba & 0x000000ff);
3325 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3331 if(buffer[0x00]!=0x01)return 8; // Header
3332 if(buffer[0x01]!=0x00)return 9; // Platform
3333 if(buffer[0x1E]!=0x55)return 10; // key 1
3334 if(buffer[0x1F]!=0xAA)return 10; // key 2
3336 // Initial/Default Entry
3337 if(buffer[0x20]!=0x88)return 11; // Bootable
3339 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3340 if(buffer[0x21]==0){
3341 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3342 // Win2000 cd boot needs to know it booted from cd
3343 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3345 else if(buffer[0x21]<4)
3346 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3348 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3350 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3351 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3353 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3354 if(boot_segment==0x0000)boot_segment=0x07C0;
3356 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3357 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3359 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3360 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3362 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3363 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3365 // And we read the image in memory
3366 memsetb(get_SS(),atacmd,0,12);
3367 atacmd[0]=0x28; // READ command
3368 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3369 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3370 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3371 atacmd[3]=(lba & 0x00ff0000) >> 16;
3372 atacmd[4]=(lba & 0x0000ff00) >> 8;
3373 atacmd[5]=(lba & 0x000000ff);
3374 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3378 // Remember the media type
3379 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3380 case 0x01: // 1.2M floppy
3381 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3382 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3383 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3385 case 0x02: // 1.44M floppy
3386 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3387 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3388 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3390 case 0x03: // 2.88M floppy
3391 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3392 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3393 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3395 case 0x04: // Harddrive
3396 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3397 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3398 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3399 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3403 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3404 // Increase bios installed hardware number of devices
3405 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3406 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3408 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3412 // everything is ok, so from now on, the emulation is active
3413 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3414 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3416 // return the boot drive + no error
3417 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3420 // ---------------------------------------------------------------------------
3421 // End of El-Torito boot functions
3422 // ---------------------------------------------------------------------------
3423 #endif // BX_ELTORITO_BOOT
3426 int14_function(regs, ds, iret_addr)
3427 pusha_regs_t regs; // regs pushed from PUSHA instruction
3428 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3429 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3431 Bit16u addr,timer,val16;
3438 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3439 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3440 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3441 switch (regs.u.r8.ah) {
3443 outb(addr+3, inb(addr+3) | 0x80);
3444 if (regs.u.r8.al & 0xE0 == 0) {
3448 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3449 outb(addr, val16 & 0xFF);
3450 outb(addr+1, val16 >> 8);
3452 outb(addr+3, regs.u.r8.al & 0x1F);
3453 regs.u.r8.ah = inb(addr+5);
3454 regs.u.r8.al = inb(addr+6);
3455 ClearCF(iret_addr.flags);
3458 timer = read_word(0x0040, 0x006C);
3459 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3460 val16 = read_word(0x0040, 0x006C);
3461 if (val16 != timer) {
3466 if (timeout) outb(addr, regs.u.r8.al);
3467 regs.u.r8.ah = inb(addr+5);
3468 if (!timeout) regs.u.r8.ah |= 0x80;
3469 ClearCF(iret_addr.flags);
3472 timer = read_word(0x0040, 0x006C);
3473 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3474 val16 = read_word(0x0040, 0x006C);
3475 if (val16 != timer) {
3482 regs.u.r8.al = inb(addr);
3484 regs.u.r8.ah = inb(addr+5);
3486 ClearCF(iret_addr.flags);
3489 regs.u.r8.ah = inb(addr+5);
3490 regs.u.r8.al = inb(addr+6);
3491 ClearCF(iret_addr.flags);
3494 SetCF(iret_addr.flags); // Unsupported
3497 SetCF(iret_addr.flags); // Unsupported
3502 int15_function(regs, ES, DS, FLAGS)
3503 pusha_regs_t regs; // REGS pushed via pusha
3504 Bit16u ES, DS, FLAGS;
3506 Bit16u ebda_seg=read_word(0x0040,0x000E);
3507 bx_bool prev_a20_enable;
3516 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3518 switch (regs.u.r8.ah) {
3519 case 0x24: /* A20 Control */
3520 switch (regs.u.r8.al) {
3532 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3542 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3544 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3550 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3554 /* keyboard intercept */
3556 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3563 case 0x52: // removable media eject
3565 regs.u.r8.ah = 0; // "ok ejection may proceed"
3569 if( regs.u.r8.al == 0 ) {
3570 // Set Interval requested.
3571 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3572 // Interval not already set.
3573 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3574 write_word( 0x40, 0x98, ES ); // Byte location, segment
3575 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3576 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3577 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3579 irqDisable = inb( 0xA1 );
3580 outb( 0xA1, irqDisable & 0xFE );
3581 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3582 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3584 // Interval already set.
3585 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3587 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3589 } else if( regs.u.r8.al == 1 ) {
3590 // Clear Interval requested
3591 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3593 bRegister = inb_cmos( 0xB );
3594 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3596 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3598 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3607 # error "Int15 function 87h not supported on < 80386"
3609 // +++ should probably have descriptor checks
3610 // +++ should have exception handlers
3612 // turn off interrupts
3617 prev_a20_enable = set_enable_a20(1); // enable A20 line
3619 // 128K max of transfer on 386+ ???
3620 // source == destination ???
3622 // ES:SI points to descriptor table
3623 // offset use initially comments
3624 // ==============================================
3625 // 00..07 Unused zeros Null descriptor
3626 // 08..0f GDT zeros filled in by BIOS
3627 // 10..17 source ssssssss source of data
3628 // 18..1f dest dddddddd destination of data
3629 // 20..27 CS zeros filled in by BIOS
3630 // 28..2f SS zeros filled in by BIOS
3637 // check for access rights of source & dest here
3639 // Initialize GDT descriptor
3640 base15_00 = (ES << 4) + regs.u.r16.si;
3641 base23_16 = ES >> 12;
3642 if (base15_00 < (ES<<4))
3644 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3645 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3646 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3647 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3648 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3650 // Initialize CS descriptor
3651 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3652 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3653 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3654 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3655 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3657 // Initialize SS descriptor
3659 base15_00 = ss << 4;
3660 base23_16 = ss >> 12;
3661 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3662 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3663 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3664 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3665 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3669 // Compile generates locals offset info relative to SP.
3670 // Get CX (word count) from stack.
3673 mov cx, _int15_function.CX [bx]
3675 // since we need to set SS:SP, save them to the BDA
3676 // for future restore
3686 lidt [pmode_IDT_info]
3687 ;; perhaps do something with IDT here
3689 ;; set PE bit in CR0
3693 ;; far jump to flush CPU queue after transition to protected mode
3694 JMP_AP(0x0020, protected_mode)
3697 ;; GDT points to valid descriptor table, now load SS, DS, ES
3698 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3700 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3702 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3708 movsw ;; move CX words from DS:SI to ES:DI
3710 ;; make sure DS and ES limits are 64KB
3715 ;; reset PG bit in CR0 ???
3720 ;; far jump to flush CPU queue after transition to real mode
3721 JMP_AP(0xf000, real_mode)
3724 ;; restore IDT to normal real-mode defaults
3726 lidt [rmode_IDT_info]
3728 // restore SS:SP from the BDA
3736 set_enable_a20(prev_a20_enable);
3738 // turn back on interrupts
3749 // Get the amount of extended memory (above 1M)
3751 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3754 regs.u.r8.al = inb_cmos(0x30);
3755 regs.u.r8.ah = inb_cmos(0x31);
3758 if(regs.u.r16.ax > 0x3c00)
3759 regs.u.r16.ax = 0x3c00;
3766 /* Device busy interrupt. Called by Int 16h when no key available */
3770 /* Interrupt complete. Called by Int 16h when key becomes available */
3774 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3776 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3782 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3787 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3797 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3799 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3803 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3804 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3806 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3811 #if BX_USE_PS2_MOUSE
3813 int15_function_mouse(regs, ES, DS, FLAGS)
3814 pusha_regs_t regs; // REGS pushed via pusha
3815 Bit16u ES, DS, FLAGS;
3817 Bit16u ebda_seg=read_word(0x0040,0x000E);
3818 Bit8u mouse_flags_1, mouse_flags_2;
3819 Bit16u mouse_driver_seg;
3820 Bit16u mouse_driver_offset;
3821 Bit8u comm_byte, prev_command_byte;
3822 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3824 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3826 switch (regs.u.r8.ah) {
3828 // Return Codes status in AH
3829 // =========================
3831 // 01: invalid subfunction (AL > 7)
3832 // 02: invalid input value (out of allowable range)
3833 // 03: interface error
3834 // 04: resend command received from mouse controller,
3835 // device driver should attempt command again
3836 // 05: cannot enable mouse, since no far call has been installed
3837 // 80/86: mouse service not implemented
3839 switch (regs.u.r8.al) {
3840 case 0: // Disable/Enable Mouse
3841 BX_DEBUG_INT15("case 0:\n");
3842 switch (regs.u.r8.bh) {
3843 case 0: // Disable Mouse
3844 BX_DEBUG_INT15("case 0: disable mouse\n");
3845 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3846 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3848 ret = get_mouse_data(&mouse_data1);
3849 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3862 case 1: // Enable Mouse
3863 BX_DEBUG_INT15("case 1: enable mouse\n");
3864 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3865 if ( (mouse_flags_2 & 0x80) == 0 ) {
3866 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3868 regs.u.r8.ah = 5; // no far call installed
3871 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3872 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3874 ret = get_mouse_data(&mouse_data1);
3875 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3876 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3886 default: // invalid subfunction
3887 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3889 regs.u.r8.ah = 1; // invalid subfunction
3894 case 1: // Reset Mouse
3895 case 5: // Initialize Mouse
3896 BX_DEBUG_INT15("case 1 or 5:\n");
3897 if (regs.u.r8.al == 5) {
3898 if (regs.u.r8.bh != 3) {
3900 regs.u.r8.ah = 0x02; // invalid input
3903 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3904 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3905 mouse_flags_1 = 0x00;
3906 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3907 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3910 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3911 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3913 ret = get_mouse_data(&mouse_data3);
3914 // if no mouse attached, it will return RESEND
3915 if (mouse_data3 == 0xfe) {
3919 if (mouse_data3 != 0xfa)
3920 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3922 ret = get_mouse_data(&mouse_data1);
3924 ret = get_mouse_data(&mouse_data2);
3926 // turn IRQ12 and packet generation on
3927 enable_mouse_int_and_events();
3930 regs.u.r8.bl = mouse_data1;
3931 regs.u.r8.bh = mouse_data2;
3943 case 2: // Set Sample Rate
3944 BX_DEBUG_INT15("case 2:\n");
3945 switch (regs.u.r8.bh) {
3946 case 0: mouse_data1 = 10; break; // 10 reports/sec
3947 case 1: mouse_data1 = 20; break; // 20 reports/sec
3948 case 2: mouse_data1 = 40; break; // 40 reports/sec
3949 case 3: mouse_data1 = 60; break; // 60 reports/sec
3950 case 4: mouse_data1 = 80; break; // 80 reports/sec
3951 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3952 case 6: mouse_data1 = 200; break; // 200 reports/sec
3953 default: mouse_data1 = 0;
3955 if (mouse_data1 > 0) {
3956 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3958 ret = get_mouse_data(&mouse_data2);
3959 ret = send_to_mouse_ctrl(mouse_data1);
3960 ret = get_mouse_data(&mouse_data2);
3966 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3971 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3975 case 3: // Set Resolution
3976 BX_DEBUG_INT15("case 3:\n");
3978 // 0 = 25 dpi, 1 count per millimeter
3979 // 1 = 50 dpi, 2 counts per millimeter
3980 // 2 = 100 dpi, 4 counts per millimeter
3981 // 3 = 200 dpi, 8 counts per millimeter
3986 case 4: // Get Device ID
3987 BX_DEBUG_INT15("case 4:\n");
3988 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3989 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3991 ret = get_mouse_data(&mouse_data1);
3992 ret = get_mouse_data(&mouse_data2);
3995 regs.u.r8.bh = mouse_data2;
3999 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4003 case 6: // Return Status & Set Scaling Factor...
4004 BX_DEBUG_INT15("case 6:\n");
4005 switch (regs.u.r8.bh) {
4006 case 0: // Return Status
4007 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4008 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4010 ret = get_mouse_data(&mouse_data1);
4011 if (mouse_data1 != 0xfa)
4012 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4014 ret = get_mouse_data(&mouse_data1);
4016 ret = get_mouse_data(&mouse_data2);
4018 ret = get_mouse_data(&mouse_data3);
4022 regs.u.r8.bl = mouse_data1;
4023 regs.u.r8.cl = mouse_data2;
4024 regs.u.r8.dl = mouse_data3;
4025 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4036 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4039 case 1: // Set Scaling Factor to 1:1
4040 case 2: // Set Scaling Factor to 2:1
4041 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4042 if (regs.u.r8.bh == 1) {
4043 ret = send_to_mouse_ctrl(0xE6);
4045 ret = send_to_mouse_ctrl(0xE7);
4048 get_mouse_data(&mouse_data1);
4049 ret = (mouse_data1 != 0xFA);
4057 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4059 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4063 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4067 case 7: // Set Mouse Handler Address
4068 BX_DEBUG_INT15("case 7:\n");
4069 mouse_driver_seg = ES;
4070 mouse_driver_offset = regs.u.r16.bx;
4071 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4072 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4073 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4074 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4075 /* remove handler */
4076 if ( (mouse_flags_2 & 0x80) != 0 ) {
4077 mouse_flags_2 &= ~0x80;
4078 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4082 /* install handler */
4083 mouse_flags_2 |= 0x80;
4085 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4091 BX_DEBUG_INT15("case default:\n");
4092 regs.u.r8.ah = 1; // invalid function
4098 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4099 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4101 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4108 int15_function32(regs, ES, DS, FLAGS)
4109 pushad_regs_t regs; // REGS pushed via pushad
4110 Bit16u ES, DS, FLAGS;
4112 Bit32u extended_memory_size=0; // 64bits long
4115 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4117 switch (regs.u.r8.ah) {
4119 // Wait for CX:DX microseconds. currently using the
4120 // refresh request port 0x61 bit4, toggling every 15usec
4128 ;; Get the count in eax
4131 mov ax, _int15_function.CX [bx]
4134 mov ax, _int15_function.DX [bx]
4136 ;; convert to numbers of 15usec ticks
4142 ;; wait for ecx number of refresh requests
4163 switch(regs.u.r8.al)
4165 case 0x20: // coded by osmaker aka K.J.
4166 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4169 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4170 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4172 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4173 memcpyb(ES, regs.u.r16.di,
4174 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4176 regs.u.r32.ebx += 0x14;
4177 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4179 regs.u.r32.eax = 0x534D4150;
4180 regs.u.r32.ecx = 0x14;
4183 } else if (regs.u.r16.bx == 1) {
4184 extended_memory_size = inb_cmos(0x35);
4185 extended_memory_size <<= 8;
4186 extended_memory_size |= inb_cmos(0x34);
4187 extended_memory_size *= 64;
4188 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4190 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4192 extended_memory_size *= 1024;
4193 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4195 if (extended_memory_size <= 15728640)
4197 extended_memory_size = inb_cmos(0x31);
4198 extended_memory_size <<= 8;
4199 extended_memory_size |= inb_cmos(0x30);
4200 extended_memory_size *= 1024;
4203 write_word(ES, regs.u.r16.di, 0x0000);
4204 write_word(ES, regs.u.r16.di+2, 0x0010);
4205 write_word(ES, regs.u.r16.di+4, 0x0000);
4206 write_word(ES, regs.u.r16.di+6, 0x0000);
4208 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4209 extended_memory_size >>= 16;
4210 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4211 extended_memory_size >>= 16;
4212 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4213 extended_memory_size >>= 16;
4214 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4216 write_word(ES, regs.u.r16.di+16, 0x1);
4217 write_word(ES, regs.u.r16.di+18, 0x0);
4220 regs.u.r32.eax = 0x534D4150;
4221 regs.u.r32.ecx = 0x14;
4224 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4225 goto int15_unimplemented;
4228 switch(regs.u.r16.bx)
4231 write_word(ES, regs.u.r16.di, 0x00);
4232 write_word(ES, regs.u.r16.di+2, 0x00);
4233 write_word(ES, regs.u.r16.di+4, 0x00);
4234 write_word(ES, regs.u.r16.di+6, 0x00);
4236 write_word(ES, regs.u.r16.di+8, 0xFC00);
4237 write_word(ES, regs.u.r16.di+10, 0x0009);
4238 write_word(ES, regs.u.r16.di+12, 0x0000);
4239 write_word(ES, regs.u.r16.di+14, 0x0000);
4241 write_word(ES, regs.u.r16.di+16, 0x1);
4242 write_word(ES, regs.u.r16.di+18, 0x0);
4246 regs.u.r32.eax = 0x534D4150;
4247 regs.u.r32.ecx = 0x14;
4252 extended_memory_size = inb_cmos(0x35);
4253 extended_memory_size <<= 8;
4254 extended_memory_size |= inb_cmos(0x34);
4255 extended_memory_size *= 64;
4256 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4258 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4260 extended_memory_size *= 1024;
4261 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4263 if(extended_memory_size <= 15728640)
4265 extended_memory_size = inb_cmos(0x31);
4266 extended_memory_size <<= 8;
4267 extended_memory_size |= inb_cmos(0x30);
4268 extended_memory_size *= 1024;
4271 write_word(ES, regs.u.r16.di, 0x0000);
4272 write_word(ES, regs.u.r16.di+2, 0x0010);
4273 write_word(ES, regs.u.r16.di+4, 0x0000);
4274 write_word(ES, regs.u.r16.di+6, 0x0000);
4276 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4277 extended_memory_size >>= 16;
4278 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4279 extended_memory_size >>= 16;
4280 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4281 extended_memory_size >>= 16;
4282 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4284 write_word(ES, regs.u.r16.di+16, 0x1);
4285 write_word(ES, regs.u.r16.di+18, 0x0);
4288 regs.u.r32.eax = 0x534D4150;
4289 regs.u.r32.ecx = 0x14;
4293 default: /* AX=E820, DX=534D4150, BX unrecognized */
4294 goto int15_unimplemented;
4299 // if DX != 0x534D4150)
4300 goto int15_unimplemented;
4305 // do we have any reason to fail here ?
4308 // my real system sets ax and bx to 0
4309 // this is confirmed by Ralph Brown list
4310 // but syslinux v1.48 is known to behave
4311 // strangely if ax is set to 0
4312 // regs.u.r16.ax = 0;
4313 // regs.u.r16.bx = 0;
4315 // Get the amount of extended memory (above 1M)
4316 regs.u.r8.cl = inb_cmos(0x30);
4317 regs.u.r8.ch = inb_cmos(0x31);
4320 if(regs.u.r16.cx > 0x3c00)
4322 regs.u.r16.cx = 0x3c00;
4325 // Get the amount of extended memory above 16M in 64k blocs
4326 regs.u.r8.dl = inb_cmos(0x34);
4327 regs.u.r8.dh = inb_cmos(0x35);
4329 // Set configured memory equal to extended memory
4330 regs.u.r16.ax = regs.u.r16.cx;
4331 regs.u.r16.bx = regs.u.r16.dx;
4333 default: /* AH=0xE8?? but not implemented */
4334 goto int15_unimplemented;
4337 int15_unimplemented:
4338 // fall into the default
4340 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4341 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4343 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4349 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4350 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4352 Bit8u scan_code, ascii_code, shift_flags, count;
4353 Bit16u kbd_code, max;
4355 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4358 case 0x00: /* read keyboard input */
4360 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4361 BX_PANIC("KBD: int16h: out of keyboard input\n");
4363 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4364 else if (ascii_code == 0xE0) ascii_code = 0;
4365 AX = (scan_code << 8) | ascii_code;
4368 case 0x01: /* check keyboard status */
4369 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4373 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4374 else if (ascii_code == 0xE0) ascii_code = 0;
4375 AX = (scan_code << 8) | ascii_code;
4379 case 0x02: /* get shift flag status */
4380 shift_flags = read_byte(0x0040, 0x17);
4381 SET_AL(shift_flags);
4384 case 0x05: /* store key-stroke into buffer */
4385 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4393 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4394 // bit Bochs Description
4396 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4397 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4398 // 4 1 INT 16/AH=0Ah supported
4399 // 3 0 INT 16/AX=0306h supported
4400 // 2 0 INT 16/AX=0305h supported
4401 // 1 0 INT 16/AX=0304h supported
4402 // 0 0 INT 16/AX=0300h supported
4407 case 0x0A: /* GET KEYBOARD ID */
4413 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4415 if ((inb(0x60) == 0xfa)) {
4418 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4421 kbd_code |= (inb(0x60) << 8);
4423 } while (--count>0);
4429 case 0x10: /* read MF-II keyboard input */
4431 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4432 BX_PANIC("KBD: int16h: out of keyboard input\n");
4434 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4435 AX = (scan_code << 8) | ascii_code;
4438 case 0x11: /* check MF-II keyboard status */
4439 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4443 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4444 AX = (scan_code << 8) | ascii_code;
4448 case 0x12: /* get extended keyboard status */
4449 shift_flags = read_byte(0x0040, 0x17);
4450 SET_AL(shift_flags);
4451 shift_flags = read_byte(0x0040, 0x18);
4452 SET_AH(shift_flags);
4453 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4456 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4457 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4460 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4461 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4465 if (GET_AL() == 0x08)
4466 SET_AH(0x02); // unsupported, aka normal keyboard
4469 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4474 dequeue_key(scan_code, ascii_code, incr)
4479 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4484 buffer_start = 0x001E;
4485 buffer_end = 0x003E;
4487 buffer_start = read_word(0x0040, 0x0080);
4488 buffer_end = read_word(0x0040, 0x0082);
4491 buffer_head = read_word(0x0040, 0x001a);
4492 buffer_tail = read_word(0x0040, 0x001c);
4494 if (buffer_head != buffer_tail) {
4496 acode = read_byte(0x0040, buffer_head);
4497 scode = read_byte(0x0040, buffer_head+1);
4498 write_byte(ss, ascii_code, acode);
4499 write_byte(ss, scan_code, scode);
4503 if (buffer_head >= buffer_end)
4504 buffer_head = buffer_start;
4505 write_word(0x0040, 0x001a, buffer_head);
4514 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4517 inhibit_mouse_int_and_events()
4519 Bit8u command_byte, prev_command_byte;
4521 // Turn off IRQ generation and aux data line
4522 if ( inb(0x64) & 0x02 )
4523 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4524 outb(0x64, 0x20); // get command byte
4525 while ( (inb(0x64) & 0x01) != 0x01 );
4526 prev_command_byte = inb(0x60);
4527 command_byte = prev_command_byte;
4528 //while ( (inb(0x64) & 0x02) );
4529 if ( inb(0x64) & 0x02 )
4530 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4531 command_byte &= 0xfd; // turn off IRQ 12 generation
4532 command_byte |= 0x20; // disable mouse serial clock line
4533 outb(0x64, 0x60); // write command byte
4534 outb(0x60, command_byte);
4535 return(prev_command_byte);
4539 enable_mouse_int_and_events()
4543 // Turn on IRQ generation and aux data line
4544 if ( inb(0x64) & 0x02 )
4545 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4546 outb(0x64, 0x20); // get command byte
4547 while ( (inb(0x64) & 0x01) != 0x01 );
4548 command_byte = inb(0x60);
4549 //while ( (inb(0x64) & 0x02) );
4550 if ( inb(0x64) & 0x02 )
4551 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4552 command_byte |= 0x02; // turn on IRQ 12 generation
4553 command_byte &= 0xdf; // enable mouse serial clock line
4554 outb(0x64, 0x60); // write command byte
4555 outb(0x60, command_byte);
4559 send_to_mouse_ctrl(sendbyte)
4564 // wait for chance to write to ctrl
4565 if ( inb(0x64) & 0x02 )
4566 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4568 outb(0x60, sendbyte);
4574 get_mouse_data(data)
4580 while ( (inb(0x64) & 0x21) != 0x21 ) {
4583 response = inb(0x60);
4586 write_byte(ss, data, response);
4591 set_kbd_command_byte(command_byte)
4594 if ( inb(0x64) & 0x02 )
4595 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4598 outb(0x64, 0x60); // write command byte
4599 outb(0x60, command_byte);
4603 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4604 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4606 Bit8u scancode, asciicode, shift_flags;
4607 Bit8u mf2_flags, mf2_state, led_flags;
4610 // DS has been set to F000 before call
4614 scancode = GET_AL();
4616 if (scancode == 0) {
4617 BX_INFO("KBD: int09 handler: AL=0\n");
4622 shift_flags = read_byte(0x0040, 0x17);
4623 mf2_flags = read_byte(0x0040, 0x18);
4624 mf2_state = read_byte(0x0040, 0x96);
4625 led_flags = read_byte(0x0040, 0x97);
4629 case 0x3a: /* Caps Lock press */
4630 shift_flags ^= 0x40;
4631 write_byte(0x0040, 0x17, shift_flags);
4633 write_byte(0x0040, 0x18, mf2_flags);
4635 write_byte(0x0040, 0x97, led_flags);
4637 case 0xba: /* Caps Lock release */
4639 write_byte(0x0040, 0x18, mf2_flags);
4642 case 0x2a: /* L Shift press */
4643 /*shift_flags &= ~0x40;*/
4644 shift_flags |= 0x02;
4645 write_byte(0x0040, 0x17, shift_flags);
4647 write_byte(0x0040, 0x97, led_flags);
4649 case 0xaa: /* L Shift release */
4650 shift_flags &= ~0x02;
4651 write_byte(0x0040, 0x17, shift_flags);
4654 case 0x36: /* R Shift press */
4655 /*shift_flags &= ~0x40;*/
4656 shift_flags |= 0x01;
4657 write_byte(0x0040, 0x17, shift_flags);
4659 write_byte(0x0040, 0x97, led_flags);
4661 case 0xb6: /* R Shift release */
4662 shift_flags &= ~0x01;
4663 write_byte(0x0040, 0x17, shift_flags);
4666 case 0x1d: /* Ctrl press */
4667 shift_flags |= 0x04;
4668 write_byte(0x0040, 0x17, shift_flags);
4669 if (mf2_state & 0x01) {
4674 write_byte(0x0040, 0x18, mf2_flags);
4676 case 0x9d: /* Ctrl release */
4677 shift_flags &= ~0x04;
4678 write_byte(0x0040, 0x17, shift_flags);
4679 if (mf2_state & 0x01) {
4684 write_byte(0x0040, 0x18, mf2_flags);
4687 case 0x38: /* Alt press */
4688 shift_flags |= 0x08;
4689 write_byte(0x0040, 0x17, shift_flags);
4690 if (mf2_state & 0x01) {
4695 write_byte(0x0040, 0x18, mf2_flags);
4697 case 0xb8: /* Alt release */
4698 shift_flags &= ~0x08;
4699 write_byte(0x0040, 0x17, shift_flags);
4700 if (mf2_state & 0x01) {
4705 write_byte(0x0040, 0x18, mf2_flags);
4708 case 0x45: /* Num Lock press */
4709 if ((mf2_state & 0x01) == 0) {
4711 write_byte(0x0040, 0x18, mf2_flags);
4712 shift_flags ^= 0x20;
4714 write_byte(0x0040, 0x17, shift_flags);
4715 write_byte(0x0040, 0x97, led_flags);
4718 case 0xc5: /* Num Lock release */
4719 if ((mf2_state & 0x01) == 0) {
4721 write_byte(0x0040, 0x18, mf2_flags);
4725 case 0x46: /* Scroll Lock press */
4727 write_byte(0x0040, 0x18, mf2_flags);
4728 shift_flags ^= 0x10;
4730 write_byte(0x0040, 0x17, shift_flags);
4731 write_byte(0x0040, 0x97, led_flags);
4734 case 0xc6: /* Scroll Lock release */
4736 write_byte(0x0040, 0x18, mf2_flags);
4740 if (scancode & 0x80) return; /* toss key releases ... */
4741 if (scancode > MAX_SCAN_CODE) {
4742 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4745 if (shift_flags & 0x08) { /* ALT */
4746 asciicode = scan_to_scanascii[scancode].alt;
4747 scancode = scan_to_scanascii[scancode].alt >> 8;
4749 else if (shift_flags & 0x04) { /* CONTROL */
4750 asciicode = scan_to_scanascii[scancode].control;
4751 scancode = scan_to_scanascii[scancode].control >> 8;
4753 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4754 /* check if lock state should be ignored
4755 * because a SHIFT key are pressed */
4757 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4758 asciicode = scan_to_scanascii[scancode].normal;
4759 scancode = scan_to_scanascii[scancode].normal >> 8;
4762 asciicode = scan_to_scanascii[scancode].shift;
4763 scancode = scan_to_scanascii[scancode].shift >> 8;
4767 /* check if lock is on */
4768 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4769 asciicode = scan_to_scanascii[scancode].shift;
4770 scancode = scan_to_scanascii[scancode].shift >> 8;
4773 asciicode = scan_to_scanascii[scancode].normal;
4774 scancode = scan_to_scanascii[scancode].normal >> 8;
4777 if (scancode==0 && asciicode==0) {
4778 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4780 enqueue_key(scancode, asciicode);
4787 enqueue_key(scan_code, ascii_code)
4788 Bit8u scan_code, ascii_code;
4790 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4792 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4793 // scan_code, ascii_code);
4796 buffer_start = 0x001E;
4797 buffer_end = 0x003E;
4799 buffer_start = read_word(0x0040, 0x0080);
4800 buffer_end = read_word(0x0040, 0x0082);
4803 buffer_head = read_word(0x0040, 0x001A);
4804 buffer_tail = read_word(0x0040, 0x001C);
4806 temp_tail = buffer_tail;
4808 if (buffer_tail >= buffer_end)
4809 buffer_tail = buffer_start;
4811 if (buffer_tail == buffer_head) {
4815 write_byte(0x0040, temp_tail, ascii_code);
4816 write_byte(0x0040, temp_tail+1, scan_code);
4817 write_word(0x0040, 0x001C, buffer_tail);
4823 int74_function(make_farcall, Z, Y, X, status)
4824 Bit16u make_farcall, Z, Y, X, status;
4826 Bit16u ebda_seg=read_word(0x0040,0x000E);
4827 Bit8u in_byte, index, package_count;
4828 Bit8u mouse_flags_1, mouse_flags_2;
4830 BX_DEBUG_INT74("entering int74_function\n");
4833 in_byte = inb(0x64);
4834 if ( (in_byte & 0x21) != 0x21 ) {
4837 in_byte = inb(0x60);
4838 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4840 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4841 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4843 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4844 // BX_PANIC("int74_function:\n");
4848 package_count = mouse_flags_2 & 0x07;
4849 index = mouse_flags_1 & 0x07;
4850 write_byte(ebda_seg, 0x28 + index, in_byte);
4852 if ( (index+1) >= package_count ) {
4853 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4854 status = read_byte(ebda_seg, 0x0028 + 0);
4855 X = read_byte(ebda_seg, 0x0028 + 1);
4856 Y = read_byte(ebda_seg, 0x0028 + 2);
4859 // check if far call handler installed
4860 if (mouse_flags_2 & 0x80)
4866 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4869 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4874 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4875 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4878 Bit16u ebda_seg=read_word(0x0040,0x000E);
4879 Bit16u cylinder, head, sector;
4880 Bit16u segment, offset;
4881 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4883 Bit8u device, status;
4885 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4887 write_byte(0x0040, 0x008e, 0); // clear completion flag
4889 // basic check : device has to be defined
4890 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4891 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4895 // Get the ata channel
4896 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4898 // basic check : device has to be valid
4899 if (device >= BX_MAX_ATA_DEVICES) {
4900 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4906 case 0x00: /* disk controller reset */
4911 case 0x01: /* read disk status */
4912 status = read_byte(0x0040, 0x0074);
4914 SET_DISK_RET_STATUS(0);
4915 /* set CF if error status read */
4916 if (status) goto int13_fail_nostatus;
4917 else goto int13_success_noah;
4920 case 0x02: // read disk sectors
4921 case 0x03: // write disk sectors
4922 case 0x04: // verify disk sectors
4925 cylinder = GET_CH();
4926 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4927 sector = (GET_CL() & 0x3f);
4933 if ( (count > 128) || (count == 0) ) {
4934 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4938 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4939 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4940 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4942 // sanity check on cyl heads, sec
4943 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4944 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4949 if ( GET_AH() == 0x04 ) goto int13_success;
4951 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4952 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4954 // if needed, translate lchs to lba, and execute command
4955 if ( (nph != nlh) || (npspt != nlspt)) {
4956 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4957 sector = 0; // this forces the command to be lba
4960 if ( GET_AH() == 0x02 )
4961 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4963 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4965 // Set nb of sector transferred
4966 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4969 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4971 goto int13_fail_noah;
4977 case 0x05: /* format disk track */
4978 BX_INFO("format disk track called\n");
4983 case 0x08: /* read disk drive parameters */
4985 // Get logical geometry from table
4986 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4987 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4988 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4989 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4991 nlc = nlc - 2; /* 0 based , last sector not used */
4994 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4996 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4998 // FIXME should set ES & DI
5003 case 0x10: /* check drive ready */
5004 // should look at 40:8E also???
5006 // Read the status from controller
5007 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5008 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5013 goto int13_fail_noah;
5017 case 0x15: /* read disk drive size */
5019 // Get physical geometry from table
5020 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5021 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5022 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5024 // Compute sector count seen by int13
5025 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5029 SET_AH(3); // hard disk accessible
5030 goto int13_success_noah;
5033 case 0x41: // IBM/MS installation check
5034 BX=0xaa55; // install check
5035 SET_AH(0x30); // EDD 3.0
5036 CX=0x0007; // ext disk access and edd, removable supported
5037 goto int13_success_noah;
5040 case 0x42: // IBM/MS extended read
5041 case 0x43: // IBM/MS extended write
5042 case 0x44: // IBM/MS verify
5043 case 0x47: // IBM/MS extended seek
5045 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5046 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5047 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5049 // Can't use 64 bits lba
5050 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5052 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5056 // Get 32 bits lba and check
5057 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5058 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5059 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5063 // If verify or seek
5064 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5067 // Execute the command
5068 if ( GET_AH() == 0x42 )
5069 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5071 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5073 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5074 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5077 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5079 goto int13_fail_noah;
5085 case 0x45: // IBM/MS lock/unlock drive
5086 case 0x49: // IBM/MS extended media change
5087 goto int13_success; // Always success for HD
5090 case 0x46: // IBM/MS eject media
5091 SET_AH(0xb2); // Volume Not Removable
5092 goto int13_fail_noah; // Always fail for HD
5095 case 0x48: // IBM/MS get drive parameters
5096 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5098 // Buffer is too small
5106 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5107 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5108 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5109 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5110 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5112 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5113 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5114 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5115 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5116 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5117 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5118 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5119 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5124 Bit8u channel, dev, irq, mode, checksum, i, translation;
5125 Bit16u iobase1, iobase2, options;
5127 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5129 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5130 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5133 channel = device / 2;
5134 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5135 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5136 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5137 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5138 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5140 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5141 options |= (1<<4); // lba translation
5142 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5143 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5144 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5146 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5147 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5148 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5149 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5150 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5151 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5152 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5153 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5154 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5155 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5156 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5159 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5160 checksum = ~checksum;
5161 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5166 Bit8u channel, iface, checksum, i;
5169 channel = device / 2;
5170 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5171 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5173 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5174 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5175 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5176 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5177 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5179 if (iface==ATA_IFACE_ISA) {
5180 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5181 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5182 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5183 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5188 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5189 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5190 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5191 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5193 if (iface==ATA_IFACE_ISA) {
5194 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5195 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5196 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5201 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5202 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5203 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5204 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5207 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5208 checksum = ~checksum;
5209 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5215 case 0x4e: // // IBM/MS set hardware configuration
5216 // DMA, prefetch, PIO maximum not supported
5229 case 0x09: /* initialize drive parameters */
5230 case 0x0c: /* seek to specified cylinder */
5231 case 0x0d: /* alternate disk reset */
5232 case 0x11: /* recalibrate */
5233 case 0x14: /* controller internal diagnostic */
5234 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5238 case 0x0a: /* read disk sectors with ECC */
5239 case 0x0b: /* write disk sectors with ECC */
5240 case 0x18: // set media type for format
5241 case 0x50: // IBM/MS send packet command
5243 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5249 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5251 SET_DISK_RET_STATUS(GET_AH());
5252 int13_fail_nostatus:
5253 SET_CF(); // error occurred
5257 SET_AH(0x00); // no error
5259 SET_DISK_RET_STATUS(0x00);
5260 CLEAR_CF(); // no error
5264 // ---------------------------------------------------------------------------
5265 // Start of int13 for cdrom
5266 // ---------------------------------------------------------------------------
5269 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5270 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5272 Bit16u ebda_seg=read_word(0x0040,0x000E);
5273 Bit8u device, status, locks;
5276 Bit16u count, segment, offset, i, size;
5278 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5279 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5281 SET_DISK_RET_STATUS(0x00);
5283 /* basic check : device should be 0xE0+ */
5284 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5285 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5289 // Get the ata channel
5290 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5292 /* basic check : device has to be valid */
5293 if (device >= BX_MAX_ATA_DEVICES) {
5294 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5300 // all those functions return SUCCESS
5301 case 0x00: /* disk controller reset */
5302 case 0x09: /* initialize drive parameters */
5303 case 0x0c: /* seek to specified cylinder */
5304 case 0x0d: /* alternate disk reset */
5305 case 0x10: /* check drive ready */
5306 case 0x11: /* recalibrate */
5307 case 0x14: /* controller internal diagnostic */
5308 case 0x16: /* detect disk change */
5312 // all those functions return disk write-protected
5313 case 0x03: /* write disk sectors */
5314 case 0x05: /* format disk track */
5315 case 0x43: // IBM/MS extended write
5317 goto int13_fail_noah;
5320 case 0x01: /* read disk status */
5321 status = read_byte(0x0040, 0x0074);
5323 SET_DISK_RET_STATUS(0);
5325 /* set CF if error status read */
5326 if (status) goto int13_fail_nostatus;
5327 else goto int13_success_noah;
5330 case 0x15: /* read disk drive size */
5332 goto int13_fail_noah;
5335 case 0x41: // IBM/MS installation check
5336 BX=0xaa55; // install check
5337 SET_AH(0x30); // EDD 2.1
5338 CX=0x0007; // ext disk access, removable and edd
5339 goto int13_success_noah;
5342 case 0x42: // IBM/MS extended read
5343 case 0x44: // IBM/MS verify sectors
5344 case 0x47: // IBM/MS extended seek
5346 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5347 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5348 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5350 // Can't use 64 bits lba
5351 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5353 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5358 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5360 // If verify or seek
5361 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5364 memsetb(get_SS(),atacmd,0,12);
5365 atacmd[0]=0x28; // READ command
5366 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5367 atacmd[8]=(count & 0x00ff); // Sectors
5368 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5369 atacmd[3]=(lba & 0x00ff0000) >> 16;
5370 atacmd[4]=(lba & 0x0000ff00) >> 8;
5371 atacmd[5]=(lba & 0x000000ff);
5372 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5374 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5375 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5378 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5380 goto int13_fail_noah;
5386 case 0x45: // IBM/MS lock/unlock drive
5387 if (GET_AL() > 2) goto int13_fail;
5389 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5393 if (locks == 0xff) {
5396 goto int13_fail_noah;
5398 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5402 if (locks == 0x00) {
5405 goto int13_fail_noah;
5407 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5408 SET_AL(locks==0?0:1);
5411 SET_AL(locks==0?0:1);
5417 case 0x46: // IBM/MS eject media
5418 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5421 SET_AH(0xb1); // media locked
5422 goto int13_fail_noah;
5424 // FIXME should handle 0x31 no media in device
5425 // FIXME should handle 0xb5 valid request failed
5427 // Call removable media eject
5434 mov _int13_cdrom.status + 2[bp], ah
5435 jnc int13_cdrom_rme_end
5436 mov _int13_cdrom.status, #1
5437 int13_cdrom_rme_end:
5442 SET_AH(0xb1); // media locked
5443 goto int13_fail_noah;
5449 case 0x48: // IBM/MS get drive parameters
5450 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5452 // Buffer is too small
5458 Bit16u cylinders, heads, spt, blksize;
5460 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5462 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5463 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5464 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5465 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5466 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5467 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5468 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5469 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5474 Bit8u channel, dev, irq, mode, checksum, i;
5475 Bit16u iobase1, iobase2, options;
5477 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5479 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5480 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5483 channel = device / 2;
5484 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5485 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5486 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5487 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5489 // FIXME atapi device
5490 options = (1<<4); // lba translation
5491 options |= (1<<5); // removable device
5492 options |= (1<<6); // atapi device
5493 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5495 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5496 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5497 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5498 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5499 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5500 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5501 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5502 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5503 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5504 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5505 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5508 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5509 checksum = ~checksum;
5510 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5515 Bit8u channel, iface, checksum, i;
5518 channel = device / 2;
5519 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5520 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5522 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5523 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5524 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5525 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5526 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5528 if (iface==ATA_IFACE_ISA) {
5529 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5530 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5531 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5532 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5537 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5538 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5539 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5540 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5542 if (iface==ATA_IFACE_ISA) {
5543 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5544 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5545 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5550 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5551 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5552 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5553 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5556 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5557 checksum = ~checksum;
5558 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5564 case 0x49: // IBM/MS extended media change
5565 // always send changed ??
5567 goto int13_fail_nostatus;
5570 case 0x4e: // // IBM/MS set hardware configuration
5571 // DMA, prefetch, PIO maximum not supported
5584 // all those functions return unimplemented
5585 case 0x02: /* read sectors */
5586 case 0x04: /* verify sectors */
5587 case 0x08: /* read disk drive parameters */
5588 case 0x0a: /* read disk sectors with ECC */
5589 case 0x0b: /* write disk sectors with ECC */
5590 case 0x18: /* set media type for format */
5591 case 0x50: // ? - send packet command
5593 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5599 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5601 SET_DISK_RET_STATUS(GET_AH());
5602 int13_fail_nostatus:
5603 SET_CF(); // error occurred
5607 SET_AH(0x00); // no error
5609 SET_DISK_RET_STATUS(0x00);
5610 CLEAR_CF(); // no error
5614 // ---------------------------------------------------------------------------
5615 // End of int13 for cdrom
5616 // ---------------------------------------------------------------------------
5618 #if BX_ELTORITO_BOOT
5619 // ---------------------------------------------------------------------------
5620 // Start of int13 for eltorito functions
5621 // ---------------------------------------------------------------------------
5624 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5625 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5627 Bit16u ebda_seg=read_word(0x0040,0x000E);
5629 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5630 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5634 // FIXME ElTorito Various. Should be implemented
5635 case 0x4a: // ElTorito - Initiate disk emu
5636 case 0x4c: // ElTorito - Initiate disk emu and boot
5637 case 0x4d: // ElTorito - Return Boot catalog
5638 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5642 case 0x4b: // ElTorito - Terminate disk emu
5643 // FIXME ElTorito Hardcoded
5644 write_byte(DS,SI+0x00,0x13);
5645 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5646 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5647 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5648 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5649 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5650 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5651 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5652 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5653 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5654 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5655 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5657 // If we have to terminate emulation
5658 if(GET_AL() == 0x00) {
5659 // FIXME ElTorito Various. Should be handled accordingly to spec
5660 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5667 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5673 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5674 SET_DISK_RET_STATUS(GET_AH());
5675 SET_CF(); // error occurred
5679 SET_AH(0x00); // no error
5680 SET_DISK_RET_STATUS(0x00);
5681 CLEAR_CF(); // no error
5685 // ---------------------------------------------------------------------------
5686 // End of int13 for eltorito functions
5687 // ---------------------------------------------------------------------------
5689 // ---------------------------------------------------------------------------
5690 // Start of int13 when emulating a device from the cd
5691 // ---------------------------------------------------------------------------
5694 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5695 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5697 Bit16u ebda_seg=read_word(0x0040,0x000E);
5698 Bit8u device, status;
5699 Bit16u vheads, vspt, vcylinders;
5700 Bit16u head, sector, cylinder, nbsectors;
5701 Bit32u vlba, ilba, slba, elba;
5702 Bit16u before, segment, offset;
5705 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5706 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5708 /* at this point, we are emulating a floppy/harddisk */
5710 // Recompute the device number
5711 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5712 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5714 SET_DISK_RET_STATUS(0x00);
5716 /* basic checks : emulation should be active, dl should equal the emulated drive */
5717 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5718 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5719 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5725 // all those functions return SUCCESS
5726 case 0x00: /* disk controller reset */
5727 case 0x09: /* initialize drive parameters */
5728 case 0x0c: /* seek to specified cylinder */
5729 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5730 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5731 case 0x11: /* recalibrate */
5732 case 0x14: /* controller internal diagnostic */
5733 case 0x16: /* detect disk change */
5737 // all those functions return disk write-protected
5738 case 0x03: /* write disk sectors */
5739 case 0x05: /* format disk track */
5741 goto int13_fail_noah;
5744 case 0x01: /* read disk status */
5745 status=read_byte(0x0040, 0x0074);
5747 SET_DISK_RET_STATUS(0);
5749 /* set CF if error status read */
5750 if (status) goto int13_fail_nostatus;
5751 else goto int13_success_noah;
5754 case 0x02: // read disk sectors
5755 case 0x04: // verify disk sectors
5756 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5757 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5758 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5760 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5762 sector = GET_CL() & 0x003f;
5763 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5765 nbsectors = GET_AL();
5769 // no sector to read ?
5770 if(nbsectors==0) goto int13_success;
5772 // sanity checks sco openserver needs this!
5774 || (cylinder >= vcylinders)
5775 || (head >= vheads)) {
5779 // After controls, verify do nothing
5780 if (GET_AH() == 0x04) goto int13_success;
5782 segment = ES+(BX / 16);
5785 // calculate the virtual lba inside the image
5786 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5788 // In advance so we don't loose the count
5792 slba = (Bit32u)vlba/4;
5793 before= (Bit16u)vlba%4;
5796 elba = (Bit32u)(vlba+nbsectors-1)/4;
5798 memsetb(get_SS(),atacmd,0,12);
5799 atacmd[0]=0x28; // READ command
5800 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5801 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5802 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5803 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5804 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5805 atacmd[5]=(ilba+slba & 0x000000ff);
5806 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5807 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5810 goto int13_fail_noah;
5816 case 0x08: /* read disk drive parameters */
5817 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5818 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5819 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5823 SET_CH( vcylinders & 0xff );
5824 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5826 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5827 // FIXME ElTorito Harddisk. should send the HD count
5829 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5830 case 0x01: SET_BL( 0x02 ); break;
5831 case 0x02: SET_BL( 0x04 ); break;
5832 case 0x03: SET_BL( 0x06 ); break;
5838 mov ax, #diskette_param_table2
5839 mov _int13_cdemu.DI+2[bp], ax
5840 mov _int13_cdemu.ES+2[bp], cs
5846 case 0x15: /* read disk drive size */
5847 // FIXME ElTorito Harddisk. What geometry to send ?
5849 goto int13_success_noah;
5852 // all those functions return unimplemented
5853 case 0x0a: /* read disk sectors with ECC */
5854 case 0x0b: /* write disk sectors with ECC */
5855 case 0x18: /* set media type for format */
5856 case 0x41: // IBM/MS installation check
5857 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5858 case 0x42: // IBM/MS extended read
5859 case 0x43: // IBM/MS extended write
5860 case 0x44: // IBM/MS verify sectors
5861 case 0x45: // IBM/MS lock/unlock drive
5862 case 0x46: // IBM/MS eject media
5863 case 0x47: // IBM/MS extended seek
5864 case 0x48: // IBM/MS get drive parameters
5865 case 0x49: // IBM/MS extended media change
5866 case 0x4e: // ? - set hardware configuration
5867 case 0x50: // ? - send packet command
5869 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5875 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5877 SET_DISK_RET_STATUS(GET_AH());
5878 int13_fail_nostatus:
5879 SET_CF(); // error occurred
5883 SET_AH(0x00); // no error
5885 SET_DISK_RET_STATUS(0x00);
5886 CLEAR_CF(); // no error
5890 // ---------------------------------------------------------------------------
5891 // End of int13 when emulating a device from the cd
5892 // ---------------------------------------------------------------------------
5894 #endif // BX_ELTORITO_BOOT
5896 #else //BX_USE_ATADRV
5899 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5914 mov ax,4[bp] // cylinder
5916 mov bl,6[bp] // hd_heads
5919 mov bl,8[bp] // head
5921 mov bl,10[bp] // hd_sectors
5923 mov bl,12[bp] // sector
5952 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5953 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5955 Bit8u drive, num_sectors, sector, head, status, mod;
5959 Bit16u max_cylinder, cylinder, total_sectors;
5960 Bit16u hd_cylinders;
5961 Bit8u hd_heads, hd_sectors;
5968 Bit16u count, segment, offset;
5972 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5974 write_byte(0x0040, 0x008e, 0); // clear completion flag
5976 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5978 /* check how many disks first (cmos reg 0x12), return an error if
5979 drive not present */
5980 drive_map = inb_cmos(0x12);
5981 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5982 (((drive_map & 0x0f)==0) ? 0 : 2);
5983 n_drives = (drive_map==0) ? 0 :
5984 ((drive_map==3) ? 2 : 1);
5986 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5988 SET_DISK_RET_STATUS(0x01);
5989 SET_CF(); /* error occurred */
5995 case 0x00: /* disk controller reset */
5996 BX_DEBUG_INT13_HD("int13_f00\n");
5999 SET_DISK_RET_STATUS(0);
6000 set_diskette_ret_status(0);
6001 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6002 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6003 CLEAR_CF(); /* successful */
6007 case 0x01: /* read disk status */
6008 BX_DEBUG_INT13_HD("int13_f01\n");
6009 status = read_byte(0x0040, 0x0074);
6011 SET_DISK_RET_STATUS(0);
6012 /* set CF if error status read */
6013 if (status) SET_CF();
6018 case 0x04: // verify disk sectors
6019 case 0x02: // read disk sectors
6021 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6023 num_sectors = GET_AL();
6024 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6025 sector = (GET_CL() & 0x3f);
6029 if (hd_cylinders > 1024) {
6030 if (hd_cylinders <= 2048) {
6033 else if (hd_cylinders <= 4096) {
6036 else if (hd_cylinders <= 8192) {
6039 else { // hd_cylinders <= 16384
6043 ax = head / hd_heads;
6044 cyl_mod = ax & 0xff;
6046 cylinder |= cyl_mod;
6049 if ( (cylinder >= hd_cylinders) ||
6050 (sector > hd_sectors) ||
6051 (head >= hd_heads) ) {
6053 SET_DISK_RET_STATUS(1);
6054 SET_CF(); /* error occurred */
6058 if ( (num_sectors > 128) || (num_sectors == 0) )
6059 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6062 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6064 if ( GET_AH() == 0x04 ) {
6066 SET_DISK_RET_STATUS(0);
6071 status = inb(0x1f7);
6072 if (status & 0x80) {
6073 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6075 outb(0x01f2, num_sectors);
6076 /* activate LBA? (tomv) */
6077 if (hd_heads > 16) {
6078 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6079 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6082 outb(0x01f3, sector);
6083 outb(0x01f4, cylinder & 0x00ff);
6084 outb(0x01f5, cylinder >> 8);
6085 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6090 status = inb(0x1f7);
6091 if ( !(status & 0x80) ) break;
6094 if (status & 0x01) {
6095 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6096 } else if ( !(status & 0x08) ) {
6097 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6098 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6105 sti ;; enable higher priority interrupts
6110 ;; store temp bx in real DI register
6113 mov di, _int13_harddisk.tempbx + 2 [bp]
6116 ;; adjust if there will be an overrun
6118 jbe i13_f02_no_adjust
6120 sub di, #0x0200 ; sub 512 bytes from offset
6122 add ax, #0x0020 ; add 512 to segment
6126 mov cx, #0x0100 ;; counter (256 words = 512b)
6127 mov dx, #0x01f0 ;; AT data read port
6130 insw ;; CX words transfered from port(DX) to ES:[DI]
6133 ;; store real DI register back to temp bx
6136 mov _int13_harddisk.tempbx + 2 [bp], di
6142 if (num_sectors == 0) {
6143 status = inb(0x1f7);
6144 if ( (status & 0xc9) != 0x40 )
6145 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6149 status = inb(0x1f7);
6150 if ( (status & 0xc9) != 0x48 )
6151 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6157 SET_DISK_RET_STATUS(0);
6158 SET_AL(sector_count);
6159 CLEAR_CF(); /* successful */
6164 case 0x03: /* write disk sectors */
6165 BX_DEBUG_INT13_HD("int13_f03\n");
6166 drive = GET_ELDL ();
6167 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6169 num_sectors = GET_AL();
6170 cylinder = GET_CH();
6171 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6172 sector = (GET_CL() & 0x3f);
6175 if (hd_cylinders > 1024) {
6176 if (hd_cylinders <= 2048) {
6179 else if (hd_cylinders <= 4096) {
6182 else if (hd_cylinders <= 8192) {
6185 else { // hd_cylinders <= 16384
6189 ax = head / hd_heads;
6190 cyl_mod = ax & 0xff;
6192 cylinder |= cyl_mod;
6195 if ( (cylinder >= hd_cylinders) ||
6196 (sector > hd_sectors) ||
6197 (head >= hd_heads) ) {
6199 SET_DISK_RET_STATUS(1);
6200 SET_CF(); /* error occurred */
6204 if ( (num_sectors > 128) || (num_sectors == 0) )
6205 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6208 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6210 status = inb(0x1f7);
6211 if (status & 0x80) {
6212 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6214 // should check for Drive Ready Bit also in status reg
6215 outb(0x01f2, num_sectors);
6217 /* activate LBA? (tomv) */
6218 if (hd_heads > 16) {
6219 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6220 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6223 outb(0x01f3, sector);
6224 outb(0x01f4, cylinder & 0x00ff);
6225 outb(0x01f5, cylinder >> 8);
6226 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6230 // wait for busy bit to turn off after seeking
6232 status = inb(0x1f7);
6233 if ( !(status & 0x80) ) break;
6236 if ( !(status & 0x08) ) {
6237 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6238 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6245 sti ;; enable higher priority interrupts
6250 ;; store temp bx in real SI register
6253 mov si, _int13_harddisk.tempbx + 2 [bp]
6256 ;; adjust if there will be an overrun
6258 jbe i13_f03_no_adjust
6260 sub si, #0x0200 ; sub 512 bytes from offset
6262 add ax, #0x0020 ; add 512 to segment
6266 mov cx, #0x0100 ;; counter (256 words = 512b)
6267 mov dx, #0x01f0 ;; AT data read port
6271 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6273 ;; store real SI register back to temp bx
6276 mov _int13_harddisk.tempbx + 2 [bp], si
6282 if (num_sectors == 0) {
6283 status = inb(0x1f7);
6284 if ( (status & 0xe9) != 0x40 )
6285 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6289 status = inb(0x1f7);
6290 if ( (status & 0xc9) != 0x48 )
6291 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6297 SET_DISK_RET_STATUS(0);
6298 SET_AL(sector_count);
6299 CLEAR_CF(); /* successful */
6303 case 0x05: /* format disk track */
6304 BX_DEBUG_INT13_HD("int13_f05\n");
6305 BX_PANIC("format disk track called\n");
6308 SET_DISK_RET_STATUS(0);
6309 CLEAR_CF(); /* successful */
6313 case 0x08: /* read disk drive parameters */
6314 BX_DEBUG_INT13_HD("int13_f08\n");
6316 drive = GET_ELDL ();
6317 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6321 if (hd_cylinders <= 1024) {
6322 // hd_cylinders >>= 0;
6325 else if (hd_cylinders <= 2048) {
6329 else if (hd_cylinders <= 4096) {
6333 else if (hd_cylinders <= 8192) {
6337 else { // hd_cylinders <= 16384
6342 max_cylinder = hd_cylinders - 2; /* 0 based */
6344 SET_CH(max_cylinder & 0xff);
6345 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6346 SET_DH(hd_heads - 1);
6347 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6349 SET_DISK_RET_STATUS(0);
6350 CLEAR_CF(); /* successful */
6355 case 0x09: /* initialize drive parameters */
6356 BX_DEBUG_INT13_HD("int13_f09\n");
6358 SET_DISK_RET_STATUS(0);
6359 CLEAR_CF(); /* successful */
6363 case 0x0a: /* read disk sectors with ECC */
6364 BX_DEBUG_INT13_HD("int13_f0a\n");
6365 case 0x0b: /* write disk sectors with ECC */
6366 BX_DEBUG_INT13_HD("int13_f0b\n");
6367 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6371 case 0x0c: /* seek to specified cylinder */
6372 BX_DEBUG_INT13_HD("int13_f0c\n");
6373 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6375 SET_DISK_RET_STATUS(0);
6376 CLEAR_CF(); /* successful */
6380 case 0x0d: /* alternate disk reset */
6381 BX_DEBUG_INT13_HD("int13_f0d\n");
6383 SET_DISK_RET_STATUS(0);
6384 CLEAR_CF(); /* successful */
6388 case 0x10: /* check drive ready */
6389 BX_DEBUG_INT13_HD("int13_f10\n");
6391 //SET_DISK_RET_STATUS(0);
6392 //CLEAR_CF(); /* successful */
6396 // should look at 40:8E also???
6397 status = inb(0x01f7);
6398 if ( (status & 0xc0) == 0x40 ) {
6400 SET_DISK_RET_STATUS(0);
6401 CLEAR_CF(); // drive ready
6406 SET_DISK_RET_STATUS(0xAA);
6407 SET_CF(); // not ready
6412 case 0x11: /* recalibrate */
6413 BX_DEBUG_INT13_HD("int13_f11\n");
6415 SET_DISK_RET_STATUS(0);
6416 CLEAR_CF(); /* successful */
6420 case 0x14: /* controller internal diagnostic */
6421 BX_DEBUG_INT13_HD("int13_f14\n");
6423 SET_DISK_RET_STATUS(0);
6424 CLEAR_CF(); /* successful */
6429 case 0x15: /* read disk drive size */
6431 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6435 mov al, _int13_harddisk.hd_heads + 2 [bp]
6436 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6437 mul al, ah ;; ax = heads * sectors
6438 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6439 dec bx ;; use (cylinders - 1) ???
6440 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6441 ;; now we need to move the 32bit result dx:ax to what the
6442 ;; BIOS wants which is cx:dx.
6443 ;; and then into CX:DX on the stack
6444 mov _int13_harddisk.CX + 2 [bp], dx
6445 mov _int13_harddisk.DX + 2 [bp], ax
6448 SET_AH(3); // hard disk accessible
6449 SET_DISK_RET_STATUS(0); // ??? should this be 0
6450 CLEAR_CF(); // successful
6454 case 0x18: // set media type for format
6455 case 0x41: // IBM/MS
6456 case 0x42: // IBM/MS
6457 case 0x43: // IBM/MS
6458 case 0x44: // IBM/MS
6459 case 0x45: // IBM/MS lock/unlock drive
6460 case 0x46: // IBM/MS eject media
6461 case 0x47: // IBM/MS extended seek
6462 case 0x49: // IBM/MS extended media change
6463 case 0x50: // IBM/MS send packet command
6465 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6467 SET_AH(1); // code=invalid function in AH or invalid parameter
6468 SET_DISK_RET_STATUS(1);
6469 SET_CF(); /* unsuccessful */
6475 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6476 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6479 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6481 Bit16u *hd_cylinders;
6491 if (drive == 0x80) {
6492 hd_type = inb_cmos(0x12) & 0xf0;
6493 if (hd_type != 0xf0)
6494 BX_INFO(panic_msg_reg12h,0);
6495 hd_type = inb_cmos(0x19); // HD0: extended type
6497 BX_INFO(panic_msg_reg19h,0,0x19);
6500 hd_type = inb_cmos(0x12) & 0x0f;
6501 if (hd_type != 0x0f)
6502 BX_INFO(panic_msg_reg12h,1);
6503 hd_type = inb_cmos(0x1a); // HD0: extended type
6505 BX_INFO(panic_msg_reg19h,0,0x1a);
6510 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6511 write_word(ss, hd_cylinders, cylinders);
6514 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6516 // sectors per track
6517 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6520 #endif //else BX_USE_ATADRV
6523 //////////////////////
6524 // FLOPPY functions //
6525 //////////////////////
6528 floppy_media_known(drive)
6532 Bit16u media_state_offset;
6534 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6541 media_state_offset = 0x0090;
6543 media_state_offset += 1;
6545 val8 = read_byte(0x0040, media_state_offset);
6546 val8 = (val8 >> 4) & 0x01;
6550 // check pass, return KNOWN
6555 floppy_media_sense(drive)
6559 Bit16u media_state_offset;
6560 Bit8u drive_type, config_data, media_state;
6562 if (floppy_drive_recal(drive) == 0) {
6566 // for now cheat and get drive type from CMOS,
6567 // assume media is same as drive type
6569 // ** config_data **
6570 // Bitfields for diskette media control:
6571 // Bit(s) Description (Table M0028)
6572 // 7-6 last data rate set by controller
6573 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6574 // 5-4 last diskette drive step rate selected
6575 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6576 // 3-2 {data rate at start of operation}
6579 // ** media_state **
6580 // Bitfields for diskette drive media state:
6581 // Bit(s) Description (Table M0030)
6583 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6584 // 5 double stepping required (e.g. 360kB in 1.2MB)
6585 // 4 media type established
6586 // 3 drive capable of supporting 4MB media
6587 // 2-0 on exit from BIOS, contains
6588 // 000 trying 360kB in 360kB
6589 // 001 trying 360kB in 1.2MB
6590 // 010 trying 1.2MB in 1.2MB
6591 // 011 360kB in 360kB established
6592 // 100 360kB in 1.2MB established
6593 // 101 1.2MB in 1.2MB established
6595 // 111 all other formats/drives
6597 drive_type = inb_cmos(0x10);
6602 if ( drive_type == 1 ) {
6604 config_data = 0x00; // 0000 0000
6605 media_state = 0x25; // 0010 0101
6608 else if ( drive_type == 2 ) {
6609 // 1.2 MB 5.25" drive
6610 config_data = 0x00; // 0000 0000
6611 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6614 else if ( drive_type == 3 ) {
6616 config_data = 0x00; // 0000 0000 ???
6617 media_state = 0x17; // 0001 0111
6620 else if ( drive_type == 4 ) {
6621 // 1.44 MB 3.5" drive
6622 config_data = 0x00; // 0000 0000
6623 media_state = 0x17; // 0001 0111
6626 else if ( drive_type == 5 ) {
6627 // 2.88 MB 3.5" drive
6628 config_data = 0xCC; // 1100 1100
6629 media_state = 0xD7; // 1101 0111
6633 // Extended floppy size uses special cmos setting
6634 else if ( drive_type == 6 ) {
6636 config_data = 0x00; // 0000 0000
6637 media_state = 0x27; // 0010 0111
6640 else if ( drive_type == 7 ) {
6642 config_data = 0x00; // 0000 0000
6643 media_state = 0x27; // 0010 0111
6646 else if ( drive_type == 8 ) {
6648 config_data = 0x00; // 0000 0000
6649 media_state = 0x27; // 0010 0111
6655 config_data = 0x00; // 0000 0000
6656 media_state = 0x00; // 0000 0000
6661 media_state_offset = 0x90;
6663 media_state_offset = 0x91;
6664 write_byte(0x0040, 0x008B, config_data);
6665 write_byte(0x0040, media_state_offset, media_state);
6671 floppy_drive_recal(drive)
6675 Bit16u curr_cyl_offset;
6677 // set 40:3e bit 7 to 0
6678 val8 = read_byte(0x0000, 0x043e);
6680 write_byte(0x0000, 0x043e, val8);
6682 // turn on motor of selected drive, DMA & int enabled, normal operation
6691 // reset the disk motor timeout value of INT 08
6692 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6694 // check port 3f4 for drive readiness
6696 if ( (val8 & 0xf0) != 0x80 )
6697 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6699 // send Recalibrate command (2 bytes) to controller
6700 outb(0x03f5, 0x07); // 07: Recalibrate
6701 outb(0x03f5, drive); // 0=drive0, 1=drive1
6703 // turn on interrupts
6708 // wait on 40:3e bit 7 to become 1
6709 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6710 while ( val8 == 0 ) {
6711 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6714 val8 = 0; // separate asm from while() loop
6715 // turn off interrupts
6720 // set 40:3e bit 7 to 0, and calibrated bit
6721 val8 = read_byte(0x0000, 0x043e);
6724 val8 |= 0x02; // Drive 1 calibrated
6725 curr_cyl_offset = 0x0095;
6728 val8 |= 0x01; // Drive 0 calibrated
6729 curr_cyl_offset = 0x0094;
6731 write_byte(0x0040, 0x003e, val8);
6732 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6740 floppy_drive_exists(drive)
6745 // just tell it both drives exist - PAD
6748 // check CMOS to see if drive exists
6749 drive_type = inb_cmos(0x10);
6754 if ( drive_type == 0 )
6760 #if BX_SUPPORT_FLOPPY
6762 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6763 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6765 Bit8u drive, num_sectors, track, sector, head, status;
6766 Bit16u base_address, base_count, base_es;
6767 Bit8u page, mode_register, val8, dor;
6768 Bit8u return_status[7];
6769 Bit8u drive_type, num_floppies, ah;
6770 Bit16u es, last_addr;
6772 printf("In int13_diskette\n");
6774 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6775 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6780 case 0x00: // diskette controller reset
6781 BX_DEBUG_INT13_FL("floppy f00\n");
6784 SET_AH(1); // invalid param
6785 set_diskette_ret_status(1);
6789 drive_type = inb_cmos(0x10);
6795 if (drive_type == 0) {
6796 SET_AH(0x80); // drive not responding
6797 set_diskette_ret_status(0x80);
6802 set_diskette_ret_status(0);
6803 CLEAR_CF(); // successful
6804 set_diskette_current_cyl(drive, 0); // current cylinder
6807 case 0x01: // Read Diskette Status
6809 val8 = read_byte(0x0000, 0x0441);
6816 case 0x02: // Read Diskette Sectors
6817 case 0x03: // Write Diskette Sectors
6818 case 0x04: // Verify Diskette Sectors
6819 num_sectors = GET_AL();
6825 if ( (drive > 1) || (head > 1) ||
6826 (num_sectors == 0) || (num_sectors > 72) ) {
6827 BX_INFO("floppy: drive>1 || head>1 ...\n");
6829 set_diskette_ret_status(1);
6830 SET_AL(0); // no sectors read
6831 SET_CF(); // error occurred
6835 // see if drive exists
6836 if (floppy_drive_exists(drive) == 0) {
6837 SET_AH(0x80); // not responding
6838 set_diskette_ret_status(0x80);
6839 SET_AL(0); // no sectors read
6840 SET_CF(); // error occurred
6844 // see if media in drive, and type is known
6845 if (floppy_media_known(drive) == 0) {
6846 if (floppy_media_sense(drive) == 0) {
6847 SET_AH(0x0C); // Media type not found
6848 set_diskette_ret_status(0x0C);
6849 SET_AL(0); // no sectors read
6850 SET_CF(); // error occurred
6856 // Read Diskette Sectors
6858 //-----------------------------------
6859 // set up DMA controller for transfer
6860 //-----------------------------------
6862 // es:bx = pointer to where to place information from diskette
6863 // port 04: DMA-1 base and current address, channel 2
6864 // port 05: DMA-1 base and current count, channel 2
6865 page = (ES >> 12); // upper 4 bits
6866 base_es = (ES << 4); // lower 16bits contributed by ES
6867 base_address = base_es + BX; // lower 16 bits of address
6868 // contributed by ES:BX
6869 if ( base_address < base_es ) {
6870 // in case of carry, adjust page by 1
6873 base_count = (num_sectors * 512) - 1;
6875 // check for 64K boundary overrun
6876 last_addr = base_address + base_count;
6877 if (last_addr < base_address) {
6879 set_diskette_ret_status(0x09);
6880 SET_AL(0); // no sectors read
6881 SET_CF(); // error occurred
6885 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6888 BX_DEBUG_INT13_FL("clear flip-flop\n");
6889 outb(0x000c, 0x00); // clear flip-flop
6890 outb(0x0004, base_address);
6891 outb(0x0004, base_address>>8);
6892 BX_DEBUG_INT13_FL("clear flip-flop\n");
6893 outb(0x000c, 0x00); // clear flip-flop
6894 outb(0x0005, base_count);
6895 outb(0x0005, base_count>>8);
6897 // port 0b: DMA-1 Mode Register
6898 mode_register = 0x46; // single mode, increment, autoinit disable,
6899 // transfer type=write, channel 2
6900 BX_DEBUG_INT13_FL("setting mode register\n");
6901 outb(0x000b, mode_register);
6903 BX_DEBUG_INT13_FL("setting page register\n");
6904 // port 81: DMA-1 Page Register, channel 2
6907 BX_DEBUG_INT13_FL("unmask chan 2\n");
6908 outb(0x000a, 0x02); // unmask channel 2
6910 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6913 //--------------------------------------
6914 // set up floppy controller for transfer
6915 //--------------------------------------
6917 // set 40:3e bit 7 to 0
6918 val8 = read_byte(0x0000, 0x043e);
6920 write_byte(0x0000, 0x043e, val8);
6922 // turn on motor of selected drive, DMA & int enabled, normal operation
6931 // reset the disk motor timeout value of INT 08
6932 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6934 // check port 3f4 for drive readiness
6936 if ( (val8 & 0xf0) != 0x80 )
6937 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6939 // send read-normal-data command (9 bytes) to controller
6940 outb(0x03f5, 0xe6); // e6: read normal data
6941 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6942 outb(0x03f5, track);
6944 outb(0x03f5, sector);
6945 outb(0x03f5, 2); // 512 byte sector size
6946 outb(0x03f5, 0); // last sector number possible on track
6947 outb(0x03f5, 0); // Gap length
6948 outb(0x03f5, 0xff); // Gap length
6950 // turn on interrupts
6955 // wait on 40:3e bit 7 to become 1
6956 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6957 while ( val8 == 0 ) {
6958 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6961 val8 = 0; // separate asm from while() loop
6962 // turn off interrupts
6967 // set 40:3e bit 7 to 0
6968 val8 = read_byte(0x0000, 0x043e);
6970 write_byte(0x0000, 0x043e, val8);
6972 // check port 3f4 for accessibility to status bytes
6974 if ( (val8 & 0xc0) != 0xc0 )
6975 BX_PANIC("int13_diskette: ctrl not ready\n");
6977 // read 7 return status bytes from controller
6978 // using loop index broken, have to unroll...
6979 return_status[0] = inb(0x3f5);
6980 return_status[1] = inb(0x3f5);
6981 return_status[2] = inb(0x3f5);
6982 return_status[3] = inb(0x3f5);
6983 return_status[4] = inb(0x3f5);
6984 return_status[5] = inb(0x3f5);
6985 return_status[6] = inb(0x3f5);
6986 // record in BIOS Data Area
6987 write_byte(0x0040, 0x0042, return_status[0]);
6988 write_byte(0x0040, 0x0043, return_status[1]);
6989 write_byte(0x0040, 0x0044, return_status[2]);
6990 write_byte(0x0040, 0x0045, return_status[3]);
6991 write_byte(0x0040, 0x0046, return_status[4]);
6992 write_byte(0x0040, 0x0047, return_status[5]);
6993 write_byte(0x0040, 0x0048, return_status[6]);
6995 if ( (return_status[0] & 0xc0) != 0 ) {
6997 set_diskette_ret_status(0x20);
6998 SET_AL(0); // no sectors read
6999 SET_CF(); // error occurred
7003 // ??? should track be new val from return_status[3] ?
7004 set_diskette_current_cyl(drive, track);
7005 // AL = number of sectors read (same value as passed)
7006 SET_AH(0x00); // success
7007 CLEAR_CF(); // success
7010 else if (ah == 0x03) {
7011 // Write Diskette Sectors
7013 //-----------------------------------
7014 // set up DMA controller for transfer
7015 //-----------------------------------
7017 // es:bx = pointer to where to place information from diskette
7018 // port 04: DMA-1 base and current address, channel 2
7019 // port 05: DMA-1 base and current count, channel 2
7020 page = (ES >> 12); // upper 4 bits
7021 base_es = (ES << 4); // lower 16bits contributed by ES
7022 base_address = base_es + BX; // lower 16 bits of address
7023 // contributed by ES:BX
7024 if ( base_address < base_es ) {
7025 // in case of carry, adjust page by 1
7028 base_count = (num_sectors * 512) - 1;
7030 // check for 64K boundary overrun
7031 last_addr = base_address + base_count;
7032 if (last_addr < base_address) {
7034 set_diskette_ret_status(0x09);
7035 SET_AL(0); // no sectors read
7036 SET_CF(); // error occurred
7040 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7043 outb(0x000c, 0x00); // clear flip-flop
7044 outb(0x0004, base_address);
7045 outb(0x0004, base_address>>8);
7046 outb(0x000c, 0x00); // clear flip-flop
7047 outb(0x0005, base_count);
7048 outb(0x0005, base_count>>8);
7050 // port 0b: DMA-1 Mode Register
7051 mode_register = 0x4a; // single mode, increment, autoinit disable,
7052 // transfer type=read, channel 2
7053 outb(0x000b, mode_register);
7055 // port 81: DMA-1 Page Register, channel 2
7058 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7061 //--------------------------------------
7062 // set up floppy controller for transfer
7063 //--------------------------------------
7065 // set 40:3e bit 7 to 0
7066 val8 = read_byte(0x0000, 0x043e);
7068 write_byte(0x0000, 0x043e, val8);
7070 // turn on motor of selected drive, DMA & int enabled, normal operation
7079 // reset the disk motor timeout value of INT 08
7080 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7082 // check port 3f4 for drive readiness
7084 if ( (val8 & 0xf0) != 0x80 )
7085 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7087 // send read-normal-data command (9 bytes) to controller
7088 outb(0x03f5, 0xc5); // c5: write normal data
7089 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7090 outb(0x03f5, track);
7092 outb(0x03f5, sector);
7093 outb(0x03f5, 2); // 512 byte sector size
7094 outb(0x03f5, 0); // last sector number possible on track
7095 outb(0x03f5, 0); // Gap length
7096 outb(0x03f5, 0xff); // Gap length
7098 // turn on interrupts
7103 // wait on 40:3e bit 7 to become 1
7104 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7105 while ( val8 == 0 ) {
7106 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7109 val8 = 0; // separate asm from while() loop
7110 // turn off interrupts
7115 // set 40:3e bit 7 to 0
7116 val8 = read_byte(0x0000, 0x043e);
7118 write_byte(0x0000, 0x043e, val8);
7120 // check port 3f4 for accessibility to status bytes
7122 if ( (val8 & 0xc0) != 0xc0 )
7123 BX_PANIC("int13_diskette: ctrl not ready\n");
7125 // read 7 return status bytes from controller
7126 // using loop index broken, have to unroll...
7127 return_status[0] = inb(0x3f5);
7128 return_status[1] = inb(0x3f5);
7129 return_status[2] = inb(0x3f5);
7130 return_status[3] = inb(0x3f5);
7131 return_status[4] = inb(0x3f5);
7132 return_status[5] = inb(0x3f5);
7133 return_status[6] = inb(0x3f5);
7134 // record in BIOS Data Area
7135 write_byte(0x0040, 0x0042, return_status[0]);
7136 write_byte(0x0040, 0x0043, return_status[1]);
7137 write_byte(0x0040, 0x0044, return_status[2]);
7138 write_byte(0x0040, 0x0045, return_status[3]);
7139 write_byte(0x0040, 0x0046, return_status[4]);
7140 write_byte(0x0040, 0x0047, return_status[5]);
7141 write_byte(0x0040, 0x0048, return_status[6]);
7143 if ( (return_status[0] & 0xc0) != 0 ) {
7144 if ( (return_status[1] & 0x02) != 0 ) {
7145 // diskette not writable.
7146 // AH=status code=0x03 (tried to write on write-protected disk)
7147 // AL=number of sectors written=0
7152 BX_PANIC("int13_diskette_function: read error\n");
7156 // ??? should track be new val from return_status[3] ?
7157 set_diskette_current_cyl(drive, track);
7158 // AL = number of sectors read (same value as passed)
7159 SET_AH(0x00); // success
7160 CLEAR_CF(); // success
7163 else { // if (ah == 0x04)
7164 // Verify Diskette Sectors
7166 // ??? should track be new val from return_status[3] ?
7167 set_diskette_current_cyl(drive, track);
7168 // AL = number of sectors verified (same value as passed)
7169 CLEAR_CF(); // success
7170 SET_AH(0x00); // success
7175 case 0x05: // format diskette track
7176 BX_DEBUG_INT13_FL("floppy f05\n");
7178 num_sectors = GET_AL();
7183 if ((drive > 1) || (head > 1) || (track > 79) ||
7184 (num_sectors == 0) || (num_sectors > 18)) {
7186 set_diskette_ret_status(1);
7187 SET_CF(); // error occurred
7190 // see if drive exists
7191 if (floppy_drive_exists(drive) == 0) {
7192 SET_AH(0x80); // drive not responding
7193 set_diskette_ret_status(0x80);
7194 SET_CF(); // error occurred
7198 // see if media in drive, and type is known
7199 if (floppy_media_known(drive) == 0) {
7200 if (floppy_media_sense(drive) == 0) {
7201 SET_AH(0x0C); // Media type not found
7202 set_diskette_ret_status(0x0C);
7203 SET_AL(0); // no sectors read
7204 SET_CF(); // error occurred
7209 // set up DMA controller for transfer
7210 page = (ES >> 12); // upper 4 bits
7211 base_es = (ES << 4); // lower 16bits contributed by ES
7212 base_address = base_es + BX; // lower 16 bits of address
7213 // contributed by ES:BX
7214 if ( base_address < base_es ) {
7215 // in case of carry, adjust page by 1
7218 base_count = (num_sectors * 4) - 1;
7220 // check for 64K boundary overrun
7221 last_addr = base_address + base_count;
7222 if (last_addr < base_address) {
7224 set_diskette_ret_status(0x09);
7225 SET_AL(0); // no sectors read
7226 SET_CF(); // error occurred
7231 outb(0x000c, 0x00); // clear flip-flop
7232 outb(0x0004, base_address);
7233 outb(0x0004, base_address>>8);
7234 outb(0x000c, 0x00); // clear flip-flop
7235 outb(0x0005, base_count);
7236 outb(0x0005, base_count>>8);
7237 mode_register = 0x4a; // single mode, increment, autoinit disable,
7238 // transfer type=read, channel 2
7239 outb(0x000b, mode_register);
7240 // port 81: DMA-1 Page Register, channel 2
7244 // set up floppy controller for transfer
7245 val8 = read_byte(0x0000, 0x043e);
7247 write_byte(0x0000, 0x043e, val8);
7248 // turn on motor of selected drive, DMA & int enabled, normal operation
7257 // reset the disk motor timeout value of INT 08
7258 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7260 // check port 3f4 for drive readiness
7262 if ( (val8 & 0xf0) != 0x80 )
7263 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7265 // send read-normal-data command (6 bytes) to controller
7266 outb(0x03f5, 0x4d); // 4d: format track
7267 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7268 outb(0x03f5, 2); // 512 byte sector size
7269 outb(0x03f5, num_sectors); // number of sectors per track
7270 outb(0x03f5, 0); // Gap length
7271 outb(0x03f5, 0xf6); // Fill byte
7272 // turn on interrupts
7276 // wait on 40:3e bit 7 to become 1
7277 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7278 while ( val8 == 0 ) {
7279 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7281 val8 = 0; // separate asm from while() loop
7282 // turn off interrupts
7286 // set 40:3e bit 7 to 0
7287 val8 = read_byte(0x0000, 0x043e);
7289 write_byte(0x0000, 0x043e, val8);
7290 // check port 3f4 for accessibility to status bytes
7292 if ( (val8 & 0xc0) != 0xc0 )
7293 BX_PANIC("int13_diskette: ctrl not ready\n");
7295 // read 7 return status bytes from controller
7296 // using loop index broken, have to unroll...
7297 return_status[0] = inb(0x3f5);
7298 return_status[1] = inb(0x3f5);
7299 return_status[2] = inb(0x3f5);
7300 return_status[3] = inb(0x3f5);
7301 return_status[4] = inb(0x3f5);
7302 return_status[5] = inb(0x3f5);
7303 return_status[6] = inb(0x3f5);
7304 // record in BIOS Data Area
7305 write_byte(0x0040, 0x0042, return_status[0]);
7306 write_byte(0x0040, 0x0043, return_status[1]);
7307 write_byte(0x0040, 0x0044, return_status[2]);
7308 write_byte(0x0040, 0x0045, return_status[3]);
7309 write_byte(0x0040, 0x0046, return_status[4]);
7310 write_byte(0x0040, 0x0047, return_status[5]);
7311 write_byte(0x0040, 0x0048, return_status[6]);
7313 if ( (return_status[0] & 0xc0) != 0 ) {
7314 if ( (return_status[1] & 0x02) != 0 ) {
7315 // diskette not writable.
7316 // AH=status code=0x03 (tried to write on write-protected disk)
7317 // AL=number of sectors written=0
7322 BX_PANIC("int13_diskette_function: write error\n");
7327 set_diskette_ret_status(0);
7328 set_diskette_current_cyl(drive, 0);
7329 CLEAR_CF(); // successful
7333 case 0x08: // read diskette drive parameters
7334 BX_DEBUG_INT13_FL("floppy f08\n");
7344 SET_DL(num_floppies);
7349 drive_type = inb_cmos(0x10);
7351 if (drive_type & 0xf0)
7353 if (drive_type & 0x0f)
7365 SET_DL(num_floppies);
7367 switch (drive_type) {
7370 SET_DH(0); // max head #
7373 case 1: // 360KB, 5.25"
7374 CX = 0x2709; // 40 tracks, 9 sectors
7375 SET_DH(1); // max head #
7378 case 2: // 1.2MB, 5.25"
7379 CX = 0x4f0f; // 80 tracks, 15 sectors
7380 SET_DH(1); // max head #
7383 case 3: // 720KB, 3.5"
7384 CX = 0x4f09; // 80 tracks, 9 sectors
7385 SET_DH(1); // max head #
7388 case 4: // 1.44MB, 3.5"
7389 CX = 0x4f12; // 80 tracks, 18 sectors
7390 SET_DH(1); // max head #
7393 case 5: // 2.88MB, 3.5"
7394 CX = 0x4f24; // 80 tracks, 36 sectors
7395 SET_DH(1); // max head #
7398 case 6: // 160k, 5.25"
7399 CX = 0x2708; // 40 tracks, 8 sectors
7400 SET_DH(0); // max head #
7403 case 7: // 180k, 5.25"
7404 CX = 0x2709; // 40 tracks, 9 sectors
7405 SET_DH(0); // max head #
7408 case 8: // 320k, 5.25"
7409 CX = 0x2708; // 40 tracks, 8 sectors
7410 SET_DH(1); // max head #
7414 BX_PANIC("floppy: int13: bad floppy type\n");
7417 /* set es & di to point to 11 byte diskette param table in ROM */
7421 mov ax, #diskette_param_table2
7422 mov _int13_diskette_function.DI+2[bp], ax
7423 mov _int13_diskette_function.ES+2[bp], cs
7426 CLEAR_CF(); // success
7427 /* disk status not changed upon success */
7431 case 0x15: // read diskette drive type
7432 BX_DEBUG_INT13_FL("floppy f15\n");
7435 SET_AH(0); // only 2 drives supported
7436 // set_diskette_ret_status here ???
7440 drive_type = inb_cmos(0x10);
7446 CLEAR_CF(); // successful, not present
7447 if (drive_type==0) {
7448 SET_AH(0); // drive not present
7451 SET_AH(1); // drive present, does not support change line
7456 case 0x16: // get diskette change line status
7457 BX_DEBUG_INT13_FL("floppy f16\n");
7460 SET_AH(0x01); // invalid drive
7461 set_diskette_ret_status(0x01);
7466 SET_AH(0x06); // change line not supported
7467 set_diskette_ret_status(0x06);
7471 case 0x17: // set diskette type for format(old)
7472 BX_DEBUG_INT13_FL("floppy f17\n");
7473 /* not used for 1.44M floppies */
7474 SET_AH(0x01); // not supported
7475 set_diskette_ret_status(1); /* not supported */
7479 case 0x18: // set diskette type for format(new)
7480 BX_DEBUG_INT13_FL("floppy f18\n");
7481 SET_AH(0x01); // do later
7482 set_diskette_ret_status(1);
7487 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7489 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7490 SET_AH(0x01); // ???
7491 set_diskette_ret_status(1);
7497 #else // #if BX_SUPPORT_FLOPPY
7499 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7500 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7504 switch ( GET_AH() ) {
7506 case 0x01: // Read Diskette Status
7508 val8 = read_byte(0x0000, 0x0441);
7517 write_byte(0x0000, 0x0441, 0x01);
7521 #endif // #if BX_SUPPORT_FLOPPY
7524 set_diskette_ret_status(value)
7527 write_byte(0x0040, 0x0041, value);
7531 set_diskette_current_cyl(drive, cyl)
7536 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7537 write_byte(0x0040, 0x0094+drive, cyl);
7541 determine_floppy_media(drive)
7545 Bit8u val8, DOR, ctrl_info;
7547 ctrl_info = read_byte(0x0040, 0x008F);
7555 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7558 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7562 if ( (ctrl_info & 0x04) != 0x04 ) {
7563 // Drive not determined means no drive exists, done.
7568 // check Main Status Register for readiness
7569 val8 = inb(0x03f4) & 0x80; // Main Status Register
7571 BX_PANIC("d_f_m: MRQ bit not set\n");
7575 // existing BDA values
7577 // turn on drive motor
7578 outb(0x03f2, DOR); // Digital Output Register
7581 BX_PANIC("d_f_m: OK so far\n");
7586 int17_function(regs, ds, iret_addr)
7587 pusha_regs_t regs; // regs pushed from PUSHA instruction
7588 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7589 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7591 Bit16u addr,timeout;
7598 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7599 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7600 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7601 if (regs.u.r8.ah == 0) {
7602 outb(addr, regs.u.r8.al);
7604 outb(addr+2, val8 | 0x01); // send strobe
7608 outb(addr+2, val8 & ~0x01);
7609 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7613 if (regs.u.r8.ah == 1) {
7615 outb(addr+2, val8 & ~0x04); // send init
7619 outb(addr+2, val8 | 0x04);
7622 regs.u.r8.ah = (val8 ^ 0x48);
7623 if (!timeout) regs.u.r8.ah |= 0x01;
7624 ClearCF(iret_addr.flags);
7626 SetCF(iret_addr.flags); // Unsupported
7630 // returns bootsegment in ax, drive in bl
7632 int19_function(bseqnr)
7635 Bit16u ebda_seg=read_word(0x0040,0x000E);
7644 // BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7646 // if BX_ELTORITO_BOOT is not defined, old behavior
7647 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7648 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7649 // 0: system boot sequence, first drive C: then A:
7650 // 1: system boot sequence, first drive A: then C:
7651 // else BX_ELTORITO_BOOT is defined
7652 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7653 // CMOS reg 0x3D & 0x0f : 1st boot device
7654 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7655 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7656 // boot device codes:
7657 // 0x00 : not defined
7658 // 0x01 : first floppy
7659 // 0x02 : first harddrive
7660 // 0x03 : first cdrom
7661 // else : boot failure
7663 // Get the boot sequence
7664 #if BX_ELTORITO_BOOT
7665 bootseq=inb_cmos(0x3d);
7666 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7668 if (bseqnr==2) bootseq >>= 4;
7669 if (bseqnr==3) bootseq >>= 8;
7670 if (bootseq<0x10) lastdrive = 1;
7671 bootdrv=0x00; bootcd=0;
7672 switch(bootseq & 0x0f) {
7673 case 0x01: bootdrv=0x00; bootcd=0; break;
7674 case 0x02: bootdrv=0x80; bootcd=0; break;
7675 case 0x03: bootdrv=0x00; bootcd=1; break;
7676 default: return 0x00000000;
7679 bootseq=inb_cmos(0x2d);
7685 bootdrv=0x00; bootcd=0;
7686 if((bootseq&0x20)==0) bootdrv=0x80;
7687 #endif // BX_ELTORITO_BOOT
7689 #if BX_ELTORITO_BOOT
7690 // We have to boot from cd
7692 status = cdrom_boot();
7694 BX_DEBUG("CDBoot:%x\n",status);
7698 if ( (status & 0x00ff) !=0 ) {
7699 print_cdromboot_failure(status);
7700 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7704 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7705 bootdrv = (Bit8u)(status>>8);
7708 #endif // BX_ELTORITO_BOOT
7710 // We have to boot from harddisk or floppy
7721 mov _int19_function.status + 2[bp], ax
7722 mov dl, _int19_function.bootdrv + 2[bp]
7723 mov ax, _int19_function.bootseg + 2[bp]
7724 mov es, ax ;; segment
7725 mov bx, #0x0000 ;; offset
7726 mov ah, #0x02 ;; function 2, read diskette sector
7727 mov al, #0x01 ;; read 1 sector
7728 mov ch, #0x00 ;; track 0
7729 mov cl, #0x01 ;; sector 1
7730 mov dh, #0x00 ;; head 0
7731 int #0x13 ;; read sector
7734 mov _int19_function.status + 2[bp], ax
7742 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7747 // check signature if instructed by cmos reg 0x38, only for floppy
7748 // bootchk = 1 : signature check disabled
7749 // bootchk = 0 : signature check enabled
7750 if (bootdrv != 0) bootchk = 0;
7751 else bootchk = inb_cmos(0x38) & 0x01;
7753 #if BX_ELTORITO_BOOT
7754 // if boot from cd, no signature check
7757 #endif // BX_ELTORITO_BOOT
7760 if (read_word(bootseg,0x1fe) != 0xaa55) {
7761 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7766 #if BX_ELTORITO_BOOT
7767 // Print out the boot string
7768 BX_DEBUG("cdrom_boot: %x\n",status);
7769 print_boot_device(bootcd, bootdrv);
7770 #else // BX_ELTORITO_BOOT
7771 print_boot_device(0, bootdrv);
7772 #endif // BX_ELTORITO_BOOT
7774 // return the boot segment
7775 return (((Bit32u)bootdrv) << 16) + bootseg;
7779 int1a_function(regs, ds, iret_addr)
7780 pusha_regs_t regs; // regs pushed from PUSHA instruction
7781 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7782 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7786 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);
7792 switch (regs.u.r8.ah) {
7793 case 0: // get current clock count
7797 regs.u.r16.cx = BiosData->ticks_high;
7798 regs.u.r16.dx = BiosData->ticks_low;
7799 regs.u.r8.al = BiosData->midnight_flag;
7800 BiosData->midnight_flag = 0; // reset flag
7805 ClearCF(iret_addr.flags); // OK
7808 case 1: // Set Current Clock Count
7812 BiosData->ticks_high = regs.u.r16.cx;
7813 BiosData->ticks_low = regs.u.r16.dx;
7814 BiosData->midnight_flag = 0; // reset flag
7819 ClearCF(iret_addr.flags); // OK
7823 case 2: // Read CMOS Time
7824 if (rtc_updating()) {
7825 SetCF(iret_addr.flags);
7829 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7830 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7831 regs.u.r8.ch = inb_cmos(0x04); // Hours
7832 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7834 regs.u.r8.al = regs.u.r8.ch;
7835 ClearCF(iret_addr.flags); // OK
7838 case 3: // Set CMOS Time
7839 // Using a debugger, I notice the following masking/setting
7840 // of bits in Status Register B, by setting Reg B to
7841 // a few values and getting its value after INT 1A was called.
7843 // try#1 try#2 try#3
7844 // before 1111 1101 0111 1101 0000 0000
7845 // after 0110 0010 0110 0010 0000 0010
7847 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7848 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7849 if (rtc_updating()) {
7851 // fall through as if an update were not in progress
7853 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7854 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7855 outb_cmos(0x04, regs.u.r8.ch); // Hours
7856 // Set Daylight Savings time enabled bit to requested value
7857 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7858 // (reg B already selected)
7859 outb_cmos(0x0b, val8);
7861 regs.u.r8.al = val8; // val last written to Reg B
7862 ClearCF(iret_addr.flags); // OK
7865 case 4: // Read CMOS Date
7867 if (rtc_updating()) {
7868 SetCF(iret_addr.flags);
7871 regs.u.r8.cl = inb_cmos(0x09); // Year
7872 regs.u.r8.dh = inb_cmos(0x08); // Month
7873 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7874 regs.u.r8.ch = inb_cmos(0x32); // Century
7875 regs.u.r8.al = regs.u.r8.ch;
7876 ClearCF(iret_addr.flags); // OK
7879 case 5: // Set CMOS Date
7880 // Using a debugger, I notice the following masking/setting
7881 // of bits in Status Register B, by setting Reg B to
7882 // a few values and getting its value after INT 1A was called.
7884 // try#1 try#2 try#3 try#4
7885 // before 1111 1101 0111 1101 0000 0010 0000 0000
7886 // after 0110 1101 0111 1101 0000 0010 0000 0000
7888 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7889 // My assumption: RegB = (RegB & 01111111b)
7890 if (rtc_updating()) {
7892 SetCF(iret_addr.flags);
7895 outb_cmos(0x09, regs.u.r8.cl); // Year
7896 outb_cmos(0x08, regs.u.r8.dh); // Month
7897 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7898 outb_cmos(0x32, regs.u.r8.ch); // Century
7899 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7900 outb_cmos(0x0b, val8);
7902 regs.u.r8.al = val8; // AL = val last written to Reg B
7903 ClearCF(iret_addr.flags); // OK
7906 case 6: // Set Alarm Time in CMOS
7907 // Using a debugger, I notice the following masking/setting
7908 // of bits in Status Register B, by setting Reg B to
7909 // a few values and getting its value after INT 1A was called.
7911 // try#1 try#2 try#3
7912 // before 1101 1111 0101 1111 0000 0000
7913 // after 0110 1111 0111 1111 0010 0000
7915 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7916 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7917 val8 = inb_cmos(0x0b); // Get Status Reg B
7920 // Alarm interrupt enabled already
7921 SetCF(iret_addr.flags); // Error: alarm in use
7924 if (rtc_updating()) {
7926 // fall through as if an update were not in progress
7928 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7929 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7930 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7931 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7932 // enable Status Reg B alarm bit, clear halt clock bit
7933 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7934 ClearCF(iret_addr.flags); // OK
7937 case 7: // Turn off Alarm
7938 // Using a debugger, I notice the following masking/setting
7939 // of bits in Status Register B, by setting Reg B to
7940 // a few values and getting its value after INT 1A was called.
7942 // try#1 try#2 try#3 try#4
7943 // before 1111 1101 0111 1101 0010 0000 0010 0010
7944 // after 0100 0101 0101 0101 0000 0000 0000 0010
7946 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7947 // My assumption: RegB = (RegB & 01010111b)
7948 val8 = inb_cmos(0x0b); // Get Status Reg B
7949 // clear clock-halt bit, disable alarm bit
7950 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7952 regs.u.r8.al = val8; // val last written to Reg B
7953 ClearCF(iret_addr.flags); // OK
7957 // real mode PCI BIOS functions now handled in assembler code
7958 // this C code handles the error code for information only
7959 if (regs.u.r8.bl == 0xff) {
7960 BX_INFO("PCI BIOS: PCI not present\n");
7961 } else if (regs.u.r8.bl == 0x81) {
7962 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7963 } else if (regs.u.r8.bl == 0x83) {
7964 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7965 } else if (regs.u.r8.bl == 0x86) {
7966 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7968 regs.u.r8.ah = regs.u.r8.bl;
7969 SetCF(iret_addr.flags);
7974 SetCF(iret_addr.flags); // Unsupported
7979 int70_function(regs, ds, iret_addr)
7980 pusha_regs_t regs; // regs pushed from PUSHA instruction
7981 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7982 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7984 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7985 Bit8u registerB = 0, registerC = 0;
7987 // Check which modes are enabled and have occurred.
7988 registerB = inb_cmos( 0xB );
7989 registerC = inb_cmos( 0xC );
7991 if( ( registerB & 0x60 ) != 0 ) {
7992 if( ( registerC & 0x20 ) != 0 ) {
7993 // Handle Alarm Interrupt.
8000 if( ( registerC & 0x40 ) != 0 ) {
8001 // Handle Periodic Interrupt.
8003 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8004 // Wait Interval (Int 15, AH=83) active.
8005 Bit32u time, toggle;
8007 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8008 if( time < 0x3D1 ) {
8010 Bit16u segment, offset;
8012 offset = read_word( 0x40, 0x98 );
8013 segment = read_word( 0x40, 0x9A );
8014 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8015 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8016 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8018 // Continue waiting.
8020 write_dword( 0x40, 0x9C, time );
8033 ;------------------------------------------
8034 ;- INT74h : PS/2 mouse hardware interrupt -
8035 ;------------------------------------------
8040 push #0x00 ;; placeholder for status
8041 push #0x00 ;; placeholder for X
8042 push #0x00 ;; placeholder for Y
8043 push #0x00 ;; placeholder for Z
8044 push #0x00 ;; placeholder for make_far_call boolean
8045 call _int74_function
8046 pop cx ;; remove make_far_call from stack
8049 ;; make far call to EBDA:0022
8052 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8054 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8059 add sp, #8 ;; pop status, x, y, z
8061 pop ds ;; restore DS
8066 ;; This will perform an IRET, but will retain value of current CF
8067 ;; by altering flags on stack. Better than RETF #02.
8072 and BYTE [bp + 0x06], #0xfe
8078 or BYTE [bp + 0x06], #0x01
8083 ;----------------------
8084 ;- INT13h (relocated) -
8085 ;----------------------
8087 ; int13_relocated is a little bit messed up since I played with it
8088 ; I have to rewrite it:
8089 ; - call a function that detect which function to call
8090 ; - make all called C function get the same parameters list
8094 #if BX_ELTORITO_BOOT
8095 ;; check for an eltorito function
8097 jb int13_not_eltorito
8099 ja int13_not_eltorito
8108 jmp _int13_eltorito ;; ELDX not used
8116 ;; check if emulation active
8117 call _cdemu_isactive
8119 je int13_cdemu_inactive
8121 ;; check if access to the emulated drive
8122 call _cdemu_emulated_drive
8125 cmp al,dl ;; int13 on emulated drive
8140 jmp _int13_cdemu ;; ELDX not used
8143 and dl,#0xE0 ;; mask to get device class, including cdroms
8144 cmp al,dl ;; al is 0x00 or 0x80
8145 jne int13_cdemu_inactive ;; inactive for device class
8157 dec dl ;; real drive is dl - 1
8160 int13_cdemu_inactive:
8166 #endif // BX_ELTORITO_BOOT
8177 push dx ;; push eltorito value of dx instead of sp
8188 ;; now the 16-bit registers can be restored with:
8189 ;; pop ds; pop es; popa; iret
8190 ;; arguments passed to functions should be
8191 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8197 jmp _int13_diskette_function
8206 // ebx is modified: BSD 5.2.1 boot loader problem
8207 // someone should figure out which 32 bit register that actually are used
8224 call _int13_harddisk
8236 int18_handler: ;; Boot Failure routing
8237 call _int18_panic_msg
8244 int19_relocated: ;; Boot function, relocated
8246 ;; int19 was beginning to be really complex, so now it
8247 ;; just calls an C function, that does the work
8248 ;; it returns in BL the boot drive, and in AX the boot segment
8249 ;; the boot segment will be 0x0000 if something has failed
8261 call _int19_function
8264 ;; bl contains the boot drive
8265 ;; ax contains the boot segment or 0 if failure
8267 test ax, ax ;; if ax is 0 try next boot device
8273 call _int19_function
8276 test ax, ax ;; if ax is 0 try next boot device
8282 call _int19_function
8285 test ax, ax ;; if ax is 0 call int18
8289 mov dl, bl ;; set drive so guest os find it
8290 shl eax, #0x04 ;; convert seg to ip
8291 mov 2[bp], ax ;; set ip
8293 shr eax, #0x04 ;; get cs back
8294 and ax, #0xF000 ;; remove what went in ip
8295 mov 4[bp], ax ;; set cs
8297 mov es, ax ;; set es to zero fixes [ 549815 ]
8298 mov [bp], ax ;; set bp to zero
8299 mov ax, #0xaa55 ;; set ok flag
8302 iret ;; Beam me up Scotty
8307 int1c_handler: ;; User Timer Tick
8311 ;----------------------
8312 ;- POST: Floppy Drive -
8313 ;----------------------
8319 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8321 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8323 mov 0x0440, al ;; diskette motor timeout counter: not active
8324 mov 0x0441, al ;; diskette controller status return code
8326 mov 0x0442, al ;; disk & diskette controller status register 0
8327 mov 0x0443, al ;; diskette controller status register 1
8328 mov 0x0444, al ;; diskette controller status register 2
8329 mov 0x0445, al ;; diskette controller cylinder number
8330 mov 0x0446, al ;; diskette controller head number
8331 mov 0x0447, al ;; diskette controller sector number
8332 mov 0x0448, al ;; diskette controller bytes written
8334 mov 0x048b, al ;; diskette configuration data
8336 ;; -----------------------------------------------------------------
8337 ;; (048F) diskette controller information
8339 mov al, #0x10 ;; get CMOS diskette drive type
8342 mov ah, al ;; save byte to AH
8345 shr al, #4 ;; look at top 4 bits for drive 0
8346 jz f0_missing ;; jump if no drive0
8347 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8350 mov bl, #0x00 ;; no drive0
8353 mov al, ah ;; restore from AH
8354 and al, #0x0f ;; look at bottom 4 bits for drive 1
8355 jz f1_missing ;; jump if no drive1
8356 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8358 ;; leave high bits in BL zerod
8359 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8360 ;; -----------------------------------------------------------------
8363 mov 0x0490, al ;; diskette 0 media state
8364 mov 0x0491, al ;; diskette 1 media state
8366 ;; diskette 0,1 operational starting state
8367 ;; drive type has not been determined,
8368 ;; has no changed detection line
8372 mov 0x0494, al ;; diskette 0 current cylinder
8373 mov 0x0495, al ;; diskette 1 current cylinder
8376 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8378 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8379 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8380 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8385 ;--------------------
8386 ;- POST: HARD DRIVE -
8387 ;--------------------
8388 ; relocated here because the primary POST area isnt big enough.
8391 // INT 76h calls INT 15h function ax=9100
8393 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8399 mov 0x0474, al /* hard disk status of last operation */
8400 mov 0x0477, al /* hard disk port offset (XT only ???) */
8401 mov 0x048c, al /* hard disk status register */
8402 mov 0x048d, al /* hard disk error register */
8403 mov 0x048e, al /* hard disk task complete flag */
8405 mov 0x0475, al /* hard disk number attached */
8407 mov 0x0476, al /* hard disk control byte */
8408 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8409 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8410 ;; INT 41h: hard disk 0 configuration pointer
8411 ;; INT 46h: hard disk 1 configuration pointer
8412 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8413 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8415 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8427 cmp al, #47 ;; decimal 47 - user definable
8431 ;; CMOS purpose param table offset
8432 ;; 1b cylinders low 0
8433 ;; 1c cylinders high 1
8435 ;; 1e write pre-comp low 5
8436 ;; 1f write pre-comp high 6
8437 ;; 20 retries/bad map/heads>8 8
8438 ;; 21 landing zone low C
8439 ;; 22 landing zone high D
8440 ;; 23 sectors/track E
8445 ;;; Filling EBDA table for hard disk 0.
8453 mov (0x003d + 0x05), ax ;; write precomp word
8458 mov (0x003d + 0x08), al ;; drive control byte
8467 mov (0x003d + 0x0C), ax ;; landing zone word
8469 mov al, #0x1c ;; get cylinders word in AX
8471 in al, #0x71 ;; high byte
8475 in al, #0x71 ;; low byte
8476 mov bx, ax ;; BX = cylinders
8481 mov cl, al ;; CL = heads
8486 mov dl, al ;; DL = sectors
8489 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8491 hd0_post_physical_chs:
8492 ;; no logical CHS mapping used, just physical CHS
8493 ;; use Standard Fixed Disk Parameter Table (FDPT)
8494 mov (0x003d + 0x00), bx ;; number of physical cylinders
8495 mov (0x003d + 0x02), cl ;; number of physical heads
8496 mov (0x003d + 0x0E), dl ;; number of physical sectors
8499 hd0_post_logical_chs:
8500 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8501 mov (0x003d + 0x09), bx ;; number of physical cylinders
8502 mov (0x003d + 0x0b), cl ;; number of physical heads
8503 mov (0x003d + 0x04), dl ;; number of physical sectors
8504 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8506 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8509 jnbe hd0_post_above_2048
8510 ;; 1024 < c <= 2048 cylinders
8513 jmp hd0_post_store_logical
8515 hd0_post_above_2048:
8517 jnbe hd0_post_above_4096
8518 ;; 2048 < c <= 4096 cylinders
8521 jmp hd0_post_store_logical
8523 hd0_post_above_4096:
8525 jnbe hd0_post_above_8192
8526 ;; 4096 < c <= 8192 cylinders
8529 jmp hd0_post_store_logical
8531 hd0_post_above_8192:
8532 ;; 8192 < c <= 16384 cylinders
8536 hd0_post_store_logical:
8537 mov (0x003d + 0x00), bx ;; number of physical cylinders
8538 mov (0x003d + 0x02), cl ;; number of physical heads
8540 mov cl, #0x0f ;; repeat count
8541 mov si, #0x003d ;; offset to disk0 FDPT
8542 mov al, #0x00 ;; sum
8543 hd0_post_checksum_loop:
8547 jnz hd0_post_checksum_loop
8548 not al ;; now take 2s complement
8551 ;;; Done filling EBDA table for hard disk 0.
8555 ;; is there really a second hard disk? if not, return now
8563 ;; check that the hd type is really 0x0f.
8568 ;; check that the extended type is 47 - user definable
8572 cmp al, #47 ;; decimal 47 - user definable
8577 ;; CMOS purpose param table offset
8578 ;; 0x24 cylinders low 0
8579 ;; 0x25 cylinders high 1
8581 ;; 0x27 write pre-comp low 5
8582 ;; 0x28 write pre-comp high 6
8584 ;; 0x2a landing zone low C
8585 ;; 0x2b landing zone high D
8586 ;; 0x2c sectors/track E
8587 ;;; Fill EBDA table for hard disk 1.
8597 mov (0x004d + 0x05), ax ;; write precomp word
8602 mov (0x004d + 0x08), al ;; drive control byte
8611 mov (0x004d + 0x0C), ax ;; landing zone word
8613 mov al, #0x25 ;; get cylinders word in AX
8615 in al, #0x71 ;; high byte
8619 in al, #0x71 ;; low byte
8620 mov bx, ax ;; BX = cylinders
8625 mov cl, al ;; CL = heads
8630 mov dl, al ;; DL = sectors
8633 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8635 hd1_post_physical_chs:
8636 ;; no logical CHS mapping used, just physical CHS
8637 ;; use Standard Fixed Disk Parameter Table (FDPT)
8638 mov (0x004d + 0x00), bx ;; number of physical cylinders
8639 mov (0x004d + 0x02), cl ;; number of physical heads
8640 mov (0x004d + 0x0E), dl ;; number of physical sectors
8643 hd1_post_logical_chs:
8644 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8645 mov (0x004d + 0x09), bx ;; number of physical cylinders
8646 mov (0x004d + 0x0b), cl ;; number of physical heads
8647 mov (0x004d + 0x04), dl ;; number of physical sectors
8648 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8650 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8653 jnbe hd1_post_above_2048
8654 ;; 1024 < c <= 2048 cylinders
8657 jmp hd1_post_store_logical
8659 hd1_post_above_2048:
8661 jnbe hd1_post_above_4096
8662 ;; 2048 < c <= 4096 cylinders
8665 jmp hd1_post_store_logical
8667 hd1_post_above_4096:
8669 jnbe hd1_post_above_8192
8670 ;; 4096 < c <= 8192 cylinders
8673 jmp hd1_post_store_logical
8675 hd1_post_above_8192:
8676 ;; 8192 < c <= 16384 cylinders
8680 hd1_post_store_logical:
8681 mov (0x004d + 0x00), bx ;; number of physical cylinders
8682 mov (0x004d + 0x02), cl ;; number of physical heads
8684 mov cl, #0x0f ;; repeat count
8685 mov si, #0x004d ;; offset to disk0 FDPT
8686 mov al, #0x00 ;; sum
8687 hd1_post_checksum_loop:
8691 jnz hd1_post_checksum_loop
8692 not al ;; now take 2s complement
8695 ;;; Done filling EBDA table for hard disk 1.
8699 ;--------------------
8700 ;- POST: EBDA segment
8701 ;--------------------
8702 ; relocated here because the primary POST area isnt big enough.
8707 mov byte ptr [0x0], #EBDA_SIZE
8709 xor ax, ax ; mov EBDA seg into 40E
8711 mov word ptr [0x40E], #EBDA_SEG
8714 ;--------------------
8715 ;- POST: EOI + jmp via [0x40:67)
8716 ;--------------------
8717 ; relocated here because the primary POST area isnt big enough.
8727 ;--------------------
8730 out #0xA0, al ;; slave PIC EOI
8733 out #0x20, al ;; master PIC EOI
8736 ;--------------------
8738 ;; in: AL in BCD format
8739 ;; out: AL in binary format, AH will always be 0
8742 and bl, #0x0f ;; bl has low digit
8743 shr al, #4 ;; al has high digit
8745 mul al, bh ;; multiply high digit by 10 (result in AX)
8746 add al, bl ;; then add low digit
8749 ;--------------------
8751 ;; Setup the Timer Ticks Count (0x46C:dword) and
8752 ;; Timer Ticks Roller Flag (0x470:byte)
8753 ;; The Timer Ticks Count needs to be set according to
8754 ;; the current CMOS time, as if ticks have been occurring
8755 ;; at 18.2hz since midnight up to this point. Calculating
8756 ;; this is a little complicated. Here are the factors I gather
8757 ;; regarding this. 14,318,180 hz was the original clock speed,
8758 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8759 ;; at the time, or 4 to drive the CGA video adapter. The div3
8760 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8761 ;; the timer. With a maximum 16bit timer count, this is again
8762 ;; divided down by 65536 to 18.2hz.
8764 ;; 14,318,180 Hz clock
8765 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8766 ;; /4 = 1,193,181 Hz fed to timer
8767 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8768 ;; 1 second = 18.20650736 ticks
8769 ;; 1 minute = 1092.390442 ticks
8770 ;; 1 hour = 65543.42651 ticks
8772 ;; Given the values in the CMOS clock, one could calculate
8773 ;; the number of ticks by the following:
8774 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8775 ;; (BcdToBin(minutes) * 1092.3904)
8776 ;; (BcdToBin(hours) * 65543.427)
8777 ;; To get a little more accuracy, since Im using integer
8778 ;; arithmatic, I use:
8779 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8780 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8781 ;; (BcdToBin(hours) * 65543427) / 1000
8786 xor eax, eax ;; clear EAX
8789 in al, #0x71 ;; AL has CMOS seconds in BCD
8790 call BcdToBin ;; EAX now has seconds in binary
8796 mov ecx, eax ;; ECX will accumulate total ticks
8799 xor eax, eax ;; clear EAX
8802 in al, #0x71 ;; AL has CMOS minutes in BCD
8803 call BcdToBin ;; EAX now has minutes in binary
8809 add ecx, eax ;; add to total ticks
8812 xor eax, eax ;; clear EAX
8815 in al, #0x71 ;; AL has CMOS hours in BCD
8816 call BcdToBin ;; EAX now has hours in binary
8822 add ecx, eax ;; add to total ticks
8824 mov 0x46C, ecx ;; Timer Ticks Count
8826 mov 0x470, al ;; Timer Ticks Rollover Flag
8829 ;--------------------
8831 ;; record completion in BIOS task complete flag
8843 ;--------------------
8848 #include "apmbios.S"
8852 #include "apmbios.S"
8855 #include "apmbios.S"
8859 ;--------------------
8864 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8865 dw bios32_entry_point, 0xf ;; 32 bit physical address
8866 db 0 ;; revision level
8867 ;; length in paragraphs and checksum stored in a word to prevent errors
8868 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8869 & 0xff) << 8) + 0x01
8870 db 0,0,0,0,0 ;; reserved
8875 cmp eax, #0x49435024
8877 mov eax, #0x80000000
8882 cmp eax, #0x12378086
8884 mov ebx, #0x000f0000
8886 mov edx, #pcibios_protected
8901 cmp al, #0x01 ;; installation check
8905 mov edx, #0x20494350
8908 pci_pro_f02: ;; find pci device
8916 call pci_pro_select_reg
8930 pci_pro_f08: ;; read configuration byte
8933 call pci_pro_select_reg
8942 pci_pro_f09: ;; read configuration word
8945 call pci_pro_select_reg
8954 pci_pro_f0a: ;; read configuration dword
8957 call pci_pro_select_reg
8964 pci_pro_f0b: ;; write configuration byte
8967 call pci_pro_select_reg
8976 pci_pro_f0c: ;; write configuration word
8979 call pci_pro_select_reg
8988 pci_pro_f0d: ;; write configuration dword
8991 call pci_pro_select_reg
9034 mov eax, #0x80000000
9039 cmp eax, #0x12378086
9049 cmp al, #0x01 ;; installation check
9054 mov edx, #0x20494350
9056 mov di, #pcibios_protected
9059 pci_real_f02: ;; find pci device
9069 call pci_real_select_reg
9073 jne pci_real_nextdev
9080 jne pci_real_devloop
9085 pci_real_f08: ;; read configuration byte
9088 call pci_real_select_reg
9097 pci_real_f09: ;; read configuration word
9100 call pci_real_select_reg
9109 pci_real_f0a: ;; read configuration dword
9112 call pci_real_select_reg
9119 pci_real_f0b: ;; write configuration byte
9122 call pci_real_select_reg
9131 pci_real_f0c: ;; write configuration word
9134 call pci_real_select_reg
9143 pci_real_f0d: ;; write configuration dword
9145 jne pci_real_unknown
9146 call pci_real_select_reg
9167 pci_real_select_reg:
9181 pci_routing_table_structure:
9182 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9184 dw 32 + (6 * 16) ;; table size
9185 db 0 ;; PCI interrupt router bus
9186 db 0x08 ;; PCI interrupt router DevFunc
9187 dw 0x0000 ;; PCI exclusive IRQs
9188 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9189 dw 0x7000 ;; compatible PCI interrupt router device ID
9190 dw 0,0 ;; Miniport data
9191 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9193 ;; first slot entry PCI-to-ISA (embedded)
9194 db 0 ;; pci bus number
9195 db 0x08 ;; pci device number (bit 7-3)
9196 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9197 dw 0xdef8 ;; IRQ bitmap INTA#
9198 db 0x61 ;; link value INTB#
9199 dw 0xdef8 ;; IRQ bitmap INTB#
9200 db 0x62 ;; link value INTC#
9201 dw 0xdef8 ;; IRQ bitmap INTC#
9202 db 0x63 ;; link value INTD#
9203 dw 0xdef8 ;; IRQ bitmap INTD#
9204 db 0 ;; physical slot (0 = embedded)
9206 ;; second slot entry: 1st PCI slot
9207 db 0 ;; pci bus number
9208 db 0x10 ;; pci device number (bit 7-3)
9209 db 0x61 ;; link value INTA#
9210 dw 0xdef8 ;; IRQ bitmap INTA#
9211 db 0x62 ;; link value INTB#
9212 dw 0xdef8 ;; IRQ bitmap INTB#
9213 db 0x63 ;; link value INTC#
9214 dw 0xdef8 ;; IRQ bitmap INTC#
9215 db 0x60 ;; link value INTD#
9216 dw 0xdef8 ;; IRQ bitmap INTD#
9217 db 1 ;; physical slot (0 = embedded)
9219 ;; third slot entry: 2nd PCI slot
9220 db 0 ;; pci bus number
9221 db 0x18 ;; pci device number (bit 7-3)
9222 db 0x62 ;; link value INTA#
9223 dw 0xdef8 ;; IRQ bitmap INTA#
9224 db 0x63 ;; link value INTB#
9225 dw 0xdef8 ;; IRQ bitmap INTB#
9226 db 0x60 ;; link value INTC#
9227 dw 0xdef8 ;; IRQ bitmap INTC#
9228 db 0x61 ;; link value INTD#
9229 dw 0xdef8 ;; IRQ bitmap INTD#
9230 db 2 ;; physical slot (0 = embedded)
9232 ;; 4th slot entry: 3rd PCI slot
9233 db 0 ;; pci bus number
9234 db 0x20 ;; pci device number (bit 7-3)
9235 db 0x63 ;; link value INTA#
9236 dw 0xdef8 ;; IRQ bitmap INTA#
9237 db 0x60 ;; link value INTB#
9238 dw 0xdef8 ;; IRQ bitmap INTB#
9239 db 0x61 ;; link value INTC#
9240 dw 0xdef8 ;; IRQ bitmap INTC#
9241 db 0x62 ;; link value INTD#
9242 dw 0xdef8 ;; IRQ bitmap INTD#
9243 db 3 ;; physical slot (0 = embedded)
9245 ;; 5th slot entry: 4rd PCI slot
9246 db 0 ;; pci bus number
9247 db 0x28 ;; pci device number (bit 7-3)
9248 db 0x60 ;; link value INTA#
9249 dw 0xdef8 ;; IRQ bitmap INTA#
9250 db 0x61 ;; link value INTB#
9251 dw 0xdef8 ;; IRQ bitmap INTB#
9252 db 0x62 ;; link value INTC#
9253 dw 0xdef8 ;; IRQ bitmap INTC#
9254 db 0x63 ;; link value INTD#
9255 dw 0xdef8 ;; IRQ bitmap INTD#
9256 db 4 ;; physical slot (0 = embedded)
9258 ;; 6th slot entry: 5rd PCI slot
9259 db 0 ;; pci bus number
9260 db 0x30 ;; pci device number (bit 7-3)
9261 db 0x61 ;; link value INTA#
9262 dw 0xdef8 ;; IRQ bitmap INTA#
9263 db 0x62 ;; link value INTB#
9264 dw 0xdef8 ;; IRQ bitmap INTB#
9265 db 0x63 ;; link value INTC#
9266 dw 0xdef8 ;; IRQ bitmap INTC#
9267 db 0x60 ;; link value INTD#
9268 dw 0xdef8 ;; IRQ bitmap INTD#
9269 db 5 ;; physical slot (0 = embedded)
9275 pcibios_init_sel_reg:
9287 pcibios_init_set_elcr:
9311 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9316 mov si, #pci_routing_table_structure
9320 call pcibios_init_sel_reg
9323 cmp eax, [si+12] ;; check irq router
9326 call pcibios_init_sel_reg
9327 push bx ;; save irq router bus + devfunc
9330 out dx, ax ;; reset PIRQ route control
9338 add si, #0x20 ;; set pointer to 1st entry
9340 mov ax, #pci_irq_list
9349 call pcibios_init_sel_reg
9353 jnz pci_test_int_pin
9359 call pcibios_init_sel_reg
9364 dec al ;; determine pirq reg
9373 call pcibios_init_sel_reg
9380 mov bx, [bp-2] ;; pci irq list pointer
9385 call pcibios_init_set_elcr
9389 add bl, [bp-3] ;; pci function number
9391 call pcibios_init_sel_reg
9401 mov byte ptr[bp-3], #0x00
9409 #endif // BX_PCIBIOS
9411 ; parallel port detection: base address in DX, index in BX, timeout in CL
9416 and al, #0xdf ; clear input mode
9426 mov [bx+0x408], dx ; Parallel I/O address
9428 mov [bx+0x478], cl ; Parallel printer timeout
9433 ; serial port detection: base address in DX, index in BX, timeout in CL
9435 ; no serial port in the VM -PAD
9455 mov [bx+0x400], dx ; Serial I/O address
9457 mov [bx+0x47c], cl ; Serial timeout
9484 ;; Scan for existence of valid expansion ROMS.
9485 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9486 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9487 ;; System ROM: only 0xE0000
9493 ;; 2 ROM length in 512-byte blocks
9494 ;; 3 ROM initialization entry point (FAR CALL)
9499 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9500 cmp [0], #0xAA55 ;; look for signature
9501 jne rom_scan_increment
9503 jnz rom_scan_increment
9504 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9506 ;; We want our increment in 512-byte quantities, rounded to
9507 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9509 jz block_count_rounded
9510 and al, #0xfc ;; needs rounding up
9512 block_count_rounded:
9514 xor bx, bx ;; Restore DS back to 0000:
9517 ;; Push addr of ROM entry point
9519 push #0x0003 ;; Push offset
9520 mov bp, sp ;; Call ROM init routine using seg:off on stack
9521 db 0xff ;; call_far ss:[bp+0]
9524 cli ;; In case expansion ROM BIOS turns IF on
9525 add sp, #2 ;; Pop offset value
9526 pop cx ;; Pop seg value (restore CX)
9527 pop ax ;; Restore AX
9529 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9530 ;; because the segment selector is shifted left 4 bits.
9535 xor ax, ax ;; Restore DS back to 0000:
9541 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9542 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9543 ; but the tables themeselves can be elsewhere.
9552 mov cx, #0x001f ; 0x1f bytes to copy
9554 mov es, ax ; destination segment is 0xf0000
9555 mov di, #smbios_entry_point ; destination offset
9557 mov ds, ax ; source segment is 0x9f000
9558 mov si, #0x0000 ; source offset is 0
9576 ;; for 'C' strings and other data, insert them here with
9577 ;; a the following hack:
9578 ;; DATA_SEG_DEFS_HERE
9584 .org 0xe05b ; POST Entry Point
9589 ;; first reset the DMA controllers
9593 ;; then initialize the DMA controllers
9595 out 0xD6, al ; cascade mode of channel 4 enabled
9597 out 0xD4, al ; unmask channel 4
9599 ;; Examine CMOS shutdown status.
9607 ;; Reset CMOS shutdown status.
9609 out 0x70, AL ; select CMOS register Fh
9611 out 0x71, AL ; set shutdown action to normal
9613 ;; Examine CMOS shutdown status.
9616 ;; 0x00, 0x09, 0x0D+ = normal startup
9624 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9628 ;; Examine CMOS shutdown status.
9629 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9631 call _shutdown_status_panic
9637 ; 0xb0, 0x20, /* mov al, #0x20 */
9638 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9648 ; case 0: normal startup
9657 ;; zero out BIOS data area (40:00..40:ff)
9659 mov cx, #0x0080 ;; 128 words
9665 call _log_bios_start
9667 ;; set all interrupts to default handler
9668 mov bx, #0x0000 ;; offset index
9669 mov cx, #0x0100 ;; counter (256 interrupts)
9670 mov ax, #dummy_iret_handler
9680 loop post_default_ints
9682 ;; set vector 0x79 to zero
9683 ;; this is used by 'gardian angel' protection system
9684 SET_INT_VECTOR(0x79, #0, #0)
9686 ;; base memory in K 40:13 (word)
9687 mov ax, #BASE_MEM_IN_K
9691 ;; Manufacturing Test 40:12
9694 ;; Warm Boot Flag 0040:0072
9695 ;; value of 1234h = skip memory checks
9699 ;; Printer Services vector
9700 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9702 ;; Bootstrap failure vector
9703 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9705 ;; Bootstrap Loader vector
9706 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9708 ;; User Timer Tick vector
9709 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9711 ;; Memory Size Check vector
9712 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9714 ;; Equipment Configuration Check vector
9715 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9718 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9724 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9725 ;; int 1C already points at dummy_iret_handler (above)
9726 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9729 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9734 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9740 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9741 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9745 mov 0x0417, al /* keyboard shift flags, set 1 */
9746 mov 0x0418, al /* keyboard shift flags, set 2 */
9747 mov 0x0419, al /* keyboard alt-numpad work area */
9748 mov 0x0471, al /* keyboard ctrl-break flag */
9749 mov 0x0497, al /* keyboard status flags 4 */
9751 mov 0x0496, al /* keyboard status flags 3 */
9754 /* keyboard head of buffer pointer */
9758 /* keyboard end of buffer pointer */
9761 /* keyboard pointer to start of buffer */
9765 /* keyboard pointer to end of buffer */
9769 /* init the keyboard */
9772 ;; mov CMOS Equipment Byte to BDA Equipment Word
9781 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9785 mov cl, #0x14 ; timeout value
9786 mov dx, #0x378 ; Parallel I/O address, port 1
9788 mov dx, #0x278 ; Parallel I/O address, port 2
9791 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9793 or ax, bx ; set number of parallel ports
9797 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9798 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9800 mov cl, #0x0a ; timeout value
9801 mov dx, #0x03f8 ; Serial I/O address, port 1
9803 mov dx, #0x02f8 ; Serial I/O address, port 2
9805 mov dx, #0x03e8 ; Serial I/O address, port 3
9807 mov dx, #0x02e8 ; Serial I/O address, port 4
9810 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9812 or ax, bx ; set number of serial port
9816 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9817 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9818 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9819 ;; BIOS DATA AREA 0x4CE ???
9820 call timer_tick_post
9823 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9825 ;; IRQ13 (FPU exception) setup
9826 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9829 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9834 mov al, #0x11 ; send initialisation commands
9849 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9850 #if BX_USE_PS2_MOUSE
9855 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9858 call _copy_e820_table
9877 call _print_bios_banner
9882 call floppy_drive_post
9889 call hard_drive_post
9892 ;; ATA/ATAPI driver setup
9897 #else // BX_USE_ATADRV
9902 call hard_drive_post
9904 #endif // BX_USE_ATADRV
9906 #if BX_ELTORITO_BOOT
9908 ;; eltorito floppy/harddisk emulation from cd
9912 #endif // BX_ELTORITO_BOOT
9915 //JMP_EP(0x0064) ; INT 19h location
9918 .org 0xe2c3 ; NMI Handler Entry Point
9920 ;; FIXME the NMI handler should not panic
9921 ;; but iret when called from int75 (fpu exception)
9922 call _nmi_handler_msg
9926 out 0xf0, al // clear irq13
9927 call eoi_both_pics // clear interrupt
9928 int 2 // legacy nmi call
9931 ;-------------------------------------------
9932 ;- INT 13h Fixed Disk Services Entry Point -
9933 ;-------------------------------------------
9934 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9936 //JMPL(int13_relocated)
9939 .org 0xe401 ; Fixed Disk Parameter Table
9944 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9948 ;-------------------------------------------
9949 ;- System BIOS Configuration Data Table
9950 ;-------------------------------------------
9951 .org BIOS_CONFIG_TABLE
9952 db 0x08 ; Table size (bytes) -Lo
9953 db 0x00 ; Table size (bytes) -Hi
9958 ; b7: 1=DMA channel 3 used by hard disk
9959 ; b6: 1=2 interrupt controllers present
9961 ; b4: 1=BIOS calls int 15h/4Fh every key
9962 ; b3: 1=wait for extern event supported (Int 15h/41h)
9963 ; b2: 1=extended BIOS data area used
9964 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9965 ; b0: 1=Dual bus (MicroChannel + ISA)
9969 (BX_CALL_INT15_4F << 4) | \
9971 (BX_USE_EBDA << 2) | \
9975 ; b7: 1=32-bit DMA supported
9976 ; b6: 1=int16h, function 9 supported
9977 ; b5: 1=int15h/C6h (get POS data) supported
9978 ; b4: 1=int15h/C7h (get mem map info) supported
9979 ; b3: 1=int15h/C8h (en/dis CPU) supported
9980 ; b2: 1=non-8042 kb controller
9981 ; b1: 1=data streaming supported
9995 ; b4: POST supports ROM-to-RAM enable/disable
9996 ; b3: SCSI on system board
9997 ; b2: info panel installed
9998 ; b1: Initial Machine Load (IML) system - BIOS on disk
9999 ; b0: SCSI supported in IML
10003 ; b6: EEPROM present
10004 ; b5-3: ABIOS presence (011 = not supported)
10006 ; b1: memory split above 16Mb supported
10007 ; b0: POSTEXT directly supported by POST
10009 ; Feature byte 5 (IBM)
10010 ; b1: enhanced mouse
10016 .org 0xe729 ; Baud Rate Generator Table
10021 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10027 call _int14_function
10033 ;----------------------------------------
10034 ;- INT 16h Keyboard Service Entry Point -
10035 ;----------------------------------------
10051 call _int16_function
10061 and BYTE [bp + 0x06], #0xbf
10069 or BYTE [bp + 0x06], #0x40
10077 int16_wait_for_key:
10081 jne int16_key_found
10085 /* no key yet, call int 15h, function AX=9002 */
10086 0x50, /* push AX */
10087 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10088 0xcd, 0x15, /* int 15h */
10090 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10092 jmp int16_wait_for_key
10097 call _int16_function
10102 /* notify int16 complete w/ int 15h, function AX=9102 */
10103 0x50, /* push AX */
10104 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10105 0xcd, 0x15, /* int 15h */
10112 ;-------------------------------------------------
10113 ;- INT09h : Keyboard Hardware Service Entry Point -
10114 ;-------------------------------------------------
10120 mov al, #0xAD ;;disable keyboard
10129 in al, #0x60 ;;read key from keyboard controller
10130 //test al, #0x80 ;;look for key release
10131 //jnz int09_process_key ;; dont pass releases to intercept?
10133 ;; check for extended key
10135 jne int09_call_int15_4f
10140 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10142 mov BYTE [0x496], al
10145 in al, #0x60 ;;read another key from keyboard controller
10149 int09_call_int15_4f:
10152 #ifdef BX_CALL_INT15_4F
10153 mov ah, #0x4f ;; allow for keyboard intercept
10160 //int09_process_key:
10163 call _int09_function
10169 call eoi_master_pic
10172 mov al, #0xAE ;;enable keyboard
10180 ;----------------------------------------
10181 ;- INT 13h Diskette Service Entry Point -
10182 ;----------------------------------------
10185 jmp int13_noeltorito
10187 ;---------------------------------------------
10188 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10189 ;---------------------------------------------
10190 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10200 mov al, #0x08 ; sense interrupt status
10218 mov ax, #0x0000 ;; segment 0000
10220 call eoi_master_pic
10222 or al, #0x80 ;; diskette interrupt has occurred
10230 .org 0xefc7 ; Diskette Controller Parameter Table
10231 diskette_param_table:
10232 ;; Since no provisions are made for multiple drive types, most
10233 ;; values in this table are ignored. I set parameters for 1.44M
10236 db 0x02 ;; head load time 0000001, DMA used
10248 ;----------------------------------------
10249 ;- INT17h : Printer Service Entry Point -
10250 ;----------------------------------------
10257 call _int17_function
10262 diskette_param_table2:
10263 ;; New diskette parameter table adding 3 parameters from IBM
10264 ;; Since no provisions are made for multiple drive types, most
10265 ;; values in this table are ignored. I set parameters for 1.44M
10268 db 0x02 ;; head load time 0000001, DMA used
10278 db 79 ;; maximum track
10279 db 0 ;; data transfer rate
10280 db 4 ;; drive type in cmos
10282 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10289 .org 0xf065 ; INT 10h Video Support Service Entry Point
10291 ;; dont do anything, since the VGA BIOS handles int10h requests
10294 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10299 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10300 ; ??? different for Pentium (machine check)?
10312 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10324 .org 0xf859 ; INT 15h System Services Entry Point
10338 #if BX_USE_PS2_MOUSE
10340 je int15_handler_mouse
10342 call _int15_function
10343 int15_handler_mouse_ret:
10345 int15_handler32_ret:
10355 #if BX_USE_PS2_MOUSE
10356 int15_handler_mouse:
10357 call _int15_function_mouse
10358 jmp int15_handler_mouse_ret
10363 call _int15_function32
10365 jmp int15_handler32_ret
10367 ;; Protected mode IDT descriptor
10369 ;; I just make the limit 0, so the machine will shutdown
10370 ;; if an exception occurs during protected mode memory
10373 ;; Set base to f0000 to correspond to beginning of BIOS,
10374 ;; in case I actually define an IDT later
10378 dw 0x0000 ;; limit 15:00
10379 dw 0x0000 ;; base 15:00
10380 db 0x0f ;; base 23:16
10382 ;; Real mode IDT descriptor
10384 ;; Set to typical real-mode values.
10389 dw 0x03ff ;; limit 15:00
10390 dw 0x0000 ;; base 15:00
10391 db 0x00 ;; base 23:16
10397 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10410 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10411 mov ds, ax ; on 16bit protected mode.
10412 jmp int1a_callfunction
10419 int1a_callfunction:
10420 call _int1a_function
10426 ;; int70h: IRQ8 - CMOS RTC
10433 call _int70_function
10441 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10449 ;; time to turn off drive(s)?
10452 jz int08_floppy_off
10455 jnz int08_floppy_off
10456 ;; turn motor(s) off
10465 mov eax, 0x046c ;; get ticks dword
10468 ;; compare eax to one days worth of timer ticks at 18.2 hz
10469 cmp eax, #0x001800B0
10470 jb int08_store_ticks
10471 ;; there has been a midnight rollover at this point
10472 xor eax, eax ;; zero out counter
10473 inc BYTE 0x0470 ;; increment rollover flag
10476 mov 0x046c, eax ;; store new ticks dword
10477 ;; chain to user timer tick INT #0x1c
10479 //;; call_ep [ds:loc]
10480 //CALL_EP( 0x1c << 2 )
10483 call eoi_master_pic
10488 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10492 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10494 ;------------------------------------------------
10495 ;- IRET Instruction for Dummy Interrupt Handler -
10496 ;------------------------------------------------
10497 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10498 dummy_iret_handler:
10501 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10510 .org 0xfff0 ; Power-up Entry Point
10517 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10518 .ascii BIOS_BUILD_DATE
10520 .org 0xfffe ; System Model ID
10524 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10527 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10528 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10529 * This font is public domain
10531 static Bit8u vgafont8[128*8]=
10533 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10534 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10535 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10536 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10537 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10538 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10539 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10540 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10541 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10542 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10543 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10544 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10545 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10546 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10547 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10548 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10549 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10550 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10551 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10552 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10553 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10554 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10555 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10556 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10557 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10558 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10559 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10560 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10561 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10562 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10563 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10564 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10566 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10567 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10568 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10569 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10570 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10571 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10572 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10573 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10574 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10575 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10576 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10577 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10578 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10579 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10580 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10581 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10582 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10583 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10584 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10585 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10586 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10587 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10588 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10589 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10590 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10591 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10592 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10593 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10594 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10595 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10596 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10597 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10598 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10599 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10600 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10601 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10602 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10603 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10604 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10605 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10606 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10607 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10608 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10609 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10610 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10611 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10612 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10613 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10614 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10615 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10616 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10617 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10618 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10619 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10620 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10621 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10622 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10623 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10624 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10625 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10626 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10627 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10629 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10630 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10631 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10632 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10633 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10634 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10635 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10636 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10637 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10638 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10639 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10640 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10641 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10642 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10643 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10644 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10645 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10646 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10647 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10648 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10649 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10650 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10651 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10652 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10653 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10654 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10655 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10656 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10657 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10658 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10659 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10660 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10666 // just carve out some blank space for HVMLOADER to write the MP tables to
10668 // NOTE: There should be enough space for a 32 processor entry MP table
10672 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10673 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
10674 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
10675 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
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 ;; 256 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 ;; 320 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 ;; 384 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 ;; 448 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 ;; 512 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 ;; 576 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 ;; 640 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 ;; 704 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 ;; 768 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 ;; 832 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 ;; 896 bytes
10689 smbios_entry_point:
10690 db 0,0,0,0,0,0,0,0 ; 8 bytes
10691 db 0,0,0,0,0,0,0,0 ; 16 bytes
10692 db 0,0,0,0,0,0,0,0 ; 24 bytes
10693 db 0,0,0,0,0,0,0 ; 31 bytes
10696 #else // !HVMASSIST
10700 // bcc-generated data will be placed here
10702 // For documentation of this config structure, look on developer.intel.com and
10703 // search for multiprocessor specification. Note that when you change anything
10704 // you must update the checksum (a pain!). It would be better to construct this
10705 // with C structures, or at least fill in the checksum automatically.
10707 // Maybe this structs could be moved elsewhere than d000
10709 #if (BX_SMP_PROCESSORS==1)
10710 // no structure necessary.
10711 #elif (BX_SMP_PROCESSORS==2)
10712 // define the Intel MP Configuration Structure for 2 processors at
10713 // APIC ID 0,1. I/O APIC at ID=2.
10716 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10717 dw (mp_config_end-mp_config_table) ;; table length
10719 db 0x65 ;; checksum
10720 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10721 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10722 db 0x20, 0x20, 0x20, 0x20
10723 db 0x20, 0x20, 0x20, 0x20
10724 dw 0,0 ;; oem table ptr
10725 dw 0 ;; oem table size
10726 dw 20 ;; entry count
10727 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10728 dw 0 ;; extended table length
10729 db 0 ;; extended table checksum
10732 db 0 ;; entry type=processor
10733 db 0 ;; local APIC id
10734 db 0x11 ;; local APIC version number
10735 db 3 ;; cpu flags: enabled, bootstrap processor
10736 db 0,6,0,0 ;; cpu signature
10737 dw 0x201,0 ;; feature flags
10741 db 0 ;; entry type=processor
10742 db 1 ;; local APIC id
10743 db 0x11 ;; local APIC version number
10744 db 1 ;; cpu flags: enabled
10745 db 0,6,0,0 ;; cpu signature
10746 dw 0x201,0 ;; feature flags
10750 db 1 ;; entry type=bus
10752 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10754 db 2 ;; entry type=I/O APIC
10755 db 2 ;; apic id=2. linux will set.
10756 db 0x11 ;; I/O APIC version number
10757 db 1 ;; flags=1=enabled
10758 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10760 db 3 ;; entry type=I/O interrupt
10761 db 0 ;; interrupt type=vectored interrupt
10762 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10763 db 0 ;; source bus ID is ISA
10764 db 0 ;; source bus IRQ
10765 db 2 ;; destination I/O APIC ID
10766 db 0 ;; destination I/O APIC interrrupt in
10767 ;; repeat pattern for interrupts 0-15
10777 db 3,0,0,0,0,10,2,10
10778 db 3,0,0,0,0,11,2,11
10779 db 3,0,0,0,0,12,2,12
10780 db 3,0,0,0,0,13,2,13
10781 db 3,0,0,0,0,14,2,14
10782 db 3,0,0,0,0,15,2,15
10783 #elif (BX_SMP_PROCESSORS==4)
10784 // define the Intel MP Configuration Structure for 4 processors at
10785 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10788 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10789 dw (mp_config_end-mp_config_table) ;; table length
10791 db 0xdd ;; checksum
10792 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10793 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10794 db 0x20, 0x20, 0x20, 0x20
10795 db 0x20, 0x20, 0x20, 0x20
10796 dw 0,0 ;; oem table ptr
10797 dw 0 ;; oem table size
10798 dw 22 ;; entry count
10799 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10800 dw 0 ;; extended table length
10801 db 0 ;; extended table checksum
10804 db 0 ;; entry type=processor
10805 db 0 ;; local APIC id
10806 db 0x11 ;; local APIC version number
10807 db 3 ;; cpu flags: enabled, bootstrap processor
10808 db 0,6,0,0 ;; cpu signature
10809 dw 0x201,0 ;; feature flags
10813 db 0 ;; entry type=processor
10814 db 1 ;; local APIC id
10815 db 0x11 ;; local APIC version number
10816 db 1 ;; cpu flags: enabled
10817 db 0,6,0,0 ;; cpu signature
10818 dw 0x201,0 ;; feature flags
10822 db 0 ;; entry type=processor
10823 db 2 ;; local APIC id
10824 db 0x11 ;; local APIC version number
10825 db 1 ;; cpu flags: enabled
10826 db 0,6,0,0 ;; cpu signature
10827 dw 0x201,0 ;; feature flags
10831 db 0 ;; entry type=processor
10832 db 3 ;; local APIC id
10833 db 0x11 ;; local APIC version number
10834 db 1 ;; cpu flags: enabled
10835 db 0,6,0,0 ;; cpu signature
10836 dw 0x201,0 ;; feature flags
10840 db 1 ;; entry type=bus
10842 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10844 db 2 ;; entry type=I/O APIC
10845 db 4 ;; apic id=4. linux will set.
10846 db 0x11 ;; I/O APIC version number
10847 db 1 ;; flags=1=enabled
10848 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10850 db 3 ;; entry type=I/O interrupt
10851 db 0 ;; interrupt type=vectored interrupt
10852 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10853 db 0 ;; source bus ID is ISA
10854 db 0 ;; source bus IRQ
10855 db 4 ;; destination I/O APIC ID
10856 db 0 ;; destination I/O APIC interrrupt in
10857 ;; repeat pattern for interrupts 0-15
10867 db 3,0,0,0,0,10,4,10
10868 db 3,0,0,0,0,11,4,11
10869 db 3,0,0,0,0,12,4,12
10870 db 3,0,0,0,0,13,4,13
10871 db 3,0,0,0,0,14,4,14
10872 db 3,0,0,0,0,15,4,15
10873 #elif (BX_SMP_PROCESSORS==8)
10874 // define the Intel MP Configuration Structure for 8 processors at
10875 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10878 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10879 dw (mp_config_end-mp_config_table) ;; table length
10881 db 0xc3 ;; checksum
10882 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10883 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10884 db 0x20, 0x20, 0x20, 0x20
10885 db 0x20, 0x20, 0x20, 0x20
10886 dw 0,0 ;; oem table ptr
10887 dw 0 ;; oem table size
10888 dw 26 ;; entry count
10889 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10890 dw 0 ;; extended table length
10891 db 0 ;; extended table checksum
10894 db 0 ;; entry type=processor
10895 db 0 ;; local APIC id
10896 db 0x11 ;; local APIC version number
10897 db 3 ;; cpu flags: enabled, bootstrap processor
10898 db 0,6,0,0 ;; cpu signature
10899 dw 0x201,0 ;; feature flags
10903 db 0 ;; entry type=processor
10904 db 1 ;; local APIC id
10905 db 0x11 ;; local APIC version number
10906 db 1 ;; cpu flags: enabled
10907 db 0,6,0,0 ;; cpu signature
10908 dw 0x201,0 ;; feature flags
10912 db 0 ;; entry type=processor
10913 db 2 ;; local APIC id
10914 db 0x11 ;; local APIC version number
10915 db 1 ;; cpu flags: enabled
10916 db 0,6,0,0 ;; cpu signature
10917 dw 0x201,0 ;; feature flags
10921 db 0 ;; entry type=processor
10922 db 3 ;; local APIC id
10923 db 0x11 ;; local APIC version number
10924 db 1 ;; cpu flags: enabled
10925 db 0,6,0,0 ;; cpu signature
10926 dw 0x201,0 ;; feature flags
10930 db 0 ;; entry type=processor
10931 db 4 ;; local APIC id
10932 db 0x11 ;; local APIC version number
10933 db 1 ;; cpu flags: enabled
10934 db 0,6,0,0 ;; cpu signature
10935 dw 0x201,0 ;; feature flags
10939 db 0 ;; entry type=processor
10940 db 5 ;; local APIC id
10941 db 0x11 ;; local APIC version number
10942 db 1 ;; cpu flags: enabled
10943 db 0,6,0,0 ;; cpu signature
10944 dw 0x201,0 ;; feature flags
10948 db 0 ;; entry type=processor
10949 db 6 ;; local APIC id
10950 db 0x11 ;; local APIC version number
10951 db 1 ;; cpu flags: enabled
10952 db 0,6,0,0 ;; cpu signature
10953 dw 0x201,0 ;; feature flags
10957 db 0 ;; entry type=processor
10958 db 7 ;; local APIC id
10959 db 0x11 ;; local APIC version number
10960 db 1 ;; cpu flags: enabled
10961 db 0,6,0,0 ;; cpu signature
10962 dw 0x201,0 ;; feature flags
10966 db 1 ;; entry type=bus
10968 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10970 db 2 ;; entry type=I/O APIC
10972 db 0x11 ;; I/O APIC version number
10973 db 1 ;; flags=1=enabled
10974 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10976 db 3 ;; entry type=I/O interrupt
10977 db 0 ;; interrupt type=vectored interrupt
10978 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10979 db 0 ;; source bus ID is ISA
10980 db 0 ;; source bus IRQ
10981 db 8 ;; destination I/O APIC ID
10982 db 0 ;; destination I/O APIC interrrupt in
10983 ;; repeat pattern for interrupts 0-15
10993 db 3,0,0,0,0,10,8,10
10994 db 3,0,0,0,0,11,8,11
10995 db 3,0,0,0,0,12,8,12
10996 db 3,0,0,0,0,13,8,13
10997 db 3,0,0,0,0,14,8,14
10998 db 3,0,0,0,0,15,8,15
11000 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11001 #endif // if (BX_SMP_PROCESSORS==...)
11003 mp_config_end: // this label used to find length of mp structure
11006 #if (BX_SMP_PROCESSORS>1)
11008 mp_floating_pointer_structure:
11009 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
11010 dw mp_config_table, 0xf ;; pointer to MP configuration table
11011 db 1 ;; length of this struct in 16-bit byte chunks
11012 db 4 ;; MP spec revision
11013 db 0xc1 ;; checksum
11014 db 0 ;; MP feature byte 1. value 0 means look at the config table
11015 db 0,0,0,0 ;; MP feature bytes 2-5.
11020 #endif // HVMASSIST