2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.3 2008/05/02 23:58:51 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 1
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.3 $";
949 static char bios_date_string[] = "$Date: 2008/05/02 23:58:51 $";
951 static char CVSID[] = "$Id: rombios.c,v 1.3 2008/05/02 23:58:51 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 status = inb(iobase1 + ATA_CB_STAT);
2881 if (status & ATA_CB_STAT_BSY) return 2;
2883 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2884 // outb(iobase1 + ATA_CB_FR, 0x00);
2885 // outb(iobase1 + ATA_CB_SC, 0x00);
2886 // outb(iobase1 + ATA_CB_SN, 0x00);
2887 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2888 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2889 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2890 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2892 // Device should ok to receive command
2894 status = inb(iobase1 + ATA_CB_STAT);
2895 if ( !(status & ATA_CB_STAT_BSY) ) break;
2898 if (status & ATA_CB_STAT_ERR) {
2899 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2901 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2902 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2906 // Normalize address
2907 cmdseg += (cmdoff / 16);
2910 // Send command to device
2912 sti ;; enable higher priority interrupts
2917 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2918 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2919 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2920 mov es, ax ;; segment in es
2922 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2926 outsw ;; CX words transfered from port(DX) to ES:[SI]
2931 if (inout == ATA_DATA_NO) {
2932 status = inb(iobase1 + ATA_CB_STAT);
2937 status = inb(iobase1 + ATA_CB_STAT);
2939 // Check if command completed
2940 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2942 if (status & ATA_CB_STAT_ERR) {
2943 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2947 // Device must be ready to send data
2948 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2949 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2950 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
2954 // Normalize address
2955 bufseg += (bufoff / 16);
2958 // Get the byte count
2959 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
2961 // adjust to read what we want
2974 lafter=lcount-length;
2986 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
2987 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
2989 // If counts not dividable by 4, use 16bits mode
2991 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
2992 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
2993 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
2995 // adds an extra byte if count are odd. before is always even
2996 if (lcount & 0x01) {
2998 if ((lafter > 0) && (lafter & 0x01)) {
3003 if (lmode == ATA_MODE_PIO32) {
3004 lcount>>=2; lbefore>>=2; lafter>>=2;
3007 lcount>>=1; lbefore>>=1; lafter>>=1;
3016 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3018 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3019 jcxz ata_packet_no_before
3021 mov ah, _ata_cmd_packet.lmode + 2[bp]
3022 cmp ah, #ATA_MODE_PIO32
3023 je ata_packet_in_before_32
3025 ata_packet_in_before_16:
3027 loop ata_packet_in_before_16
3028 jmp ata_packet_no_before
3030 ata_packet_in_before_32:
3032 ata_packet_in_before_32_loop:
3034 loop ata_packet_in_before_32_loop
3037 ata_packet_no_before:
3038 mov cx, _ata_cmd_packet.lcount + 2[bp]
3039 jcxz ata_packet_after
3041 mov di, _ata_cmd_packet.bufoff + 2[bp]
3042 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3045 mov ah, _ata_cmd_packet.lmode + 2[bp]
3046 cmp ah, #ATA_MODE_PIO32
3051 insw ;; CX words transfered tp port(DX) to ES:[DI]
3052 jmp ata_packet_after
3056 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3059 mov cx, _ata_cmd_packet.lafter + 2[bp]
3060 jcxz ata_packet_done
3062 mov ah, _ata_cmd_packet.lmode + 2[bp]
3063 cmp ah, #ATA_MODE_PIO32
3064 je ata_packet_in_after_32
3066 ata_packet_in_after_16:
3068 loop ata_packet_in_after_16
3071 ata_packet_in_after_32:
3073 ata_packet_in_after_32_loop:
3075 loop ata_packet_in_after_32_loop
3082 // Compute new buffer address
3085 // Save transferred bytes count
3087 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3091 // Final check, device must be ready
3092 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3093 != ATA_CB_STAT_RDY ) {
3094 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3098 // Enable interrupts
3099 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3103 // ---------------------------------------------------------------------------
3104 // End of ATA/ATAPI Driver
3105 // ---------------------------------------------------------------------------
3107 // ---------------------------------------------------------------------------
3108 // Start of ATA/ATAPI generic functions
3109 // ---------------------------------------------------------------------------
3112 atapi_get_sense(device)
3119 memsetb(get_SS(),atacmd,0,12);
3124 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3127 if ((buffer[0] & 0x7e) == 0x70) {
3128 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3135 atapi_is_ready(device)
3141 memsetb(get_SS(),atacmd,0,12);
3144 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3147 if (atapi_get_sense(device) !=0 ) {
3148 memsetb(get_SS(),atacmd,0,12);
3150 // try to send Test Unit Ready again
3151 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3154 return atapi_get_sense(device);
3160 atapi_is_cdrom(device)
3163 Bit16u ebda_seg=read_word(0x0040,0x000E);
3165 if (device >= BX_MAX_ATA_DEVICES)
3168 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3171 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3177 // ---------------------------------------------------------------------------
3178 // End of ATA/ATAPI generic functions
3179 // ---------------------------------------------------------------------------
3181 #endif // BX_USE_ATADRV
3183 #if BX_ELTORITO_BOOT
3185 // ---------------------------------------------------------------------------
3186 // Start of El-Torito boot functions
3187 // ---------------------------------------------------------------------------
3192 Bit16u ebda_seg=read_word(0x0040,0x000E);
3194 //BX_DEBUG("rombios: cdemu_init\n");
3196 // the only important data is this one for now
3197 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3203 Bit16u ebda_seg=read_word(0x0040,0x000E);
3205 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3209 cdemu_emulated_drive()
3211 Bit16u ebda_seg=read_word(0x0040,0x000E);
3213 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3216 static char isotag[6]="CD001";
3217 static char eltorito[24]="EL TORITO SPECIFICATION";
3219 // Returns ah: emulated drive, al: error code
3224 Bit16u ebda_seg=read_word(0x0040,0x000E);
3225 Bit8u atacmd[12], buffer[2048];
3227 Bit16u boot_segment, nbsectors, i, error;
3231 // Find out the first cdrom
3232 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3233 if (atapi_is_cdrom(device)) break;
3237 if(device >= BX_MAX_ATA_DEVICES) return 2;
3239 // Read the Boot Record Volume Descriptor
3240 memsetb(get_SS(),atacmd,0,12);
3241 atacmd[0]=0x28; // READ command
3242 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3243 atacmd[8]=(0x01 & 0x00ff); // Sectors
3244 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3245 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3246 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3247 atacmd[5]=(0x11 & 0x000000ff);
3248 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3253 if(buffer[0]!=0)return 4;
3255 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3258 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3260 // ok, now we calculate the Boot catalog address
3261 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3263 // And we read the Boot Catalog
3264 memsetb(get_SS(),atacmd,0,12);
3265 atacmd[0]=0x28; // READ command
3266 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3267 atacmd[8]=(0x01 & 0x00ff); // Sectors
3268 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3269 atacmd[3]=(lba & 0x00ff0000) >> 16;
3270 atacmd[4]=(lba & 0x0000ff00) >> 8;
3271 atacmd[5]=(lba & 0x000000ff);
3272 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3278 if(buffer[0x00]!=0x01)return 8; // Header
3279 if(buffer[0x01]!=0x00)return 9; // Platform
3280 if(buffer[0x1E]!=0x55)return 10; // key 1
3281 if(buffer[0x1F]!=0xAA)return 10; // key 2
3283 // Initial/Default Entry
3284 if(buffer[0x20]!=0x88)return 11; // Bootable
3286 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3287 if(buffer[0x21]==0){
3288 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3289 // Win2000 cd boot needs to know it booted from cd
3290 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3292 else if(buffer[0x21]<4)
3293 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3295 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3297 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3298 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3300 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3301 if(boot_segment==0x0000)boot_segment=0x07C0;
3303 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3304 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3306 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3307 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3309 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3310 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3312 // And we read the image in memory
3313 memsetb(get_SS(),atacmd,0,12);
3314 atacmd[0]=0x28; // READ command
3315 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3316 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3317 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3318 atacmd[3]=(lba & 0x00ff0000) >> 16;
3319 atacmd[4]=(lba & 0x0000ff00) >> 8;
3320 atacmd[5]=(lba & 0x000000ff);
3321 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3325 // Remember the media type
3326 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3327 case 0x01: // 1.2M floppy
3328 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3329 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3330 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3332 case 0x02: // 1.44M floppy
3333 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3334 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3335 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3337 case 0x03: // 2.88M floppy
3338 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3339 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3340 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3342 case 0x04: // Harddrive
3343 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3344 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3345 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3346 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3350 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3351 // Increase bios installed hardware number of devices
3352 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3353 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3355 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3359 // everything is ok, so from now on, the emulation is active
3360 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3361 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3363 // return the boot drive + no error
3364 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3367 // ---------------------------------------------------------------------------
3368 // End of El-Torito boot functions
3369 // ---------------------------------------------------------------------------
3370 #endif // BX_ELTORITO_BOOT
3373 int14_function(regs, ds, iret_addr)
3374 pusha_regs_t regs; // regs pushed from PUSHA instruction
3375 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3376 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3378 Bit16u addr,timer,val16;
3385 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3386 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3387 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3388 switch (regs.u.r8.ah) {
3390 outb(addr+3, inb(addr+3) | 0x80);
3391 if (regs.u.r8.al & 0xE0 == 0) {
3395 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3396 outb(addr, val16 & 0xFF);
3397 outb(addr+1, val16 >> 8);
3399 outb(addr+3, regs.u.r8.al & 0x1F);
3400 regs.u.r8.ah = inb(addr+5);
3401 regs.u.r8.al = inb(addr+6);
3402 ClearCF(iret_addr.flags);
3405 timer = read_word(0x0040, 0x006C);
3406 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3407 val16 = read_word(0x0040, 0x006C);
3408 if (val16 != timer) {
3413 if (timeout) outb(addr, regs.u.r8.al);
3414 regs.u.r8.ah = inb(addr+5);
3415 if (!timeout) regs.u.r8.ah |= 0x80;
3416 ClearCF(iret_addr.flags);
3419 timer = read_word(0x0040, 0x006C);
3420 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3421 val16 = read_word(0x0040, 0x006C);
3422 if (val16 != timer) {
3429 regs.u.r8.al = inb(addr);
3431 regs.u.r8.ah = inb(addr+5);
3433 ClearCF(iret_addr.flags);
3436 regs.u.r8.ah = inb(addr+5);
3437 regs.u.r8.al = inb(addr+6);
3438 ClearCF(iret_addr.flags);
3441 SetCF(iret_addr.flags); // Unsupported
3444 SetCF(iret_addr.flags); // Unsupported
3449 int15_function(regs, ES, DS, FLAGS)
3450 pusha_regs_t regs; // REGS pushed via pusha
3451 Bit16u ES, DS, FLAGS;
3453 Bit16u ebda_seg=read_word(0x0040,0x000E);
3454 bx_bool prev_a20_enable;
3463 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3465 switch (regs.u.r8.ah) {
3466 case 0x24: /* A20 Control */
3467 switch (regs.u.r8.al) {
3479 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3489 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3491 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3497 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3501 /* keyboard intercept */
3503 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3510 case 0x52: // removable media eject
3512 regs.u.r8.ah = 0; // "ok ejection may proceed"
3516 if( regs.u.r8.al == 0 ) {
3517 // Set Interval requested.
3518 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3519 // Interval not already set.
3520 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3521 write_word( 0x40, 0x98, ES ); // Byte location, segment
3522 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3523 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3524 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3526 irqDisable = inb( 0xA1 );
3527 outb( 0xA1, irqDisable & 0xFE );
3528 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3529 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3531 // Interval already set.
3532 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3534 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3536 } else if( regs.u.r8.al == 1 ) {
3537 // Clear Interval requested
3538 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3540 bRegister = inb_cmos( 0xB );
3541 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3543 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3545 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3554 # error "Int15 function 87h not supported on < 80386"
3556 // +++ should probably have descriptor checks
3557 // +++ should have exception handlers
3559 // turn off interrupts
3564 prev_a20_enable = set_enable_a20(1); // enable A20 line
3566 // 128K max of transfer on 386+ ???
3567 // source == destination ???
3569 // ES:SI points to descriptor table
3570 // offset use initially comments
3571 // ==============================================
3572 // 00..07 Unused zeros Null descriptor
3573 // 08..0f GDT zeros filled in by BIOS
3574 // 10..17 source ssssssss source of data
3575 // 18..1f dest dddddddd destination of data
3576 // 20..27 CS zeros filled in by BIOS
3577 // 28..2f SS zeros filled in by BIOS
3584 // check for access rights of source & dest here
3586 // Initialize GDT descriptor
3587 base15_00 = (ES << 4) + regs.u.r16.si;
3588 base23_16 = ES >> 12;
3589 if (base15_00 < (ES<<4))
3591 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3592 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3593 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3594 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3595 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3597 // Initialize CS descriptor
3598 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3599 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3600 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3601 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3602 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3604 // Initialize SS descriptor
3606 base15_00 = ss << 4;
3607 base23_16 = ss >> 12;
3608 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3609 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3610 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3611 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3612 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3616 // Compile generates locals offset info relative to SP.
3617 // Get CX (word count) from stack.
3620 mov cx, _int15_function.CX [bx]
3622 // since we need to set SS:SP, save them to the BDA
3623 // for future restore
3633 lidt [pmode_IDT_info]
3634 ;; perhaps do something with IDT here
3636 ;; set PE bit in CR0
3640 ;; far jump to flush CPU queue after transition to protected mode
3641 JMP_AP(0x0020, protected_mode)
3644 ;; GDT points to valid descriptor table, now load SS, DS, ES
3645 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3647 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3649 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3655 movsw ;; move CX words from DS:SI to ES:DI
3657 ;; make sure DS and ES limits are 64KB
3662 ;; reset PG bit in CR0 ???
3667 ;; far jump to flush CPU queue after transition to real mode
3668 JMP_AP(0xf000, real_mode)
3671 ;; restore IDT to normal real-mode defaults
3673 lidt [rmode_IDT_info]
3675 // restore SS:SP from the BDA
3683 set_enable_a20(prev_a20_enable);
3685 // turn back on interrupts
3696 // Get the amount of extended memory (above 1M)
3698 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3701 regs.u.r8.al = inb_cmos(0x30);
3702 regs.u.r8.ah = inb_cmos(0x31);
3705 if(regs.u.r16.ax > 0x3c00)
3706 regs.u.r16.ax = 0x3c00;
3713 /* Device busy interrupt. Called by Int 16h when no key available */
3717 /* Interrupt complete. Called by Int 16h when key becomes available */
3721 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3723 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3729 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3734 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3744 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3746 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3750 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3751 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3753 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3758 #if BX_USE_PS2_MOUSE
3760 int15_function_mouse(regs, ES, DS, FLAGS)
3761 pusha_regs_t regs; // REGS pushed via pusha
3762 Bit16u ES, DS, FLAGS;
3764 Bit16u ebda_seg=read_word(0x0040,0x000E);
3765 Bit8u mouse_flags_1, mouse_flags_2;
3766 Bit16u mouse_driver_seg;
3767 Bit16u mouse_driver_offset;
3768 Bit8u comm_byte, prev_command_byte;
3769 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3771 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3773 switch (regs.u.r8.ah) {
3775 // Return Codes status in AH
3776 // =========================
3778 // 01: invalid subfunction (AL > 7)
3779 // 02: invalid input value (out of allowable range)
3780 // 03: interface error
3781 // 04: resend command received from mouse controller,
3782 // device driver should attempt command again
3783 // 05: cannot enable mouse, since no far call has been installed
3784 // 80/86: mouse service not implemented
3786 switch (regs.u.r8.al) {
3787 case 0: // Disable/Enable Mouse
3788 BX_DEBUG_INT15("case 0:\n");
3789 switch (regs.u.r8.bh) {
3790 case 0: // Disable Mouse
3791 BX_DEBUG_INT15("case 0: disable mouse\n");
3792 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3793 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3795 ret = get_mouse_data(&mouse_data1);
3796 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3809 case 1: // Enable Mouse
3810 BX_DEBUG_INT15("case 1: enable mouse\n");
3811 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3812 if ( (mouse_flags_2 & 0x80) == 0 ) {
3813 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3815 regs.u.r8.ah = 5; // no far call installed
3818 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3819 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3821 ret = get_mouse_data(&mouse_data1);
3822 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3823 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3833 default: // invalid subfunction
3834 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3836 regs.u.r8.ah = 1; // invalid subfunction
3841 case 1: // Reset Mouse
3842 case 5: // Initialize Mouse
3843 BX_DEBUG_INT15("case 1 or 5:\n");
3844 if (regs.u.r8.al == 5) {
3845 if (regs.u.r8.bh != 3) {
3847 regs.u.r8.ah = 0x02; // invalid input
3850 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3851 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3852 mouse_flags_1 = 0x00;
3853 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3854 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3857 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3858 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3860 ret = get_mouse_data(&mouse_data3);
3861 // if no mouse attached, it will return RESEND
3862 if (mouse_data3 == 0xfe) {
3866 if (mouse_data3 != 0xfa)
3867 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3869 ret = get_mouse_data(&mouse_data1);
3871 ret = get_mouse_data(&mouse_data2);
3873 // turn IRQ12 and packet generation on
3874 enable_mouse_int_and_events();
3877 regs.u.r8.bl = mouse_data1;
3878 regs.u.r8.bh = mouse_data2;
3890 case 2: // Set Sample Rate
3891 BX_DEBUG_INT15("case 2:\n");
3892 switch (regs.u.r8.bh) {
3893 case 0: mouse_data1 = 10; break; // 10 reports/sec
3894 case 1: mouse_data1 = 20; break; // 20 reports/sec
3895 case 2: mouse_data1 = 40; break; // 40 reports/sec
3896 case 3: mouse_data1 = 60; break; // 60 reports/sec
3897 case 4: mouse_data1 = 80; break; // 80 reports/sec
3898 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3899 case 6: mouse_data1 = 200; break; // 200 reports/sec
3900 default: mouse_data1 = 0;
3902 if (mouse_data1 > 0) {
3903 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3905 ret = get_mouse_data(&mouse_data2);
3906 ret = send_to_mouse_ctrl(mouse_data1);
3907 ret = get_mouse_data(&mouse_data2);
3913 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3918 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3922 case 3: // Set Resolution
3923 BX_DEBUG_INT15("case 3:\n");
3925 // 0 = 25 dpi, 1 count per millimeter
3926 // 1 = 50 dpi, 2 counts per millimeter
3927 // 2 = 100 dpi, 4 counts per millimeter
3928 // 3 = 200 dpi, 8 counts per millimeter
3933 case 4: // Get Device ID
3934 BX_DEBUG_INT15("case 4:\n");
3935 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3936 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3938 ret = get_mouse_data(&mouse_data1);
3939 ret = get_mouse_data(&mouse_data2);
3942 regs.u.r8.bh = mouse_data2;
3946 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3950 case 6: // Return Status & Set Scaling Factor...
3951 BX_DEBUG_INT15("case 6:\n");
3952 switch (regs.u.r8.bh) {
3953 case 0: // Return Status
3954 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3955 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
3957 ret = get_mouse_data(&mouse_data1);
3958 if (mouse_data1 != 0xfa)
3959 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
3961 ret = get_mouse_data(&mouse_data1);
3963 ret = get_mouse_data(&mouse_data2);
3965 ret = get_mouse_data(&mouse_data3);
3969 regs.u.r8.bl = mouse_data1;
3970 regs.u.r8.cl = mouse_data2;
3971 regs.u.r8.dl = mouse_data3;
3972 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3983 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3986 case 1: // Set Scaling Factor to 1:1
3987 case 2: // Set Scaling Factor to 2:1
3988 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3989 if (regs.u.r8.bh == 1) {
3990 ret = send_to_mouse_ctrl(0xE6);
3992 ret = send_to_mouse_ctrl(0xE7);
3995 get_mouse_data(&mouse_data1);
3996 ret = (mouse_data1 != 0xFA);
4004 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4006 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4010 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4014 case 7: // Set Mouse Handler Address
4015 BX_DEBUG_INT15("case 7:\n");
4016 mouse_driver_seg = ES;
4017 mouse_driver_offset = regs.u.r16.bx;
4018 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4019 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4020 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4021 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4022 /* remove handler */
4023 if ( (mouse_flags_2 & 0x80) != 0 ) {
4024 mouse_flags_2 &= ~0x80;
4025 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4029 /* install handler */
4030 mouse_flags_2 |= 0x80;
4032 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4038 BX_DEBUG_INT15("case default:\n");
4039 regs.u.r8.ah = 1; // invalid function
4045 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4046 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4048 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4055 int15_function32(regs, ES, DS, FLAGS)
4056 pushad_regs_t regs; // REGS pushed via pushad
4057 Bit16u ES, DS, FLAGS;
4059 Bit32u extended_memory_size=0; // 64bits long
4062 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4064 switch (regs.u.r8.ah) {
4066 // Wait for CX:DX microseconds. currently using the
4067 // refresh request port 0x61 bit4, toggling every 15usec
4075 ;; Get the count in eax
4078 mov ax, _int15_function.CX [bx]
4081 mov ax, _int15_function.DX [bx]
4083 ;; convert to numbers of 15usec ticks
4089 ;; wait for ecx number of refresh requests
4110 switch(regs.u.r8.al)
4112 case 0x20: // coded by osmaker aka K.J.
4113 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4116 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4117 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4119 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4120 memcpyb(ES, regs.u.r16.di,
4121 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4123 regs.u.r32.ebx += 0x14;
4124 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4126 regs.u.r32.eax = 0x534D4150;
4127 regs.u.r32.ecx = 0x14;
4130 } else if (regs.u.r16.bx == 1) {
4131 extended_memory_size = inb_cmos(0x35);
4132 extended_memory_size <<= 8;
4133 extended_memory_size |= inb_cmos(0x34);
4134 extended_memory_size *= 64;
4135 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4137 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4139 extended_memory_size *= 1024;
4140 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4142 if (extended_memory_size <= 15728640)
4144 extended_memory_size = inb_cmos(0x31);
4145 extended_memory_size <<= 8;
4146 extended_memory_size |= inb_cmos(0x30);
4147 extended_memory_size *= 1024;
4150 write_word(ES, regs.u.r16.di, 0x0000);
4151 write_word(ES, regs.u.r16.di+2, 0x0010);
4152 write_word(ES, regs.u.r16.di+4, 0x0000);
4153 write_word(ES, regs.u.r16.di+6, 0x0000);
4155 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4156 extended_memory_size >>= 16;
4157 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4158 extended_memory_size >>= 16;
4159 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4160 extended_memory_size >>= 16;
4161 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4163 write_word(ES, regs.u.r16.di+16, 0x1);
4164 write_word(ES, regs.u.r16.di+18, 0x0);
4167 regs.u.r32.eax = 0x534D4150;
4168 regs.u.r32.ecx = 0x14;
4171 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4172 goto int15_unimplemented;
4175 switch(regs.u.r16.bx)
4178 write_word(ES, regs.u.r16.di, 0x00);
4179 write_word(ES, regs.u.r16.di+2, 0x00);
4180 write_word(ES, regs.u.r16.di+4, 0x00);
4181 write_word(ES, regs.u.r16.di+6, 0x00);
4183 write_word(ES, regs.u.r16.di+8, 0xFC00);
4184 write_word(ES, regs.u.r16.di+10, 0x0009);
4185 write_word(ES, regs.u.r16.di+12, 0x0000);
4186 write_word(ES, regs.u.r16.di+14, 0x0000);
4188 write_word(ES, regs.u.r16.di+16, 0x1);
4189 write_word(ES, regs.u.r16.di+18, 0x0);
4193 regs.u.r32.eax = 0x534D4150;
4194 regs.u.r32.ecx = 0x14;
4199 extended_memory_size = inb_cmos(0x35);
4200 extended_memory_size <<= 8;
4201 extended_memory_size |= inb_cmos(0x34);
4202 extended_memory_size *= 64;
4203 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4205 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4207 extended_memory_size *= 1024;
4208 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4210 if(extended_memory_size <= 15728640)
4212 extended_memory_size = inb_cmos(0x31);
4213 extended_memory_size <<= 8;
4214 extended_memory_size |= inb_cmos(0x30);
4215 extended_memory_size *= 1024;
4218 write_word(ES, regs.u.r16.di, 0x0000);
4219 write_word(ES, regs.u.r16.di+2, 0x0010);
4220 write_word(ES, regs.u.r16.di+4, 0x0000);
4221 write_word(ES, regs.u.r16.di+6, 0x0000);
4223 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4224 extended_memory_size >>= 16;
4225 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4226 extended_memory_size >>= 16;
4227 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4228 extended_memory_size >>= 16;
4229 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4231 write_word(ES, regs.u.r16.di+16, 0x1);
4232 write_word(ES, regs.u.r16.di+18, 0x0);
4235 regs.u.r32.eax = 0x534D4150;
4236 regs.u.r32.ecx = 0x14;
4240 default: /* AX=E820, DX=534D4150, BX unrecognized */
4241 goto int15_unimplemented;
4246 // if DX != 0x534D4150)
4247 goto int15_unimplemented;
4252 // do we have any reason to fail here ?
4255 // my real system sets ax and bx to 0
4256 // this is confirmed by Ralph Brown list
4257 // but syslinux v1.48 is known to behave
4258 // strangely if ax is set to 0
4259 // regs.u.r16.ax = 0;
4260 // regs.u.r16.bx = 0;
4262 // Get the amount of extended memory (above 1M)
4263 regs.u.r8.cl = inb_cmos(0x30);
4264 regs.u.r8.ch = inb_cmos(0x31);
4267 if(regs.u.r16.cx > 0x3c00)
4269 regs.u.r16.cx = 0x3c00;
4272 // Get the amount of extended memory above 16M in 64k blocs
4273 regs.u.r8.dl = inb_cmos(0x34);
4274 regs.u.r8.dh = inb_cmos(0x35);
4276 // Set configured memory equal to extended memory
4277 regs.u.r16.ax = regs.u.r16.cx;
4278 regs.u.r16.bx = regs.u.r16.dx;
4280 default: /* AH=0xE8?? but not implemented */
4281 goto int15_unimplemented;
4284 int15_unimplemented:
4285 // fall into the default
4287 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4288 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4290 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4296 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4297 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4299 Bit8u scan_code, ascii_code, shift_flags, count;
4300 Bit16u kbd_code, max;
4302 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4305 case 0x00: /* read keyboard input */
4307 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4308 BX_PANIC("KBD: int16h: out of keyboard input\n");
4310 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4311 else if (ascii_code == 0xE0) ascii_code = 0;
4312 AX = (scan_code << 8) | ascii_code;
4315 case 0x01: /* check keyboard status */
4316 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4320 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4321 else if (ascii_code == 0xE0) ascii_code = 0;
4322 AX = (scan_code << 8) | ascii_code;
4326 case 0x02: /* get shift flag status */
4327 shift_flags = read_byte(0x0040, 0x17);
4328 SET_AL(shift_flags);
4331 case 0x05: /* store key-stroke into buffer */
4332 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4340 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4341 // bit Bochs Description
4343 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4344 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4345 // 4 1 INT 16/AH=0Ah supported
4346 // 3 0 INT 16/AX=0306h supported
4347 // 2 0 INT 16/AX=0305h supported
4348 // 1 0 INT 16/AX=0304h supported
4349 // 0 0 INT 16/AX=0300h supported
4354 case 0x0A: /* GET KEYBOARD ID */
4360 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4362 if ((inb(0x60) == 0xfa)) {
4365 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4368 kbd_code |= (inb(0x60) << 8);
4370 } while (--count>0);
4376 case 0x10: /* read MF-II keyboard input */
4378 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4379 BX_PANIC("KBD: int16h: out of keyboard input\n");
4381 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4382 AX = (scan_code << 8) | ascii_code;
4385 case 0x11: /* check MF-II keyboard status */
4386 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4390 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4391 AX = (scan_code << 8) | ascii_code;
4395 case 0x12: /* get extended keyboard status */
4396 shift_flags = read_byte(0x0040, 0x17);
4397 SET_AL(shift_flags);
4398 shift_flags = read_byte(0x0040, 0x18);
4399 SET_AH(shift_flags);
4400 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4403 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4404 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4407 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4408 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4412 if (GET_AL() == 0x08)
4413 SET_AH(0x02); // unsupported, aka normal keyboard
4416 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4421 dequeue_key(scan_code, ascii_code, incr)
4426 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4431 buffer_start = 0x001E;
4432 buffer_end = 0x003E;
4434 buffer_start = read_word(0x0040, 0x0080);
4435 buffer_end = read_word(0x0040, 0x0082);
4438 buffer_head = read_word(0x0040, 0x001a);
4439 buffer_tail = read_word(0x0040, 0x001c);
4441 if (buffer_head != buffer_tail) {
4443 acode = read_byte(0x0040, buffer_head);
4444 scode = read_byte(0x0040, buffer_head+1);
4445 write_byte(ss, ascii_code, acode);
4446 write_byte(ss, scan_code, scode);
4450 if (buffer_head >= buffer_end)
4451 buffer_head = buffer_start;
4452 write_word(0x0040, 0x001a, buffer_head);
4461 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4464 inhibit_mouse_int_and_events()
4466 Bit8u command_byte, prev_command_byte;
4468 // Turn off IRQ generation and aux data line
4469 if ( inb(0x64) & 0x02 )
4470 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4471 outb(0x64, 0x20); // get command byte
4472 while ( (inb(0x64) & 0x01) != 0x01 );
4473 prev_command_byte = inb(0x60);
4474 command_byte = prev_command_byte;
4475 //while ( (inb(0x64) & 0x02) );
4476 if ( inb(0x64) & 0x02 )
4477 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4478 command_byte &= 0xfd; // turn off IRQ 12 generation
4479 command_byte |= 0x20; // disable mouse serial clock line
4480 outb(0x64, 0x60); // write command byte
4481 outb(0x60, command_byte);
4482 return(prev_command_byte);
4486 enable_mouse_int_and_events()
4490 // Turn on IRQ generation and aux data line
4491 if ( inb(0x64) & 0x02 )
4492 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4493 outb(0x64, 0x20); // get command byte
4494 while ( (inb(0x64) & 0x01) != 0x01 );
4495 command_byte = inb(0x60);
4496 //while ( (inb(0x64) & 0x02) );
4497 if ( inb(0x64) & 0x02 )
4498 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4499 command_byte |= 0x02; // turn on IRQ 12 generation
4500 command_byte &= 0xdf; // enable mouse serial clock line
4501 outb(0x64, 0x60); // write command byte
4502 outb(0x60, command_byte);
4506 send_to_mouse_ctrl(sendbyte)
4511 // wait for chance to write to ctrl
4512 if ( inb(0x64) & 0x02 )
4513 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4515 outb(0x60, sendbyte);
4521 get_mouse_data(data)
4527 while ( (inb(0x64) & 0x21) != 0x21 ) {
4530 response = inb(0x60);
4533 write_byte(ss, data, response);
4538 set_kbd_command_byte(command_byte)
4541 if ( inb(0x64) & 0x02 )
4542 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4545 outb(0x64, 0x60); // write command byte
4546 outb(0x60, command_byte);
4550 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4551 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4553 Bit8u scancode, asciicode, shift_flags;
4554 Bit8u mf2_flags, mf2_state, led_flags;
4557 // DS has been set to F000 before call
4561 scancode = GET_AL();
4563 if (scancode == 0) {
4564 BX_INFO("KBD: int09 handler: AL=0\n");
4569 shift_flags = read_byte(0x0040, 0x17);
4570 mf2_flags = read_byte(0x0040, 0x18);
4571 mf2_state = read_byte(0x0040, 0x96);
4572 led_flags = read_byte(0x0040, 0x97);
4576 case 0x3a: /* Caps Lock press */
4577 shift_flags ^= 0x40;
4578 write_byte(0x0040, 0x17, shift_flags);
4580 write_byte(0x0040, 0x18, mf2_flags);
4582 write_byte(0x0040, 0x97, led_flags);
4584 case 0xba: /* Caps Lock release */
4586 write_byte(0x0040, 0x18, mf2_flags);
4589 case 0x2a: /* L Shift press */
4590 /*shift_flags &= ~0x40;*/
4591 shift_flags |= 0x02;
4592 write_byte(0x0040, 0x17, shift_flags);
4594 write_byte(0x0040, 0x97, led_flags);
4596 case 0xaa: /* L Shift release */
4597 shift_flags &= ~0x02;
4598 write_byte(0x0040, 0x17, shift_flags);
4601 case 0x36: /* R Shift press */
4602 /*shift_flags &= ~0x40;*/
4603 shift_flags |= 0x01;
4604 write_byte(0x0040, 0x17, shift_flags);
4606 write_byte(0x0040, 0x97, led_flags);
4608 case 0xb6: /* R Shift release */
4609 shift_flags &= ~0x01;
4610 write_byte(0x0040, 0x17, shift_flags);
4613 case 0x1d: /* Ctrl press */
4614 shift_flags |= 0x04;
4615 write_byte(0x0040, 0x17, shift_flags);
4616 if (mf2_state & 0x01) {
4621 write_byte(0x0040, 0x18, mf2_flags);
4623 case 0x9d: /* Ctrl release */
4624 shift_flags &= ~0x04;
4625 write_byte(0x0040, 0x17, shift_flags);
4626 if (mf2_state & 0x01) {
4631 write_byte(0x0040, 0x18, mf2_flags);
4634 case 0x38: /* Alt press */
4635 shift_flags |= 0x08;
4636 write_byte(0x0040, 0x17, shift_flags);
4637 if (mf2_state & 0x01) {
4642 write_byte(0x0040, 0x18, mf2_flags);
4644 case 0xb8: /* Alt release */
4645 shift_flags &= ~0x08;
4646 write_byte(0x0040, 0x17, shift_flags);
4647 if (mf2_state & 0x01) {
4652 write_byte(0x0040, 0x18, mf2_flags);
4655 case 0x45: /* Num Lock press */
4656 if ((mf2_state & 0x01) == 0) {
4658 write_byte(0x0040, 0x18, mf2_flags);
4659 shift_flags ^= 0x20;
4661 write_byte(0x0040, 0x17, shift_flags);
4662 write_byte(0x0040, 0x97, led_flags);
4665 case 0xc5: /* Num Lock release */
4666 if ((mf2_state & 0x01) == 0) {
4668 write_byte(0x0040, 0x18, mf2_flags);
4672 case 0x46: /* Scroll Lock press */
4674 write_byte(0x0040, 0x18, mf2_flags);
4675 shift_flags ^= 0x10;
4677 write_byte(0x0040, 0x17, shift_flags);
4678 write_byte(0x0040, 0x97, led_flags);
4681 case 0xc6: /* Scroll Lock release */
4683 write_byte(0x0040, 0x18, mf2_flags);
4687 if (scancode & 0x80) return; /* toss key releases ... */
4688 if (scancode > MAX_SCAN_CODE) {
4689 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4692 if (shift_flags & 0x08) { /* ALT */
4693 asciicode = scan_to_scanascii[scancode].alt;
4694 scancode = scan_to_scanascii[scancode].alt >> 8;
4696 else if (shift_flags & 0x04) { /* CONTROL */
4697 asciicode = scan_to_scanascii[scancode].control;
4698 scancode = scan_to_scanascii[scancode].control >> 8;
4700 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4701 /* check if lock state should be ignored
4702 * because a SHIFT key are pressed */
4704 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4705 asciicode = scan_to_scanascii[scancode].normal;
4706 scancode = scan_to_scanascii[scancode].normal >> 8;
4709 asciicode = scan_to_scanascii[scancode].shift;
4710 scancode = scan_to_scanascii[scancode].shift >> 8;
4714 /* check if lock is on */
4715 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4716 asciicode = scan_to_scanascii[scancode].shift;
4717 scancode = scan_to_scanascii[scancode].shift >> 8;
4720 asciicode = scan_to_scanascii[scancode].normal;
4721 scancode = scan_to_scanascii[scancode].normal >> 8;
4724 if (scancode==0 && asciicode==0) {
4725 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4727 enqueue_key(scancode, asciicode);
4734 enqueue_key(scan_code, ascii_code)
4735 Bit8u scan_code, ascii_code;
4737 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4739 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4740 // scan_code, ascii_code);
4743 buffer_start = 0x001E;
4744 buffer_end = 0x003E;
4746 buffer_start = read_word(0x0040, 0x0080);
4747 buffer_end = read_word(0x0040, 0x0082);
4750 buffer_head = read_word(0x0040, 0x001A);
4751 buffer_tail = read_word(0x0040, 0x001C);
4753 temp_tail = buffer_tail;
4755 if (buffer_tail >= buffer_end)
4756 buffer_tail = buffer_start;
4758 if (buffer_tail == buffer_head) {
4762 write_byte(0x0040, temp_tail, ascii_code);
4763 write_byte(0x0040, temp_tail+1, scan_code);
4764 write_word(0x0040, 0x001C, buffer_tail);
4770 int74_function(make_farcall, Z, Y, X, status)
4771 Bit16u make_farcall, Z, Y, X, status;
4773 Bit16u ebda_seg=read_word(0x0040,0x000E);
4774 Bit8u in_byte, index, package_count;
4775 Bit8u mouse_flags_1, mouse_flags_2;
4777 BX_DEBUG_INT74("entering int74_function\n");
4780 in_byte = inb(0x64);
4781 if ( (in_byte & 0x21) != 0x21 ) {
4784 in_byte = inb(0x60);
4785 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4787 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4788 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4790 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4791 // BX_PANIC("int74_function:\n");
4795 package_count = mouse_flags_2 & 0x07;
4796 index = mouse_flags_1 & 0x07;
4797 write_byte(ebda_seg, 0x28 + index, in_byte);
4799 if ( (index+1) >= package_count ) {
4800 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4801 status = read_byte(ebda_seg, 0x0028 + 0);
4802 X = read_byte(ebda_seg, 0x0028 + 1);
4803 Y = read_byte(ebda_seg, 0x0028 + 2);
4806 // check if far call handler installed
4807 if (mouse_flags_2 & 0x80)
4813 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4816 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4821 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4822 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4825 Bit16u ebda_seg=read_word(0x0040,0x000E);
4826 Bit16u cylinder, head, sector;
4827 Bit16u segment, offset;
4828 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4830 Bit8u device, status;
4832 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4834 write_byte(0x0040, 0x008e, 0); // clear completion flag
4836 // basic check : device has to be defined
4837 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4838 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4842 // Get the ata channel
4843 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4845 // basic check : device has to be valid
4846 if (device >= BX_MAX_ATA_DEVICES) {
4847 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4853 case 0x00: /* disk controller reset */
4858 case 0x01: /* read disk status */
4859 status = read_byte(0x0040, 0x0074);
4861 SET_DISK_RET_STATUS(0);
4862 /* set CF if error status read */
4863 if (status) goto int13_fail_nostatus;
4864 else goto int13_success_noah;
4867 case 0x02: // read disk sectors
4868 case 0x03: // write disk sectors
4869 case 0x04: // verify disk sectors
4872 cylinder = GET_CH();
4873 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4874 sector = (GET_CL() & 0x3f);
4880 if ( (count > 128) || (count == 0) ) {
4881 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4885 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4886 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4887 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4889 // sanity check on cyl heads, sec
4890 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4891 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4896 if ( GET_AH() == 0x04 ) goto int13_success;
4898 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4899 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4901 // if needed, translate lchs to lba, and execute command
4902 if ( (nph != nlh) || (npspt != nlspt)) {
4903 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4904 sector = 0; // this forces the command to be lba
4907 if ( GET_AH() == 0x02 )
4908 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4910 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4912 // Set nb of sector transferred
4913 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4916 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4918 goto int13_fail_noah;
4924 case 0x05: /* format disk track */
4925 BX_INFO("format disk track called\n");
4930 case 0x08: /* read disk drive parameters */
4932 // Get logical geometry from table
4933 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4934 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4935 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4936 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4938 nlc = nlc - 2; /* 0 based , last sector not used */
4941 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4943 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4945 // FIXME should set ES & DI
4950 case 0x10: /* check drive ready */
4951 // should look at 40:8E also???
4953 // Read the status from controller
4954 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
4955 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
4960 goto int13_fail_noah;
4964 case 0x15: /* read disk drive size */
4966 // Get physical geometry from table
4967 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4968 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4969 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4971 // Compute sector count seen by int13
4972 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
4976 SET_AH(3); // hard disk accessible
4977 goto int13_success_noah;
4980 case 0x41: // IBM/MS installation check
4981 BX=0xaa55; // install check
4982 SET_AH(0x30); // EDD 3.0
4983 CX=0x0007; // ext disk access and edd, removable supported
4984 goto int13_success_noah;
4987 case 0x42: // IBM/MS extended read
4988 case 0x43: // IBM/MS extended write
4989 case 0x44: // IBM/MS verify
4990 case 0x47: // IBM/MS extended seek
4992 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
4993 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
4994 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
4996 // Can't use 64 bits lba
4997 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
4999 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5003 // Get 32 bits lba and check
5004 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5005 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5006 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5010 // If verify or seek
5011 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5014 // Execute the command
5015 if ( GET_AH() == 0x42 )
5016 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5018 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5020 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5021 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5024 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5026 goto int13_fail_noah;
5032 case 0x45: // IBM/MS lock/unlock drive
5033 case 0x49: // IBM/MS extended media change
5034 goto int13_success; // Always success for HD
5037 case 0x46: // IBM/MS eject media
5038 SET_AH(0xb2); // Volume Not Removable
5039 goto int13_fail_noah; // Always fail for HD
5042 case 0x48: // IBM/MS get drive parameters
5043 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5045 // Buffer is too small
5053 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5054 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5055 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5056 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5057 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5059 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5060 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5061 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5062 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5063 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5064 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5065 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5066 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5071 Bit8u channel, dev, irq, mode, checksum, i, translation;
5072 Bit16u iobase1, iobase2, options;
5074 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5076 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5077 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5080 channel = device / 2;
5081 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5082 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5083 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5084 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5085 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5087 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5088 options |= (1<<4); // lba translation
5089 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5090 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5091 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5093 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5094 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5095 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5096 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5097 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5098 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5099 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5100 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5101 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5102 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5103 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5106 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5107 checksum = ~checksum;
5108 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5113 Bit8u channel, iface, checksum, i;
5116 channel = device / 2;
5117 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5118 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5120 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5121 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5122 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5123 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5124 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5126 if (iface==ATA_IFACE_ISA) {
5127 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5128 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5129 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5130 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5135 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5136 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5137 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5138 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5140 if (iface==ATA_IFACE_ISA) {
5141 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5142 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5143 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5148 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5149 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5150 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5151 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5154 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5155 checksum = ~checksum;
5156 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5162 case 0x4e: // // IBM/MS set hardware configuration
5163 // DMA, prefetch, PIO maximum not supported
5176 case 0x09: /* initialize drive parameters */
5177 case 0x0c: /* seek to specified cylinder */
5178 case 0x0d: /* alternate disk reset */
5179 case 0x11: /* recalibrate */
5180 case 0x14: /* controller internal diagnostic */
5181 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5185 case 0x0a: /* read disk sectors with ECC */
5186 case 0x0b: /* write disk sectors with ECC */
5187 case 0x18: // set media type for format
5188 case 0x50: // IBM/MS send packet command
5190 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5196 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5198 SET_DISK_RET_STATUS(GET_AH());
5199 int13_fail_nostatus:
5200 SET_CF(); // error occurred
5204 SET_AH(0x00); // no error
5206 SET_DISK_RET_STATUS(0x00);
5207 CLEAR_CF(); // no error
5211 // ---------------------------------------------------------------------------
5212 // Start of int13 for cdrom
5213 // ---------------------------------------------------------------------------
5216 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5217 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5219 Bit16u ebda_seg=read_word(0x0040,0x000E);
5220 Bit8u device, status, locks;
5223 Bit16u count, segment, offset, i, size;
5225 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5226 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5228 SET_DISK_RET_STATUS(0x00);
5230 /* basic check : device should be 0xE0+ */
5231 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5232 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5236 // Get the ata channel
5237 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5239 /* basic check : device has to be valid */
5240 if (device >= BX_MAX_ATA_DEVICES) {
5241 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5247 // all those functions return SUCCESS
5248 case 0x00: /* disk controller reset */
5249 case 0x09: /* initialize drive parameters */
5250 case 0x0c: /* seek to specified cylinder */
5251 case 0x0d: /* alternate disk reset */
5252 case 0x10: /* check drive ready */
5253 case 0x11: /* recalibrate */
5254 case 0x14: /* controller internal diagnostic */
5255 case 0x16: /* detect disk change */
5259 // all those functions return disk write-protected
5260 case 0x03: /* write disk sectors */
5261 case 0x05: /* format disk track */
5262 case 0x43: // IBM/MS extended write
5264 goto int13_fail_noah;
5267 case 0x01: /* read disk status */
5268 status = read_byte(0x0040, 0x0074);
5270 SET_DISK_RET_STATUS(0);
5272 /* set CF if error status read */
5273 if (status) goto int13_fail_nostatus;
5274 else goto int13_success_noah;
5277 case 0x15: /* read disk drive size */
5279 goto int13_fail_noah;
5282 case 0x41: // IBM/MS installation check
5283 BX=0xaa55; // install check
5284 SET_AH(0x30); // EDD 2.1
5285 CX=0x0007; // ext disk access, removable and edd
5286 goto int13_success_noah;
5289 case 0x42: // IBM/MS extended read
5290 case 0x44: // IBM/MS verify sectors
5291 case 0x47: // IBM/MS extended seek
5293 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5294 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5295 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5297 // Can't use 64 bits lba
5298 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5300 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5305 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5307 // If verify or seek
5308 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5311 memsetb(get_SS(),atacmd,0,12);
5312 atacmd[0]=0x28; // READ command
5313 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5314 atacmd[8]=(count & 0x00ff); // Sectors
5315 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5316 atacmd[3]=(lba & 0x00ff0000) >> 16;
5317 atacmd[4]=(lba & 0x0000ff00) >> 8;
5318 atacmd[5]=(lba & 0x000000ff);
5319 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5321 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5322 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5325 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5327 goto int13_fail_noah;
5333 case 0x45: // IBM/MS lock/unlock drive
5334 if (GET_AL() > 2) goto int13_fail;
5336 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5340 if (locks == 0xff) {
5343 goto int13_fail_noah;
5345 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5349 if (locks == 0x00) {
5352 goto int13_fail_noah;
5354 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5355 SET_AL(locks==0?0:1);
5358 SET_AL(locks==0?0:1);
5364 case 0x46: // IBM/MS eject media
5365 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5368 SET_AH(0xb1); // media locked
5369 goto int13_fail_noah;
5371 // FIXME should handle 0x31 no media in device
5372 // FIXME should handle 0xb5 valid request failed
5374 // Call removable media eject
5381 mov _int13_cdrom.status + 2[bp], ah
5382 jnc int13_cdrom_rme_end
5383 mov _int13_cdrom.status, #1
5384 int13_cdrom_rme_end:
5389 SET_AH(0xb1); // media locked
5390 goto int13_fail_noah;
5396 case 0x48: // IBM/MS get drive parameters
5397 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5399 // Buffer is too small
5405 Bit16u cylinders, heads, spt, blksize;
5407 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5409 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5410 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5411 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5412 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5413 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5414 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5415 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5416 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5421 Bit8u channel, dev, irq, mode, checksum, i;
5422 Bit16u iobase1, iobase2, options;
5424 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5426 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5427 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5430 channel = device / 2;
5431 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5432 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5433 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5434 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5436 // FIXME atapi device
5437 options = (1<<4); // lba translation
5438 options |= (1<<5); // removable device
5439 options |= (1<<6); // atapi device
5440 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5442 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5443 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5444 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5445 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5446 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5447 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5448 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5449 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5450 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5451 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5452 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5455 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5456 checksum = ~checksum;
5457 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5462 Bit8u channel, iface, checksum, i;
5465 channel = device / 2;
5466 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5467 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5469 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5470 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5471 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5472 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5473 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5475 if (iface==ATA_IFACE_ISA) {
5476 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5477 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5478 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5479 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5484 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5485 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5486 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5487 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5489 if (iface==ATA_IFACE_ISA) {
5490 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5491 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5492 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5497 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5498 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5499 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5500 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5503 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5504 checksum = ~checksum;
5505 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5511 case 0x49: // IBM/MS extended media change
5512 // always send changed ??
5514 goto int13_fail_nostatus;
5517 case 0x4e: // // IBM/MS set hardware configuration
5518 // DMA, prefetch, PIO maximum not supported
5531 // all those functions return unimplemented
5532 case 0x02: /* read sectors */
5533 case 0x04: /* verify sectors */
5534 case 0x08: /* read disk drive parameters */
5535 case 0x0a: /* read disk sectors with ECC */
5536 case 0x0b: /* write disk sectors with ECC */
5537 case 0x18: /* set media type for format */
5538 case 0x50: // ? - send packet command
5540 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5546 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5548 SET_DISK_RET_STATUS(GET_AH());
5549 int13_fail_nostatus:
5550 SET_CF(); // error occurred
5554 SET_AH(0x00); // no error
5556 SET_DISK_RET_STATUS(0x00);
5557 CLEAR_CF(); // no error
5561 // ---------------------------------------------------------------------------
5562 // End of int13 for cdrom
5563 // ---------------------------------------------------------------------------
5565 #if BX_ELTORITO_BOOT
5566 // ---------------------------------------------------------------------------
5567 // Start of int13 for eltorito functions
5568 // ---------------------------------------------------------------------------
5571 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5572 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5574 Bit16u ebda_seg=read_word(0x0040,0x000E);
5576 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5577 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5581 // FIXME ElTorito Various. Should be implemented
5582 case 0x4a: // ElTorito - Initiate disk emu
5583 case 0x4c: // ElTorito - Initiate disk emu and boot
5584 case 0x4d: // ElTorito - Return Boot catalog
5585 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5589 case 0x4b: // ElTorito - Terminate disk emu
5590 // FIXME ElTorito Hardcoded
5591 write_byte(DS,SI+0x00,0x13);
5592 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5593 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5594 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5595 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5596 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5597 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5598 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5599 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5600 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5601 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5602 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5604 // If we have to terminate emulation
5605 if(GET_AL() == 0x00) {
5606 // FIXME ElTorito Various. Should be handled accordingly to spec
5607 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5614 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5620 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5621 SET_DISK_RET_STATUS(GET_AH());
5622 SET_CF(); // error occurred
5626 SET_AH(0x00); // no error
5627 SET_DISK_RET_STATUS(0x00);
5628 CLEAR_CF(); // no error
5632 // ---------------------------------------------------------------------------
5633 // End of int13 for eltorito functions
5634 // ---------------------------------------------------------------------------
5636 // ---------------------------------------------------------------------------
5637 // Start of int13 when emulating a device from the cd
5638 // ---------------------------------------------------------------------------
5641 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5642 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5644 Bit16u ebda_seg=read_word(0x0040,0x000E);
5645 Bit8u device, status;
5646 Bit16u vheads, vspt, vcylinders;
5647 Bit16u head, sector, cylinder, nbsectors;
5648 Bit32u vlba, ilba, slba, elba;
5649 Bit16u before, segment, offset;
5652 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5653 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5655 /* at this point, we are emulating a floppy/harddisk */
5657 // Recompute the device number
5658 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5659 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5661 SET_DISK_RET_STATUS(0x00);
5663 /* basic checks : emulation should be active, dl should equal the emulated drive */
5664 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5665 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5666 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5672 // all those functions return SUCCESS
5673 case 0x00: /* disk controller reset */
5674 case 0x09: /* initialize drive parameters */
5675 case 0x0c: /* seek to specified cylinder */
5676 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5677 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5678 case 0x11: /* recalibrate */
5679 case 0x14: /* controller internal diagnostic */
5680 case 0x16: /* detect disk change */
5684 // all those functions return disk write-protected
5685 case 0x03: /* write disk sectors */
5686 case 0x05: /* format disk track */
5688 goto int13_fail_noah;
5691 case 0x01: /* read disk status */
5692 status=read_byte(0x0040, 0x0074);
5694 SET_DISK_RET_STATUS(0);
5696 /* set CF if error status read */
5697 if (status) goto int13_fail_nostatus;
5698 else goto int13_success_noah;
5701 case 0x02: // read disk sectors
5702 case 0x04: // verify disk sectors
5703 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5704 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5705 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5707 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5709 sector = GET_CL() & 0x003f;
5710 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5712 nbsectors = GET_AL();
5716 // no sector to read ?
5717 if(nbsectors==0) goto int13_success;
5719 // sanity checks sco openserver needs this!
5721 || (cylinder >= vcylinders)
5722 || (head >= vheads)) {
5726 // After controls, verify do nothing
5727 if (GET_AH() == 0x04) goto int13_success;
5729 segment = ES+(BX / 16);
5732 // calculate the virtual lba inside the image
5733 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5735 // In advance so we don't loose the count
5739 slba = (Bit32u)vlba/4;
5740 before= (Bit16u)vlba%4;
5743 elba = (Bit32u)(vlba+nbsectors-1)/4;
5745 memsetb(get_SS(),atacmd,0,12);
5746 atacmd[0]=0x28; // READ command
5747 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5748 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5749 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5750 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5751 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5752 atacmd[5]=(ilba+slba & 0x000000ff);
5753 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5754 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5757 goto int13_fail_noah;
5763 case 0x08: /* read disk drive parameters */
5764 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5765 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5766 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5770 SET_CH( vcylinders & 0xff );
5771 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5773 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5774 // FIXME ElTorito Harddisk. should send the HD count
5776 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5777 case 0x01: SET_BL( 0x02 ); break;
5778 case 0x02: SET_BL( 0x04 ); break;
5779 case 0x03: SET_BL( 0x06 ); break;
5785 mov ax, #diskette_param_table2
5786 mov _int13_cdemu.DI+2[bp], ax
5787 mov _int13_cdemu.ES+2[bp], cs
5793 case 0x15: /* read disk drive size */
5794 // FIXME ElTorito Harddisk. What geometry to send ?
5796 goto int13_success_noah;
5799 // all those functions return unimplemented
5800 case 0x0a: /* read disk sectors with ECC */
5801 case 0x0b: /* write disk sectors with ECC */
5802 case 0x18: /* set media type for format */
5803 case 0x41: // IBM/MS installation check
5804 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5805 case 0x42: // IBM/MS extended read
5806 case 0x43: // IBM/MS extended write
5807 case 0x44: // IBM/MS verify sectors
5808 case 0x45: // IBM/MS lock/unlock drive
5809 case 0x46: // IBM/MS eject media
5810 case 0x47: // IBM/MS extended seek
5811 case 0x48: // IBM/MS get drive parameters
5812 case 0x49: // IBM/MS extended media change
5813 case 0x4e: // ? - set hardware configuration
5814 case 0x50: // ? - send packet command
5816 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5822 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5824 SET_DISK_RET_STATUS(GET_AH());
5825 int13_fail_nostatus:
5826 SET_CF(); // error occurred
5830 SET_AH(0x00); // no error
5832 SET_DISK_RET_STATUS(0x00);
5833 CLEAR_CF(); // no error
5837 // ---------------------------------------------------------------------------
5838 // End of int13 when emulating a device from the cd
5839 // ---------------------------------------------------------------------------
5841 #endif // BX_ELTORITO_BOOT
5843 #else //BX_USE_ATADRV
5846 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5861 mov ax,4[bp] // cylinder
5863 mov bl,6[bp] // hd_heads
5866 mov bl,8[bp] // head
5868 mov bl,10[bp] // hd_sectors
5870 mov bl,12[bp] // sector
5899 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5900 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5902 Bit8u drive, num_sectors, sector, head, status, mod;
5906 Bit16u max_cylinder, cylinder, total_sectors;
5907 Bit16u hd_cylinders;
5908 Bit8u hd_heads, hd_sectors;
5915 Bit16u count, segment, offset;
5919 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5921 write_byte(0x0040, 0x008e, 0); // clear completion flag
5923 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5925 /* check how many disks first (cmos reg 0x12), return an error if
5926 drive not present */
5927 drive_map = inb_cmos(0x12);
5928 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5929 (((drive_map & 0x0f)==0) ? 0 : 2);
5930 n_drives = (drive_map==0) ? 0 :
5931 ((drive_map==3) ? 2 : 1);
5933 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5935 SET_DISK_RET_STATUS(0x01);
5936 SET_CF(); /* error occurred */
5942 case 0x00: /* disk controller reset */
5943 BX_DEBUG_INT13_HD("int13_f00\n");
5946 SET_DISK_RET_STATUS(0);
5947 set_diskette_ret_status(0);
5948 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5949 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5950 CLEAR_CF(); /* successful */
5954 case 0x01: /* read disk status */
5955 BX_DEBUG_INT13_HD("int13_f01\n");
5956 status = read_byte(0x0040, 0x0074);
5958 SET_DISK_RET_STATUS(0);
5959 /* set CF if error status read */
5960 if (status) SET_CF();
5965 case 0x04: // verify disk sectors
5966 case 0x02: // read disk sectors
5968 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5970 num_sectors = GET_AL();
5971 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5972 sector = (GET_CL() & 0x3f);
5976 if (hd_cylinders > 1024) {
5977 if (hd_cylinders <= 2048) {
5980 else if (hd_cylinders <= 4096) {
5983 else if (hd_cylinders <= 8192) {
5986 else { // hd_cylinders <= 16384
5990 ax = head / hd_heads;
5991 cyl_mod = ax & 0xff;
5993 cylinder |= cyl_mod;
5996 if ( (cylinder >= hd_cylinders) ||
5997 (sector > hd_sectors) ||
5998 (head >= hd_heads) ) {
6000 SET_DISK_RET_STATUS(1);
6001 SET_CF(); /* error occurred */
6005 if ( (num_sectors > 128) || (num_sectors == 0) )
6006 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6009 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6011 if ( GET_AH() == 0x04 ) {
6013 SET_DISK_RET_STATUS(0);
6018 status = inb(0x1f7);
6019 if (status & 0x80) {
6020 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6022 outb(0x01f2, num_sectors);
6023 /* activate LBA? (tomv) */
6024 if (hd_heads > 16) {
6025 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6026 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6029 outb(0x01f3, sector);
6030 outb(0x01f4, cylinder & 0x00ff);
6031 outb(0x01f5, cylinder >> 8);
6032 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6037 status = inb(0x1f7);
6038 if ( !(status & 0x80) ) break;
6041 if (status & 0x01) {
6042 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6043 } else if ( !(status & 0x08) ) {
6044 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6045 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6052 sti ;; enable higher priority interrupts
6057 ;; store temp bx in real DI register
6060 mov di, _int13_harddisk.tempbx + 2 [bp]
6063 ;; adjust if there will be an overrun
6065 jbe i13_f02_no_adjust
6067 sub di, #0x0200 ; sub 512 bytes from offset
6069 add ax, #0x0020 ; add 512 to segment
6073 mov cx, #0x0100 ;; counter (256 words = 512b)
6074 mov dx, #0x01f0 ;; AT data read port
6077 insw ;; CX words transfered from port(DX) to ES:[DI]
6080 ;; store real DI register back to temp bx
6083 mov _int13_harddisk.tempbx + 2 [bp], di
6089 if (num_sectors == 0) {
6090 status = inb(0x1f7);
6091 if ( (status & 0xc9) != 0x40 )
6092 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6096 status = inb(0x1f7);
6097 if ( (status & 0xc9) != 0x48 )
6098 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6104 SET_DISK_RET_STATUS(0);
6105 SET_AL(sector_count);
6106 CLEAR_CF(); /* successful */
6111 case 0x03: /* write disk sectors */
6112 BX_DEBUG_INT13_HD("int13_f03\n");
6113 drive = GET_ELDL ();
6114 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6116 num_sectors = GET_AL();
6117 cylinder = GET_CH();
6118 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6119 sector = (GET_CL() & 0x3f);
6122 if (hd_cylinders > 1024) {
6123 if (hd_cylinders <= 2048) {
6126 else if (hd_cylinders <= 4096) {
6129 else if (hd_cylinders <= 8192) {
6132 else { // hd_cylinders <= 16384
6136 ax = head / hd_heads;
6137 cyl_mod = ax & 0xff;
6139 cylinder |= cyl_mod;
6142 if ( (cylinder >= hd_cylinders) ||
6143 (sector > hd_sectors) ||
6144 (head >= hd_heads) ) {
6146 SET_DISK_RET_STATUS(1);
6147 SET_CF(); /* error occurred */
6151 if ( (num_sectors > 128) || (num_sectors == 0) )
6152 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6155 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6157 status = inb(0x1f7);
6158 if (status & 0x80) {
6159 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6161 // should check for Drive Ready Bit also in status reg
6162 outb(0x01f2, num_sectors);
6164 /* activate LBA? (tomv) */
6165 if (hd_heads > 16) {
6166 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6167 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6170 outb(0x01f3, sector);
6171 outb(0x01f4, cylinder & 0x00ff);
6172 outb(0x01f5, cylinder >> 8);
6173 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6177 // wait for busy bit to turn off after seeking
6179 status = inb(0x1f7);
6180 if ( !(status & 0x80) ) break;
6183 if ( !(status & 0x08) ) {
6184 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6185 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6192 sti ;; enable higher priority interrupts
6197 ;; store temp bx in real SI register
6200 mov si, _int13_harddisk.tempbx + 2 [bp]
6203 ;; adjust if there will be an overrun
6205 jbe i13_f03_no_adjust
6207 sub si, #0x0200 ; sub 512 bytes from offset
6209 add ax, #0x0020 ; add 512 to segment
6213 mov cx, #0x0100 ;; counter (256 words = 512b)
6214 mov dx, #0x01f0 ;; AT data read port
6218 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6220 ;; store real SI register back to temp bx
6223 mov _int13_harddisk.tempbx + 2 [bp], si
6229 if (num_sectors == 0) {
6230 status = inb(0x1f7);
6231 if ( (status & 0xe9) != 0x40 )
6232 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6236 status = inb(0x1f7);
6237 if ( (status & 0xc9) != 0x48 )
6238 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6244 SET_DISK_RET_STATUS(0);
6245 SET_AL(sector_count);
6246 CLEAR_CF(); /* successful */
6250 case 0x05: /* format disk track */
6251 BX_DEBUG_INT13_HD("int13_f05\n");
6252 BX_PANIC("format disk track called\n");
6255 SET_DISK_RET_STATUS(0);
6256 CLEAR_CF(); /* successful */
6260 case 0x08: /* read disk drive parameters */
6261 BX_DEBUG_INT13_HD("int13_f08\n");
6263 drive = GET_ELDL ();
6264 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6268 if (hd_cylinders <= 1024) {
6269 // hd_cylinders >>= 0;
6272 else if (hd_cylinders <= 2048) {
6276 else if (hd_cylinders <= 4096) {
6280 else if (hd_cylinders <= 8192) {
6284 else { // hd_cylinders <= 16384
6289 max_cylinder = hd_cylinders - 2; /* 0 based */
6291 SET_CH(max_cylinder & 0xff);
6292 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6293 SET_DH(hd_heads - 1);
6294 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6296 SET_DISK_RET_STATUS(0);
6297 CLEAR_CF(); /* successful */
6302 case 0x09: /* initialize drive parameters */
6303 BX_DEBUG_INT13_HD("int13_f09\n");
6305 SET_DISK_RET_STATUS(0);
6306 CLEAR_CF(); /* successful */
6310 case 0x0a: /* read disk sectors with ECC */
6311 BX_DEBUG_INT13_HD("int13_f0a\n");
6312 case 0x0b: /* write disk sectors with ECC */
6313 BX_DEBUG_INT13_HD("int13_f0b\n");
6314 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6318 case 0x0c: /* seek to specified cylinder */
6319 BX_DEBUG_INT13_HD("int13_f0c\n");
6320 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6322 SET_DISK_RET_STATUS(0);
6323 CLEAR_CF(); /* successful */
6327 case 0x0d: /* alternate disk reset */
6328 BX_DEBUG_INT13_HD("int13_f0d\n");
6330 SET_DISK_RET_STATUS(0);
6331 CLEAR_CF(); /* successful */
6335 case 0x10: /* check drive ready */
6336 BX_DEBUG_INT13_HD("int13_f10\n");
6338 //SET_DISK_RET_STATUS(0);
6339 //CLEAR_CF(); /* successful */
6343 // should look at 40:8E also???
6344 status = inb(0x01f7);
6345 if ( (status & 0xc0) == 0x40 ) {
6347 SET_DISK_RET_STATUS(0);
6348 CLEAR_CF(); // drive ready
6353 SET_DISK_RET_STATUS(0xAA);
6354 SET_CF(); // not ready
6359 case 0x11: /* recalibrate */
6360 BX_DEBUG_INT13_HD("int13_f11\n");
6362 SET_DISK_RET_STATUS(0);
6363 CLEAR_CF(); /* successful */
6367 case 0x14: /* controller internal diagnostic */
6368 BX_DEBUG_INT13_HD("int13_f14\n");
6370 SET_DISK_RET_STATUS(0);
6371 CLEAR_CF(); /* successful */
6376 case 0x15: /* read disk drive size */
6378 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6382 mov al, _int13_harddisk.hd_heads + 2 [bp]
6383 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6384 mul al, ah ;; ax = heads * sectors
6385 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6386 dec bx ;; use (cylinders - 1) ???
6387 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6388 ;; now we need to move the 32bit result dx:ax to what the
6389 ;; BIOS wants which is cx:dx.
6390 ;; and then into CX:DX on the stack
6391 mov _int13_harddisk.CX + 2 [bp], dx
6392 mov _int13_harddisk.DX + 2 [bp], ax
6395 SET_AH(3); // hard disk accessible
6396 SET_DISK_RET_STATUS(0); // ??? should this be 0
6397 CLEAR_CF(); // successful
6401 case 0x18: // set media type for format
6402 case 0x41: // IBM/MS
6403 case 0x42: // IBM/MS
6404 case 0x43: // IBM/MS
6405 case 0x44: // IBM/MS
6406 case 0x45: // IBM/MS lock/unlock drive
6407 case 0x46: // IBM/MS eject media
6408 case 0x47: // IBM/MS extended seek
6409 case 0x49: // IBM/MS extended media change
6410 case 0x50: // IBM/MS send packet command
6412 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6414 SET_AH(1); // code=invalid function in AH or invalid parameter
6415 SET_DISK_RET_STATUS(1);
6416 SET_CF(); /* unsuccessful */
6422 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6423 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6426 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6428 Bit16u *hd_cylinders;
6438 if (drive == 0x80) {
6439 hd_type = inb_cmos(0x12) & 0xf0;
6440 if (hd_type != 0xf0)
6441 BX_INFO(panic_msg_reg12h,0);
6442 hd_type = inb_cmos(0x19); // HD0: extended type
6444 BX_INFO(panic_msg_reg19h,0,0x19);
6447 hd_type = inb_cmos(0x12) & 0x0f;
6448 if (hd_type != 0x0f)
6449 BX_INFO(panic_msg_reg12h,1);
6450 hd_type = inb_cmos(0x1a); // HD0: extended type
6452 BX_INFO(panic_msg_reg19h,0,0x1a);
6457 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6458 write_word(ss, hd_cylinders, cylinders);
6461 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6463 // sectors per track
6464 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6467 #endif //else BX_USE_ATADRV
6470 //////////////////////
6471 // FLOPPY functions //
6472 //////////////////////
6475 floppy_media_known(drive)
6479 Bit16u media_state_offset;
6481 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6488 media_state_offset = 0x0090;
6490 media_state_offset += 1;
6492 val8 = read_byte(0x0040, media_state_offset);
6493 val8 = (val8 >> 4) & 0x01;
6497 // check pass, return KNOWN
6502 floppy_media_sense(drive)
6506 Bit16u media_state_offset;
6507 Bit8u drive_type, config_data, media_state;
6509 if (floppy_drive_recal(drive) == 0) {
6513 // for now cheat and get drive type from CMOS,
6514 // assume media is same as drive type
6516 // ** config_data **
6517 // Bitfields for diskette media control:
6518 // Bit(s) Description (Table M0028)
6519 // 7-6 last data rate set by controller
6520 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6521 // 5-4 last diskette drive step rate selected
6522 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6523 // 3-2 {data rate at start of operation}
6526 // ** media_state **
6527 // Bitfields for diskette drive media state:
6528 // Bit(s) Description (Table M0030)
6530 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6531 // 5 double stepping required (e.g. 360kB in 1.2MB)
6532 // 4 media type established
6533 // 3 drive capable of supporting 4MB media
6534 // 2-0 on exit from BIOS, contains
6535 // 000 trying 360kB in 360kB
6536 // 001 trying 360kB in 1.2MB
6537 // 010 trying 1.2MB in 1.2MB
6538 // 011 360kB in 360kB established
6539 // 100 360kB in 1.2MB established
6540 // 101 1.2MB in 1.2MB established
6542 // 111 all other formats/drives
6544 drive_type = inb_cmos(0x10);
6549 if ( drive_type == 1 ) {
6551 config_data = 0x00; // 0000 0000
6552 media_state = 0x25; // 0010 0101
6555 else if ( drive_type == 2 ) {
6556 // 1.2 MB 5.25" drive
6557 config_data = 0x00; // 0000 0000
6558 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6561 else if ( drive_type == 3 ) {
6563 config_data = 0x00; // 0000 0000 ???
6564 media_state = 0x17; // 0001 0111
6567 else if ( drive_type == 4 ) {
6568 // 1.44 MB 3.5" drive
6569 config_data = 0x00; // 0000 0000
6570 media_state = 0x17; // 0001 0111
6573 else if ( drive_type == 5 ) {
6574 // 2.88 MB 3.5" drive
6575 config_data = 0xCC; // 1100 1100
6576 media_state = 0xD7; // 1101 0111
6580 // Extended floppy size uses special cmos setting
6581 else if ( drive_type == 6 ) {
6583 config_data = 0x00; // 0000 0000
6584 media_state = 0x27; // 0010 0111
6587 else if ( drive_type == 7 ) {
6589 config_data = 0x00; // 0000 0000
6590 media_state = 0x27; // 0010 0111
6593 else if ( drive_type == 8 ) {
6595 config_data = 0x00; // 0000 0000
6596 media_state = 0x27; // 0010 0111
6602 config_data = 0x00; // 0000 0000
6603 media_state = 0x00; // 0000 0000
6608 media_state_offset = 0x90;
6610 media_state_offset = 0x91;
6611 write_byte(0x0040, 0x008B, config_data);
6612 write_byte(0x0040, media_state_offset, media_state);
6618 floppy_drive_recal(drive)
6622 Bit16u curr_cyl_offset;
6624 // set 40:3e bit 7 to 0
6625 val8 = read_byte(0x0000, 0x043e);
6627 write_byte(0x0000, 0x043e, val8);
6629 // turn on motor of selected drive, DMA & int enabled, normal operation
6638 // reset the disk motor timeout value of INT 08
6639 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6641 // check port 3f4 for drive readiness
6643 if ( (val8 & 0xf0) != 0x80 )
6644 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6646 // send Recalibrate command (2 bytes) to controller
6647 outb(0x03f5, 0x07); // 07: Recalibrate
6648 outb(0x03f5, drive); // 0=drive0, 1=drive1
6650 // turn on interrupts
6655 // wait on 40:3e bit 7 to become 1
6656 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6657 while ( val8 == 0 ) {
6658 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6661 val8 = 0; // separate asm from while() loop
6662 // turn off interrupts
6667 // set 40:3e bit 7 to 0, and calibrated bit
6668 val8 = read_byte(0x0000, 0x043e);
6671 val8 |= 0x02; // Drive 1 calibrated
6672 curr_cyl_offset = 0x0095;
6675 val8 |= 0x01; // Drive 0 calibrated
6676 curr_cyl_offset = 0x0094;
6678 write_byte(0x0040, 0x003e, val8);
6679 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6687 floppy_drive_exists(drive)
6692 // just tell it both drives exist - PAD
6695 // check CMOS to see if drive exists
6696 drive_type = inb_cmos(0x10);
6701 if ( drive_type == 0 )
6707 #if BX_SUPPORT_FLOPPY
6709 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6710 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6712 Bit8u drive, num_sectors, track, sector, head, status;
6713 Bit16u base_address, base_count, base_es;
6714 Bit8u page, mode_register, val8, dor;
6715 Bit8u return_status[7];
6716 Bit8u drive_type, num_floppies, ah;
6717 Bit16u es, last_addr;
6719 printf("In int13_diskette\n");
6721 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6722 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6727 case 0x00: // diskette controller reset
6728 BX_DEBUG_INT13_FL("floppy f00\n");
6731 SET_AH(1); // invalid param
6732 set_diskette_ret_status(1);
6736 drive_type = inb_cmos(0x10);
6742 if (drive_type == 0) {
6743 SET_AH(0x80); // drive not responding
6744 set_diskette_ret_status(0x80);
6749 set_diskette_ret_status(0);
6750 CLEAR_CF(); // successful
6751 set_diskette_current_cyl(drive, 0); // current cylinder
6754 case 0x01: // Read Diskette Status
6756 val8 = read_byte(0x0000, 0x0441);
6763 case 0x02: // Read Diskette Sectors
6764 case 0x03: // Write Diskette Sectors
6765 case 0x04: // Verify Diskette Sectors
6766 num_sectors = GET_AL();
6772 if ( (drive > 1) || (head > 1) ||
6773 (num_sectors == 0) || (num_sectors > 72) ) {
6774 BX_INFO("floppy: drive>1 || head>1 ...\n");
6776 set_diskette_ret_status(1);
6777 SET_AL(0); // no sectors read
6778 SET_CF(); // error occurred
6782 // see if drive exists
6783 if (floppy_drive_exists(drive) == 0) {
6784 SET_AH(0x80); // not responding
6785 set_diskette_ret_status(0x80);
6786 SET_AL(0); // no sectors read
6787 SET_CF(); // error occurred
6791 // see if media in drive, and type is known
6792 if (floppy_media_known(drive) == 0) {
6793 if (floppy_media_sense(drive) == 0) {
6794 SET_AH(0x0C); // Media type not found
6795 set_diskette_ret_status(0x0C);
6796 SET_AL(0); // no sectors read
6797 SET_CF(); // error occurred
6803 // Read Diskette Sectors
6805 //-----------------------------------
6806 // set up DMA controller for transfer
6807 //-----------------------------------
6809 // es:bx = pointer to where to place information from diskette
6810 // port 04: DMA-1 base and current address, channel 2
6811 // port 05: DMA-1 base and current count, channel 2
6812 page = (ES >> 12); // upper 4 bits
6813 base_es = (ES << 4); // lower 16bits contributed by ES
6814 base_address = base_es + BX; // lower 16 bits of address
6815 // contributed by ES:BX
6816 if ( base_address < base_es ) {
6817 // in case of carry, adjust page by 1
6820 base_count = (num_sectors * 512) - 1;
6822 // check for 64K boundary overrun
6823 last_addr = base_address + base_count;
6824 if (last_addr < base_address) {
6826 set_diskette_ret_status(0x09);
6827 SET_AL(0); // no sectors read
6828 SET_CF(); // error occurred
6832 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6835 BX_DEBUG_INT13_FL("clear flip-flop\n");
6836 outb(0x000c, 0x00); // clear flip-flop
6837 outb(0x0004, base_address);
6838 outb(0x0004, base_address>>8);
6839 BX_DEBUG_INT13_FL("clear flip-flop\n");
6840 outb(0x000c, 0x00); // clear flip-flop
6841 outb(0x0005, base_count);
6842 outb(0x0005, base_count>>8);
6844 // port 0b: DMA-1 Mode Register
6845 mode_register = 0x46; // single mode, increment, autoinit disable,
6846 // transfer type=write, channel 2
6847 BX_DEBUG_INT13_FL("setting mode register\n");
6848 outb(0x000b, mode_register);
6850 BX_DEBUG_INT13_FL("setting page register\n");
6851 // port 81: DMA-1 Page Register, channel 2
6854 BX_DEBUG_INT13_FL("unmask chan 2\n");
6855 outb(0x000a, 0x02); // unmask channel 2
6857 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6860 //--------------------------------------
6861 // set up floppy controller for transfer
6862 //--------------------------------------
6864 // set 40:3e bit 7 to 0
6865 val8 = read_byte(0x0000, 0x043e);
6867 write_byte(0x0000, 0x043e, val8);
6869 // turn on motor of selected drive, DMA & int enabled, normal operation
6878 // reset the disk motor timeout value of INT 08
6879 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6881 // check port 3f4 for drive readiness
6883 if ( (val8 & 0xf0) != 0x80 )
6884 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6886 // send read-normal-data command (9 bytes) to controller
6887 outb(0x03f5, 0xe6); // e6: read normal data
6888 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6889 outb(0x03f5, track);
6891 outb(0x03f5, sector);
6892 outb(0x03f5, 2); // 512 byte sector size
6893 outb(0x03f5, 0); // last sector number possible on track
6894 outb(0x03f5, 0); // Gap length
6895 outb(0x03f5, 0xff); // Gap length
6897 // turn on interrupts
6902 // wait on 40:3e bit 7 to become 1
6903 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6904 while ( val8 == 0 ) {
6905 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6908 val8 = 0; // separate asm from while() loop
6909 // turn off interrupts
6914 // set 40:3e bit 7 to 0
6915 val8 = read_byte(0x0000, 0x043e);
6917 write_byte(0x0000, 0x043e, val8);
6919 // check port 3f4 for accessibility to status bytes
6921 if ( (val8 & 0xc0) != 0xc0 )
6922 BX_PANIC("int13_diskette: ctrl not ready\n");
6924 // read 7 return status bytes from controller
6925 // using loop index broken, have to unroll...
6926 return_status[0] = inb(0x3f5);
6927 return_status[1] = inb(0x3f5);
6928 return_status[2] = inb(0x3f5);
6929 return_status[3] = inb(0x3f5);
6930 return_status[4] = inb(0x3f5);
6931 return_status[5] = inb(0x3f5);
6932 return_status[6] = inb(0x3f5);
6933 // record in BIOS Data Area
6934 write_byte(0x0040, 0x0042, return_status[0]);
6935 write_byte(0x0040, 0x0043, return_status[1]);
6936 write_byte(0x0040, 0x0044, return_status[2]);
6937 write_byte(0x0040, 0x0045, return_status[3]);
6938 write_byte(0x0040, 0x0046, return_status[4]);
6939 write_byte(0x0040, 0x0047, return_status[5]);
6940 write_byte(0x0040, 0x0048, return_status[6]);
6942 if ( (return_status[0] & 0xc0) != 0 ) {
6944 set_diskette_ret_status(0x20);
6945 SET_AL(0); // no sectors read
6946 SET_CF(); // error occurred
6950 // ??? should track be new val from return_status[3] ?
6951 set_diskette_current_cyl(drive, track);
6952 // AL = number of sectors read (same value as passed)
6953 SET_AH(0x00); // success
6954 CLEAR_CF(); // success
6957 else if (ah == 0x03) {
6958 // Write Diskette Sectors
6960 //-----------------------------------
6961 // set up DMA controller for transfer
6962 //-----------------------------------
6964 // es:bx = pointer to where to place information from diskette
6965 // port 04: DMA-1 base and current address, channel 2
6966 // port 05: DMA-1 base and current count, channel 2
6967 page = (ES >> 12); // upper 4 bits
6968 base_es = (ES << 4); // lower 16bits contributed by ES
6969 base_address = base_es + BX; // lower 16 bits of address
6970 // contributed by ES:BX
6971 if ( base_address < base_es ) {
6972 // in case of carry, adjust page by 1
6975 base_count = (num_sectors * 512) - 1;
6977 // check for 64K boundary overrun
6978 last_addr = base_address + base_count;
6979 if (last_addr < base_address) {
6981 set_diskette_ret_status(0x09);
6982 SET_AL(0); // no sectors read
6983 SET_CF(); // error occurred
6987 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6990 outb(0x000c, 0x00); // clear flip-flop
6991 outb(0x0004, base_address);
6992 outb(0x0004, base_address>>8);
6993 outb(0x000c, 0x00); // clear flip-flop
6994 outb(0x0005, base_count);
6995 outb(0x0005, base_count>>8);
6997 // port 0b: DMA-1 Mode Register
6998 mode_register = 0x4a; // single mode, increment, autoinit disable,
6999 // transfer type=read, channel 2
7000 outb(0x000b, mode_register);
7002 // port 81: DMA-1 Page Register, channel 2
7005 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7008 //--------------------------------------
7009 // set up floppy controller for transfer
7010 //--------------------------------------
7012 // set 40:3e bit 7 to 0
7013 val8 = read_byte(0x0000, 0x043e);
7015 write_byte(0x0000, 0x043e, val8);
7017 // turn on motor of selected drive, DMA & int enabled, normal operation
7026 // reset the disk motor timeout value of INT 08
7027 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7029 // check port 3f4 for drive readiness
7031 if ( (val8 & 0xf0) != 0x80 )
7032 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7034 // send read-normal-data command (9 bytes) to controller
7035 outb(0x03f5, 0xc5); // c5: write normal data
7036 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7037 outb(0x03f5, track);
7039 outb(0x03f5, sector);
7040 outb(0x03f5, 2); // 512 byte sector size
7041 outb(0x03f5, 0); // last sector number possible on track
7042 outb(0x03f5, 0); // Gap length
7043 outb(0x03f5, 0xff); // Gap length
7045 // turn on interrupts
7050 // wait on 40:3e bit 7 to become 1
7051 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7052 while ( val8 == 0 ) {
7053 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7056 val8 = 0; // separate asm from while() loop
7057 // turn off interrupts
7062 // set 40:3e bit 7 to 0
7063 val8 = read_byte(0x0000, 0x043e);
7065 write_byte(0x0000, 0x043e, val8);
7067 // check port 3f4 for accessibility to status bytes
7069 if ( (val8 & 0xc0) != 0xc0 )
7070 BX_PANIC("int13_diskette: ctrl not ready\n");
7072 // read 7 return status bytes from controller
7073 // using loop index broken, have to unroll...
7074 return_status[0] = inb(0x3f5);
7075 return_status[1] = inb(0x3f5);
7076 return_status[2] = inb(0x3f5);
7077 return_status[3] = inb(0x3f5);
7078 return_status[4] = inb(0x3f5);
7079 return_status[5] = inb(0x3f5);
7080 return_status[6] = inb(0x3f5);
7081 // record in BIOS Data Area
7082 write_byte(0x0040, 0x0042, return_status[0]);
7083 write_byte(0x0040, 0x0043, return_status[1]);
7084 write_byte(0x0040, 0x0044, return_status[2]);
7085 write_byte(0x0040, 0x0045, return_status[3]);
7086 write_byte(0x0040, 0x0046, return_status[4]);
7087 write_byte(0x0040, 0x0047, return_status[5]);
7088 write_byte(0x0040, 0x0048, return_status[6]);
7090 if ( (return_status[0] & 0xc0) != 0 ) {
7091 if ( (return_status[1] & 0x02) != 0 ) {
7092 // diskette not writable.
7093 // AH=status code=0x03 (tried to write on write-protected disk)
7094 // AL=number of sectors written=0
7099 BX_PANIC("int13_diskette_function: read error\n");
7103 // ??? should track be new val from return_status[3] ?
7104 set_diskette_current_cyl(drive, track);
7105 // AL = number of sectors read (same value as passed)
7106 SET_AH(0x00); // success
7107 CLEAR_CF(); // success
7110 else { // if (ah == 0x04)
7111 // Verify Diskette Sectors
7113 // ??? should track be new val from return_status[3] ?
7114 set_diskette_current_cyl(drive, track);
7115 // AL = number of sectors verified (same value as passed)
7116 CLEAR_CF(); // success
7117 SET_AH(0x00); // success
7122 case 0x05: // format diskette track
7123 BX_DEBUG_INT13_FL("floppy f05\n");
7125 num_sectors = GET_AL();
7130 if ((drive > 1) || (head > 1) || (track > 79) ||
7131 (num_sectors == 0) || (num_sectors > 18)) {
7133 set_diskette_ret_status(1);
7134 SET_CF(); // error occurred
7137 // see if drive exists
7138 if (floppy_drive_exists(drive) == 0) {
7139 SET_AH(0x80); // drive not responding
7140 set_diskette_ret_status(0x80);
7141 SET_CF(); // error occurred
7145 // see if media in drive, and type is known
7146 if (floppy_media_known(drive) == 0) {
7147 if (floppy_media_sense(drive) == 0) {
7148 SET_AH(0x0C); // Media type not found
7149 set_diskette_ret_status(0x0C);
7150 SET_AL(0); // no sectors read
7151 SET_CF(); // error occurred
7156 // set up DMA controller for transfer
7157 page = (ES >> 12); // upper 4 bits
7158 base_es = (ES << 4); // lower 16bits contributed by ES
7159 base_address = base_es + BX; // lower 16 bits of address
7160 // contributed by ES:BX
7161 if ( base_address < base_es ) {
7162 // in case of carry, adjust page by 1
7165 base_count = (num_sectors * 4) - 1;
7167 // check for 64K boundary overrun
7168 last_addr = base_address + base_count;
7169 if (last_addr < base_address) {
7171 set_diskette_ret_status(0x09);
7172 SET_AL(0); // no sectors read
7173 SET_CF(); // error occurred
7178 outb(0x000c, 0x00); // clear flip-flop
7179 outb(0x0004, base_address);
7180 outb(0x0004, base_address>>8);
7181 outb(0x000c, 0x00); // clear flip-flop
7182 outb(0x0005, base_count);
7183 outb(0x0005, base_count>>8);
7184 mode_register = 0x4a; // single mode, increment, autoinit disable,
7185 // transfer type=read, channel 2
7186 outb(0x000b, mode_register);
7187 // port 81: DMA-1 Page Register, channel 2
7191 // set up floppy controller for transfer
7192 val8 = read_byte(0x0000, 0x043e);
7194 write_byte(0x0000, 0x043e, val8);
7195 // turn on motor of selected drive, DMA & int enabled, normal operation
7204 // reset the disk motor timeout value of INT 08
7205 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7207 // check port 3f4 for drive readiness
7209 if ( (val8 & 0xf0) != 0x80 )
7210 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7212 // send read-normal-data command (6 bytes) to controller
7213 outb(0x03f5, 0x4d); // 4d: format track
7214 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7215 outb(0x03f5, 2); // 512 byte sector size
7216 outb(0x03f5, num_sectors); // number of sectors per track
7217 outb(0x03f5, 0); // Gap length
7218 outb(0x03f5, 0xf6); // Fill byte
7219 // turn on interrupts
7223 // wait on 40:3e bit 7 to become 1
7224 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7225 while ( val8 == 0 ) {
7226 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7228 val8 = 0; // separate asm from while() loop
7229 // turn off interrupts
7233 // set 40:3e bit 7 to 0
7234 val8 = read_byte(0x0000, 0x043e);
7236 write_byte(0x0000, 0x043e, val8);
7237 // check port 3f4 for accessibility to status bytes
7239 if ( (val8 & 0xc0) != 0xc0 )
7240 BX_PANIC("int13_diskette: ctrl not ready\n");
7242 // read 7 return status bytes from controller
7243 // using loop index broken, have to unroll...
7244 return_status[0] = inb(0x3f5);
7245 return_status[1] = inb(0x3f5);
7246 return_status[2] = inb(0x3f5);
7247 return_status[3] = inb(0x3f5);
7248 return_status[4] = inb(0x3f5);
7249 return_status[5] = inb(0x3f5);
7250 return_status[6] = inb(0x3f5);
7251 // record in BIOS Data Area
7252 write_byte(0x0040, 0x0042, return_status[0]);
7253 write_byte(0x0040, 0x0043, return_status[1]);
7254 write_byte(0x0040, 0x0044, return_status[2]);
7255 write_byte(0x0040, 0x0045, return_status[3]);
7256 write_byte(0x0040, 0x0046, return_status[4]);
7257 write_byte(0x0040, 0x0047, return_status[5]);
7258 write_byte(0x0040, 0x0048, return_status[6]);
7260 if ( (return_status[0] & 0xc0) != 0 ) {
7261 if ( (return_status[1] & 0x02) != 0 ) {
7262 // diskette not writable.
7263 // AH=status code=0x03 (tried to write on write-protected disk)
7264 // AL=number of sectors written=0
7269 BX_PANIC("int13_diskette_function: write error\n");
7274 set_diskette_ret_status(0);
7275 set_diskette_current_cyl(drive, 0);
7276 CLEAR_CF(); // successful
7280 case 0x08: // read diskette drive parameters
7281 BX_DEBUG_INT13_FL("floppy f08\n");
7291 SET_DL(num_floppies);
7296 drive_type = inb_cmos(0x10);
7298 if (drive_type & 0xf0)
7300 if (drive_type & 0x0f)
7312 SET_DL(num_floppies);
7314 switch (drive_type) {
7317 SET_DH(0); // max head #
7320 case 1: // 360KB, 5.25"
7321 CX = 0x2709; // 40 tracks, 9 sectors
7322 SET_DH(1); // max head #
7325 case 2: // 1.2MB, 5.25"
7326 CX = 0x4f0f; // 80 tracks, 15 sectors
7327 SET_DH(1); // max head #
7330 case 3: // 720KB, 3.5"
7331 CX = 0x4f09; // 80 tracks, 9 sectors
7332 SET_DH(1); // max head #
7335 case 4: // 1.44MB, 3.5"
7336 CX = 0x4f12; // 80 tracks, 18 sectors
7337 SET_DH(1); // max head #
7340 case 5: // 2.88MB, 3.5"
7341 CX = 0x4f24; // 80 tracks, 36 sectors
7342 SET_DH(1); // max head #
7345 case 6: // 160k, 5.25"
7346 CX = 0x2708; // 40 tracks, 8 sectors
7347 SET_DH(0); // max head #
7350 case 7: // 180k, 5.25"
7351 CX = 0x2709; // 40 tracks, 9 sectors
7352 SET_DH(0); // max head #
7355 case 8: // 320k, 5.25"
7356 CX = 0x2708; // 40 tracks, 8 sectors
7357 SET_DH(1); // max head #
7361 BX_PANIC("floppy: int13: bad floppy type\n");
7364 /* set es & di to point to 11 byte diskette param table in ROM */
7368 mov ax, #diskette_param_table2
7369 mov _int13_diskette_function.DI+2[bp], ax
7370 mov _int13_diskette_function.ES+2[bp], cs
7373 CLEAR_CF(); // success
7374 /* disk status not changed upon success */
7378 case 0x15: // read diskette drive type
7379 BX_DEBUG_INT13_FL("floppy f15\n");
7382 SET_AH(0); // only 2 drives supported
7383 // set_diskette_ret_status here ???
7387 drive_type = inb_cmos(0x10);
7393 CLEAR_CF(); // successful, not present
7394 if (drive_type==0) {
7395 SET_AH(0); // drive not present
7398 SET_AH(1); // drive present, does not support change line
7403 case 0x16: // get diskette change line status
7404 BX_DEBUG_INT13_FL("floppy f16\n");
7407 SET_AH(0x01); // invalid drive
7408 set_diskette_ret_status(0x01);
7413 SET_AH(0x06); // change line not supported
7414 set_diskette_ret_status(0x06);
7418 case 0x17: // set diskette type for format(old)
7419 BX_DEBUG_INT13_FL("floppy f17\n");
7420 /* not used for 1.44M floppies */
7421 SET_AH(0x01); // not supported
7422 set_diskette_ret_status(1); /* not supported */
7426 case 0x18: // set diskette type for format(new)
7427 BX_DEBUG_INT13_FL("floppy f18\n");
7428 SET_AH(0x01); // do later
7429 set_diskette_ret_status(1);
7434 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7436 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7437 SET_AH(0x01); // ???
7438 set_diskette_ret_status(1);
7444 #else // #if BX_SUPPORT_FLOPPY
7446 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7447 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7451 switch ( GET_AH() ) {
7453 case 0x01: // Read Diskette Status
7455 val8 = read_byte(0x0000, 0x0441);
7464 write_byte(0x0000, 0x0441, 0x01);
7468 #endif // #if BX_SUPPORT_FLOPPY
7471 set_diskette_ret_status(value)
7474 write_byte(0x0040, 0x0041, value);
7478 set_diskette_current_cyl(drive, cyl)
7483 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7484 write_byte(0x0040, 0x0094+drive, cyl);
7488 determine_floppy_media(drive)
7492 Bit8u val8, DOR, ctrl_info;
7494 ctrl_info = read_byte(0x0040, 0x008F);
7502 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7505 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7509 if ( (ctrl_info & 0x04) != 0x04 ) {
7510 // Drive not determined means no drive exists, done.
7515 // check Main Status Register for readiness
7516 val8 = inb(0x03f4) & 0x80; // Main Status Register
7518 BX_PANIC("d_f_m: MRQ bit not set\n");
7522 // existing BDA values
7524 // turn on drive motor
7525 outb(0x03f2, DOR); // Digital Output Register
7528 BX_PANIC("d_f_m: OK so far\n");
7533 int17_function(regs, ds, iret_addr)
7534 pusha_regs_t regs; // regs pushed from PUSHA instruction
7535 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7536 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7538 Bit16u addr,timeout;
7545 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7546 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7547 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7548 if (regs.u.r8.ah == 0) {
7549 outb(addr, regs.u.r8.al);
7551 outb(addr+2, val8 | 0x01); // send strobe
7555 outb(addr+2, val8 & ~0x01);
7556 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7560 if (regs.u.r8.ah == 1) {
7562 outb(addr+2, val8 & ~0x04); // send init
7566 outb(addr+2, val8 | 0x04);
7569 regs.u.r8.ah = (val8 ^ 0x48);
7570 if (!timeout) regs.u.r8.ah |= 0x01;
7571 ClearCF(iret_addr.flags);
7573 SetCF(iret_addr.flags); // Unsupported
7577 // returns bootsegment in ax, drive in bl
7579 int19_function(bseqnr)
7582 Bit16u ebda_seg=read_word(0x0040,0x000E);
7591 // BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7593 // if BX_ELTORITO_BOOT is not defined, old behavior
7594 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7595 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7596 // 0: system boot sequence, first drive C: then A:
7597 // 1: system boot sequence, first drive A: then C:
7598 // else BX_ELTORITO_BOOT is defined
7599 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7600 // CMOS reg 0x3D & 0x0f : 1st boot device
7601 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7602 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7603 // boot device codes:
7604 // 0x00 : not defined
7605 // 0x01 : first floppy
7606 // 0x02 : first harddrive
7607 // 0x03 : first cdrom
7608 // else : boot failure
7610 // Get the boot sequence
7611 #if BX_ELTORITO_BOOT
7612 bootseq=inb_cmos(0x3d);
7613 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7615 if (bseqnr==2) bootseq >>= 4;
7616 if (bseqnr==3) bootseq >>= 8;
7617 if (bootseq<0x10) lastdrive = 1;
7618 bootdrv=0x00; bootcd=0;
7619 switch(bootseq & 0x0f) {
7620 case 0x01: bootdrv=0x00; bootcd=0; break;
7621 case 0x02: bootdrv=0x80; bootcd=0; break;
7622 case 0x03: bootdrv=0x00; bootcd=1; break;
7623 default: return 0x00000000;
7626 bootseq=inb_cmos(0x2d);
7632 bootdrv=0x00; bootcd=0;
7633 if((bootseq&0x20)==0) bootdrv=0x80;
7634 #endif // BX_ELTORITO_BOOT
7636 #if BX_ELTORITO_BOOT
7637 // We have to boot from cd
7639 status = cdrom_boot();
7644 if ( (status & 0x00ff) !=0 ) {
7645 print_cdromboot_failure(status);
7646 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7650 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7651 bootdrv = (Bit8u)(status>>8);
7654 #endif // BX_ELTORITO_BOOT
7656 // We have to boot from harddisk or floppy
7667 mov _int19_function.status + 2[bp], ax
7668 mov dl, _int19_function.bootdrv + 2[bp]
7669 mov ax, _int19_function.bootseg + 2[bp]
7670 mov es, ax ;; segment
7671 mov bx, #0x0000 ;; offset
7672 mov ah, #0x02 ;; function 2, read diskette sector
7673 mov al, #0x01 ;; read 1 sector
7674 mov ch, #0x00 ;; track 0
7675 mov cl, #0x01 ;; sector 1
7676 mov dh, #0x00 ;; head 0
7677 int #0x13 ;; read sector
7680 mov _int19_function.status + 2[bp], ax
7688 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7693 // check signature if instructed by cmos reg 0x38, only for floppy
7694 // bootchk = 1 : signature check disabled
7695 // bootchk = 0 : signature check enabled
7696 if (bootdrv != 0) bootchk = 0;
7697 else bootchk = inb_cmos(0x38) & 0x01;
7699 #if BX_ELTORITO_BOOT
7700 // if boot from cd, no signature check
7703 #endif // BX_ELTORITO_BOOT
7706 if (read_word(bootseg,0x1fe) != 0xaa55) {
7707 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7712 #if BX_ELTORITO_BOOT
7713 // Print out the boot string
7714 BX_DEBUG("cdrom_boot: %x\n",status);
7715 print_boot_device(bootcd, bootdrv);
7716 #else // BX_ELTORITO_BOOT
7717 print_boot_device(0, bootdrv);
7718 #endif // BX_ELTORITO_BOOT
7720 // return the boot segment
7721 return (((Bit32u)bootdrv) << 16) + bootseg;
7725 int1a_function(regs, ds, iret_addr)
7726 pusha_regs_t regs; // regs pushed from PUSHA instruction
7727 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7728 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7732 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);
7738 switch (regs.u.r8.ah) {
7739 case 0: // get current clock count
7743 regs.u.r16.cx = BiosData->ticks_high;
7744 regs.u.r16.dx = BiosData->ticks_low;
7745 regs.u.r8.al = BiosData->midnight_flag;
7746 BiosData->midnight_flag = 0; // reset flag
7751 ClearCF(iret_addr.flags); // OK
7754 case 1: // Set Current Clock Count
7758 BiosData->ticks_high = regs.u.r16.cx;
7759 BiosData->ticks_low = regs.u.r16.dx;
7760 BiosData->midnight_flag = 0; // reset flag
7765 ClearCF(iret_addr.flags); // OK
7769 case 2: // Read CMOS Time
7770 if (rtc_updating()) {
7771 SetCF(iret_addr.flags);
7775 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7776 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7777 regs.u.r8.ch = inb_cmos(0x04); // Hours
7778 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7780 regs.u.r8.al = regs.u.r8.ch;
7781 ClearCF(iret_addr.flags); // OK
7784 case 3: // Set CMOS Time
7785 // Using a debugger, I notice the following masking/setting
7786 // of bits in Status Register B, by setting Reg B to
7787 // a few values and getting its value after INT 1A was called.
7789 // try#1 try#2 try#3
7790 // before 1111 1101 0111 1101 0000 0000
7791 // after 0110 0010 0110 0010 0000 0010
7793 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7794 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7795 if (rtc_updating()) {
7797 // fall through as if an update were not in progress
7799 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7800 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7801 outb_cmos(0x04, regs.u.r8.ch); // Hours
7802 // Set Daylight Savings time enabled bit to requested value
7803 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7804 // (reg B already selected)
7805 outb_cmos(0x0b, val8);
7807 regs.u.r8.al = val8; // val last written to Reg B
7808 ClearCF(iret_addr.flags); // OK
7811 case 4: // Read CMOS Date
7813 if (rtc_updating()) {
7814 SetCF(iret_addr.flags);
7817 regs.u.r8.cl = inb_cmos(0x09); // Year
7818 regs.u.r8.dh = inb_cmos(0x08); // Month
7819 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7820 regs.u.r8.ch = inb_cmos(0x32); // Century
7821 regs.u.r8.al = regs.u.r8.ch;
7822 ClearCF(iret_addr.flags); // OK
7825 case 5: // Set CMOS Date
7826 // Using a debugger, I notice the following masking/setting
7827 // of bits in Status Register B, by setting Reg B to
7828 // a few values and getting its value after INT 1A was called.
7830 // try#1 try#2 try#3 try#4
7831 // before 1111 1101 0111 1101 0000 0010 0000 0000
7832 // after 0110 1101 0111 1101 0000 0010 0000 0000
7834 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7835 // My assumption: RegB = (RegB & 01111111b)
7836 if (rtc_updating()) {
7838 SetCF(iret_addr.flags);
7841 outb_cmos(0x09, regs.u.r8.cl); // Year
7842 outb_cmos(0x08, regs.u.r8.dh); // Month
7843 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7844 outb_cmos(0x32, regs.u.r8.ch); // Century
7845 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7846 outb_cmos(0x0b, val8);
7848 regs.u.r8.al = val8; // AL = val last written to Reg B
7849 ClearCF(iret_addr.flags); // OK
7852 case 6: // Set Alarm Time in CMOS
7853 // Using a debugger, I notice the following masking/setting
7854 // of bits in Status Register B, by setting Reg B to
7855 // a few values and getting its value after INT 1A was called.
7857 // try#1 try#2 try#3
7858 // before 1101 1111 0101 1111 0000 0000
7859 // after 0110 1111 0111 1111 0010 0000
7861 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7862 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7863 val8 = inb_cmos(0x0b); // Get Status Reg B
7866 // Alarm interrupt enabled already
7867 SetCF(iret_addr.flags); // Error: alarm in use
7870 if (rtc_updating()) {
7872 // fall through as if an update were not in progress
7874 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7875 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7876 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7877 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7878 // enable Status Reg B alarm bit, clear halt clock bit
7879 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7880 ClearCF(iret_addr.flags); // OK
7883 case 7: // Turn off Alarm
7884 // Using a debugger, I notice the following masking/setting
7885 // of bits in Status Register B, by setting Reg B to
7886 // a few values and getting its value after INT 1A was called.
7888 // try#1 try#2 try#3 try#4
7889 // before 1111 1101 0111 1101 0010 0000 0010 0010
7890 // after 0100 0101 0101 0101 0000 0000 0000 0010
7892 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7893 // My assumption: RegB = (RegB & 01010111b)
7894 val8 = inb_cmos(0x0b); // Get Status Reg B
7895 // clear clock-halt bit, disable alarm bit
7896 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7898 regs.u.r8.al = val8; // val last written to Reg B
7899 ClearCF(iret_addr.flags); // OK
7903 // real mode PCI BIOS functions now handled in assembler code
7904 // this C code handles the error code for information only
7905 if (regs.u.r8.bl == 0xff) {
7906 BX_INFO("PCI BIOS: PCI not present\n");
7907 } else if (regs.u.r8.bl == 0x81) {
7908 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7909 } else if (regs.u.r8.bl == 0x83) {
7910 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7911 } else if (regs.u.r8.bl == 0x86) {
7912 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7914 regs.u.r8.ah = regs.u.r8.bl;
7915 SetCF(iret_addr.flags);
7920 SetCF(iret_addr.flags); // Unsupported
7925 int70_function(regs, ds, iret_addr)
7926 pusha_regs_t regs; // regs pushed from PUSHA instruction
7927 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7928 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7930 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7931 Bit8u registerB = 0, registerC = 0;
7933 // Check which modes are enabled and have occurred.
7934 registerB = inb_cmos( 0xB );
7935 registerC = inb_cmos( 0xC );
7937 if( ( registerB & 0x60 ) != 0 ) {
7938 if( ( registerC & 0x20 ) != 0 ) {
7939 // Handle Alarm Interrupt.
7946 if( ( registerC & 0x40 ) != 0 ) {
7947 // Handle Periodic Interrupt.
7949 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7950 // Wait Interval (Int 15, AH=83) active.
7951 Bit32u time, toggle;
7953 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
7954 if( time < 0x3D1 ) {
7956 Bit16u segment, offset;
7958 offset = read_word( 0x40, 0x98 );
7959 segment = read_word( 0x40, 0x9A );
7960 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7961 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
7962 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
7964 // Continue waiting.
7966 write_dword( 0x40, 0x9C, time );
7979 ;------------------------------------------
7980 ;- INT74h : PS/2 mouse hardware interrupt -
7981 ;------------------------------------------
7986 push #0x00 ;; placeholder for status
7987 push #0x00 ;; placeholder for X
7988 push #0x00 ;; placeholder for Y
7989 push #0x00 ;; placeholder for Z
7990 push #0x00 ;; placeholder for make_far_call boolean
7991 call _int74_function
7992 pop cx ;; remove make_far_call from stack
7995 ;; make far call to EBDA:0022
7998 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8000 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8005 add sp, #8 ;; pop status, x, y, z
8007 pop ds ;; restore DS
8012 ;; This will perform an IRET, but will retain value of current CF
8013 ;; by altering flags on stack. Better than RETF #02.
8018 and BYTE [bp + 0x06], #0xfe
8024 or BYTE [bp + 0x06], #0x01
8029 ;----------------------
8030 ;- INT13h (relocated) -
8031 ;----------------------
8033 ; int13_relocated is a little bit messed up since I played with it
8034 ; I have to rewrite it:
8035 ; - call a function that detect which function to call
8036 ; - make all called C function get the same parameters list
8040 #if BX_ELTORITO_BOOT
8041 ;; check for an eltorito function
8043 jb int13_not_eltorito
8045 ja int13_not_eltorito
8054 jmp _int13_eltorito ;; ELDX not used
8062 ;; check if emulation active
8063 call _cdemu_isactive
8065 je int13_cdemu_inactive
8067 ;; check if access to the emulated drive
8068 call _cdemu_emulated_drive
8071 cmp al,dl ;; int13 on emulated drive
8086 jmp _int13_cdemu ;; ELDX not used
8089 and dl,#0xE0 ;; mask to get device class, including cdroms
8090 cmp al,dl ;; al is 0x00 or 0x80
8091 jne int13_cdemu_inactive ;; inactive for device class
8103 dec dl ;; real drive is dl - 1
8106 int13_cdemu_inactive:
8112 #endif // BX_ELTORITO_BOOT
8123 push dx ;; push eltorito value of dx instead of sp
8134 ;; now the 16-bit registers can be restored with:
8135 ;; pop ds; pop es; popa; iret
8136 ;; arguments passed to functions should be
8137 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8143 jmp _int13_diskette_function
8152 // ebx is modified: BSD 5.2.1 boot loader problem
8153 // someone should figure out which 32 bit register that actually are used
8170 call _int13_harddisk
8182 int18_handler: ;; Boot Failure routing
8183 call _int18_panic_msg
8190 int19_relocated: ;; Boot function, relocated
8192 ;; int19 was beginning to be really complex, so now it
8193 ;; just calls an C function, that does the work
8194 ;; it returns in BL the boot drive, and in AX the boot segment
8195 ;; the boot segment will be 0x0000 if something has failed
8207 call _int19_function
8210 ;; bl contains the boot drive
8211 ;; ax contains the boot segment or 0 if failure
8213 test ax, ax ;; if ax is 0 try next boot device
8219 call _int19_function
8222 test ax, ax ;; if ax is 0 try next boot device
8228 call _int19_function
8231 test ax, ax ;; if ax is 0 call int18
8235 mov dl, bl ;; set drive so guest os find it
8236 shl eax, #0x04 ;; convert seg to ip
8237 mov 2[bp], ax ;; set ip
8239 shr eax, #0x04 ;; get cs back
8240 and ax, #0xF000 ;; remove what went in ip
8241 mov 4[bp], ax ;; set cs
8243 mov es, ax ;; set es to zero fixes [ 549815 ]
8244 mov [bp], ax ;; set bp to zero
8245 mov ax, #0xaa55 ;; set ok flag
8248 iret ;; Beam me up Scotty
8253 int1c_handler: ;; User Timer Tick
8257 ;----------------------
8258 ;- POST: Floppy Drive -
8259 ;----------------------
8265 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8267 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8269 mov 0x0440, al ;; diskette motor timeout counter: not active
8270 mov 0x0441, al ;; diskette controller status return code
8272 mov 0x0442, al ;; disk & diskette controller status register 0
8273 mov 0x0443, al ;; diskette controller status register 1
8274 mov 0x0444, al ;; diskette controller status register 2
8275 mov 0x0445, al ;; diskette controller cylinder number
8276 mov 0x0446, al ;; diskette controller head number
8277 mov 0x0447, al ;; diskette controller sector number
8278 mov 0x0448, al ;; diskette controller bytes written
8280 mov 0x048b, al ;; diskette configuration data
8282 ;; -----------------------------------------------------------------
8283 ;; (048F) diskette controller information
8285 mov al, #0x10 ;; get CMOS diskette drive type
8288 mov ah, al ;; save byte to AH
8291 shr al, #4 ;; look at top 4 bits for drive 0
8292 jz f0_missing ;; jump if no drive0
8293 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8296 mov bl, #0x00 ;; no drive0
8299 mov al, ah ;; restore from AH
8300 and al, #0x0f ;; look at bottom 4 bits for drive 1
8301 jz f1_missing ;; jump if no drive1
8302 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8304 ;; leave high bits in BL zerod
8305 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8306 ;; -----------------------------------------------------------------
8309 mov 0x0490, al ;; diskette 0 media state
8310 mov 0x0491, al ;; diskette 1 media state
8312 ;; diskette 0,1 operational starting state
8313 ;; drive type has not been determined,
8314 ;; has no changed detection line
8318 mov 0x0494, al ;; diskette 0 current cylinder
8319 mov 0x0495, al ;; diskette 1 current cylinder
8322 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8324 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8325 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8326 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8331 ;--------------------
8332 ;- POST: HARD DRIVE -
8333 ;--------------------
8334 ; relocated here because the primary POST area isnt big enough.
8337 // INT 76h calls INT 15h function ax=9100
8339 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8345 mov 0x0474, al /* hard disk status of last operation */
8346 mov 0x0477, al /* hard disk port offset (XT only ???) */
8347 mov 0x048c, al /* hard disk status register */
8348 mov 0x048d, al /* hard disk error register */
8349 mov 0x048e, al /* hard disk task complete flag */
8351 mov 0x0475, al /* hard disk number attached */
8353 mov 0x0476, al /* hard disk control byte */
8354 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8355 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8356 ;; INT 41h: hard disk 0 configuration pointer
8357 ;; INT 46h: hard disk 1 configuration pointer
8358 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8359 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8361 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8373 cmp al, #47 ;; decimal 47 - user definable
8377 ;; CMOS purpose param table offset
8378 ;; 1b cylinders low 0
8379 ;; 1c cylinders high 1
8381 ;; 1e write pre-comp low 5
8382 ;; 1f write pre-comp high 6
8383 ;; 20 retries/bad map/heads>8 8
8384 ;; 21 landing zone low C
8385 ;; 22 landing zone high D
8386 ;; 23 sectors/track E
8391 ;;; Filling EBDA table for hard disk 0.
8399 mov (0x003d + 0x05), ax ;; write precomp word
8404 mov (0x003d + 0x08), al ;; drive control byte
8413 mov (0x003d + 0x0C), ax ;; landing zone word
8415 mov al, #0x1c ;; get cylinders word in AX
8417 in al, #0x71 ;; high byte
8421 in al, #0x71 ;; low byte
8422 mov bx, ax ;; BX = cylinders
8427 mov cl, al ;; CL = heads
8432 mov dl, al ;; DL = sectors
8435 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8437 hd0_post_physical_chs:
8438 ;; no logical CHS mapping used, just physical CHS
8439 ;; use Standard Fixed Disk Parameter Table (FDPT)
8440 mov (0x003d + 0x00), bx ;; number of physical cylinders
8441 mov (0x003d + 0x02), cl ;; number of physical heads
8442 mov (0x003d + 0x0E), dl ;; number of physical sectors
8445 hd0_post_logical_chs:
8446 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8447 mov (0x003d + 0x09), bx ;; number of physical cylinders
8448 mov (0x003d + 0x0b), cl ;; number of physical heads
8449 mov (0x003d + 0x04), dl ;; number of physical sectors
8450 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8452 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8455 jnbe hd0_post_above_2048
8456 ;; 1024 < c <= 2048 cylinders
8459 jmp hd0_post_store_logical
8461 hd0_post_above_2048:
8463 jnbe hd0_post_above_4096
8464 ;; 2048 < c <= 4096 cylinders
8467 jmp hd0_post_store_logical
8469 hd0_post_above_4096:
8471 jnbe hd0_post_above_8192
8472 ;; 4096 < c <= 8192 cylinders
8475 jmp hd0_post_store_logical
8477 hd0_post_above_8192:
8478 ;; 8192 < c <= 16384 cylinders
8482 hd0_post_store_logical:
8483 mov (0x003d + 0x00), bx ;; number of physical cylinders
8484 mov (0x003d + 0x02), cl ;; number of physical heads
8486 mov cl, #0x0f ;; repeat count
8487 mov si, #0x003d ;; offset to disk0 FDPT
8488 mov al, #0x00 ;; sum
8489 hd0_post_checksum_loop:
8493 jnz hd0_post_checksum_loop
8494 not al ;; now take 2s complement
8497 ;;; Done filling EBDA table for hard disk 0.
8501 ;; is there really a second hard disk? if not, return now
8509 ;; check that the hd type is really 0x0f.
8514 ;; check that the extended type is 47 - user definable
8518 cmp al, #47 ;; decimal 47 - user definable
8523 ;; CMOS purpose param table offset
8524 ;; 0x24 cylinders low 0
8525 ;; 0x25 cylinders high 1
8527 ;; 0x27 write pre-comp low 5
8528 ;; 0x28 write pre-comp high 6
8530 ;; 0x2a landing zone low C
8531 ;; 0x2b landing zone high D
8532 ;; 0x2c sectors/track E
8533 ;;; Fill EBDA table for hard disk 1.
8543 mov (0x004d + 0x05), ax ;; write precomp word
8548 mov (0x004d + 0x08), al ;; drive control byte
8557 mov (0x004d + 0x0C), ax ;; landing zone word
8559 mov al, #0x25 ;; get cylinders word in AX
8561 in al, #0x71 ;; high byte
8565 in al, #0x71 ;; low byte
8566 mov bx, ax ;; BX = cylinders
8571 mov cl, al ;; CL = heads
8576 mov dl, al ;; DL = sectors
8579 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8581 hd1_post_physical_chs:
8582 ;; no logical CHS mapping used, just physical CHS
8583 ;; use Standard Fixed Disk Parameter Table (FDPT)
8584 mov (0x004d + 0x00), bx ;; number of physical cylinders
8585 mov (0x004d + 0x02), cl ;; number of physical heads
8586 mov (0x004d + 0x0E), dl ;; number of physical sectors
8589 hd1_post_logical_chs:
8590 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8591 mov (0x004d + 0x09), bx ;; number of physical cylinders
8592 mov (0x004d + 0x0b), cl ;; number of physical heads
8593 mov (0x004d + 0x04), dl ;; number of physical sectors
8594 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8596 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8599 jnbe hd1_post_above_2048
8600 ;; 1024 < c <= 2048 cylinders
8603 jmp hd1_post_store_logical
8605 hd1_post_above_2048:
8607 jnbe hd1_post_above_4096
8608 ;; 2048 < c <= 4096 cylinders
8611 jmp hd1_post_store_logical
8613 hd1_post_above_4096:
8615 jnbe hd1_post_above_8192
8616 ;; 4096 < c <= 8192 cylinders
8619 jmp hd1_post_store_logical
8621 hd1_post_above_8192:
8622 ;; 8192 < c <= 16384 cylinders
8626 hd1_post_store_logical:
8627 mov (0x004d + 0x00), bx ;; number of physical cylinders
8628 mov (0x004d + 0x02), cl ;; number of physical heads
8630 mov cl, #0x0f ;; repeat count
8631 mov si, #0x004d ;; offset to disk0 FDPT
8632 mov al, #0x00 ;; sum
8633 hd1_post_checksum_loop:
8637 jnz hd1_post_checksum_loop
8638 not al ;; now take 2s complement
8641 ;;; Done filling EBDA table for hard disk 1.
8645 ;--------------------
8646 ;- POST: EBDA segment
8647 ;--------------------
8648 ; relocated here because the primary POST area isnt big enough.
8653 mov byte ptr [0x0], #EBDA_SIZE
8655 xor ax, ax ; mov EBDA seg into 40E
8657 mov word ptr [0x40E], #EBDA_SEG
8660 ;--------------------
8661 ;- POST: EOI + jmp via [0x40:67)
8662 ;--------------------
8663 ; relocated here because the primary POST area isnt big enough.
8673 ;--------------------
8676 out #0xA0, al ;; slave PIC EOI
8679 out #0x20, al ;; master PIC EOI
8682 ;--------------------
8684 ;; in: AL in BCD format
8685 ;; out: AL in binary format, AH will always be 0
8688 and bl, #0x0f ;; bl has low digit
8689 shr al, #4 ;; al has high digit
8691 mul al, bh ;; multiply high digit by 10 (result in AX)
8692 add al, bl ;; then add low digit
8695 ;--------------------
8697 ;; Setup the Timer Ticks Count (0x46C:dword) and
8698 ;; Timer Ticks Roller Flag (0x470:byte)
8699 ;; The Timer Ticks Count needs to be set according to
8700 ;; the current CMOS time, as if ticks have been occurring
8701 ;; at 18.2hz since midnight up to this point. Calculating
8702 ;; this is a little complicated. Here are the factors I gather
8703 ;; regarding this. 14,318,180 hz was the original clock speed,
8704 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8705 ;; at the time, or 4 to drive the CGA video adapter. The div3
8706 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8707 ;; the timer. With a maximum 16bit timer count, this is again
8708 ;; divided down by 65536 to 18.2hz.
8710 ;; 14,318,180 Hz clock
8711 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8712 ;; /4 = 1,193,181 Hz fed to timer
8713 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8714 ;; 1 second = 18.20650736 ticks
8715 ;; 1 minute = 1092.390442 ticks
8716 ;; 1 hour = 65543.42651 ticks
8718 ;; Given the values in the CMOS clock, one could calculate
8719 ;; the number of ticks by the following:
8720 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8721 ;; (BcdToBin(minutes) * 1092.3904)
8722 ;; (BcdToBin(hours) * 65543.427)
8723 ;; To get a little more accuracy, since Im using integer
8724 ;; arithmatic, I use:
8725 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8726 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8727 ;; (BcdToBin(hours) * 65543427) / 1000
8732 xor eax, eax ;; clear EAX
8735 in al, #0x71 ;; AL has CMOS seconds in BCD
8736 call BcdToBin ;; EAX now has seconds in binary
8742 mov ecx, eax ;; ECX will accumulate total ticks
8745 xor eax, eax ;; clear EAX
8748 in al, #0x71 ;; AL has CMOS minutes in BCD
8749 call BcdToBin ;; EAX now has minutes in binary
8755 add ecx, eax ;; add to total ticks
8758 xor eax, eax ;; clear EAX
8761 in al, #0x71 ;; AL has CMOS hours in BCD
8762 call BcdToBin ;; EAX now has hours in binary
8768 add ecx, eax ;; add to total ticks
8770 mov 0x46C, ecx ;; Timer Ticks Count
8772 mov 0x470, al ;; Timer Ticks Rollover Flag
8775 ;--------------------
8777 ;; record completion in BIOS task complete flag
8789 ;--------------------
8794 #include "apmbios.S"
8798 #include "apmbios.S"
8801 #include "apmbios.S"
8805 ;--------------------
8810 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8811 dw bios32_entry_point, 0xf ;; 32 bit physical address
8812 db 0 ;; revision level
8813 ;; length in paragraphs and checksum stored in a word to prevent errors
8814 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8815 & 0xff) << 8) + 0x01
8816 db 0,0,0,0,0 ;; reserved
8821 cmp eax, #0x49435024
8823 mov eax, #0x80000000
8828 cmp eax, #0x12378086
8830 mov ebx, #0x000f0000
8832 mov edx, #pcibios_protected
8847 cmp al, #0x01 ;; installation check
8851 mov edx, #0x20494350
8854 pci_pro_f02: ;; find pci device
8862 call pci_pro_select_reg
8876 pci_pro_f08: ;; read configuration byte
8879 call pci_pro_select_reg
8888 pci_pro_f09: ;; read configuration word
8891 call pci_pro_select_reg
8900 pci_pro_f0a: ;; read configuration dword
8903 call pci_pro_select_reg
8910 pci_pro_f0b: ;; write configuration byte
8913 call pci_pro_select_reg
8922 pci_pro_f0c: ;; write configuration word
8925 call pci_pro_select_reg
8934 pci_pro_f0d: ;; write configuration dword
8937 call pci_pro_select_reg
8980 mov eax, #0x80000000
8985 cmp eax, #0x12378086
8995 cmp al, #0x01 ;; installation check
9000 mov edx, #0x20494350
9002 mov di, #pcibios_protected
9005 pci_real_f02: ;; find pci device
9015 call pci_real_select_reg
9019 jne pci_real_nextdev
9026 jne pci_real_devloop
9031 pci_real_f08: ;; read configuration byte
9034 call pci_real_select_reg
9043 pci_real_f09: ;; read configuration word
9046 call pci_real_select_reg
9055 pci_real_f0a: ;; read configuration dword
9058 call pci_real_select_reg
9065 pci_real_f0b: ;; write configuration byte
9068 call pci_real_select_reg
9077 pci_real_f0c: ;; write configuration word
9080 call pci_real_select_reg
9089 pci_real_f0d: ;; write configuration dword
9091 jne pci_real_unknown
9092 call pci_real_select_reg
9113 pci_real_select_reg:
9127 pci_routing_table_structure:
9128 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9130 dw 32 + (6 * 16) ;; table size
9131 db 0 ;; PCI interrupt router bus
9132 db 0x08 ;; PCI interrupt router DevFunc
9133 dw 0x0000 ;; PCI exclusive IRQs
9134 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9135 dw 0x7000 ;; compatible PCI interrupt router device ID
9136 dw 0,0 ;; Miniport data
9137 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9139 ;; first slot entry PCI-to-ISA (embedded)
9140 db 0 ;; pci bus number
9141 db 0x08 ;; pci device number (bit 7-3)
9142 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9143 dw 0xdef8 ;; IRQ bitmap INTA#
9144 db 0x61 ;; link value INTB#
9145 dw 0xdef8 ;; IRQ bitmap INTB#
9146 db 0x62 ;; link value INTC#
9147 dw 0xdef8 ;; IRQ bitmap INTC#
9148 db 0x63 ;; link value INTD#
9149 dw 0xdef8 ;; IRQ bitmap INTD#
9150 db 0 ;; physical slot (0 = embedded)
9152 ;; second slot entry: 1st PCI slot
9153 db 0 ;; pci bus number
9154 db 0x10 ;; pci device number (bit 7-3)
9155 db 0x61 ;; link value INTA#
9156 dw 0xdef8 ;; IRQ bitmap INTA#
9157 db 0x62 ;; link value INTB#
9158 dw 0xdef8 ;; IRQ bitmap INTB#
9159 db 0x63 ;; link value INTC#
9160 dw 0xdef8 ;; IRQ bitmap INTC#
9161 db 0x60 ;; link value INTD#
9162 dw 0xdef8 ;; IRQ bitmap INTD#
9163 db 1 ;; physical slot (0 = embedded)
9165 ;; third slot entry: 2nd PCI slot
9166 db 0 ;; pci bus number
9167 db 0x18 ;; pci device number (bit 7-3)
9168 db 0x62 ;; link value INTA#
9169 dw 0xdef8 ;; IRQ bitmap INTA#
9170 db 0x63 ;; link value INTB#
9171 dw 0xdef8 ;; IRQ bitmap INTB#
9172 db 0x60 ;; link value INTC#
9173 dw 0xdef8 ;; IRQ bitmap INTC#
9174 db 0x61 ;; link value INTD#
9175 dw 0xdef8 ;; IRQ bitmap INTD#
9176 db 2 ;; physical slot (0 = embedded)
9178 ;; 4th slot entry: 3rd PCI slot
9179 db 0 ;; pci bus number
9180 db 0x20 ;; pci device number (bit 7-3)
9181 db 0x63 ;; link value INTA#
9182 dw 0xdef8 ;; IRQ bitmap INTA#
9183 db 0x60 ;; link value INTB#
9184 dw 0xdef8 ;; IRQ bitmap INTB#
9185 db 0x61 ;; link value INTC#
9186 dw 0xdef8 ;; IRQ bitmap INTC#
9187 db 0x62 ;; link value INTD#
9188 dw 0xdef8 ;; IRQ bitmap INTD#
9189 db 3 ;; physical slot (0 = embedded)
9191 ;; 5th slot entry: 4rd PCI slot
9192 db 0 ;; pci bus number
9193 db 0x28 ;; pci device number (bit 7-3)
9194 db 0x60 ;; link value INTA#
9195 dw 0xdef8 ;; IRQ bitmap INTA#
9196 db 0x61 ;; link value INTB#
9197 dw 0xdef8 ;; IRQ bitmap INTB#
9198 db 0x62 ;; link value INTC#
9199 dw 0xdef8 ;; IRQ bitmap INTC#
9200 db 0x63 ;; link value INTD#
9201 dw 0xdef8 ;; IRQ bitmap INTD#
9202 db 4 ;; physical slot (0 = embedded)
9204 ;; 6th slot entry: 5rd PCI slot
9205 db 0 ;; pci bus number
9206 db 0x30 ;; pci device number (bit 7-3)
9207 db 0x61 ;; link value INTA#
9208 dw 0xdef8 ;; IRQ bitmap INTA#
9209 db 0x62 ;; link value INTB#
9210 dw 0xdef8 ;; IRQ bitmap INTB#
9211 db 0x63 ;; link value INTC#
9212 dw 0xdef8 ;; IRQ bitmap INTC#
9213 db 0x60 ;; link value INTD#
9214 dw 0xdef8 ;; IRQ bitmap INTD#
9215 db 5 ;; physical slot (0 = embedded)
9221 pcibios_init_sel_reg:
9233 pcibios_init_set_elcr:
9257 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9262 mov si, #pci_routing_table_structure
9266 call pcibios_init_sel_reg
9269 cmp eax, [si+12] ;; check irq router
9272 call pcibios_init_sel_reg
9273 push bx ;; save irq router bus + devfunc
9276 out dx, ax ;; reset PIRQ route control
9284 add si, #0x20 ;; set pointer to 1st entry
9286 mov ax, #pci_irq_list
9295 call pcibios_init_sel_reg
9299 jnz pci_test_int_pin
9305 call pcibios_init_sel_reg
9310 dec al ;; determine pirq reg
9319 call pcibios_init_sel_reg
9326 mov bx, [bp-2] ;; pci irq list pointer
9331 call pcibios_init_set_elcr
9335 add bl, [bp-3] ;; pci function number
9337 call pcibios_init_sel_reg
9347 mov byte ptr[bp-3], #0x00
9355 #endif // BX_PCIBIOS
9357 ; parallel port detection: base address in DX, index in BX, timeout in CL
9362 and al, #0xdf ; clear input mode
9372 mov [bx+0x408], dx ; Parallel I/O address
9374 mov [bx+0x478], cl ; Parallel printer timeout
9379 ; serial port detection: base address in DX, index in BX, timeout in CL
9381 ; no serial port in the VM -PAD
9401 mov [bx+0x400], dx ; Serial I/O address
9403 mov [bx+0x47c], cl ; Serial timeout
9430 ;; Scan for existence of valid expansion ROMS.
9431 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9432 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9433 ;; System ROM: only 0xE0000
9439 ;; 2 ROM length in 512-byte blocks
9440 ;; 3 ROM initialization entry point (FAR CALL)
9445 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9446 cmp [0], #0xAA55 ;; look for signature
9447 jne rom_scan_increment
9449 jnz rom_scan_increment
9450 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9452 ;; We want our increment in 512-byte quantities, rounded to
9453 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9455 jz block_count_rounded
9456 and al, #0xfc ;; needs rounding up
9458 block_count_rounded:
9460 xor bx, bx ;; Restore DS back to 0000:
9463 ;; Push addr of ROM entry point
9465 push #0x0003 ;; Push offset
9466 mov bp, sp ;; Call ROM init routine using seg:off on stack
9467 db 0xff ;; call_far ss:[bp+0]
9470 cli ;; In case expansion ROM BIOS turns IF on
9471 add sp, #2 ;; Pop offset value
9472 pop cx ;; Pop seg value (restore CX)
9473 pop ax ;; Restore AX
9475 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9476 ;; because the segment selector is shifted left 4 bits.
9481 xor ax, ax ;; Restore DS back to 0000:
9487 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9488 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9489 ; but the tables themeselves can be elsewhere.
9498 mov cx, #0x001f ; 0x1f bytes to copy
9500 mov es, ax ; destination segment is 0xf0000
9501 mov di, #smbios_entry_point ; destination offset
9503 mov ds, ax ; source segment is 0x9f000
9504 mov si, #0x0000 ; source offset is 0
9522 ;; for 'C' strings and other data, insert them here with
9523 ;; a the following hack:
9524 ;; DATA_SEG_DEFS_HERE
9530 .org 0xe05b ; POST Entry Point
9535 ;; first reset the DMA controllers
9539 ;; then initialize the DMA controllers
9541 out 0xD6, al ; cascade mode of channel 4 enabled
9543 out 0xD4, al ; unmask channel 4
9545 ;; Examine CMOS shutdown status.
9553 ;; Reset CMOS shutdown status.
9555 out 0x70, AL ; select CMOS register Fh
9557 out 0x71, AL ; set shutdown action to normal
9559 ;; Examine CMOS shutdown status.
9562 ;; 0x00, 0x09, 0x0D+ = normal startup
9570 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9574 ;; Examine CMOS shutdown status.
9575 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9577 call _shutdown_status_panic
9583 ; 0xb0, 0x20, /* mov al, #0x20 */
9584 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9594 ; case 0: normal startup
9603 ;; zero out BIOS data area (40:00..40:ff)
9605 mov cx, #0x0080 ;; 128 words
9611 call _log_bios_start
9613 ;; set all interrupts to default handler
9614 mov bx, #0x0000 ;; offset index
9615 mov cx, #0x0100 ;; counter (256 interrupts)
9616 mov ax, #dummy_iret_handler
9626 loop post_default_ints
9628 ;; set vector 0x79 to zero
9629 ;; this is used by 'gardian angel' protection system
9630 SET_INT_VECTOR(0x79, #0, #0)
9632 ;; base memory in K 40:13 (word)
9633 mov ax, #BASE_MEM_IN_K
9637 ;; Manufacturing Test 40:12
9640 ;; Warm Boot Flag 0040:0072
9641 ;; value of 1234h = skip memory checks
9645 ;; Printer Services vector
9646 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9648 ;; Bootstrap failure vector
9649 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9651 ;; Bootstrap Loader vector
9652 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9654 ;; User Timer Tick vector
9655 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9657 ;; Memory Size Check vector
9658 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9660 ;; Equipment Configuration Check vector
9661 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9664 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9670 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9671 ;; int 1C already points at dummy_iret_handler (above)
9672 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9675 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9680 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9686 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9687 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9691 mov 0x0417, al /* keyboard shift flags, set 1 */
9692 mov 0x0418, al /* keyboard shift flags, set 2 */
9693 mov 0x0419, al /* keyboard alt-numpad work area */
9694 mov 0x0471, al /* keyboard ctrl-break flag */
9695 mov 0x0497, al /* keyboard status flags 4 */
9697 mov 0x0496, al /* keyboard status flags 3 */
9700 /* keyboard head of buffer pointer */
9704 /* keyboard end of buffer pointer */
9707 /* keyboard pointer to start of buffer */
9711 /* keyboard pointer to end of buffer */
9715 /* init the keyboard */
9718 ;; mov CMOS Equipment Byte to BDA Equipment Word
9727 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9731 mov cl, #0x14 ; timeout value
9732 mov dx, #0x378 ; Parallel I/O address, port 1
9734 mov dx, #0x278 ; Parallel I/O address, port 2
9737 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9739 or ax, bx ; set number of parallel ports
9743 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9744 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9746 mov cl, #0x0a ; timeout value
9747 mov dx, #0x03f8 ; Serial I/O address, port 1
9749 mov dx, #0x02f8 ; Serial I/O address, port 2
9751 mov dx, #0x03e8 ; Serial I/O address, port 3
9753 mov dx, #0x02e8 ; Serial I/O address, port 4
9756 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9758 or ax, bx ; set number of serial port
9762 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9763 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9764 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9765 ;; BIOS DATA AREA 0x4CE ???
9766 call timer_tick_post
9769 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9771 ;; IRQ13 (FPU exception) setup
9772 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9775 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9780 mov al, #0x11 ; send initialisation commands
9795 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9796 #if BX_USE_PS2_MOUSE
9801 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9804 call _copy_e820_table
9823 call _print_bios_banner
9828 call floppy_drive_post
9835 call hard_drive_post
9838 ;; ATA/ATAPI driver setup
9843 #else // BX_USE_ATADRV
9848 call hard_drive_post
9850 #endif // BX_USE_ATADRV
9852 #if BX_ELTORITO_BOOT
9854 ;; eltorito floppy/harddisk emulation from cd
9858 #endif // BX_ELTORITO_BOOT
9861 //JMP_EP(0x0064) ; INT 19h location
9864 .org 0xe2c3 ; NMI Handler Entry Point
9866 ;; FIXME the NMI handler should not panic
9867 ;; but iret when called from int75 (fpu exception)
9868 call _nmi_handler_msg
9872 out 0xf0, al // clear irq13
9873 call eoi_both_pics // clear interrupt
9874 int 2 // legacy nmi call
9877 ;-------------------------------------------
9878 ;- INT 13h Fixed Disk Services Entry Point -
9879 ;-------------------------------------------
9880 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9882 //JMPL(int13_relocated)
9885 .org 0xe401 ; Fixed Disk Parameter Table
9890 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9894 ;-------------------------------------------
9895 ;- System BIOS Configuration Data Table
9896 ;-------------------------------------------
9897 .org BIOS_CONFIG_TABLE
9898 db 0x08 ; Table size (bytes) -Lo
9899 db 0x00 ; Table size (bytes) -Hi
9904 ; b7: 1=DMA channel 3 used by hard disk
9905 ; b6: 1=2 interrupt controllers present
9907 ; b4: 1=BIOS calls int 15h/4Fh every key
9908 ; b3: 1=wait for extern event supported (Int 15h/41h)
9909 ; b2: 1=extended BIOS data area used
9910 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9911 ; b0: 1=Dual bus (MicroChannel + ISA)
9915 (BX_CALL_INT15_4F << 4) | \
9917 (BX_USE_EBDA << 2) | \
9921 ; b7: 1=32-bit DMA supported
9922 ; b6: 1=int16h, function 9 supported
9923 ; b5: 1=int15h/C6h (get POS data) supported
9924 ; b4: 1=int15h/C7h (get mem map info) supported
9925 ; b3: 1=int15h/C8h (en/dis CPU) supported
9926 ; b2: 1=non-8042 kb controller
9927 ; b1: 1=data streaming supported
9941 ; b4: POST supports ROM-to-RAM enable/disable
9942 ; b3: SCSI on system board
9943 ; b2: info panel installed
9944 ; b1: Initial Machine Load (IML) system - BIOS on disk
9945 ; b0: SCSI supported in IML
9949 ; b6: EEPROM present
9950 ; b5-3: ABIOS presence (011 = not supported)
9952 ; b1: memory split above 16Mb supported
9953 ; b0: POSTEXT directly supported by POST
9955 ; Feature byte 5 (IBM)
9956 ; b1: enhanced mouse
9962 .org 0xe729 ; Baud Rate Generator Table
9967 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
9973 call _int14_function
9979 ;----------------------------------------
9980 ;- INT 16h Keyboard Service Entry Point -
9981 ;----------------------------------------
9997 call _int16_function
10007 and BYTE [bp + 0x06], #0xbf
10015 or BYTE [bp + 0x06], #0x40
10023 int16_wait_for_key:
10027 jne int16_key_found
10031 /* no key yet, call int 15h, function AX=9002 */
10032 0x50, /* push AX */
10033 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10034 0xcd, 0x15, /* int 15h */
10036 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10038 jmp int16_wait_for_key
10043 call _int16_function
10048 /* notify int16 complete w/ int 15h, function AX=9102 */
10049 0x50, /* push AX */
10050 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10051 0xcd, 0x15, /* int 15h */
10058 ;-------------------------------------------------
10059 ;- INT09h : Keyboard Hardware Service Entry Point -
10060 ;-------------------------------------------------
10066 mov al, #0xAD ;;disable keyboard
10075 in al, #0x60 ;;read key from keyboard controller
10076 //test al, #0x80 ;;look for key release
10077 //jnz int09_process_key ;; dont pass releases to intercept?
10079 ;; check for extended key
10081 jne int09_call_int15_4f
10086 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10088 mov BYTE [0x496], al
10091 in al, #0x60 ;;read another key from keyboard controller
10095 int09_call_int15_4f:
10098 #ifdef BX_CALL_INT15_4F
10099 mov ah, #0x4f ;; allow for keyboard intercept
10106 //int09_process_key:
10109 call _int09_function
10115 call eoi_master_pic
10118 mov al, #0xAE ;;enable keyboard
10126 ;----------------------------------------
10127 ;- INT 13h Diskette Service Entry Point -
10128 ;----------------------------------------
10131 jmp int13_noeltorito
10133 ;---------------------------------------------
10134 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10135 ;---------------------------------------------
10136 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10146 mov al, #0x08 ; sense interrupt status
10164 mov ax, #0x0000 ;; segment 0000
10166 call eoi_master_pic
10168 or al, #0x80 ;; diskette interrupt has occurred
10176 .org 0xefc7 ; Diskette Controller Parameter Table
10177 diskette_param_table:
10178 ;; Since no provisions are made for multiple drive types, most
10179 ;; values in this table are ignored. I set parameters for 1.44M
10182 db 0x02 ;; head load time 0000001, DMA used
10194 ;----------------------------------------
10195 ;- INT17h : Printer Service Entry Point -
10196 ;----------------------------------------
10203 call _int17_function
10208 diskette_param_table2:
10209 ;; New diskette parameter table adding 3 parameters from IBM
10210 ;; Since no provisions are made for multiple drive types, most
10211 ;; values in this table are ignored. I set parameters for 1.44M
10214 db 0x02 ;; head load time 0000001, DMA used
10224 db 79 ;; maximum track
10225 db 0 ;; data transfer rate
10226 db 4 ;; drive type in cmos
10228 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10235 .org 0xf065 ; INT 10h Video Support Service Entry Point
10237 ;; dont do anything, since the VGA BIOS handles int10h requests
10240 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10245 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10246 ; ??? different for Pentium (machine check)?
10258 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10270 .org 0xf859 ; INT 15h System Services Entry Point
10284 #if BX_USE_PS2_MOUSE
10286 je int15_handler_mouse
10288 call _int15_function
10289 int15_handler_mouse_ret:
10291 int15_handler32_ret:
10301 #if BX_USE_PS2_MOUSE
10302 int15_handler_mouse:
10303 call _int15_function_mouse
10304 jmp int15_handler_mouse_ret
10309 call _int15_function32
10311 jmp int15_handler32_ret
10313 ;; Protected mode IDT descriptor
10315 ;; I just make the limit 0, so the machine will shutdown
10316 ;; if an exception occurs during protected mode memory
10319 ;; Set base to f0000 to correspond to beginning of BIOS,
10320 ;; in case I actually define an IDT later
10324 dw 0x0000 ;; limit 15:00
10325 dw 0x0000 ;; base 15:00
10326 db 0x0f ;; base 23:16
10328 ;; Real mode IDT descriptor
10330 ;; Set to typical real-mode values.
10335 dw 0x03ff ;; limit 15:00
10336 dw 0x0000 ;; base 15:00
10337 db 0x00 ;; base 23:16
10343 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10356 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10357 mov ds, ax ; on 16bit protected mode.
10358 jmp int1a_callfunction
10365 int1a_callfunction:
10366 call _int1a_function
10372 ;; int70h: IRQ8 - CMOS RTC
10379 call _int70_function
10387 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10395 ;; time to turn off drive(s)?
10398 jz int08_floppy_off
10401 jnz int08_floppy_off
10402 ;; turn motor(s) off
10411 mov eax, 0x046c ;; get ticks dword
10414 ;; compare eax to one days worth of timer ticks at 18.2 hz
10415 cmp eax, #0x001800B0
10416 jb int08_store_ticks
10417 ;; there has been a midnight rollover at this point
10418 xor eax, eax ;; zero out counter
10419 inc BYTE 0x0470 ;; increment rollover flag
10422 mov 0x046c, eax ;; store new ticks dword
10423 ;; chain to user timer tick INT #0x1c
10425 //;; call_ep [ds:loc]
10426 //CALL_EP( 0x1c << 2 )
10429 call eoi_master_pic
10434 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10438 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10440 ;------------------------------------------------
10441 ;- IRET Instruction for Dummy Interrupt Handler -
10442 ;------------------------------------------------
10443 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10444 dummy_iret_handler:
10447 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10456 .org 0xfff0 ; Power-up Entry Point
10463 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10464 .ascii BIOS_BUILD_DATE
10466 .org 0xfffe ; System Model ID
10470 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10473 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10474 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10475 * This font is public domain
10477 static Bit8u vgafont8[128*8]=
10479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10480 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10481 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10482 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10483 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10484 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10485 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10486 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10487 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10488 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10489 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10490 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10491 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10492 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10493 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10494 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10495 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10496 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10497 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10498 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10499 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10500 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10501 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10502 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10503 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10504 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10505 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10506 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10507 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10508 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10509 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10510 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10512 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10513 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10514 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10515 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10516 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10517 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10518 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10519 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10520 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10521 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10522 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10523 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10524 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10525 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10526 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10527 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10528 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10529 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10530 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10531 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10532 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10533 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10534 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10535 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10536 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10537 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10538 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10539 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10540 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10541 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10542 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10543 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10544 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10545 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10546 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10547 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10548 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10549 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10550 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10551 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10552 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10553 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10554 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10555 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10556 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10557 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10558 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10559 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10560 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10561 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10562 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10563 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10564 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10565 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10566 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10567 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10568 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10569 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10570 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10571 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10572 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10573 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10575 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10576 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10577 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10578 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10579 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10580 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10581 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10582 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10583 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10584 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10585 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10586 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10587 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10588 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10589 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10590 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10591 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10592 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10593 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10594 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10595 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10596 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10597 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10598 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10599 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10600 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10601 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10602 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10603 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10604 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10605 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10606 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10612 // just carve out some blank space for HVMLOADER to write the MP tables to
10614 // NOTE: There should be enough space for a 32 processor entry MP table
10618 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10619 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
10620 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
10621 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
10622 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
10623 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
10624 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
10625 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
10626 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
10627 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
10628 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
10629 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
10630 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
10631 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
10632 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
10635 smbios_entry_point:
10636 db 0,0,0,0,0,0,0,0 ; 8 bytes
10637 db 0,0,0,0,0,0,0,0 ; 16 bytes
10638 db 0,0,0,0,0,0,0,0 ; 24 bytes
10639 db 0,0,0,0,0,0,0 ; 31 bytes
10642 #else // !HVMASSIST
10646 // bcc-generated data will be placed here
10648 // For documentation of this config structure, look on developer.intel.com and
10649 // search for multiprocessor specification. Note that when you change anything
10650 // you must update the checksum (a pain!). It would be better to construct this
10651 // with C structures, or at least fill in the checksum automatically.
10653 // Maybe this structs could be moved elsewhere than d000
10655 #if (BX_SMP_PROCESSORS==1)
10656 // no structure necessary.
10657 #elif (BX_SMP_PROCESSORS==2)
10658 // define the Intel MP Configuration Structure for 2 processors at
10659 // APIC ID 0,1. I/O APIC at ID=2.
10662 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10663 dw (mp_config_end-mp_config_table) ;; table length
10665 db 0x65 ;; checksum
10666 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10667 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10668 db 0x20, 0x20, 0x20, 0x20
10669 db 0x20, 0x20, 0x20, 0x20
10670 dw 0,0 ;; oem table ptr
10671 dw 0 ;; oem table size
10672 dw 20 ;; entry count
10673 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10674 dw 0 ;; extended table length
10675 db 0 ;; extended table checksum
10678 db 0 ;; entry type=processor
10679 db 0 ;; local APIC id
10680 db 0x11 ;; local APIC version number
10681 db 3 ;; cpu flags: enabled, bootstrap processor
10682 db 0,6,0,0 ;; cpu signature
10683 dw 0x201,0 ;; feature flags
10687 db 0 ;; entry type=processor
10688 db 1 ;; local APIC id
10689 db 0x11 ;; local APIC version number
10690 db 1 ;; cpu flags: enabled
10691 db 0,6,0,0 ;; cpu signature
10692 dw 0x201,0 ;; feature flags
10696 db 1 ;; entry type=bus
10698 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10700 db 2 ;; entry type=I/O APIC
10701 db 2 ;; apic id=2. linux will set.
10702 db 0x11 ;; I/O APIC version number
10703 db 1 ;; flags=1=enabled
10704 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10706 db 3 ;; entry type=I/O interrupt
10707 db 0 ;; interrupt type=vectored interrupt
10708 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10709 db 0 ;; source bus ID is ISA
10710 db 0 ;; source bus IRQ
10711 db 2 ;; destination I/O APIC ID
10712 db 0 ;; destination I/O APIC interrrupt in
10713 ;; repeat pattern for interrupts 0-15
10723 db 3,0,0,0,0,10,2,10
10724 db 3,0,0,0,0,11,2,11
10725 db 3,0,0,0,0,12,2,12
10726 db 3,0,0,0,0,13,2,13
10727 db 3,0,0,0,0,14,2,14
10728 db 3,0,0,0,0,15,2,15
10729 #elif (BX_SMP_PROCESSORS==4)
10730 // define the Intel MP Configuration Structure for 4 processors at
10731 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10734 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10735 dw (mp_config_end-mp_config_table) ;; table length
10737 db 0xdd ;; checksum
10738 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10739 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10740 db 0x20, 0x20, 0x20, 0x20
10741 db 0x20, 0x20, 0x20, 0x20
10742 dw 0,0 ;; oem table ptr
10743 dw 0 ;; oem table size
10744 dw 22 ;; entry count
10745 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10746 dw 0 ;; extended table length
10747 db 0 ;; extended table checksum
10750 db 0 ;; entry type=processor
10751 db 0 ;; local APIC id
10752 db 0x11 ;; local APIC version number
10753 db 3 ;; cpu flags: enabled, bootstrap processor
10754 db 0,6,0,0 ;; cpu signature
10755 dw 0x201,0 ;; feature flags
10759 db 0 ;; entry type=processor
10760 db 1 ;; local APIC id
10761 db 0x11 ;; local APIC version number
10762 db 1 ;; cpu flags: enabled
10763 db 0,6,0,0 ;; cpu signature
10764 dw 0x201,0 ;; feature flags
10768 db 0 ;; entry type=processor
10769 db 2 ;; local APIC id
10770 db 0x11 ;; local APIC version number
10771 db 1 ;; cpu flags: enabled
10772 db 0,6,0,0 ;; cpu signature
10773 dw 0x201,0 ;; feature flags
10777 db 0 ;; entry type=processor
10778 db 3 ;; local APIC id
10779 db 0x11 ;; local APIC version number
10780 db 1 ;; cpu flags: enabled
10781 db 0,6,0,0 ;; cpu signature
10782 dw 0x201,0 ;; feature flags
10786 db 1 ;; entry type=bus
10788 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10790 db 2 ;; entry type=I/O APIC
10791 db 4 ;; apic id=4. linux will set.
10792 db 0x11 ;; I/O APIC version number
10793 db 1 ;; flags=1=enabled
10794 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10796 db 3 ;; entry type=I/O interrupt
10797 db 0 ;; interrupt type=vectored interrupt
10798 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10799 db 0 ;; source bus ID is ISA
10800 db 0 ;; source bus IRQ
10801 db 4 ;; destination I/O APIC ID
10802 db 0 ;; destination I/O APIC interrrupt in
10803 ;; repeat pattern for interrupts 0-15
10813 db 3,0,0,0,0,10,4,10
10814 db 3,0,0,0,0,11,4,11
10815 db 3,0,0,0,0,12,4,12
10816 db 3,0,0,0,0,13,4,13
10817 db 3,0,0,0,0,14,4,14
10818 db 3,0,0,0,0,15,4,15
10819 #elif (BX_SMP_PROCESSORS==8)
10820 // define the Intel MP Configuration Structure for 8 processors at
10821 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10824 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10825 dw (mp_config_end-mp_config_table) ;; table length
10827 db 0xc3 ;; checksum
10828 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10829 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10830 db 0x20, 0x20, 0x20, 0x20
10831 db 0x20, 0x20, 0x20, 0x20
10832 dw 0,0 ;; oem table ptr
10833 dw 0 ;; oem table size
10834 dw 26 ;; entry count
10835 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10836 dw 0 ;; extended table length
10837 db 0 ;; extended table checksum
10840 db 0 ;; entry type=processor
10841 db 0 ;; local APIC id
10842 db 0x11 ;; local APIC version number
10843 db 3 ;; cpu flags: enabled, bootstrap processor
10844 db 0,6,0,0 ;; cpu signature
10845 dw 0x201,0 ;; feature flags
10849 db 0 ;; entry type=processor
10850 db 1 ;; local APIC id
10851 db 0x11 ;; local APIC version number
10852 db 1 ;; cpu flags: enabled
10853 db 0,6,0,0 ;; cpu signature
10854 dw 0x201,0 ;; feature flags
10858 db 0 ;; entry type=processor
10859 db 2 ;; local APIC id
10860 db 0x11 ;; local APIC version number
10861 db 1 ;; cpu flags: enabled
10862 db 0,6,0,0 ;; cpu signature
10863 dw 0x201,0 ;; feature flags
10867 db 0 ;; entry type=processor
10868 db 3 ;; local APIC id
10869 db 0x11 ;; local APIC version number
10870 db 1 ;; cpu flags: enabled
10871 db 0,6,0,0 ;; cpu signature
10872 dw 0x201,0 ;; feature flags
10876 db 0 ;; entry type=processor
10877 db 4 ;; local APIC id
10878 db 0x11 ;; local APIC version number
10879 db 1 ;; cpu flags: enabled
10880 db 0,6,0,0 ;; cpu signature
10881 dw 0x201,0 ;; feature flags
10885 db 0 ;; entry type=processor
10886 db 5 ;; local APIC id
10887 db 0x11 ;; local APIC version number
10888 db 1 ;; cpu flags: enabled
10889 db 0,6,0,0 ;; cpu signature
10890 dw 0x201,0 ;; feature flags
10894 db 0 ;; entry type=processor
10895 db 6 ;; local APIC id
10896 db 0x11 ;; local APIC version number
10897 db 1 ;; cpu flags: enabled
10898 db 0,6,0,0 ;; cpu signature
10899 dw 0x201,0 ;; feature flags
10903 db 0 ;; entry type=processor
10904 db 7 ;; 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 1 ;; entry type=bus
10914 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10916 db 2 ;; entry type=I/O APIC
10918 db 0x11 ;; I/O APIC version number
10919 db 1 ;; flags=1=enabled
10920 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10922 db 3 ;; entry type=I/O interrupt
10923 db 0 ;; interrupt type=vectored interrupt
10924 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10925 db 0 ;; source bus ID is ISA
10926 db 0 ;; source bus IRQ
10927 db 8 ;; destination I/O APIC ID
10928 db 0 ;; destination I/O APIC interrrupt in
10929 ;; repeat pattern for interrupts 0-15
10939 db 3,0,0,0,0,10,8,10
10940 db 3,0,0,0,0,11,8,11
10941 db 3,0,0,0,0,12,8,12
10942 db 3,0,0,0,0,13,8,13
10943 db 3,0,0,0,0,14,8,14
10944 db 3,0,0,0,0,15,8,15
10946 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
10947 #endif // if (BX_SMP_PROCESSORS==...)
10949 mp_config_end: // this label used to find length of mp structure
10952 #if (BX_SMP_PROCESSORS>1)
10954 mp_floating_pointer_structure:
10955 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
10956 dw mp_config_table, 0xf ;; pointer to MP configuration table
10957 db 1 ;; length of this struct in 16-bit byte chunks
10958 db 4 ;; MP spec revision
10959 db 0xc1 ;; checksum
10960 db 0 ;; MP feature byte 1. value 0 means look at the config table
10961 db 0,0,0,0 ;; MP feature bytes 2-5.
10966 #endif // HVMASSIST