2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.12 2008/07/11 22:59:38 pdinda Exp $
4 /////////////////////////////////////////////////////////////////////////
6 // Copyright (C) 2002 MandrakeSoft S.A.
10 // 75002 Paris - France
11 // http://www.linux-mandrake.com/
12 // http://www.mandrakesoft.com/
14 // This library is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Lesser General Public
16 // License as published by the Free Software Foundation; either
17 // version 2 of the License, or (at your option) any later version.
19 // This library is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 // Lesser General Public License for more details.
24 // You should have received a copy of the GNU Lesser General Public
25 // License along with this library; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 // ROM BIOS for use with Bochs/Plex x86 emulation environment
33 // Xen full virtualization does not handle unaligned IO with page crossing.
34 // Disable 32-bit PIO as a workaround.
38 // ROM BIOS compatability entry points:
39 // ===================================
40 // $e05b ; POST Entry Point
41 // $e2c3 ; NMI Handler Entry Point
42 // $e3fe ; INT 13h Fixed Disk Services Entry Point
43 // $e401 ; Fixed Disk Parameter Table
44 // $e6f2 ; INT 19h Boot Load Service Entry Point
45 // $e6f5 ; Configuration Data Table
46 // $e729 ; Baud Rate Generator Table
47 // $e739 ; INT 14h Serial Communications Service Entry Point
48 // $e82e ; INT 16h Keyboard Service Entry Point
49 // $e987 ; INT 09h Keyboard Service Entry Point
50 // $ec59 ; INT 13h Diskette Service Entry Point
51 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
52 // $efc7 ; Diskette Controller Parameter Table
53 // $efd2 ; INT 17h Printer Service Entry Point
54 // $f045 ; INT 10 Functions 0-Fh Entry Point
55 // $f065 ; INT 10h Video Support Service Entry Point
56 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
57 // $f841 ; INT 12h Memory Size Service Entry Point
58 // $f84d ; INT 11h Equipment List Service Entry Point
59 // $f859 ; INT 15h System Services Entry Point
60 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
61 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
62 /// $fea5 ; INT 08h System Timer ISR Entry Point
63 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
64 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
65 // $ff54 ; INT 05h Print Screen Service Entry Point
66 // $fff0 ; Power-up Entry Point
67 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
68 // $fffe ; System Model ID
70 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
72 // - supports up to 4 ATA interfaces
73 // - device/geometry detection
74 // - 16bits/32bits device access
76 // - datain/dataout/packet command support
78 // NOTES for El-Torito Boot (cbbochs@free.fr)
79 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
80 // - Current code is only able to boot mono-session cds
81 // - Current code can not boot and emulate a hard-disk
82 // the bios will panic otherwise
83 // - Current code also use memory in EBDA segement.
84 // - I used cmos byte 0x3D to store extended information on boot-device
85 // - Code has to be modified modified to handle multiple cdrom drives
86 // - Here are the cdrom boot failure codes:
87 // 1 : no atapi device found
88 // 2 : no atapi cdrom found
89 // 3 : can not read cd - BRVD
90 // 4 : cd is not eltorito (BRVD)
91 // 5 : cd is not eltorito (ISO TAG)
92 // 6 : cd is not eltorito (ELTORITO TAG)
93 // 7 : can not read cd - boot catalog
94 // 8 : boot catalog : bad header
95 // 9 : boot catalog : bad platform
96 // 10 : boot catalog : bad signature
97 // 11 : boot catalog : bootable flag not set
98 // 12 : can not read cd - boot image
102 // I used memory starting at 0x121 in the segment
103 // - the translation policy is defined in cmos regs 0x39 & 0x3a
108 // - needs to be reworked. Uses direct [bp] offsets. (?)
111 // - f04 (verify sectors) isn't complete (?)
112 // - f02/03/04 should set current cyl,etc in BDA (?)
113 // - rewrite int13_relocated & clean up int13 entry code
116 // - NMI access (bit7 of addr written to 70h)
119 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
120 // - could send the multiple-sector read/write commands
123 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
124 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
125 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
126 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
127 // This is ok. But DL should be reincremented afterwards.
128 // - Fix all "FIXME ElTorito Various"
129 // - should be able to boot any cdrom instead of the first one
131 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
133 #define DEBUG_ROMBIOS 1
136 #define DEBUG_INT13_HD 0
137 #define DEBUG_INT13_CD 0
138 #define DEBUG_INT13_ET 0
139 #define DEBUG_INT13_FL 0
140 #define DEBUG_INT15 0
141 #define DEBUG_INT16 0
142 #define DEBUG_INT1A 0
143 #define DEBUG_INT74 0
147 #define BX_USE_PS2_MOUSE 1
148 #define BX_CALL_INT15_4F 1
149 #define BX_USE_EBDA 1
150 #define BX_SUPPORT_FLOPPY 1
151 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
155 #define BX_USE_ATADRV 1
156 #define BX_ELTORITO_BOOT 1
158 #define BX_MAX_ATA_INTERFACES 4
159 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
161 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
162 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
164 /* model byte 0xFC = AT */
165 #define SYS_MODEL_ID 0xFC
166 #define SYS_SUBMODEL_ID 0x00
167 #define BIOS_REVISION 1
168 #define BIOS_CONFIG_TABLE 0xe6f5
170 #ifndef BIOS_BUILD_DATE
171 # define BIOS_BUILD_DATE "06/23/99"
174 // 1K of base memory used for Extended Bios Data Area (EBDA)
175 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
176 #define EBDA_SEG 0x9FC0
177 #define EBDA_SIZE 1 // In KiB
178 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
180 // Define the application NAME
182 # define BX_APPNAME "HVMAssist"
184 # define BX_APPNAME "Plex86"
186 # define BX_APPNAME "Bochs"
190 #if BX_USE_ATADRV && BX_CPU<3
191 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
193 #if BX_USE_ATADRV && !BX_USE_EBDA
194 # error ATA/ATAPI Driver can only be used if EBDA is available
196 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
197 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
199 #if BX_PCIBIOS && BX_CPU<3
200 # error PCI BIOS can only be used with 386+ cpu
202 #if BX_APM && BX_CPU<3
203 # error APM BIOS can only be used with 386+ cpu
206 #ifndef BX_SMP_PROCESSORS
207 #define BX_SMP_PROCESSORS 1
208 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
211 #define PANIC_PORT 0x400
212 #define PANIC_PORT2 0x401
213 #define INFO_PORT 0x402
214 #define DEBUG_PORT 0x403
217 // #$20 is hex 20 = 32
218 // #0x20 is hex 20 = 32
225 // all hex literals should be prefixed with '0x'
226 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
227 // no mov SEG-REG, #value, must mov register into seg-reg
228 // grep -i "mov[ ]*.s" rombios.c
230 // This is for compiling with gcc2 and gcc3
231 #define ASM_START #asm
232 #define ASM_END #endasm
246 ;; the HALT macro is called with the line number of the HALT call.
247 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
248 ;; to print a BX_PANIC message. This will normally halt the simulation
249 ;; with a message such as "BIOS panic at rombios.c, line 4091".
250 ;; However, users can choose to make panics non-fatal and continue.
277 typedef unsigned char Bit8u;
278 typedef unsigned short Bit16u;
279 typedef unsigned short bx_bool;
280 typedef unsigned long Bit32u;
284 void memsetb(seg,offset,value,count);
285 void memcpyb(dseg,doffset,sseg,soffset,count);
286 void memcpyd(dseg,doffset,sseg,soffset,count);
288 // memset of count bytes
290 memsetb(seg,offset,value,count)
305 mov cx, 10[bp] ; count
308 mov ax, 4[bp] ; segment
310 mov ax, 6[bp] ; offset
312 mov al, 8[bp] ; value
327 // memcpy of count bytes
329 memcpyb(dseg,doffset,sseg,soffset,count)
347 mov cx, 12[bp] ; count
350 mov ax, 4[bp] ; dsegment
352 mov ax, 6[bp] ; doffset
354 mov ax, 8[bp] ; ssegment
356 mov ax, 10[bp] ; soffset
375 // memcpy of count dword
377 memcpyd(dseg,doffset,sseg,soffset,count)
395 mov cx, 12[bp] ; count
398 mov ax, 4[bp] ; dsegment
400 mov ax, 6[bp] ; doffset
402 mov ax, 8[bp] ; ssegment
404 mov ax, 10[bp] ; soffset
422 #endif //BX_USE_ATADRV
424 // read_dword and write_dword functions
425 static Bit32u read_dword();
426 static void write_dword();
429 read_dword(seg, offset)
439 mov ax, 4[bp] ; segment
441 mov bx, 6[bp] ; offset
446 ;; ax = return value (word)
447 ;; dx = return value (word)
456 write_dword(seg, offset, data)
468 mov ax, 4[bp] ; segment
470 mov bx, 6[bp] ; offset
471 mov ax, 8[bp] ; data word
472 mov [bx], ax ; write data word
475 mov ax, 10[bp] ; data word
476 mov [bx], ax ; write data word
485 // Bit32u (unsigned long) and long helper functions
514 cmp eax, dword ptr [di]
533 mul eax, dword ptr [di]
629 // for access to RAM area which is used by interrupt vectors
630 // and BIOS Data Area
633 unsigned char filler1[0x400];
634 unsigned char filler2[0x6c];
640 #define BiosData ((bios_data_t *) 0)
644 Bit16u heads; // # heads
645 Bit16u cylinders; // # cylinders
646 Bit16u spt; // # sectors / track
666 Bit8u iface; // ISA or PCI
667 Bit16u iobase1; // IO Base 1
668 Bit16u iobase2; // IO Base 2
673 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
674 Bit8u device; // Detected type of attached devices (hd/cd/none)
675 Bit8u removable; // Removable device flag
676 Bit8u lock; // Locks for removable devices
677 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
678 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
679 Bit16u blksize; // block size
681 Bit8u translation; // type of translation
682 chs_t lchs; // Logical CHS
683 chs_t pchs; // Physical CHS
685 Bit32u sectors; // Total sectors count
690 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
693 ata_device_t devices[BX_MAX_ATA_DEVICES];
695 // map between (bios hd id - 0x80) and ata channels
696 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
698 // map between (bios cd id - 0xE0) and ata channels
699 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
701 // Buffer for DPTE table
704 // Count of transferred sectors and bytes
711 // ElTorito Device Emulation data
715 Bit8u emulated_drive;
716 Bit8u controller_index;
719 Bit16u buffer_segment;
726 #endif // BX_ELTORITO_BOOT
728 // for access to EBDA area
729 // The EBDA structure should conform to
730 // http://www.cybertrails.com/~fys/rombios.htm document
731 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
733 unsigned char filler1[0x3D];
735 // FDPT - Can be splitted in data members if needed
736 unsigned char fdpt0[0x10];
737 unsigned char fdpt1[0x10];
739 unsigned char filler2[0xC4];
745 // El Torito Emulation data
747 #endif // BX_ELTORITO_BOOT
751 #define EbdaData ((ebda_data_t *) 0)
753 // for access to the int13ext structure
764 #define Int13Ext ((int13ext_t *) 0)
766 // Disk Physical Table definition
773 Bit32u sector_count1;
774 Bit32u sector_count2;
785 Bit8u device_path[8];
790 #define Int13DPT ((dpt_t *) 0)
792 #endif // BX_USE_ATADRV
797 Bit16u di, si, bp, sp;
798 Bit16u bx, dx, cx, ax;
802 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
810 Bit32u edi, esi, ebp, esp;
811 Bit32u ebx, edx, ecx, eax;
814 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
815 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
843 #define SetCF(x) x.u.r8.flagsl |= 0x01
844 #define SetZF(x) x.u.r8.flagsl |= 0x40
845 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
846 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
847 #define GetCF(x) (x.u.r8.flagsl & 0x01)
858 static Bit8u inb_cmos();
860 static void outb_cmos();
863 static void init_rtc();
864 static bx_bool rtc_updating();
866 static Bit8u read_byte();
867 static Bit16u read_word();
868 static void write_byte();
869 static void write_word();
870 static void bios_printf();
871 static void copy_e820_table();
873 static Bit8u inhibit_mouse_int_and_events();
874 static void enable_mouse_int_and_events();
875 static Bit8u send_to_mouse_ctrl();
876 static Bit8u get_mouse_data();
877 static void set_kbd_command_byte();
879 static void int09_function();
880 static void int13_harddisk();
881 static void int13_cdrom();
882 static void int13_cdemu();
883 static void int13_eltorito();
884 static void int13_diskette_function();
885 static void int14_function();
886 static void int15_function();
887 static void int16_function();
888 static void int17_function();
889 static Bit32u int19_function();
890 static void int1a_function();
891 static void int70_function();
892 static void int74_function();
893 static Bit16u get_CS();
894 //static Bit16u get_DS();
895 //static void set_DS();
896 static Bit16u get_SS();
897 static unsigned int enqueue_key();
898 static unsigned int dequeue_key();
899 static void get_hd_geometry();
900 static void set_diskette_ret_status();
901 static void set_diskette_current_cyl();
902 static void determine_floppy_media();
903 static bx_bool floppy_drive_exists();
904 static bx_bool floppy_drive_recal();
905 static bx_bool floppy_media_known();
906 static bx_bool floppy_media_sense();
907 static bx_bool set_enable_a20();
908 static void debugger_on();
909 static void debugger_off();
910 static void keyboard_init();
911 static void keyboard_panic();
912 static void shutdown_status_panic();
913 static void nmi_handler_msg();
915 static void print_bios_banner();
916 static void print_boot_device();
917 static void print_boot_failure();
918 static void print_cdromboot_failure();
922 // ATA / ATAPI driver
927 Bit16u ata_cmd_non_data();
928 Bit16u ata_cmd_data_in();
929 Bit16u ata_cmd_data_out();
930 Bit16u ata_cmd_packet();
932 Bit16u atapi_get_sense();
933 Bit16u atapi_is_ready();
934 Bit16u atapi_is_cdrom();
936 #endif // BX_USE_ATADRV
941 Bit8u cdemu_isactive();
942 Bit8u cdemu_emulated_drive();
946 #endif // BX_ELTORITO_BOOT
948 static char bios_cvs_version_string[] = "$Revision: 1.12 $";
949 static char bios_date_string[] = "$Date: 2008/07/11 22:59:38 $";
951 static char CVSID[] = "$Id: rombios.c,v 1.12 2008/07/11 22:59:38 pdinda Exp $";
953 /* Offset to skip the CVS $Id: prefix */
954 #define bios_version_string (CVSID + 4)
956 #define BIOS_PRINTF_HALT 1
957 #define BIOS_PRINTF_SCREEN 2
958 #define BIOS_PRINTF_INFO 4
959 #define BIOS_PRINTF_DEBUG 8
960 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
961 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
963 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
965 // Defines the output macros.
966 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
967 // per-device basis. Debug info are sent only in debug mode
969 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_ALL, format, ##p)
971 # define BX_DEBUG(format, p...)
973 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
974 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
977 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
979 # define BX_DEBUG_ATA(a...)
982 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
984 # define BX_DEBUG_INT13_HD(a...)
987 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
989 # define BX_DEBUG_INT13_CD(a...)
992 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
994 # define BX_DEBUG_INT13_ET(a...)
997 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
999 # define BX_DEBUG_INT13_FL(a...)
1002 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1004 # define BX_DEBUG_INT15(a...)
1007 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1009 # define BX_DEBUG_INT16(a...)
1012 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1014 # define BX_DEBUG_INT1A(a...)
1017 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1019 # define BX_DEBUG_INT74(a...)
1022 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1023 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1024 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1025 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1026 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1027 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1028 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1029 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1031 #define GET_AL() ( AX & 0x00ff )
1032 #define GET_BL() ( BX & 0x00ff )
1033 #define GET_CL() ( CX & 0x00ff )
1034 #define GET_DL() ( DX & 0x00ff )
1035 #define GET_AH() ( AX >> 8 )
1036 #define GET_BH() ( BX >> 8 )
1037 #define GET_CH() ( CX >> 8 )
1038 #define GET_DH() ( DX >> 8 )
1040 #define GET_ELDL() ( ELDX & 0x00ff )
1041 #define GET_ELDH() ( ELDX >> 8 )
1043 #define SET_CF() FLAGS |= 0x0001
1044 #define CLEAR_CF() FLAGS &= 0xfffe
1045 #define GET_CF() (FLAGS & 0x0001)
1047 #define SET_ZF() FLAGS |= 0x0040
1048 #define CLEAR_ZF() FLAGS &= 0xffbf
1049 #define GET_ZF() (FLAGS & 0x0040)
1051 #define UNSUPPORTED_FUNCTION 0x86
1054 #define MAX_SCAN_CODE 0x53
1062 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1063 { none, none, none, none, none },
1064 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1065 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1066 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1067 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1068 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1069 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1070 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1071 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1072 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1073 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1074 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1075 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1076 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1077 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1078 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1079 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1080 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1081 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1082 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1083 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1084 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1085 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1086 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1087 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1088 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1089 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1090 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1091 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1092 { none, none, none, none, none }, /* L Ctrl */
1093 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1094 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1095 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1096 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1097 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1098 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1099 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1100 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1101 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1102 { 0x273b, 0x273a, none, none, none }, /* ;: */
1103 { 0x2827, 0x2822, none, none, none }, /* '" */
1104 { 0x2960, 0x297e, none, none, none }, /* `~ */
1105 { none, none, none, none, none }, /* L shift */
1106 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1107 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1108 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1109 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1110 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1111 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1112 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1113 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1114 { 0x332c, 0x333c, none, none, none }, /* ,< */
1115 { 0x342e, 0x343e, none, none, none }, /* .> */
1116 { 0x352f, 0x353f, none, none, none }, /* /? */
1117 { none, none, none, none, none }, /* R Shift */
1118 { 0x372a, 0x372a, none, none, none }, /* * */
1119 { none, none, none, none, none }, /* L Alt */
1120 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1121 { none, none, none, none, none }, /* caps lock */
1122 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1123 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1124 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1125 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1126 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1127 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1128 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1129 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1130 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1131 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1132 { none, none, none, none, none }, /* Num Lock */
1133 { none, none, none, none, none }, /* Scroll Lock */
1134 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1135 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1136 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1137 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1138 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1139 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1140 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1141 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1142 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1143 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1144 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1145 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1146 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1230 outb_cmos(cmos_reg, val)
1238 mov al, 4[bp] ;; cmos_reg
1240 mov al, 6[bp] ;; val
1255 mov al, 4[bp] ;; cmos_reg
1266 printf("rombios: init_rtc()\n");
1267 outb_cmos(0x0a, 0x26);
1268 outb_cmos(0x0b, 0x02);
1276 // This function checks to see if the update-in-progress bit
1277 // is set in CMOS Status Register A. If not, it returns 0.
1278 // If it is set, it tries to wait until there is a transition
1279 // to 0, and will return 0 if such a transition occurs. A 1
1280 // is returned only after timing out. The maximum period
1281 // that this bit should be set is constrained to 244useconds.
1282 // The count I use below guarantees coverage or more than
1283 // this time, with any reasonable IPS setting.
1288 while (--count != 0) {
1289 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1292 return(1); // update-in-progress never transitioned to 0
1297 read_byte(seg, offset)
1307 mov ax, 4[bp] ; segment
1309 mov bx, 6[bp] ; offset
1311 ;; al = return value (byte)
1320 read_word(seg, offset)
1330 mov ax, 4[bp] ; segment
1332 mov bx, 6[bp] ; offset
1334 ;; ax = return value (word)
1343 write_byte(seg, offset, data)
1355 mov ax, 4[bp] ; segment
1357 mov bx, 6[bp] ; offset
1358 mov al, 8[bp] ; data byte
1359 mov [bx], al ; write data byte
1369 write_word(seg, offset, data)
1381 mov ax, 4[bp] ; segment
1383 mov bx, 6[bp] ; offset
1384 mov ax, 8[bp] ; data word
1385 mov [bx], ax ; write data word
1412 //set_DS(ds_selector)
1413 // Bit16u ds_selector;
1420 // mov ax, 4[bp] ; ds_selector
1440 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1441 if (nr_entries > 32)
1443 write_word(0xe000, 0x8, nr_entries);
1444 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1446 #endif /* HVMASSIST */
1449 /* serial debug port*/
1450 #define BX_DEBUG_PORT 0x03f8
1453 #define UART_RBR 0x00
1454 #define UART_THR 0x00
1457 #define UART_IER 0x01
1458 #define UART_IIR 0x02
1459 #define UART_FCR 0x02
1460 #define UART_LCR 0x03
1461 #define UART_MCR 0x04
1462 #define UART_DLL 0x00
1463 #define UART_DLM 0x01
1466 #define UART_LSR 0x05
1467 #define UART_MSR 0x06
1468 #define UART_SCR 0x07
1470 int uart_can_tx_byte(base_port)
1473 return inb(base_port + UART_LSR) & 0x20;
1476 void uart_wait_to_tx_byte(base_port)
1479 while (!uart_can_tx_byte(base_port));
1482 void uart_wait_until_sent(base_port)
1485 while (!(inb(base_port + UART_LSR) & 0x40));
1488 void uart_tx_byte(base_port, data)
1492 uart_wait_to_tx_byte(base_port);
1493 outb(base_port + UART_THR, data);
1494 uart_wait_until_sent(base_port);
1523 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1524 uart_tx_byte(BX_DEBUG_PORT, c);
1529 #if BX_VIRTUAL_PORTS
1530 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1531 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1533 if (action & BIOS_PRINTF_SCREEN) {
1534 if (c == '\n') wrch('\r');
1540 put_int(action, val, width, neg)
1545 short nval = val / 10;
1547 put_int(action, nval, width - 1, neg);
1549 while (--width > 0) send(action, ' ');
1550 if (neg) send(action, '-');
1552 send(action, val - (nval * 10) + '0');
1556 put_uint(action, val, width, neg)
1562 unsigned short nval = val / 10;
1564 put_uint(action, nval, width - 1, neg);
1566 while (--width > 0) send(action, ' ');
1567 if (neg) send(action, '-');
1569 send(action, val - (nval * 10) + '0');
1572 //--------------------------------------------------------------------------
1574 // A compact variable argument printf function which prints its output via
1575 // an I/O port so that it can be logged by Bochs/Plex.
1576 // Currently, only %x is supported (or %02x, %04x, etc).
1578 // Supports %[format_width][format]
1579 // where format can be d,x,c,s
1580 //--------------------------------------------------------------------------
1582 bios_printf(action, s)
1586 Bit8u c, format_char;
1590 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1598 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1599 #if BX_VIRTUAL_PORTS
1600 outb(PANIC_PORT2, 0x00);
1602 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1605 while (c = read_byte(get_CS(), s)) {
1610 else if (in_format) {
1611 if ( (c>='0') && (c<='9') ) {
1612 format_width = (format_width * 10) + (c - '0');
1615 arg_ptr++; // increment to next arg
1616 arg = read_word(arg_seg, arg_ptr);
1618 if (format_width == 0)
1620 for (i=format_width-1; i>=0; i--) {
1621 nibble = (arg >> (4 * i)) & 0x000f;
1622 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1625 else if (c == 'u') {
1626 put_uint(action, arg, format_width, 0);
1628 else if (c == 'd') {
1630 put_int(action, -arg, format_width - 1, 1);
1632 put_int(action, arg, format_width, 0);
1634 else if (c == 's') {
1635 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1637 else if (c == 'c') {
1641 BX_PANIC("bios_printf: unknown format\n");
1651 if (action & BIOS_PRINTF_HALT) {
1652 // freeze in a busy loop.
1662 //--------------------------------------------------------------------------
1664 //--------------------------------------------------------------------------
1665 // this file is based on LinuxBIOS implementation of keyboard.c
1666 // could convert to #asm to gain space
1673 BX_DEBUG("rombios: keyboard_init\n");
1675 /* printf("Assuming keyboard already inited and returning\n");
1678 /* ------------------- Flush buffers ------------------------*/
1679 /* Wait until buffer is empty */
1681 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1683 /* flush incoming keys */
1684 // temporarily chaged for debug -PAD
1689 if (inb(0x64) & 0x01) {
1695 // Due to timer issues, and if the IPS setting is > 15000000,
1696 // the incoming keys might not be flushed here. That will
1697 // cause a panic a few lines below. See sourceforge bug report :
1698 // [ 642031 ] FATAL: Keyboard RESET error:993
1700 /* ------------------- controller side ----------------------*/
1701 /* send cmd = 0xAA, self test 8042 */
1704 /* Wait until buffer is empty */
1706 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x02);
1707 if (max==0x0) keyboard_panic(00);
1711 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x03);
1712 if (max==0x0) keyboard_panic(01);
1714 /* read self-test result, 0x55 should be returned from 0x60 */
1715 if ((inb(0x60) != 0x55)){
1716 keyboard_panic(991);
1719 /* send cmd = 0xAB, keyboard interface test */
1722 /* Wait until buffer is empty */
1724 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1725 if (max==0x0) keyboard_panic(10);
1729 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1730 if (max==0x0) keyboard_panic(11);
1732 /* read keyboard interface test result, */
1733 /* 0x00 should be returned form 0x60 */
1734 if ((inb(0x60) != 0x00)) {
1735 keyboard_panic(992);
1738 /* Enable Keyboard clock */
1742 /* ------------------- keyboard side ------------------------*/
1743 /* reset kerboard and self test (keyboard side) */
1746 /* Wait until buffer is empty */
1748 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1749 if (max==0x0) keyboard_panic(20);
1753 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1754 if (max==0x0) keyboard_panic(21);
1756 /* keyboard should return ACK */
1757 if ((inb(0x60) != 0xfa)) {
1758 keyboard_panic(993);
1763 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1764 if (max==0x0) keyboard_panic(31);
1766 if ((inb(0x60) != 0xaa)) {
1767 keyboard_panic(994);
1770 /* Disable keyboard */
1773 /* Wait until buffer is empty */
1775 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1776 if (max==0x0) keyboard_panic(40);
1780 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1781 if (max==0x0) keyboard_panic(41);
1783 /* keyboard should return ACK */
1786 printf("rc=0x%x\n",rc);
1787 keyboard_panic(995);
1790 /* Write Keyboard Mode */
1793 /* Wait until buffer is empty */
1795 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1796 if (max==0x0) keyboard_panic(50);
1798 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1801 /* Wait until buffer is empty */
1803 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1804 if (max==0x0) keyboard_panic(60);
1806 /* Enable keyboard */
1809 /* Wait until buffer is empty */
1811 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1812 if (max==0x0) keyboard_panic(70);
1816 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1817 if (max==0x0) keyboard_panic(70);
1819 /* keyboard should return ACK */
1820 if ((inb(0x60) != 0xfa)) {
1821 keyboard_panic(996);
1825 printf("keyboard init done.\n");
1828 //--------------------------------------------------------------------------
1830 //--------------------------------------------------------------------------
1832 keyboard_panic(status)
1835 // If you're getting a 993 keyboard panic here,
1836 // please see the comment in keyboard_init
1837 printf("Keyboard error:%u CONTINUING\n",status); return;
1838 BX_PANIC("Keyboard error:%u\n",status);
1841 //--------------------------------------------------------------------------
1842 // shutdown_status_panic
1843 // called when the shutdown statsu is not implemented, displays the status
1844 //--------------------------------------------------------------------------
1846 shutdown_status_panic(status)
1849 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1852 //--------------------------------------------------------------------------
1853 // print_bios_banner
1854 // displays a the bios version
1855 //--------------------------------------------------------------------------
1859 printf("Hi from peter's modified bios\n");
1860 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1861 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1865 //--------------------------------------------------------------------------
1866 // print_boot_device
1867 // displays the boot device
1868 //--------------------------------------------------------------------------
1870 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1873 print_boot_device(cdboot, drive)
1874 Bit8u cdboot; Bit16u drive;
1878 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1879 // drive contains real/emulated boot drive
1881 if(cdboot)i=2; // CD-Rom
1882 else if((drive&0x0080)==0x00)i=0; // Floppy
1883 else if((drive&0x0080)==0x80)i=1; // Hard drive
1886 printf("Booting from %s...\n",drivetypes[i]);
1889 //--------------------------------------------------------------------------
1890 // print_boot_failure
1891 // displays the reason why boot failed
1892 //--------------------------------------------------------------------------
1894 print_boot_failure(cdboot, drive, reason, lastdrive)
1895 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1897 Bit16u drivenum = drive&0x7f;
1899 // cdboot: 1 if boot from cd, 0 otherwise
1900 // drive : drive number
1901 // reason: 0 signature check failed, 1 read error
1902 // lastdrive: 1 boot drive is the last one in boot sequence
1905 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1906 else if (drive & 0x80)
1907 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1909 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1913 BX_PANIC("Not a bootable disk\n");
1915 BX_PANIC("Could not read the boot disk\n");
1919 //--------------------------------------------------------------------------
1920 // print_cdromboot_failure
1921 // displays the reason why boot failed
1922 //--------------------------------------------------------------------------
1924 print_cdromboot_failure( code )
1927 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1935 BX_PANIC("NMI Handler called\n");
1941 BX_PANIC("INT18: BOOT FAILURE\n");
1948 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1950 BX_INFO("%s\n", bios_version_string);
1959 // Use PS2 System Control port A to set A20 enable
1961 // get current setting first
1964 // change A20 status
1966 outb(0x92, oldval | 0x02);
1968 outb(0x92, oldval & 0xfd);
1970 return((oldval & 0x02) != 0);
1987 // ---------------------------------------------------------------------------
1988 // Start of ATA/ATAPI Driver
1989 // ---------------------------------------------------------------------------
1991 // Global defines -- ATA register and register bits.
1992 // command block & control block regs
1993 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1994 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1995 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1996 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1997 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1998 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1999 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2000 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2001 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2002 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2003 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2004 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2005 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2007 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2008 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2009 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2010 #define ATA_CB_ER_MC 0x20 // ATA media change
2011 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2012 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2013 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2014 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2015 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2017 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2018 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2019 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2020 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2021 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2023 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2024 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2025 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2026 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2027 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2029 // bits 7-4 of the device/head (CB_DH) reg
2030 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2031 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2033 // status reg (CB_STAT and CB_ASTAT) bits
2034 #define ATA_CB_STAT_BSY 0x80 // busy
2035 #define ATA_CB_STAT_RDY 0x40 // ready
2036 #define ATA_CB_STAT_DF 0x20 // device fault
2037 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2038 #define ATA_CB_STAT_SKC 0x10 // seek complete
2039 #define ATA_CB_STAT_SERV 0x10 // service
2040 #define ATA_CB_STAT_DRQ 0x08 // data request
2041 #define ATA_CB_STAT_CORR 0x04 // corrected
2042 #define ATA_CB_STAT_IDX 0x02 // index
2043 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2044 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2046 // device control reg (CB_DC) bits
2047 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2048 #define ATA_CB_DC_SRST 0x04 // soft reset
2049 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2051 // Most mandtory and optional ATA commands (from ATA-3),
2052 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2053 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2054 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2055 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2056 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2057 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2058 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2059 #define ATA_CMD_DEVICE_RESET 0x08
2060 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2061 #define ATA_CMD_FLUSH_CACHE 0xE7
2062 #define ATA_CMD_FORMAT_TRACK 0x50
2063 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2064 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2065 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2066 #define ATA_CMD_IDLE1 0xE3
2067 #define ATA_CMD_IDLE2 0x97
2068 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2069 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2070 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2071 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2072 #define ATA_CMD_NOP 0x00
2073 #define ATA_CMD_PACKET 0xA0
2074 #define ATA_CMD_READ_BUFFER 0xE4
2075 #define ATA_CMD_READ_DMA 0xC8
2076 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2077 #define ATA_CMD_READ_MULTIPLE 0xC4
2078 #define ATA_CMD_READ_SECTORS 0x20
2079 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2080 #define ATA_CMD_RECALIBRATE 0x10
2081 #define ATA_CMD_SEEK 0x70
2082 #define ATA_CMD_SET_FEATURES 0xEF
2083 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2084 #define ATA_CMD_SLEEP1 0xE6
2085 #define ATA_CMD_SLEEP2 0x99
2086 #define ATA_CMD_STANDBY1 0xE2
2087 #define ATA_CMD_STANDBY2 0x96
2088 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2089 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2090 #define ATA_CMD_WRITE_BUFFER 0xE8
2091 #define ATA_CMD_WRITE_DMA 0xCA
2092 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2093 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2094 #define ATA_CMD_WRITE_SECTORS 0x30
2095 #define ATA_CMD_WRITE_VERIFY 0x3C
2097 #define ATA_IFACE_NONE 0x00
2098 #define ATA_IFACE_ISA 0x00
2099 #define ATA_IFACE_PCI 0x01
2101 #define ATA_TYPE_NONE 0x00
2102 #define ATA_TYPE_UNKNOWN 0x01
2103 #define ATA_TYPE_ATA 0x02
2104 #define ATA_TYPE_ATAPI 0x03
2106 #define ATA_DEVICE_NONE 0x00
2107 #define ATA_DEVICE_HD 0xFF
2108 #define ATA_DEVICE_CDROM 0x05
2110 #define ATA_MODE_NONE 0x00
2111 #define ATA_MODE_PIO16 0x00
2112 #define ATA_MODE_PIO32 0x01
2113 #define ATA_MODE_ISADMA 0x02
2114 #define ATA_MODE_PCIDMA 0x03
2115 #define ATA_MODE_USEIRQ 0x10
2117 #define ATA_TRANSLATION_NONE 0
2118 #define ATA_TRANSLATION_LBA 1
2119 #define ATA_TRANSLATION_LARGE 2
2120 #define ATA_TRANSLATION_RECHS 3
2122 #define ATA_DATA_NO 0x00
2123 #define ATA_DATA_IN 0x01
2124 #define ATA_DATA_OUT 0x02
2126 // ---------------------------------------------------------------------------
2127 // ATA/ATAPI driver : initialization
2128 // ---------------------------------------------------------------------------
2131 Bit16u ebda_seg=read_word(0x0040,0x000E);
2132 Bit8u channel, device;
2134 //BX_DEBUG("rombios: ata_init\n");
2136 // Channels info init.
2137 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2138 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2139 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2140 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2141 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2144 // Devices info init.
2145 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2146 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2147 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2148 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2149 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2150 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2151 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2152 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2153 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2154 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2155 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2156 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2157 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2158 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2160 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2163 // hdidmap and cdidmap init.
2164 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2165 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2166 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2169 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2170 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2173 // ---------------------------------------------------------------------------
2174 // ATA/ATAPI driver : device detection
2175 // ---------------------------------------------------------------------------
2179 Bit16u ebda_seg=read_word(0x0040,0x000E);
2180 Bit8u hdcount, cdcount, device, type;
2181 Bit8u buffer[0x0200];
2183 //BX_DEBUG("rombios: ata_detect\n");
2185 #if BX_MAX_ATA_INTERFACES > 0
2186 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2187 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2188 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2189 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2191 #if BX_MAX_ATA_INTERFACES > 1
2192 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2193 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2194 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2195 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2197 #if BX_MAX_ATA_INTERFACES > 2
2198 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2199 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2200 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2201 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2203 #if BX_MAX_ATA_INTERFACES > 3
2204 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2205 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2206 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2207 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2209 #if BX_MAX_ATA_INTERFACES > 4
2210 #error Please fill the ATA interface informations
2216 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2217 Bit16u iobase1, iobase2;
2218 Bit8u channel, slave, shift;
2219 Bit8u sc, sn, cl, ch, st;
2221 channel = device / 2;
2224 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2225 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2227 // Disable interrupts
2228 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2231 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2232 outb(iobase1+ATA_CB_SC, 0x55);
2233 outb(iobase1+ATA_CB_SN, 0xaa);
2234 outb(iobase1+ATA_CB_SC, 0xaa);
2235 outb(iobase1+ATA_CB_SN, 0x55);
2236 outb(iobase1+ATA_CB_SC, 0x55);
2237 outb(iobase1+ATA_CB_SN, 0xaa);
2239 // If we found something
2240 sc = inb(iobase1+ATA_CB_SC);
2241 sn = inb(iobase1+ATA_CB_SN);
2243 if ( (sc == 0x55) && (sn == 0xaa) ) {
2244 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2246 // reset the channel
2249 // check for ATA or ATAPI
2250 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2251 sc = inb(iobase1+ATA_CB_SC);
2252 sn = inb(iobase1+ATA_CB_SN);
2253 if ( (sc==0x01) && (sn==0x01) ) {
2254 cl = inb(iobase1+ATA_CB_CL);
2255 ch = inb(iobase1+ATA_CB_CH);
2256 st = inb(iobase1+ATA_CB_STAT);
2258 if ( (cl==0x14) && (ch==0xeb) ) {
2259 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2261 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2262 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2267 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2269 // Now we send a IDENTIFY command to ATA device
2270 if(type == ATA_TYPE_ATA) {
2272 Bit16u cylinders, heads, spt, blksize;
2273 Bit8u translation, removable, mode;
2275 // default mode to PIO16
2276 mode = ATA_MODE_PIO16;
2278 //Temporary values to do the transfer
2279 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2280 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2282 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2283 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2285 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2287 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2290 blksize = read_word(get_SS(),buffer+10);
2292 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2293 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2294 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2296 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2298 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2299 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2300 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2301 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2302 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2303 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2304 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2305 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2306 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2308 translation = inb_cmos(0x39 + channel/2);
2309 for (shift=device%4; shift>0; shift--) translation >>= 2;
2310 translation &= 0x03;
2312 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2314 switch (translation) {
2315 case ATA_TRANSLATION_NONE:
2318 case ATA_TRANSLATION_LBA:
2321 case ATA_TRANSLATION_LARGE:
2324 case ATA_TRANSLATION_RECHS:
2328 switch (translation) {
2329 case ATA_TRANSLATION_NONE:
2331 case ATA_TRANSLATION_LBA:
2334 heads = sectors / 1024;
2335 if (heads>128) heads = 255;
2336 else if (heads>64) heads = 128;
2337 else if (heads>32) heads = 64;
2338 else if (heads>16) heads = 32;
2340 cylinders = sectors / heads;
2342 case ATA_TRANSLATION_RECHS:
2343 // Take care not to overflow
2345 if(cylinders>61439) cylinders=61439;
2347 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2349 // then go through the large bitshift process
2350 case ATA_TRANSLATION_LARGE:
2351 while(cylinders > 1024) {
2355 // If we max out the head count
2356 if (heads > 127) break;
2360 // clip to 1024 cylinders in lchs
2361 if (cylinders > 1024) cylinders=1024;
2362 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2364 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2365 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2366 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2369 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2373 // Now we send a IDENTIFY command to ATAPI device
2374 if(type == ATA_TYPE_ATAPI) {
2376 Bit8u type, removable, mode;
2379 // default mode to PIO16
2380 mode = ATA_MODE_PIO16;
2382 //Temporary values to do the transfer
2383 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2384 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2386 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2387 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2389 type = read_byte(get_SS(),buffer+1) & 0x1f;
2390 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2392 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2396 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2397 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2398 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2399 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2402 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2409 Bit8u c, i, version, model[41];
2413 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2415 case ATA_TYPE_ATAPI:
2416 // Read ATA/ATAPI version
2417 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2418 for(version=15;version>0;version--) {
2419 if((ataversion&(1<<version))!=0)
2425 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2426 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2430 write_byte(get_SS(),model+40,0x00);
2432 if(read_byte(get_SS(),model+i)==0x20)
2433 write_byte(get_SS(),model+i,0x00);
2441 printf("ata%d %s: ",channel,slave?" slave":"master");
2442 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2443 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2445 case ATA_TYPE_ATAPI:
2446 printf("ata%d %s: ",channel,slave?" slave":"master");
2447 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2448 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2449 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2451 printf(" ATAPI-%d Device\n",version);
2453 case ATA_TYPE_UNKNOWN:
2454 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2460 // Store the devices counts
2461 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2462 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2463 write_byte(0x40,0x75, hdcount);
2467 // FIXME : should use bios=cmos|auto|disable bits
2468 // FIXME : should know about translation bits
2469 // FIXME : move hard_drive_post here
2473 // ---------------------------------------------------------------------------
2474 // ATA/ATAPI driver : software reset
2475 // ---------------------------------------------------------------------------
2477 // 8.2.1 Software reset - Device 0
2479 void ata_reset(device)
2482 Bit16u ebda_seg=read_word(0x0040,0x000E);
2483 Bit16u iobase1, iobase2;
2484 Bit8u channel, slave, sn, sc;
2487 channel = device / 2;
2490 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2491 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2495 // 8.2.1 (a) -- set SRST in DC
2496 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2498 // 8.2.1 (b) -- wait for BSY
2501 Bit8u status = inb(iobase1+ATA_CB_STAT);
2502 if ((status & ATA_CB_STAT_BSY) != 0) break;
2505 // 8.2.1 (f) -- clear SRST
2506 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2508 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2510 // 8.2.1 (g) -- check for sc==sn==0x01
2512 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2513 sc = inb(iobase1+ATA_CB_SC);
2514 sn = inb(iobase1+ATA_CB_SN);
2516 if ( (sc==0x01) && (sn==0x01) ) {
2518 // 8.2.1 (h) -- wait for not BSY
2521 Bit8u status = inb(iobase1+ATA_CB_STAT);
2522 if ((status & ATA_CB_STAT_BSY) == 0) break;
2527 // 8.2.1 (i) -- wait for DRDY
2530 Bit8u status = inb(iobase1+ATA_CB_STAT);
2531 if ((status & ATA_CB_STAT_RDY) != 0) break;
2534 // Enable interrupts
2535 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2538 // ---------------------------------------------------------------------------
2539 // ATA/ATAPI driver : execute a non data command
2540 // ---------------------------------------------------------------------------
2542 Bit16u ata_cmd_non_data()
2545 // ---------------------------------------------------------------------------
2546 // ATA/ATAPI driver : execute a data-in command
2547 // ---------------------------------------------------------------------------
2552 // 3 : expected DRQ=1
2553 // 4 : no sectors left to read/verify
2554 // 5 : more sectors to read/verify
2555 // 6 : no sectors left to write
2556 // 7 : more sectors to write
2557 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2558 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2561 Bit16u ebda_seg=read_word(0x0040,0x000E);
2562 Bit16u iobase1, iobase2, blksize;
2563 Bit8u channel, slave;
2564 Bit8u status, current, mode;
2566 channel = device / 2;
2569 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2570 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2571 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2572 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2573 if (mode == ATA_MODE_PIO32) blksize>>=2;
2576 // sector will be 0 only on lba access. Convert to lba-chs
2578 sector = (Bit16u) (lba & 0x000000ffL);
2580 cylinder = (Bit16u) (lba & 0x0000ffffL);
2582 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2585 // Reset count of transferred data
2586 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2587 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2590 status = inb(iobase1 + ATA_CB_STAT);
2591 if (status & ATA_CB_STAT_BSY) return 1;
2593 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2594 outb(iobase1 + ATA_CB_FR, 0x00);
2595 outb(iobase1 + ATA_CB_SC, count);
2596 outb(iobase1 + ATA_CB_SN, sector);
2597 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2598 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2599 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2600 outb(iobase1 + ATA_CB_CMD, command);
2603 status = inb(iobase1 + ATA_CB_STAT);
2604 if ( !(status & ATA_CB_STAT_BSY) ) break;
2607 if (status & ATA_CB_STAT_ERR) {
2608 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2610 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2611 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2615 // FIXME : move seg/off translation here
2618 sti ;; enable higher priority interrupts
2626 mov di, _ata_cmd_data_in.offset + 2[bp]
2627 mov ax, _ata_cmd_data_in.segment + 2[bp]
2628 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2630 ;; adjust if there will be an overrun. 2K max sector size
2632 jbe ata_in_no_adjust
2635 sub di, #0x0800 ;; sub 2 kbytes from offset
2636 add ax, #0x0080 ;; add 2 Kbytes to segment
2639 mov es, ax ;; segment in es
2641 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2643 mov ah, _ata_cmd_data_in.mode + 2[bp]
2644 cmp ah, #ATA_MODE_PIO32
2649 insw ;; CX words transfered from port(DX) to ES:[DI]
2654 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2657 mov _ata_cmd_data_in.offset + 2[bp], di
2658 mov _ata_cmd_data_in.segment + 2[bp], es
2663 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2665 status = inb(iobase1 + ATA_CB_STAT);
2667 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2668 != ATA_CB_STAT_RDY ) {
2669 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2675 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2676 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2677 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2683 // Enable interrupts
2684 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2688 // ---------------------------------------------------------------------------
2689 // ATA/ATAPI driver : execute a data-out command
2690 // ---------------------------------------------------------------------------
2695 // 3 : expected DRQ=1
2696 // 4 : no sectors left to read/verify
2697 // 5 : more sectors to read/verify
2698 // 6 : no sectors left to write
2699 // 7 : more sectors to write
2700 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2701 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2704 Bit16u ebda_seg=read_word(0x0040,0x000E);
2705 Bit16u iobase1, iobase2, blksize;
2706 Bit8u channel, slave;
2707 Bit8u status, current, mode;
2709 channel = device / 2;
2712 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2713 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2714 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2715 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2716 if (mode == ATA_MODE_PIO32) blksize>>=2;
2719 // sector will be 0 only on lba access. Convert to lba-chs
2721 sector = (Bit16u) (lba & 0x000000ffL);
2723 cylinder = (Bit16u) (lba & 0x0000ffffL);
2725 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2728 // Reset count of transferred data
2729 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2730 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2733 status = inb(iobase1 + ATA_CB_STAT);
2734 if (status & ATA_CB_STAT_BSY) return 1;
2736 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2737 outb(iobase1 + ATA_CB_FR, 0x00);
2738 outb(iobase1 + ATA_CB_SC, count);
2739 outb(iobase1 + ATA_CB_SN, sector);
2740 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2741 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2742 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2743 outb(iobase1 + ATA_CB_CMD, command);
2746 status = inb(iobase1 + ATA_CB_STAT);
2747 if ( !(status & ATA_CB_STAT_BSY) ) break;
2750 if (status & ATA_CB_STAT_ERR) {
2751 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2753 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2754 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2758 // FIXME : move seg/off translation here
2761 sti ;; enable higher priority interrupts
2769 mov si, _ata_cmd_data_out.offset + 2[bp]
2770 mov ax, _ata_cmd_data_out.segment + 2[bp]
2771 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2773 ;; adjust if there will be an overrun. 2K max sector size
2775 jbe ata_out_no_adjust
2778 sub si, #0x0800 ;; sub 2 kbytes from offset
2779 add ax, #0x0080 ;; add 2 Kbytes to segment
2782 mov es, ax ;; segment in es
2784 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2786 mov ah, _ata_cmd_data_out.mode + 2[bp]
2787 cmp ah, #ATA_MODE_PIO32
2793 outsw ;; CX words transfered from port(DX) to ES:[SI]
2799 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2802 mov _ata_cmd_data_out.offset + 2[bp], si
2803 mov _ata_cmd_data_out.segment + 2[bp], es
2808 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2810 status = inb(iobase1 + ATA_CB_STAT);
2812 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2813 != ATA_CB_STAT_RDY ) {
2814 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2820 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2821 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2822 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2828 // Enable interrupts
2829 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2833 // ---------------------------------------------------------------------------
2834 // ATA/ATAPI driver : execute a packet command
2835 // ---------------------------------------------------------------------------
2838 // 1 : error in parameters
2842 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2844 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2848 Bit16u ebda_seg=read_word(0x0040,0x000E);
2849 Bit16u iobase1, iobase2;
2850 Bit16u lcount, lbefore, lafter, count;
2851 Bit8u channel, slave;
2852 Bit8u status, error, mode, lmode;
2853 Bit32u total, transfer;
2855 channel = device / 2;
2858 // Data out is not supported yet
2859 if (inout == ATA_DATA_OUT) {
2860 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2864 // The header length must be even
2866 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2870 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2871 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2872 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2875 if (cmdlen < 12) cmdlen=12;
2876 if (cmdlen > 12) cmdlen=16;
2879 // Reset count of transferred data
2880 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2881 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2883 #define STATUS_WAIT_FOR(x) do { status=inb(iobase1+ATA_CB_STAT); } while (!(x))
2884 #define ALT_STATUS_WAIT_FOR(x) do { status=inb(iobase2+ATA_CB_ASTAT); } while (!(x))
2885 #define ERROR_UPDATE() do { error=inb(iobase1+ATA_CB_ERR); } while (0)
2886 #define STATUS_UPDATE() do { status=inb(iobase1+ATA_CB_STAT); } while (0)
2887 #define ALT_STATUS_UPDATE() do { status=inb(iobase1+ATA_CB_STAT); } while (0)
2888 #define WAIT_FOR_NOT_BUSY() STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0)
2889 #define WAIT_FOR_DATA_REQUEST() STATUS_WAIT_FOR((status&ATA_CB_STAT_DRQ))
2890 #define WAIT_FOR_DRIVE_READY() STATUS_WAIT_FOR((status&ATA_CB_STAT_RDY))
2891 #define WAIT_FOR_NOT_BUSY_AND_DRIVE_READY() STATUS_WAIT_FOR(((status&ATA_CB_STAT_BSY)==0)&&((status&ATA_CB_STAT_RDY)))
2892 #define WAIT_FOR_NOT_BUSY_AND_DATA_REQUEST() STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0)&&((status&ATA_CB_STAT_DRQ)))
2896 retry_on_media_change:
2898 WAIT_FOR_NOT_BUSY();
2900 //BX_DEBUG_ATA("ata_cmd_packet: not busy done\n");
2902 // We have already selected the appropriate controller (iobase1,2)
2903 // select master or slave
2904 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2908 //BX_DEBUG_ATA("ata_cmd_packet: drive selected (%d) status=0x%x\n", slave,(unsigned)status);
2911 // Technically, we should be calling this here
2912 // but QEMU's device model appears to be broken and RDY never is assserted
2913 // on a drive change
2914 // WAIT_FOR_NOT_BUSY_AND_DRIVE_READY();
2915 WAIT_FOR_NOT_BUSY();
2917 //BX_DEBUG_ATA("ata_cmd_packet: not busy\n");
2919 // set "noninterruptable"
2920 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2922 outb(iobase1 + ATA_CB_FR, 0x00);
2923 // This conveys the maximum bytecount. count&0xff in low, count>>8 in high
2924 // it is not actually doing anything with cylinders
2925 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2926 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2927 // Not sure about these
2928 outb(iobase1 + ATA_CB_SC, 0x00);
2929 outb(iobase1 + ATA_CB_SN, 0x00);
2931 //BX_DEBUG_ATA("ata_cmd_packet: configuration done\n");
2933 // Issue command for packet
2934 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2936 //BX_DEBUG_ATA("ata_cmd_packet: A0 issued to drive\n");
2938 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
2940 //BX_DEBUG_ATA("ata_cmd_packet: alt status shows not busy\n");
2944 //BX_DEBUG_ATA("ata_cmd_packet: main status shows 0x%x\n",(unsigned)status);
2946 WAIT_FOR_DATA_REQUEST();
2948 //BX_DEBUG_ATA("ata_cmd_packet: data request is set\n");
2950 // Normalize address
2951 cmdseg += (cmdoff / 16);
2954 // Send command to device
2956 sti ;; enable higher priority interrupts
2961 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2962 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2963 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2964 mov es, ax ;; segment in es
2966 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2970 outsw ;; CX words transfered from port(DX) to ES:[SI]
2976 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
2981 BX_DEBUG_ATA("ata_cmd_packet: after packet: 0x%x error 0x%x\n",(unsigned)status,(unsigned)error);
2983 if (status&ATA_CB_STAT_ERR && error&ATA_CB_ER_MC) {
2984 BX_DEBUG_ATA("ata_cmd_packet: caught unexpected media change. Retrying\n");
2985 goto retry_on_media_change;
2990 if (inout == ATA_DATA_NO) {
2997 // This while loop is quite bizarre
2998 // Under both success and failure, you'll go through it once
2999 // and then just a wee bit the second time - PAD
3002 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
3007 BX_DEBUG_ATA("ata_cmd_packet/dataxferloop: status=0x%x, error=0x%x\n",(unsigned)status,(unsigned)error);
3013 // According to specatapi, the following is how you're supposed
3014 // To tell when there is no more data for you
3015 // But it doesn't work on at least some hardware - PAD
3016 if ((status&ATA_CB_STAT_BSY) && !(status&ATA_CB_STAT_DRQ)) {
3017 // done with data tranfer
3018 // we wait for it to flip
3019 ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
3020 // then read one more time
3028 // Check if command completed
3029 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3032 if (status & ATA_CB_STAT_ERR) {
3033 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3037 // If we get here, we are ready and should have DRQ
3038 // and so data is available
3039 // Device must be ready to send data
3040 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3041 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3042 BX_DEBUG_ATA("ata_cmd_packet 1: not ready (status %02x)\n", status);
3046 // Normalize address
3047 bufseg += (bufoff / 16);
3050 // Get the byte count
3051 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3053 // adjust to read what we want
3066 lafter=lcount-length;
3078 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3079 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3081 // If counts not dividable by 4, use 16bits mode
3083 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3084 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3085 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3087 // adds an extra byte if count are odd. before is always even
3088 if (lcount & 0x01) {
3090 if ((lafter > 0) && (lafter & 0x01)) {
3095 if (lmode == ATA_MODE_PIO32) {
3096 lcount>>=2; lbefore>>=2; lafter>>=2;
3099 lcount>>=1; lbefore>>=1; lafter>>=1;
3108 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3110 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3111 jcxz ata_packet_no_before
3113 mov ah, _ata_cmd_packet.lmode + 2[bp]
3114 cmp ah, #ATA_MODE_PIO32
3115 je ata_packet_in_before_32
3117 ata_packet_in_before_16:
3119 loop ata_packet_in_before_16
3120 jmp ata_packet_no_before
3122 ata_packet_in_before_32:
3124 ata_packet_in_before_32_loop:
3126 loop ata_packet_in_before_32_loop
3129 ata_packet_no_before:
3130 mov cx, _ata_cmd_packet.lcount + 2[bp]
3131 jcxz ata_packet_after
3133 mov di, _ata_cmd_packet.bufoff + 2[bp]
3134 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3137 mov ah, _ata_cmd_packet.lmode + 2[bp]
3138 cmp ah, #ATA_MODE_PIO32
3143 insw ;; CX words transfered tp port(DX) to ES:[DI]
3144 jmp ata_packet_after
3148 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3151 mov cx, _ata_cmd_packet.lafter + 2[bp]
3152 jcxz ata_packet_done
3154 mov ah, _ata_cmd_packet.lmode + 2[bp]
3155 cmp ah, #ATA_MODE_PIO32
3156 je ata_packet_in_after_32
3158 ata_packet_in_after_16:
3160 loop ata_packet_in_after_16
3163 ata_packet_in_after_32:
3165 ata_packet_in_after_32_loop:
3167 loop ata_packet_in_after_32_loop
3174 // Compute new buffer address
3177 // Save transferred bytes count
3179 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3183 // Final check, device must be ready
3184 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3185 != ATA_CB_STAT_RDY ) {
3186 BX_DEBUG_ATA("ata_cmd_packet 2 : not ready (status %02x)\n", (unsigned) status);
3190 // Enable interrupts
3191 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3196 // ---------------------------------------------------------------------------
3197 // End of ATA/ATAPI Driver
3198 // ---------------------------------------------------------------------------
3201 // ---------------------------------------------------------------------------
3202 // Start of ATA/ATAPI generic functions
3203 // ---------------------------------------------------------------------------
3206 atapi_get_sense(device)
3213 memsetb(get_SS(),atacmd,0,12);
3218 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3221 if ((buffer[0] & 0x7e) == 0x70) {
3222 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3229 atapi_is_ready(device)
3235 memsetb(get_SS(),atacmd,0,12);
3238 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3241 if (atapi_get_sense(device) !=0 ) {
3242 memsetb(get_SS(),atacmd,0,12);
3244 // try to send Test Unit Ready again
3245 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3248 return atapi_get_sense(device);
3254 atapi_is_cdrom(device)
3257 Bit16u ebda_seg=read_word(0x0040,0x000E);
3259 if (device >= BX_MAX_ATA_DEVICES)
3262 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3265 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3271 // ---------------------------------------------------------------------------
3272 // End of ATA/ATAPI generic functions
3273 // ---------------------------------------------------------------------------
3275 #endif // BX_USE_ATADRV
3277 #if BX_ELTORITO_BOOT
3279 // ---------------------------------------------------------------------------
3280 // Start of El-Torito boot functions
3281 // ---------------------------------------------------------------------------
3286 Bit16u ebda_seg=read_word(0x0040,0x000E);
3288 //BX_DEBUG("rombios: cdemu_init\n");
3290 // the only important data is this one for now
3291 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3297 Bit16u ebda_seg=read_word(0x0040,0x000E);
3299 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3303 cdemu_emulated_drive()
3305 Bit16u ebda_seg=read_word(0x0040,0x000E);
3307 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3310 static char isotag[6]="CD001";
3311 static char eltorito[24]="EL TORITO SPECIFICATION";
3313 // Returns ah: emulated drive, al: error code
3318 Bit16u ebda_seg=read_word(0x0040,0x000E);
3319 Bit8u atacmd[12], buffer[2048];
3321 Bit16u boot_segment, nbsectors, i, error;
3325 // Find out the first cdrom
3326 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3327 if (atapi_is_cdrom(device)) break;
3331 if(device >= BX_MAX_ATA_DEVICES) return 2;
3335 // Read the Boot Record Volume Descriptor
3336 memsetb(get_SS(),atacmd,0,12);
3337 atacmd[0]=0x28; // READ command
3338 atacmd[1]=0x0 ; // reserved - not sure why this wasn't zeroed to begin with -PAD
3339 atacmd[6]=0x0 ; // reserved - ... -PAD
3340 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3341 atacmd[8]=(0x01 & 0x00ff); // Sectors
3342 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3343 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3344 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3345 atacmd[5]=(0x11 & 0x000000ff);
3346 atacmd[9]=atacmd[10]=atacmd[11]=0x0; // just to be safe -PAD
3347 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3352 if(buffer[0]!=0)return 4;
3354 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3357 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3359 // ok, now we calculate the Boot catalog address
3360 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3362 // And we read the Boot Catalog
3363 memsetb(get_SS(),atacmd,0,12);
3364 atacmd[0]=0x28; // READ command
3365 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3366 atacmd[8]=(0x01 & 0x00ff); // Sectors
3367 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3368 atacmd[3]=(lba & 0x00ff0000) >> 16;
3369 atacmd[4]=(lba & 0x0000ff00) >> 8;
3370 atacmd[5]=(lba & 0x000000ff);
3371 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3377 if(buffer[0x00]!=0x01)return 8; // Header
3378 if(buffer[0x01]!=0x00)return 9; // Platform
3379 if(buffer[0x1E]!=0x55)return 10; // key 1
3380 if(buffer[0x1F]!=0xAA)return 10; // key 2
3382 // Initial/Default Entry
3383 if(buffer[0x20]!=0x88)return 11; // Bootable
3385 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3386 if(buffer[0x21]==0){
3387 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3388 // Win2000 cd boot needs to know it booted from cd
3389 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3391 else if(buffer[0x21]<4)
3392 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3394 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3396 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3397 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3399 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3400 if(boot_segment==0x0000)boot_segment=0x07C0;
3402 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3403 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3405 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3406 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3408 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3409 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3411 // And we read the image in memory
3412 memsetb(get_SS(),atacmd,0,12);
3413 atacmd[0]=0x28; // READ command
3414 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3415 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3416 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3417 atacmd[3]=(lba & 0x00ff0000) >> 16;
3418 atacmd[4]=(lba & 0x0000ff00) >> 8;
3419 atacmd[5]=(lba & 0x000000ff);
3420 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3424 // Remember the media type
3425 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3426 case 0x01: // 1.2M floppy
3427 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3428 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3429 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3431 case 0x02: // 1.44M floppy
3432 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3433 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3434 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3436 case 0x03: // 2.88M floppy
3437 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3438 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3439 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3441 case 0x04: // Harddrive
3442 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3443 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3444 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3445 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3449 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3450 // Increase bios installed hardware number of devices
3451 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3452 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3454 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3458 // everything is ok, so from now on, the emulation is active
3459 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3460 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3462 // return the boot drive + no error
3463 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3466 // ---------------------------------------------------------------------------
3467 // End of El-Torito boot functions
3468 // ---------------------------------------------------------------------------
3469 #endif // BX_ELTORITO_BOOT
3472 int14_function(regs, ds, iret_addr)
3473 pusha_regs_t regs; // regs pushed from PUSHA instruction
3474 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3475 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3477 Bit16u addr,timer,val16;
3484 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3485 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3486 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3487 switch (regs.u.r8.ah) {
3489 outb(addr+3, inb(addr+3) | 0x80);
3490 if (regs.u.r8.al & 0xE0 == 0) {
3494 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3495 outb(addr, val16 & 0xFF);
3496 outb(addr+1, val16 >> 8);
3498 outb(addr+3, regs.u.r8.al & 0x1F);
3499 regs.u.r8.ah = inb(addr+5);
3500 regs.u.r8.al = inb(addr+6);
3501 ClearCF(iret_addr.flags);
3504 timer = read_word(0x0040, 0x006C);
3505 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3506 val16 = read_word(0x0040, 0x006C);
3507 if (val16 != timer) {
3512 if (timeout) outb(addr, regs.u.r8.al);
3513 regs.u.r8.ah = inb(addr+5);
3514 if (!timeout) regs.u.r8.ah |= 0x80;
3515 ClearCF(iret_addr.flags);
3518 timer = read_word(0x0040, 0x006C);
3519 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3520 val16 = read_word(0x0040, 0x006C);
3521 if (val16 != timer) {
3528 regs.u.r8.al = inb(addr);
3530 regs.u.r8.ah = inb(addr+5);
3532 ClearCF(iret_addr.flags);
3535 regs.u.r8.ah = inb(addr+5);
3536 regs.u.r8.al = inb(addr+6);
3537 ClearCF(iret_addr.flags);
3540 SetCF(iret_addr.flags); // Unsupported
3543 SetCF(iret_addr.flags); // Unsupported
3548 int15_function(regs, ES, DS, FLAGS)
3549 pusha_regs_t regs; // REGS pushed via pusha
3550 Bit16u ES, DS, FLAGS;
3552 Bit16u ebda_seg=read_word(0x0040,0x000E);
3553 bx_bool prev_a20_enable;
3562 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3564 switch (regs.u.r8.ah) {
3565 case 0x24: /* A20 Control */
3566 switch (regs.u.r8.al) {
3578 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3588 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3590 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3596 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3600 /* keyboard intercept */
3602 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3609 case 0x52: // removable media eject
3611 regs.u.r8.ah = 0; // "ok ejection may proceed"
3615 if( regs.u.r8.al == 0 ) {
3616 // Set Interval requested.
3617 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3618 // Interval not already set.
3619 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3620 write_word( 0x40, 0x98, ES ); // Byte location, segment
3621 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3622 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3623 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3625 irqDisable = inb( 0xA1 );
3626 outb( 0xA1, irqDisable & 0xFE );
3627 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3628 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3630 // Interval already set.
3631 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3633 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3635 } else if( regs.u.r8.al == 1 ) {
3636 // Clear Interval requested
3637 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3639 bRegister = inb_cmos( 0xB );
3640 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3642 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3644 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3653 # error "Int15 function 87h not supported on < 80386"
3655 // +++ should probably have descriptor checks
3656 // +++ should have exception handlers
3658 // turn off interrupts
3663 prev_a20_enable = set_enable_a20(1); // enable A20 line
3665 // 128K max of transfer on 386+ ???
3666 // source == destination ???
3668 // ES:SI points to descriptor table
3669 // offset use initially comments
3670 // ==============================================
3671 // 00..07 Unused zeros Null descriptor
3672 // 08..0f GDT zeros filled in by BIOS
3673 // 10..17 source ssssssss source of data
3674 // 18..1f dest dddddddd destination of data
3675 // 20..27 CS zeros filled in by BIOS
3676 // 28..2f SS zeros filled in by BIOS
3683 // check for access rights of source & dest here
3685 // Initialize GDT descriptor
3686 base15_00 = (ES << 4) + regs.u.r16.si;
3687 base23_16 = ES >> 12;
3688 if (base15_00 < (ES<<4))
3690 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3691 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3692 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3693 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3694 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3696 // Initialize CS descriptor
3697 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3698 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3699 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3700 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3701 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3703 // Initialize SS descriptor
3705 base15_00 = ss << 4;
3706 base23_16 = ss >> 12;
3707 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3708 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3709 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3710 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3711 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3715 // Compile generates locals offset info relative to SP.
3716 // Get CX (word count) from stack.
3719 mov cx, _int15_function.CX [bx]
3721 // since we need to set SS:SP, save them to the BDA
3722 // for future restore
3732 lidt [pmode_IDT_info]
3733 ;; perhaps do something with IDT here
3735 ;; set PE bit in CR0
3739 ;; far jump to flush CPU queue after transition to protected mode
3740 JMP_AP(0x0020, protected_mode)
3743 ;; GDT points to valid descriptor table, now load SS, DS, ES
3744 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3746 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3748 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3754 movsw ;; move CX words from DS:SI to ES:DI
3756 ;; make sure DS and ES limits are 64KB
3761 ;; reset PG bit in CR0 ???
3766 ;; far jump to flush CPU queue after transition to real mode
3767 JMP_AP(0xf000, real_mode)
3770 ;; restore IDT to normal real-mode defaults
3772 lidt [rmode_IDT_info]
3774 // restore SS:SP from the BDA
3782 set_enable_a20(prev_a20_enable);
3784 // turn back on interrupts
3795 // Get the amount of extended memory (above 1M)
3797 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3800 regs.u.r8.al = inb_cmos(0x30);
3801 regs.u.r8.ah = inb_cmos(0x31);
3804 if(regs.u.r16.ax > 0x3c00)
3805 regs.u.r16.ax = 0x3c00;
3812 /* Device busy interrupt. Called by Int 16h when no key available */
3816 /* Interrupt complete. Called by Int 16h when key becomes available */
3820 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3822 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3828 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3833 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3843 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3845 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3849 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3850 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3852 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3857 #if BX_USE_PS2_MOUSE
3859 int15_function_mouse(regs, ES, DS, FLAGS)
3860 pusha_regs_t regs; // REGS pushed via pusha
3861 Bit16u ES, DS, FLAGS;
3863 Bit16u ebda_seg=read_word(0x0040,0x000E);
3864 Bit8u mouse_flags_1, mouse_flags_2;
3865 Bit16u mouse_driver_seg;
3866 Bit16u mouse_driver_offset;
3867 Bit8u comm_byte, prev_command_byte;
3868 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3870 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3872 switch (regs.u.r8.ah) {
3874 // Return Codes status in AH
3875 // =========================
3877 // 01: invalid subfunction (AL > 7)
3878 // 02: invalid input value (out of allowable range)
3879 // 03: interface error
3880 // 04: resend command received from mouse controller,
3881 // device driver should attempt command again
3882 // 05: cannot enable mouse, since no far call has been installed
3883 // 80/86: mouse service not implemented
3885 switch (regs.u.r8.al) {
3886 case 0: // Disable/Enable Mouse
3887 BX_DEBUG_INT15("case 0:\n");
3888 switch (regs.u.r8.bh) {
3889 case 0: // Disable Mouse
3890 BX_DEBUG_INT15("case 0: disable mouse\n");
3891 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3892 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3894 ret = get_mouse_data(&mouse_data1);
3895 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3908 case 1: // Enable Mouse
3909 BX_DEBUG_INT15("case 1: enable mouse\n");
3910 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3911 if ( (mouse_flags_2 & 0x80) == 0 ) {
3912 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3914 regs.u.r8.ah = 5; // no far call installed
3917 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3918 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3920 ret = get_mouse_data(&mouse_data1);
3921 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3922 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3932 default: // invalid subfunction
3933 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3935 regs.u.r8.ah = 1; // invalid subfunction
3940 case 1: // Reset Mouse
3941 case 5: // Initialize Mouse
3942 BX_DEBUG_INT15("case 1 or 5:\n");
3943 if (regs.u.r8.al == 5) {
3944 if (regs.u.r8.bh != 3) {
3946 regs.u.r8.ah = 0x02; // invalid input
3949 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3950 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3951 mouse_flags_1 = 0x00;
3952 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3953 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3956 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3957 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3959 ret = get_mouse_data(&mouse_data3);
3960 // if no mouse attached, it will return RESEND
3961 if (mouse_data3 == 0xfe) {
3965 if (mouse_data3 != 0xfa)
3966 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3968 ret = get_mouse_data(&mouse_data1);
3970 ret = get_mouse_data(&mouse_data2);
3972 // turn IRQ12 and packet generation on
3973 enable_mouse_int_and_events();
3976 regs.u.r8.bl = mouse_data1;
3977 regs.u.r8.bh = mouse_data2;
3989 case 2: // Set Sample Rate
3990 BX_DEBUG_INT15("case 2:\n");
3991 switch (regs.u.r8.bh) {
3992 case 0: mouse_data1 = 10; break; // 10 reports/sec
3993 case 1: mouse_data1 = 20; break; // 20 reports/sec
3994 case 2: mouse_data1 = 40; break; // 40 reports/sec
3995 case 3: mouse_data1 = 60; break; // 60 reports/sec
3996 case 4: mouse_data1 = 80; break; // 80 reports/sec
3997 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3998 case 6: mouse_data1 = 200; break; // 200 reports/sec
3999 default: mouse_data1 = 0;
4001 if (mouse_data1 > 0) {
4002 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4004 ret = get_mouse_data(&mouse_data2);
4005 ret = send_to_mouse_ctrl(mouse_data1);
4006 ret = get_mouse_data(&mouse_data2);
4012 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4017 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4021 case 3: // Set Resolution
4022 BX_DEBUG_INT15("case 3:\n");
4024 // 0 = 25 dpi, 1 count per millimeter
4025 // 1 = 50 dpi, 2 counts per millimeter
4026 // 2 = 100 dpi, 4 counts per millimeter
4027 // 3 = 200 dpi, 8 counts per millimeter
4032 case 4: // Get Device ID
4033 BX_DEBUG_INT15("case 4:\n");
4034 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4035 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4037 ret = get_mouse_data(&mouse_data1);
4038 ret = get_mouse_data(&mouse_data2);
4041 regs.u.r8.bh = mouse_data2;
4045 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4049 case 6: // Return Status & Set Scaling Factor...
4050 BX_DEBUG_INT15("case 6:\n");
4051 switch (regs.u.r8.bh) {
4052 case 0: // Return Status
4053 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4054 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4056 ret = get_mouse_data(&mouse_data1);
4057 if (mouse_data1 != 0xfa)
4058 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4060 ret = get_mouse_data(&mouse_data1);
4062 ret = get_mouse_data(&mouse_data2);
4064 ret = get_mouse_data(&mouse_data3);
4068 regs.u.r8.bl = mouse_data1;
4069 regs.u.r8.cl = mouse_data2;
4070 regs.u.r8.dl = mouse_data3;
4071 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4082 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4085 case 1: // Set Scaling Factor to 1:1
4086 case 2: // Set Scaling Factor to 2:1
4087 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4088 if (regs.u.r8.bh == 1) {
4089 ret = send_to_mouse_ctrl(0xE6);
4091 ret = send_to_mouse_ctrl(0xE7);
4094 get_mouse_data(&mouse_data1);
4095 ret = (mouse_data1 != 0xFA);
4103 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4105 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4109 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4113 case 7: // Set Mouse Handler Address
4114 BX_DEBUG_INT15("case 7:\n");
4115 mouse_driver_seg = ES;
4116 mouse_driver_offset = regs.u.r16.bx;
4117 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4118 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4119 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4120 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4121 /* remove handler */
4122 if ( (mouse_flags_2 & 0x80) != 0 ) {
4123 mouse_flags_2 &= ~0x80;
4124 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4128 /* install handler */
4129 mouse_flags_2 |= 0x80;
4131 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4137 BX_DEBUG_INT15("case default:\n");
4138 regs.u.r8.ah = 1; // invalid function
4144 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4145 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4147 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4154 int15_function32(regs, ES, DS, FLAGS)
4155 pushad_regs_t regs; // REGS pushed via pushad
4156 Bit16u ES, DS, FLAGS;
4158 Bit32u extended_memory_size=0; // 64bits long
4161 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4163 switch (regs.u.r8.ah) {
4165 // Wait for CX:DX microseconds. currently using the
4166 // refresh request port 0x61 bit4, toggling every 15usec
4174 ;; Get the count in eax
4177 mov ax, _int15_function.CX [bx]
4180 mov ax, _int15_function.DX [bx]
4182 ;; convert to numbers of 15usec ticks
4188 ;; wait for ecx number of refresh requests
4209 switch(regs.u.r8.al)
4211 case 0x20: // coded by osmaker aka K.J.
4212 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4214 #if defined(HVMASSIST) && 0
4215 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4217 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4219 BX_DEBUG_INT15("OK bx=%x\n",regs.u.r16.bx);
4221 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4222 memcpyb(ES, regs.u.r16.di,
4223 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4225 regs.u.r32.ebx += 0x14;
4226 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4228 regs.u.r32.eax = 0x534D4150;
4229 regs.u.r32.ecx = 0x14;
4232 } else if (regs.u.r16.bx == 1) {
4233 extended_memory_size = inb_cmos(0x35);
4234 extended_memory_size <<= 8;
4235 extended_memory_size |= inb_cmos(0x34);
4236 extended_memory_size *= 64;
4237 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4239 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4241 extended_memory_size *= 1024;
4242 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4244 if (extended_memory_size <= 15728640)
4246 extended_memory_size = inb_cmos(0x31);
4247 extended_memory_size <<= 8;
4248 extended_memory_size |= inb_cmos(0x30);
4249 extended_memory_size *= 1024;
4252 write_word(ES, regs.u.r16.di, 0x0000);
4253 write_word(ES, regs.u.r16.di+2, 0x0010);
4254 write_word(ES, regs.u.r16.di+4, 0x0000);
4255 write_word(ES, regs.u.r16.di+6, 0x0000);
4257 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4258 extended_memory_size >>= 16;
4259 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4260 extended_memory_size >>= 16;
4261 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4262 extended_memory_size >>= 16;
4263 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4265 write_word(ES, regs.u.r16.di+16, 0x1);
4266 write_word(ES, regs.u.r16.di+18, 0x0);
4269 regs.u.r32.eax = 0x534D4150;
4270 regs.u.r32.ecx = 0x14;
4273 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4274 goto int15_unimplemented;
4277 switch(regs.u.r16.bx)
4280 write_word(ES, regs.u.r16.di, 0x00);
4281 write_word(ES, regs.u.r16.di+2, 0x00);
4282 write_word(ES, regs.u.r16.di+4, 0x00);
4283 write_word(ES, regs.u.r16.di+6, 0x00);
4285 write_word(ES, regs.u.r16.di+8, 0xFC00);
4286 write_word(ES, regs.u.r16.di+10, 0x0009);
4287 write_word(ES, regs.u.r16.di+12, 0x0000);
4288 write_word(ES, regs.u.r16.di+14, 0x0000);
4290 write_word(ES, regs.u.r16.di+16, 0x1);
4291 write_word(ES, regs.u.r16.di+18, 0x0);
4295 regs.u.r32.eax = 0x534D4150;
4296 regs.u.r32.ecx = 0x14;
4301 extended_memory_size = inb_cmos(0x35);
4302 extended_memory_size <<= 8;
4303 extended_memory_size |= inb_cmos(0x34);
4304 extended_memory_size *= 64;
4305 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4307 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4309 extended_memory_size *= 1024;
4310 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4312 if(extended_memory_size <= 15728640)
4314 extended_memory_size = inb_cmos(0x31);
4315 extended_memory_size <<= 8;
4316 extended_memory_size |= inb_cmos(0x30);
4317 extended_memory_size *= 1024;
4320 write_word(ES, regs.u.r16.di, 0x0000);
4321 write_word(ES, regs.u.r16.di+2, 0x0010);
4322 write_word(ES, regs.u.r16.di+4, 0x0000);
4323 write_word(ES, regs.u.r16.di+6, 0x0000);
4325 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4326 extended_memory_size >>= 16;
4327 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4328 extended_memory_size >>= 16;
4329 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4330 extended_memory_size >>= 16;
4331 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4333 write_word(ES, regs.u.r16.di+16, 0x1);
4334 write_word(ES, regs.u.r16.di+18, 0x0);
4337 regs.u.r32.eax = 0x534D4150;
4338 regs.u.r32.ecx = 0x14;
4342 default: /* AX=E820, DX=534D4150, BX unrecognized */
4343 goto int15_unimplemented;
4348 // if DX != 0x534D4150)
4349 goto int15_unimplemented;
4354 // do we have any reason to fail here ?
4357 // my real system sets ax and bx to 0
4358 // this is confirmed by Ralph Brown list
4359 // but syslinux v1.48 is known to behave
4360 // strangely if ax is set to 0
4361 // regs.u.r16.ax = 0;
4362 // regs.u.r16.bx = 0;
4364 // Get the amount of extended memory (above 1M)
4365 regs.u.r8.cl = inb_cmos(0x30);
4366 regs.u.r8.ch = inb_cmos(0x31);
4369 if(regs.u.r16.cx > 0x3c00)
4371 regs.u.r16.cx = 0x3c00;
4374 // Get the amount of extended memory above 16M in 64k blocs
4375 regs.u.r8.dl = inb_cmos(0x34);
4376 regs.u.r8.dh = inb_cmos(0x35);
4378 // Set configured memory equal to extended memory
4379 regs.u.r16.ax = regs.u.r16.cx;
4380 regs.u.r16.bx = regs.u.r16.dx;
4382 default: /* AH=0xE8?? but not implemented */
4383 goto int15_unimplemented;
4386 int15_unimplemented:
4387 // fall into the default
4389 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4390 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4392 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4398 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4399 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4401 Bit8u scan_code, ascii_code, shift_flags, count;
4402 Bit16u kbd_code, max;
4404 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4407 case 0x00: /* read keyboard input */
4409 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4410 BX_PANIC("KBD: int16h: out of keyboard input\n");
4412 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4413 else if (ascii_code == 0xE0) ascii_code = 0;
4414 AX = (scan_code << 8) | ascii_code;
4417 case 0x01: /* check keyboard status */
4418 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4422 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4423 else if (ascii_code == 0xE0) ascii_code = 0;
4424 AX = (scan_code << 8) | ascii_code;
4428 case 0x02: /* get shift flag status */
4429 shift_flags = read_byte(0x0040, 0x17);
4430 SET_AL(shift_flags);
4433 case 0x05: /* store key-stroke into buffer */
4434 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4442 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4443 // bit Bochs Description
4445 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4446 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4447 // 4 1 INT 16/AH=0Ah supported
4448 // 3 0 INT 16/AX=0306h supported
4449 // 2 0 INT 16/AX=0305h supported
4450 // 1 0 INT 16/AX=0304h supported
4451 // 0 0 INT 16/AX=0300h supported
4456 case 0x0A: /* GET KEYBOARD ID */
4462 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4464 if ((inb(0x60) == 0xfa)) {
4467 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4470 kbd_code |= (inb(0x60) << 8);
4472 } while (--count>0);
4478 case 0x10: /* read MF-II keyboard input */
4480 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4481 BX_PANIC("KBD: int16h: out of keyboard input\n");
4483 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4484 AX = (scan_code << 8) | ascii_code;
4487 case 0x11: /* check MF-II keyboard status */
4488 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4492 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4493 AX = (scan_code << 8) | ascii_code;
4497 case 0x12: /* get extended keyboard status */
4498 shift_flags = read_byte(0x0040, 0x17);
4499 SET_AL(shift_flags);
4500 shift_flags = read_byte(0x0040, 0x18);
4501 SET_AH(shift_flags);
4502 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4505 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4506 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4509 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4510 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4514 if (GET_AL() == 0x08)
4515 SET_AH(0x02); // unsupported, aka normal keyboard
4518 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4523 dequeue_key(scan_code, ascii_code, incr)
4528 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4533 buffer_start = 0x001E;
4534 buffer_end = 0x003E;
4536 buffer_start = read_word(0x0040, 0x0080);
4537 buffer_end = read_word(0x0040, 0x0082);
4540 buffer_head = read_word(0x0040, 0x001a);
4541 buffer_tail = read_word(0x0040, 0x001c);
4543 if (buffer_head != buffer_tail) {
4545 acode = read_byte(0x0040, buffer_head);
4546 scode = read_byte(0x0040, buffer_head+1);
4547 write_byte(ss, ascii_code, acode);
4548 write_byte(ss, scan_code, scode);
4552 if (buffer_head >= buffer_end)
4553 buffer_head = buffer_start;
4554 write_word(0x0040, 0x001a, buffer_head);
4563 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4566 inhibit_mouse_int_and_events()
4568 Bit8u command_byte, prev_command_byte;
4570 // Turn off IRQ generation and aux data line
4571 if ( inb(0x64) & 0x02 )
4572 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4573 outb(0x64, 0x20); // get command byte
4574 while ( (inb(0x64) & 0x01) != 0x01 );
4575 prev_command_byte = inb(0x60);
4576 command_byte = prev_command_byte;
4577 //while ( (inb(0x64) & 0x02) );
4578 if ( inb(0x64) & 0x02 )
4579 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4580 command_byte &= 0xfd; // turn off IRQ 12 generation
4581 command_byte |= 0x20; // disable mouse serial clock line
4582 outb(0x64, 0x60); // write command byte
4583 outb(0x60, command_byte);
4584 return(prev_command_byte);
4588 enable_mouse_int_and_events()
4592 // Turn on IRQ generation and aux data line
4593 if ( inb(0x64) & 0x02 )
4594 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4595 outb(0x64, 0x20); // get command byte
4596 while ( (inb(0x64) & 0x01) != 0x01 );
4597 command_byte = inb(0x60);
4598 //while ( (inb(0x64) & 0x02) );
4599 if ( inb(0x64) & 0x02 )
4600 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4601 command_byte |= 0x02; // turn on IRQ 12 generation
4602 command_byte &= 0xdf; // enable mouse serial clock line
4603 outb(0x64, 0x60); // write command byte
4604 outb(0x60, command_byte);
4608 send_to_mouse_ctrl(sendbyte)
4613 // wait for chance to write to ctrl
4614 if ( inb(0x64) & 0x02 )
4615 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4617 outb(0x60, sendbyte);
4623 get_mouse_data(data)
4629 while ( (inb(0x64) & 0x21) != 0x21 ) {
4632 response = inb(0x60);
4635 write_byte(ss, data, response);
4640 set_kbd_command_byte(command_byte)
4643 if ( inb(0x64) & 0x02 )
4644 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4647 outb(0x64, 0x60); // write command byte
4648 outb(0x60, command_byte);
4652 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4653 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4655 Bit8u scancode, asciicode, shift_flags;
4656 Bit8u mf2_flags, mf2_state, led_flags;
4659 // DS has been set to F000 before call
4663 scancode = GET_AL();
4665 if (scancode == 0) {
4666 BX_INFO("KBD: int09 handler: AL=0\n");
4671 shift_flags = read_byte(0x0040, 0x17);
4672 mf2_flags = read_byte(0x0040, 0x18);
4673 mf2_state = read_byte(0x0040, 0x96);
4674 led_flags = read_byte(0x0040, 0x97);
4678 case 0x3a: /* Caps Lock press */
4679 shift_flags ^= 0x40;
4680 write_byte(0x0040, 0x17, shift_flags);
4682 write_byte(0x0040, 0x18, mf2_flags);
4684 write_byte(0x0040, 0x97, led_flags);
4686 case 0xba: /* Caps Lock release */
4688 write_byte(0x0040, 0x18, mf2_flags);
4691 case 0x2a: /* L Shift press */
4692 /*shift_flags &= ~0x40;*/
4693 shift_flags |= 0x02;
4694 write_byte(0x0040, 0x17, shift_flags);
4696 write_byte(0x0040, 0x97, led_flags);
4698 case 0xaa: /* L Shift release */
4699 shift_flags &= ~0x02;
4700 write_byte(0x0040, 0x17, shift_flags);
4703 case 0x36: /* R Shift press */
4704 /*shift_flags &= ~0x40;*/
4705 shift_flags |= 0x01;
4706 write_byte(0x0040, 0x17, shift_flags);
4708 write_byte(0x0040, 0x97, led_flags);
4710 case 0xb6: /* R Shift release */
4711 shift_flags &= ~0x01;
4712 write_byte(0x0040, 0x17, shift_flags);
4715 case 0x1d: /* Ctrl press */
4716 shift_flags |= 0x04;
4717 write_byte(0x0040, 0x17, shift_flags);
4718 if (mf2_state & 0x01) {
4723 write_byte(0x0040, 0x18, mf2_flags);
4725 case 0x9d: /* Ctrl release */
4726 shift_flags &= ~0x04;
4727 write_byte(0x0040, 0x17, shift_flags);
4728 if (mf2_state & 0x01) {
4733 write_byte(0x0040, 0x18, mf2_flags);
4736 case 0x38: /* Alt press */
4737 shift_flags |= 0x08;
4738 write_byte(0x0040, 0x17, shift_flags);
4739 if (mf2_state & 0x01) {
4744 write_byte(0x0040, 0x18, mf2_flags);
4746 case 0xb8: /* Alt release */
4747 shift_flags &= ~0x08;
4748 write_byte(0x0040, 0x17, shift_flags);
4749 if (mf2_state & 0x01) {
4754 write_byte(0x0040, 0x18, mf2_flags);
4757 case 0x45: /* Num Lock press */
4758 if ((mf2_state & 0x01) == 0) {
4760 write_byte(0x0040, 0x18, mf2_flags);
4761 shift_flags ^= 0x20;
4763 write_byte(0x0040, 0x17, shift_flags);
4764 write_byte(0x0040, 0x97, led_flags);
4767 case 0xc5: /* Num Lock release */
4768 if ((mf2_state & 0x01) == 0) {
4770 write_byte(0x0040, 0x18, mf2_flags);
4774 case 0x46: /* Scroll Lock press */
4776 write_byte(0x0040, 0x18, mf2_flags);
4777 shift_flags ^= 0x10;
4779 write_byte(0x0040, 0x17, shift_flags);
4780 write_byte(0x0040, 0x97, led_flags);
4783 case 0xc6: /* Scroll Lock release */
4785 write_byte(0x0040, 0x18, mf2_flags);
4789 if (scancode & 0x80) return; /* toss key releases ... */
4790 if (scancode > MAX_SCAN_CODE) {
4791 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4794 if (shift_flags & 0x08) { /* ALT */
4795 asciicode = scan_to_scanascii[scancode].alt;
4796 scancode = scan_to_scanascii[scancode].alt >> 8;
4798 else if (shift_flags & 0x04) { /* CONTROL */
4799 asciicode = scan_to_scanascii[scancode].control;
4800 scancode = scan_to_scanascii[scancode].control >> 8;
4802 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4803 /* check if lock state should be ignored
4804 * because a SHIFT key are pressed */
4806 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4807 asciicode = scan_to_scanascii[scancode].normal;
4808 scancode = scan_to_scanascii[scancode].normal >> 8;
4811 asciicode = scan_to_scanascii[scancode].shift;
4812 scancode = scan_to_scanascii[scancode].shift >> 8;
4816 /* check if lock is on */
4817 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4818 asciicode = scan_to_scanascii[scancode].shift;
4819 scancode = scan_to_scanascii[scancode].shift >> 8;
4822 asciicode = scan_to_scanascii[scancode].normal;
4823 scancode = scan_to_scanascii[scancode].normal >> 8;
4826 if (scancode==0 && asciicode==0) {
4827 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4829 enqueue_key(scancode, asciicode);
4836 enqueue_key(scan_code, ascii_code)
4837 Bit8u scan_code, ascii_code;
4839 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4841 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4842 // scan_code, ascii_code);
4845 buffer_start = 0x001E;
4846 buffer_end = 0x003E;
4848 buffer_start = read_word(0x0040, 0x0080);
4849 buffer_end = read_word(0x0040, 0x0082);
4852 buffer_head = read_word(0x0040, 0x001A);
4853 buffer_tail = read_word(0x0040, 0x001C);
4855 temp_tail = buffer_tail;
4857 if (buffer_tail >= buffer_end)
4858 buffer_tail = buffer_start;
4860 if (buffer_tail == buffer_head) {
4864 write_byte(0x0040, temp_tail, ascii_code);
4865 write_byte(0x0040, temp_tail+1, scan_code);
4866 write_word(0x0040, 0x001C, buffer_tail);
4872 int74_function(make_farcall, Z, Y, X, status)
4873 Bit16u make_farcall, Z, Y, X, status;
4875 Bit16u ebda_seg=read_word(0x0040,0x000E);
4876 Bit8u in_byte, index, package_count;
4877 Bit8u mouse_flags_1, mouse_flags_2;
4879 BX_DEBUG_INT74("entering int74_function\n");
4882 in_byte = inb(0x64);
4883 if ( (in_byte & 0x21) != 0x21 ) {
4886 in_byte = inb(0x60);
4887 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4889 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4890 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4892 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4893 // BX_PANIC("int74_function:\n");
4897 package_count = mouse_flags_2 & 0x07;
4898 index = mouse_flags_1 & 0x07;
4899 write_byte(ebda_seg, 0x28 + index, in_byte);
4901 if ( (index+1) >= package_count ) {
4902 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4903 status = read_byte(ebda_seg, 0x0028 + 0);
4904 X = read_byte(ebda_seg, 0x0028 + 1);
4905 Y = read_byte(ebda_seg, 0x0028 + 2);
4908 // check if far call handler installed
4909 if (mouse_flags_2 & 0x80)
4915 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4918 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4923 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4924 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4927 Bit16u ebda_seg=read_word(0x0040,0x000E);
4928 Bit16u cylinder, head, sector;
4929 Bit16u segment, offset;
4930 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4932 Bit8u device, status;
4934 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4936 write_byte(0x0040, 0x008e, 0); // clear completion flag
4938 // basic check : device has to be defined
4939 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4940 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4944 // Get the ata channel
4945 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4947 // basic check : device has to be valid
4948 if (device >= BX_MAX_ATA_DEVICES) {
4949 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4955 case 0x00: /* disk controller reset */
4960 case 0x01: /* read disk status */
4961 status = read_byte(0x0040, 0x0074);
4963 SET_DISK_RET_STATUS(0);
4964 /* set CF if error status read */
4965 if (status) goto int13_fail_nostatus;
4966 else goto int13_success_noah;
4969 case 0x02: // read disk sectors
4970 case 0x03: // write disk sectors
4971 case 0x04: // verify disk sectors
4974 cylinder = GET_CH();
4975 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4976 sector = (GET_CL() & 0x3f);
4982 if ( (count > 128) || (count == 0) ) {
4983 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4987 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4988 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4989 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4991 // sanity check on cyl heads, sec
4992 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4993 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4998 if ( GET_AH() == 0x04 ) goto int13_success;
5000 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5001 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5003 // if needed, translate lchs to lba, and execute command
5004 if ( (nph != nlh) || (npspt != nlspt)) {
5005 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5006 sector = 0; // this forces the command to be lba
5009 if ( GET_AH() == 0x02 )
5010 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5012 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5014 // Set nb of sector transferred
5015 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5018 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5020 goto int13_fail_noah;
5026 case 0x05: /* format disk track */
5027 BX_INFO("format disk track called\n");
5032 case 0x08: /* read disk drive parameters */
5034 // Get logical geometry from table
5035 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5036 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5037 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5038 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5040 nlc = nlc - 2; /* 0 based , last sector not used */
5043 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5045 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5047 // FIXME should set ES & DI
5052 case 0x10: /* check drive ready */
5053 // should look at 40:8E also???
5055 // Read the status from controller
5056 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5057 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5062 goto int13_fail_noah;
5066 case 0x15: /* read disk drive size */
5068 // Get physical geometry from table
5069 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5070 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5071 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5073 // Compute sector count seen by int13
5074 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5078 SET_AH(3); // hard disk accessible
5079 goto int13_success_noah;
5082 case 0x41: // IBM/MS installation check
5083 BX=0xaa55; // install check
5084 SET_AH(0x30); // EDD 3.0
5085 CX=0x0007; // ext disk access and edd, removable supported
5086 goto int13_success_noah;
5089 case 0x42: // IBM/MS extended read
5090 case 0x43: // IBM/MS extended write
5091 case 0x44: // IBM/MS verify
5092 case 0x47: // IBM/MS extended seek
5094 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5095 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5096 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5098 // Can't use 64 bits lba
5099 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5101 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5105 // Get 32 bits lba and check
5106 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5107 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5108 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5112 // If verify or seek
5113 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5116 // Execute the command
5117 if ( GET_AH() == 0x42 )
5118 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5120 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5122 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5123 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5126 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5128 goto int13_fail_noah;
5134 case 0x45: // IBM/MS lock/unlock drive
5135 case 0x49: // IBM/MS extended media change
5136 goto int13_success; // Always success for HD
5139 case 0x46: // IBM/MS eject media
5140 SET_AH(0xb2); // Volume Not Removable
5141 goto int13_fail_noah; // Always fail for HD
5144 case 0x48: // IBM/MS get drive parameters
5145 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5147 // Buffer is too small
5155 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5156 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5157 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5158 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5159 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5161 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5162 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5163 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5164 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5165 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5166 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5167 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5168 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5173 Bit8u channel, dev, irq, mode, checksum, i, translation;
5174 Bit16u iobase1, iobase2, options;
5176 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5178 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5179 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5182 channel = device / 2;
5183 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5184 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5185 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5186 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5187 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5189 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5190 options |= (1<<4); // lba translation
5191 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5192 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5193 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5195 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5196 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5197 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5198 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5199 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5200 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5201 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5202 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5203 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5204 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5205 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5208 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5209 checksum = ~checksum;
5210 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5215 Bit8u channel, iface, checksum, i;
5218 channel = device / 2;
5219 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5220 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5222 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5223 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5224 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5225 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5226 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5228 if (iface==ATA_IFACE_ISA) {
5229 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5230 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5231 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5232 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5237 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5238 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5239 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5240 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5242 if (iface==ATA_IFACE_ISA) {
5243 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5244 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5245 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5250 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5251 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5252 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5253 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5256 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5257 checksum = ~checksum;
5258 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5264 case 0x4e: // // IBM/MS set hardware configuration
5265 // DMA, prefetch, PIO maximum not supported
5278 case 0x09: /* initialize drive parameters */
5279 case 0x0c: /* seek to specified cylinder */
5280 case 0x0d: /* alternate disk reset */
5281 case 0x11: /* recalibrate */
5282 case 0x14: /* controller internal diagnostic */
5283 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5287 case 0x0a: /* read disk sectors with ECC */
5288 case 0x0b: /* write disk sectors with ECC */
5289 case 0x18: // set media type for format
5290 case 0x50: // IBM/MS send packet command
5292 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5298 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5300 SET_DISK_RET_STATUS(GET_AH());
5301 int13_fail_nostatus:
5302 SET_CF(); // error occurred
5306 SET_AH(0x00); // no error
5308 SET_DISK_RET_STATUS(0x00);
5309 CLEAR_CF(); // no error
5313 // ---------------------------------------------------------------------------
5314 // Start of int13 for cdrom
5315 // ---------------------------------------------------------------------------
5318 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5319 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5321 Bit16u ebda_seg=read_word(0x0040,0x000E);
5322 Bit8u device, status, locks;
5325 Bit16u count, segment, offset, i, size;
5327 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5328 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5330 SET_DISK_RET_STATUS(0x00);
5332 /* basic check : device should be 0xE0+ */
5333 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5334 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5338 // Get the ata channel
5339 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5341 /* basic check : device has to be valid */
5342 if (device >= BX_MAX_ATA_DEVICES) {
5343 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5349 // all those functions return SUCCESS
5350 case 0x00: /* disk controller reset */
5351 case 0x09: /* initialize drive parameters */
5352 case 0x0c: /* seek to specified cylinder */
5353 case 0x0d: /* alternate disk reset */
5354 case 0x10: /* check drive ready */
5355 case 0x11: /* recalibrate */
5356 case 0x14: /* controller internal diagnostic */
5357 case 0x16: /* detect disk change */
5361 // all those functions return disk write-protected
5362 case 0x03: /* write disk sectors */
5363 case 0x05: /* format disk track */
5364 case 0x43: // IBM/MS extended write
5366 goto int13_fail_noah;
5369 case 0x01: /* read disk status */
5370 status = read_byte(0x0040, 0x0074);
5372 SET_DISK_RET_STATUS(0);
5374 /* set CF if error status read */
5375 if (status) goto int13_fail_nostatus;
5376 else goto int13_success_noah;
5379 case 0x15: /* read disk drive size */
5381 goto int13_fail_noah;
5384 case 0x41: // IBM/MS installation check
5385 BX=0xaa55; // install check
5386 SET_AH(0x30); // EDD 2.1
5387 CX=0x0007; // ext disk access, removable and edd
5388 goto int13_success_noah;
5391 case 0x42: // IBM/MS extended read
5392 case 0x44: // IBM/MS verify sectors
5393 case 0x47: // IBM/MS extended seek
5395 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5396 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5397 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5399 // Can't use 64 bits lba
5400 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5402 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5407 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5409 // If verify or seek
5410 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5413 memsetb(get_SS(),atacmd,0,12);
5414 atacmd[0]=0x28; // READ command
5415 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5416 atacmd[8]=(count & 0x00ff); // Sectors
5417 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5418 atacmd[3]=(lba & 0x00ff0000) >> 16;
5419 atacmd[4]=(lba & 0x0000ff00) >> 8;
5420 atacmd[5]=(lba & 0x000000ff);
5421 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5423 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5424 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5427 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5429 goto int13_fail_noah;
5435 case 0x45: // IBM/MS lock/unlock drive
5436 if (GET_AL() > 2) goto int13_fail;
5438 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5442 if (locks == 0xff) {
5445 goto int13_fail_noah;
5447 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5451 if (locks == 0x00) {
5454 goto int13_fail_noah;
5456 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5457 SET_AL(locks==0?0:1);
5460 SET_AL(locks==0?0:1);
5466 case 0x46: // IBM/MS eject media
5467 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5470 SET_AH(0xb1); // media locked
5471 goto int13_fail_noah;
5473 // FIXME should handle 0x31 no media in device
5474 // FIXME should handle 0xb5 valid request failed
5476 // Call removable media eject
5483 mov _int13_cdrom.status + 2[bp], ah
5484 jnc int13_cdrom_rme_end
5485 mov _int13_cdrom.status, #1
5486 int13_cdrom_rme_end:
5491 SET_AH(0xb1); // media locked
5492 goto int13_fail_noah;
5498 case 0x48: // IBM/MS get drive parameters
5499 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5501 // Buffer is too small
5507 Bit16u cylinders, heads, spt, blksize;
5509 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5511 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5512 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5513 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5514 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5515 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5516 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5517 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5518 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5523 Bit8u channel, dev, irq, mode, checksum, i;
5524 Bit16u iobase1, iobase2, options;
5526 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5528 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5529 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5532 channel = device / 2;
5533 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5534 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5535 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5536 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5538 // FIXME atapi device
5539 options = (1<<4); // lba translation
5540 options |= (1<<5); // removable device
5541 options |= (1<<6); // atapi device
5542 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5544 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5545 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5546 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5547 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5548 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5549 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5550 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5551 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5552 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5553 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5554 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5557 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5558 checksum = ~checksum;
5559 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5564 Bit8u channel, iface, checksum, i;
5567 channel = device / 2;
5568 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5569 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5571 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5572 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5573 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5574 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5575 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5577 if (iface==ATA_IFACE_ISA) {
5578 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5579 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5580 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5581 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5586 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5587 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5588 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5589 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5591 if (iface==ATA_IFACE_ISA) {
5592 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5593 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5594 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5599 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5600 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5601 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5602 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5605 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5606 checksum = ~checksum;
5607 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5613 case 0x49: // IBM/MS extended media change
5614 // always send changed ??
5616 goto int13_fail_nostatus;
5619 case 0x4e: // // IBM/MS set hardware configuration
5620 // DMA, prefetch, PIO maximum not supported
5633 // all those functions return unimplemented
5634 case 0x02: /* read sectors */
5635 case 0x04: /* verify sectors */
5636 case 0x08: /* read disk drive parameters */
5637 case 0x0a: /* read disk sectors with ECC */
5638 case 0x0b: /* write disk sectors with ECC */
5639 case 0x18: /* set media type for format */
5640 case 0x50: // ? - send packet command
5642 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5648 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5650 SET_DISK_RET_STATUS(GET_AH());
5651 int13_fail_nostatus:
5652 SET_CF(); // error occurred
5656 SET_AH(0x00); // no error
5658 SET_DISK_RET_STATUS(0x00);
5659 CLEAR_CF(); // no error
5663 // ---------------------------------------------------------------------------
5664 // End of int13 for cdrom
5665 // ---------------------------------------------------------------------------
5667 #if BX_ELTORITO_BOOT
5668 // ---------------------------------------------------------------------------
5669 // Start of int13 for eltorito functions
5670 // ---------------------------------------------------------------------------
5673 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5674 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5676 Bit16u ebda_seg=read_word(0x0040,0x000E);
5678 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5679 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5683 // FIXME ElTorito Various. Should be implemented
5684 case 0x4a: // ElTorito - Initiate disk emu
5685 case 0x4c: // ElTorito - Initiate disk emu and boot
5686 case 0x4d: // ElTorito - Return Boot catalog
5687 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5691 case 0x4b: // ElTorito - Terminate disk emu
5692 // FIXME ElTorito Hardcoded
5693 write_byte(DS,SI+0x00,0x13);
5694 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5695 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5696 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5697 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5698 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5699 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5700 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5701 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5702 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5703 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5704 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5706 // If we have to terminate emulation
5707 if(GET_AL() == 0x00) {
5708 // FIXME ElTorito Various. Should be handled accordingly to spec
5709 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5716 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5722 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5723 SET_DISK_RET_STATUS(GET_AH());
5724 SET_CF(); // error occurred
5728 SET_AH(0x00); // no error
5729 SET_DISK_RET_STATUS(0x00);
5730 CLEAR_CF(); // no error
5734 // ---------------------------------------------------------------------------
5735 // End of int13 for eltorito functions
5736 // ---------------------------------------------------------------------------
5738 // ---------------------------------------------------------------------------
5739 // Start of int13 when emulating a device from the cd
5740 // ---------------------------------------------------------------------------
5743 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5744 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5746 Bit16u ebda_seg=read_word(0x0040,0x000E);
5747 Bit8u device, status;
5748 Bit16u vheads, vspt, vcylinders;
5749 Bit16u head, sector, cylinder, nbsectors;
5750 Bit32u vlba, ilba, slba, elba;
5751 Bit16u before, segment, offset;
5754 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5755 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5757 /* at this point, we are emulating a floppy/harddisk */
5759 // Recompute the device number
5760 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5761 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5763 SET_DISK_RET_STATUS(0x00);
5765 /* basic checks : emulation should be active, dl should equal the emulated drive */
5766 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5767 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5768 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5774 // all those functions return SUCCESS
5775 case 0x00: /* disk controller reset */
5776 case 0x09: /* initialize drive parameters */
5777 case 0x0c: /* seek to specified cylinder */
5778 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5779 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5780 case 0x11: /* recalibrate */
5781 case 0x14: /* controller internal diagnostic */
5782 case 0x16: /* detect disk change */
5786 // all those functions return disk write-protected
5787 case 0x03: /* write disk sectors */
5788 case 0x05: /* format disk track */
5790 goto int13_fail_noah;
5793 case 0x01: /* read disk status */
5794 status=read_byte(0x0040, 0x0074);
5796 SET_DISK_RET_STATUS(0);
5798 /* set CF if error status read */
5799 if (status) goto int13_fail_nostatus;
5800 else goto int13_success_noah;
5803 case 0x02: // read disk sectors
5804 case 0x04: // verify disk sectors
5805 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5806 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5807 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5809 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5811 sector = GET_CL() & 0x003f;
5812 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5814 nbsectors = GET_AL();
5818 // no sector to read ?
5819 if(nbsectors==0) goto int13_success;
5821 // sanity checks sco openserver needs this!
5823 || (cylinder >= vcylinders)
5824 || (head >= vheads)) {
5828 // After controls, verify do nothing
5829 if (GET_AH() == 0x04) goto int13_success;
5831 segment = ES+(BX / 16);
5834 // calculate the virtual lba inside the image
5835 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5837 // In advance so we don't loose the count
5841 slba = (Bit32u)vlba/4;
5842 before= (Bit16u)vlba%4;
5845 elba = (Bit32u)(vlba+nbsectors-1)/4;
5847 memsetb(get_SS(),atacmd,0,12);
5848 atacmd[0]=0x28; // READ command
5849 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5850 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5851 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5852 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5853 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5854 atacmd[5]=(ilba+slba & 0x000000ff);
5855 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5856 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5859 goto int13_fail_noah;
5865 case 0x08: /* read disk drive parameters */
5866 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5867 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5868 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5872 SET_CH( vcylinders & 0xff );
5873 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5875 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5876 // FIXME ElTorito Harddisk. should send the HD count
5878 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5879 case 0x01: SET_BL( 0x02 ); break;
5880 case 0x02: SET_BL( 0x04 ); break;
5881 case 0x03: SET_BL( 0x06 ); break;
5887 mov ax, #diskette_param_table2
5888 mov _int13_cdemu.DI+2[bp], ax
5889 mov _int13_cdemu.ES+2[bp], cs
5895 case 0x15: /* read disk drive size */
5896 // FIXME ElTorito Harddisk. What geometry to send ?
5898 goto int13_success_noah;
5901 // all those functions return unimplemented
5902 case 0x0a: /* read disk sectors with ECC */
5903 case 0x0b: /* write disk sectors with ECC */
5904 case 0x18: /* set media type for format */
5905 case 0x41: // IBM/MS installation check
5906 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5907 case 0x42: // IBM/MS extended read
5908 case 0x43: // IBM/MS extended write
5909 case 0x44: // IBM/MS verify sectors
5910 case 0x45: // IBM/MS lock/unlock drive
5911 case 0x46: // IBM/MS eject media
5912 case 0x47: // IBM/MS extended seek
5913 case 0x48: // IBM/MS get drive parameters
5914 case 0x49: // IBM/MS extended media change
5915 case 0x4e: // ? - set hardware configuration
5916 case 0x50: // ? - send packet command
5918 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5924 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5926 SET_DISK_RET_STATUS(GET_AH());
5927 int13_fail_nostatus:
5928 SET_CF(); // error occurred
5932 SET_AH(0x00); // no error
5934 SET_DISK_RET_STATUS(0x00);
5935 CLEAR_CF(); // no error
5939 // ---------------------------------------------------------------------------
5940 // End of int13 when emulating a device from the cd
5941 // ---------------------------------------------------------------------------
5943 #endif // BX_ELTORITO_BOOT
5945 #else //BX_USE_ATADRV
5948 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5963 mov ax,4[bp] // cylinder
5965 mov bl,6[bp] // hd_heads
5968 mov bl,8[bp] // head
5970 mov bl,10[bp] // hd_sectors
5972 mov bl,12[bp] // sector
6001 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6002 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6004 Bit8u drive, num_sectors, sector, head, status, mod;
6008 Bit16u max_cylinder, cylinder, total_sectors;
6009 Bit16u hd_cylinders;
6010 Bit8u hd_heads, hd_sectors;
6017 Bit16u count, segment, offset;
6021 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6023 write_byte(0x0040, 0x008e, 0); // clear completion flag
6025 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6027 /* check how many disks first (cmos reg 0x12), return an error if
6028 drive not present */
6029 drive_map = inb_cmos(0x12);
6030 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6031 (((drive_map & 0x0f)==0) ? 0 : 2);
6032 n_drives = (drive_map==0) ? 0 :
6033 ((drive_map==3) ? 2 : 1);
6035 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6037 SET_DISK_RET_STATUS(0x01);
6038 SET_CF(); /* error occurred */
6044 case 0x00: /* disk controller reset */
6045 BX_DEBUG_INT13_HD("int13_f00\n");
6048 SET_DISK_RET_STATUS(0);
6049 set_diskette_ret_status(0);
6050 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6051 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6052 CLEAR_CF(); /* successful */
6056 case 0x01: /* read disk status */
6057 BX_DEBUG_INT13_HD("int13_f01\n");
6058 status = read_byte(0x0040, 0x0074);
6060 SET_DISK_RET_STATUS(0);
6061 /* set CF if error status read */
6062 if (status) SET_CF();
6067 case 0x04: // verify disk sectors
6068 case 0x02: // read disk sectors
6070 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6072 num_sectors = GET_AL();
6073 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6074 sector = (GET_CL() & 0x3f);
6078 if (hd_cylinders > 1024) {
6079 if (hd_cylinders <= 2048) {
6082 else if (hd_cylinders <= 4096) {
6085 else if (hd_cylinders <= 8192) {
6088 else { // hd_cylinders <= 16384
6092 ax = head / hd_heads;
6093 cyl_mod = ax & 0xff;
6095 cylinder |= cyl_mod;
6098 if ( (cylinder >= hd_cylinders) ||
6099 (sector > hd_sectors) ||
6100 (head >= hd_heads) ) {
6102 SET_DISK_RET_STATUS(1);
6103 SET_CF(); /* error occurred */
6107 if ( (num_sectors > 128) || (num_sectors == 0) )
6108 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6111 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6113 if ( GET_AH() == 0x04 ) {
6115 SET_DISK_RET_STATUS(0);
6120 status = inb(0x1f7);
6121 if (status & 0x80) {
6122 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6124 outb(0x01f2, num_sectors);
6125 /* activate LBA? (tomv) */
6126 if (hd_heads > 16) {
6127 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6128 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6131 outb(0x01f3, sector);
6132 outb(0x01f4, cylinder & 0x00ff);
6133 outb(0x01f5, cylinder >> 8);
6134 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6139 status = inb(0x1f7);
6140 if ( !(status & 0x80) ) break;
6143 if (status & 0x01) {
6144 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6145 } else if ( !(status & 0x08) ) {
6146 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6147 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6154 sti ;; enable higher priority interrupts
6159 ;; store temp bx in real DI register
6162 mov di, _int13_harddisk.tempbx + 2 [bp]
6165 ;; adjust if there will be an overrun
6167 jbe i13_f02_no_adjust
6169 sub di, #0x0200 ; sub 512 bytes from offset
6171 add ax, #0x0020 ; add 512 to segment
6175 mov cx, #0x0100 ;; counter (256 words = 512b)
6176 mov dx, #0x01f0 ;; AT data read port
6179 insw ;; CX words transfered from port(DX) to ES:[DI]
6182 ;; store real DI register back to temp bx
6185 mov _int13_harddisk.tempbx + 2 [bp], di
6191 if (num_sectors == 0) {
6192 status = inb(0x1f7);
6193 if ( (status & 0xc9) != 0x40 )
6194 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6198 status = inb(0x1f7);
6199 if ( (status & 0xc9) != 0x48 )
6200 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6206 SET_DISK_RET_STATUS(0);
6207 SET_AL(sector_count);
6208 CLEAR_CF(); /* successful */
6213 case 0x03: /* write disk sectors */
6214 BX_DEBUG_INT13_HD("int13_f03\n");
6215 drive = GET_ELDL ();
6216 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6218 num_sectors = GET_AL();
6219 cylinder = GET_CH();
6220 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6221 sector = (GET_CL() & 0x3f);
6224 if (hd_cylinders > 1024) {
6225 if (hd_cylinders <= 2048) {
6228 else if (hd_cylinders <= 4096) {
6231 else if (hd_cylinders <= 8192) {
6234 else { // hd_cylinders <= 16384
6238 ax = head / hd_heads;
6239 cyl_mod = ax & 0xff;
6241 cylinder |= cyl_mod;
6244 if ( (cylinder >= hd_cylinders) ||
6245 (sector > hd_sectors) ||
6246 (head >= hd_heads) ) {
6248 SET_DISK_RET_STATUS(1);
6249 SET_CF(); /* error occurred */
6253 if ( (num_sectors > 128) || (num_sectors == 0) )
6254 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6257 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6259 status = inb(0x1f7);
6260 if (status & 0x80) {
6261 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6263 // should check for Drive Ready Bit also in status reg
6264 outb(0x01f2, num_sectors);
6266 /* activate LBA? (tomv) */
6267 if (hd_heads > 16) {
6268 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6269 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6272 outb(0x01f3, sector);
6273 outb(0x01f4, cylinder & 0x00ff);
6274 outb(0x01f5, cylinder >> 8);
6275 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6279 // wait for busy bit to turn off after seeking
6281 status = inb(0x1f7);
6282 if ( !(status & 0x80) ) break;
6285 if ( !(status & 0x08) ) {
6286 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6287 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6294 sti ;; enable higher priority interrupts
6299 ;; store temp bx in real SI register
6302 mov si, _int13_harddisk.tempbx + 2 [bp]
6305 ;; adjust if there will be an overrun
6307 jbe i13_f03_no_adjust
6309 sub si, #0x0200 ; sub 512 bytes from offset
6311 add ax, #0x0020 ; add 512 to segment
6315 mov cx, #0x0100 ;; counter (256 words = 512b)
6316 mov dx, #0x01f0 ;; AT data read port
6320 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6322 ;; store real SI register back to temp bx
6325 mov _int13_harddisk.tempbx + 2 [bp], si
6331 if (num_sectors == 0) {
6332 status = inb(0x1f7);
6333 if ( (status & 0xe9) != 0x40 )
6334 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6338 status = inb(0x1f7);
6339 if ( (status & 0xc9) != 0x48 )
6340 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6346 SET_DISK_RET_STATUS(0);
6347 SET_AL(sector_count);
6348 CLEAR_CF(); /* successful */
6352 case 0x05: /* format disk track */
6353 BX_DEBUG_INT13_HD("int13_f05\n");
6354 BX_PANIC("format disk track called\n");
6357 SET_DISK_RET_STATUS(0);
6358 CLEAR_CF(); /* successful */
6362 case 0x08: /* read disk drive parameters */
6363 BX_DEBUG_INT13_HD("int13_f08\n");
6365 drive = GET_ELDL ();
6366 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6370 if (hd_cylinders <= 1024) {
6371 // hd_cylinders >>= 0;
6374 else if (hd_cylinders <= 2048) {
6378 else if (hd_cylinders <= 4096) {
6382 else if (hd_cylinders <= 8192) {
6386 else { // hd_cylinders <= 16384
6391 max_cylinder = hd_cylinders - 2; /* 0 based */
6393 SET_CH(max_cylinder & 0xff);
6394 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6395 SET_DH(hd_heads - 1);
6396 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6398 SET_DISK_RET_STATUS(0);
6399 CLEAR_CF(); /* successful */
6404 case 0x09: /* initialize drive parameters */
6405 BX_DEBUG_INT13_HD("int13_f09\n");
6407 SET_DISK_RET_STATUS(0);
6408 CLEAR_CF(); /* successful */
6412 case 0x0a: /* read disk sectors with ECC */
6413 BX_DEBUG_INT13_HD("int13_f0a\n");
6414 case 0x0b: /* write disk sectors with ECC */
6415 BX_DEBUG_INT13_HD("int13_f0b\n");
6416 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6420 case 0x0c: /* seek to specified cylinder */
6421 BX_DEBUG_INT13_HD("int13_f0c\n");
6422 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6424 SET_DISK_RET_STATUS(0);
6425 CLEAR_CF(); /* successful */
6429 case 0x0d: /* alternate disk reset */
6430 BX_DEBUG_INT13_HD("int13_f0d\n");
6432 SET_DISK_RET_STATUS(0);
6433 CLEAR_CF(); /* successful */
6437 case 0x10: /* check drive ready */
6438 BX_DEBUG_INT13_HD("int13_f10\n");
6440 //SET_DISK_RET_STATUS(0);
6441 //CLEAR_CF(); /* successful */
6445 // should look at 40:8E also???
6446 status = inb(0x01f7);
6447 if ( (status & 0xc0) == 0x40 ) {
6449 SET_DISK_RET_STATUS(0);
6450 CLEAR_CF(); // drive ready
6455 SET_DISK_RET_STATUS(0xAA);
6456 SET_CF(); // not ready
6461 case 0x11: /* recalibrate */
6462 BX_DEBUG_INT13_HD("int13_f11\n");
6464 SET_DISK_RET_STATUS(0);
6465 CLEAR_CF(); /* successful */
6469 case 0x14: /* controller internal diagnostic */
6470 BX_DEBUG_INT13_HD("int13_f14\n");
6472 SET_DISK_RET_STATUS(0);
6473 CLEAR_CF(); /* successful */
6478 case 0x15: /* read disk drive size */
6480 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6484 mov al, _int13_harddisk.hd_heads + 2 [bp]
6485 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6486 mul al, ah ;; ax = heads * sectors
6487 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6488 dec bx ;; use (cylinders - 1) ???
6489 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6490 ;; now we need to move the 32bit result dx:ax to what the
6491 ;; BIOS wants which is cx:dx.
6492 ;; and then into CX:DX on the stack
6493 mov _int13_harddisk.CX + 2 [bp], dx
6494 mov _int13_harddisk.DX + 2 [bp], ax
6497 SET_AH(3); // hard disk accessible
6498 SET_DISK_RET_STATUS(0); // ??? should this be 0
6499 CLEAR_CF(); // successful
6503 case 0x18: // set media type for format
6504 case 0x41: // IBM/MS
6505 case 0x42: // IBM/MS
6506 case 0x43: // IBM/MS
6507 case 0x44: // IBM/MS
6508 case 0x45: // IBM/MS lock/unlock drive
6509 case 0x46: // IBM/MS eject media
6510 case 0x47: // IBM/MS extended seek
6511 case 0x49: // IBM/MS extended media change
6512 case 0x50: // IBM/MS send packet command
6514 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6516 SET_AH(1); // code=invalid function in AH or invalid parameter
6517 SET_DISK_RET_STATUS(1);
6518 SET_CF(); /* unsuccessful */
6524 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6525 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6528 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6530 Bit16u *hd_cylinders;
6540 if (drive == 0x80) {
6541 hd_type = inb_cmos(0x12) & 0xf0;
6542 if (hd_type != 0xf0)
6543 BX_INFO(panic_msg_reg12h,0);
6544 hd_type = inb_cmos(0x19); // HD0: extended type
6546 BX_INFO(panic_msg_reg19h,0,0x19);
6549 hd_type = inb_cmos(0x12) & 0x0f;
6550 if (hd_type != 0x0f)
6551 BX_INFO(panic_msg_reg12h,1);
6552 hd_type = inb_cmos(0x1a); // HD0: extended type
6554 BX_INFO(panic_msg_reg19h,0,0x1a);
6559 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6560 write_word(ss, hd_cylinders, cylinders);
6563 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6565 // sectors per track
6566 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6569 #endif //else BX_USE_ATADRV
6572 //////////////////////
6573 // FLOPPY functions //
6574 //////////////////////
6577 floppy_media_known(drive)
6581 Bit16u media_state_offset;
6583 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6590 media_state_offset = 0x0090;
6592 media_state_offset += 1;
6594 val8 = read_byte(0x0040, media_state_offset);
6595 val8 = (val8 >> 4) & 0x01;
6599 // check pass, return KNOWN
6604 floppy_media_sense(drive)
6608 Bit16u media_state_offset;
6609 Bit8u drive_type, config_data, media_state;
6611 if (floppy_drive_recal(drive) == 0) {
6615 // for now cheat and get drive type from CMOS,
6616 // assume media is same as drive type
6618 // ** config_data **
6619 // Bitfields for diskette media control:
6620 // Bit(s) Description (Table M0028)
6621 // 7-6 last data rate set by controller
6622 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6623 // 5-4 last diskette drive step rate selected
6624 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6625 // 3-2 {data rate at start of operation}
6628 // ** media_state **
6629 // Bitfields for diskette drive media state:
6630 // Bit(s) Description (Table M0030)
6632 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6633 // 5 double stepping required (e.g. 360kB in 1.2MB)
6634 // 4 media type established
6635 // 3 drive capable of supporting 4MB media
6636 // 2-0 on exit from BIOS, contains
6637 // 000 trying 360kB in 360kB
6638 // 001 trying 360kB in 1.2MB
6639 // 010 trying 1.2MB in 1.2MB
6640 // 011 360kB in 360kB established
6641 // 100 360kB in 1.2MB established
6642 // 101 1.2MB in 1.2MB established
6644 // 111 all other formats/drives
6646 drive_type = inb_cmos(0x10);
6651 if ( drive_type == 1 ) {
6653 config_data = 0x00; // 0000 0000
6654 media_state = 0x25; // 0010 0101
6657 else if ( drive_type == 2 ) {
6658 // 1.2 MB 5.25" drive
6659 config_data = 0x00; // 0000 0000
6660 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6663 else if ( drive_type == 3 ) {
6665 config_data = 0x00; // 0000 0000 ???
6666 media_state = 0x17; // 0001 0111
6669 else if ( drive_type == 4 ) {
6670 // 1.44 MB 3.5" drive
6671 config_data = 0x00; // 0000 0000
6672 media_state = 0x17; // 0001 0111
6675 else if ( drive_type == 5 ) {
6676 // 2.88 MB 3.5" drive
6677 config_data = 0xCC; // 1100 1100
6678 media_state = 0xD7; // 1101 0111
6682 // Extended floppy size uses special cmos setting
6683 else if ( drive_type == 6 ) {
6685 config_data = 0x00; // 0000 0000
6686 media_state = 0x27; // 0010 0111
6689 else if ( drive_type == 7 ) {
6691 config_data = 0x00; // 0000 0000
6692 media_state = 0x27; // 0010 0111
6695 else if ( drive_type == 8 ) {
6697 config_data = 0x00; // 0000 0000
6698 media_state = 0x27; // 0010 0111
6704 config_data = 0x00; // 0000 0000
6705 media_state = 0x00; // 0000 0000
6710 media_state_offset = 0x90;
6712 media_state_offset = 0x91;
6713 write_byte(0x0040, 0x008B, config_data);
6714 write_byte(0x0040, media_state_offset, media_state);
6720 floppy_drive_recal(drive)
6724 Bit16u curr_cyl_offset;
6726 // set 40:3e bit 7 to 0
6727 val8 = read_byte(0x0000, 0x043e);
6729 write_byte(0x0000, 0x043e, val8);
6731 // turn on motor of selected drive, DMA & int enabled, normal operation
6740 // reset the disk motor timeout value of INT 08
6741 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6743 // check port 3f4 for drive readiness
6745 if ( (val8 & 0xf0) != 0x80 )
6746 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6748 // send Recalibrate command (2 bytes) to controller
6749 outb(0x03f5, 0x07); // 07: Recalibrate
6750 outb(0x03f5, drive); // 0=drive0, 1=drive1
6752 // turn on interrupts
6757 // wait on 40:3e bit 7 to become 1
6758 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6759 while ( val8 == 0 ) {
6760 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6763 val8 = 0; // separate asm from while() loop
6764 // turn off interrupts
6769 // set 40:3e bit 7 to 0, and calibrated bit
6770 val8 = read_byte(0x0000, 0x043e);
6773 val8 |= 0x02; // Drive 1 calibrated
6774 curr_cyl_offset = 0x0095;
6777 val8 |= 0x01; // Drive 0 calibrated
6778 curr_cyl_offset = 0x0094;
6780 write_byte(0x0040, 0x003e, val8);
6781 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6789 floppy_drive_exists(drive)
6794 // just tell it both drives exist - PAD
6797 // check CMOS to see if drive exists
6798 drive_type = inb_cmos(0x10);
6803 if ( drive_type == 0 )
6809 #if BX_SUPPORT_FLOPPY
6811 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6812 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6814 Bit8u drive, num_sectors, track, sector, head, status;
6815 Bit16u base_address, base_count, base_es;
6816 Bit8u page, mode_register, val8, dor;
6817 Bit8u return_status[7];
6818 Bit8u drive_type, num_floppies, ah;
6819 Bit16u es, last_addr;
6822 //printf("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6823 BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(),get_DS(), ES, DI, SI);
6828 case 0x00: // diskette controller reset
6829 BX_DEBUG_INT13_FL("floppy f00\n");
6832 SET_AH(1); // invalid param
6833 set_diskette_ret_status(1);
6837 drive_type = inb_cmos(0x10);
6843 if (drive_type == 0) {
6844 SET_AH(0x80); // drive not responding
6845 set_diskette_ret_status(0x80);
6850 set_diskette_ret_status(0);
6851 CLEAR_CF(); // successful
6852 set_diskette_current_cyl(drive, 0); // current cylinder
6855 case 0x01: // Read Diskette Status
6857 val8 = read_byte(0x0000, 0x0441);
6864 case 0x02: // Read Diskette Sectors
6865 case 0x03: // Write Diskette Sectors
6866 case 0x04: // Verify Diskette Sectors
6867 num_sectors = GET_AL();
6873 if ( (drive > 1) || (head > 1) ||
6874 (num_sectors == 0) || (num_sectors > 72) ) {
6875 BX_INFO("floppy: drive>1 || head>1 ...\n");
6877 set_diskette_ret_status(1);
6878 SET_AL(0); // no sectors read
6879 SET_CF(); // error occurred
6883 // see if drive exists
6884 if (floppy_drive_exists(drive) == 0) {
6885 SET_AH(0x80); // not responding
6886 set_diskette_ret_status(0x80);
6887 SET_AL(0); // no sectors read
6888 SET_CF(); // error occurred
6892 // see if media in drive, and type is known
6893 if (floppy_media_known(drive) == 0) {
6894 if (floppy_media_sense(drive) == 0) {
6895 SET_AH(0x0C); // Media type not found
6896 set_diskette_ret_status(0x0C);
6897 SET_AL(0); // no sectors read
6898 SET_CF(); // error occurred
6904 // Read Diskette Sectors
6906 //-----------------------------------
6907 // set up DMA controller for transfer
6908 //-----------------------------------
6910 // es:bx = pointer to where to place information from diskette
6911 // port 04: DMA-1 base and current address, channel 2
6912 // port 05: DMA-1 base and current count, channel 2
6913 page = (ES >> 12); // upper 4 bits
6914 base_es = (ES << 4); // lower 16bits contributed by ES
6915 base_address = base_es + BX; // lower 16 bits of address
6916 // contributed by ES:BX
6917 if ( base_address < base_es ) {
6918 // in case of carry, adjust page by 1
6921 base_count = (num_sectors * 512) - 1;
6923 // check for 64K boundary overrun
6924 last_addr = base_address + base_count;
6925 if (last_addr < base_address) {
6927 set_diskette_ret_status(0x09);
6928 SET_AL(0); // no sectors read
6929 SET_CF(); // error occurred
6933 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6936 BX_DEBUG_INT13_FL("clear flip-flop\n");
6937 outb(0x000c, 0x00); // clear flip-flop
6938 outb(0x0004, base_address);
6939 outb(0x0004, base_address>>8);
6940 BX_DEBUG_INT13_FL("clear flip-flop\n");
6941 outb(0x000c, 0x00); // clear flip-flop
6942 outb(0x0005, base_count);
6943 outb(0x0005, base_count>>8);
6945 // port 0b: DMA-1 Mode Register
6946 mode_register = 0x46; // single mode, increment, autoinit disable,
6947 // transfer type=write, channel 2
6948 BX_DEBUG_INT13_FL("setting mode register\n");
6949 outb(0x000b, mode_register);
6951 BX_DEBUG_INT13_FL("setting page register\n");
6952 // port 81: DMA-1 Page Register, channel 2
6955 BX_DEBUG_INT13_FL("unmask chan 2\n");
6956 outb(0x000a, 0x02); // unmask channel 2
6958 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6961 //--------------------------------------
6962 // set up floppy controller for transfer
6963 //--------------------------------------
6965 // set 40:3e bit 7 to 0
6966 val8 = read_byte(0x0000, 0x043e);
6968 write_byte(0x0000, 0x043e, val8);
6970 // turn on motor of selected drive, DMA & int enabled, normal operation
6979 // reset the disk motor timeout value of INT 08
6980 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6982 // check port 3f4 for drive readiness
6984 if ( (val8 & 0xf0) != 0x80 )
6985 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6987 // send read-normal-data command (9 bytes) to controller
6988 outb(0x03f5, 0xe6); // e6: read normal data
6989 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6990 outb(0x03f5, track);
6992 outb(0x03f5, sector);
6993 outb(0x03f5, 2); // 512 byte sector size
6994 outb(0x03f5, 0); // last sector number possible on track
6995 outb(0x03f5, 0); // Gap length
6996 outb(0x03f5, 0xff); // Gap length
6998 // turn on interrupts
7003 // wait on 40:3e bit 7 to become 1
7004 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7005 while ( val8 == 0 ) {
7006 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7009 val8 = 0; // separate asm from while() loop
7010 // turn off interrupts
7015 // set 40:3e bit 7 to 0
7016 val8 = read_byte(0x0000, 0x043e);
7018 write_byte(0x0000, 0x043e, val8);
7020 // check port 3f4 for accessibility to status bytes
7022 if ( (val8 & 0xc0) != 0xc0 )
7023 BX_PANIC("int13_diskette: ctrl not ready\n");
7025 // read 7 return status bytes from controller
7026 // using loop index broken, have to unroll...
7027 return_status[0] = inb(0x3f5);
7028 return_status[1] = inb(0x3f5);
7029 return_status[2] = inb(0x3f5);
7030 return_status[3] = inb(0x3f5);
7031 return_status[4] = inb(0x3f5);
7032 return_status[5] = inb(0x3f5);
7033 return_status[6] = inb(0x3f5);
7034 // record in BIOS Data Area
7035 write_byte(0x0040, 0x0042, return_status[0]);
7036 write_byte(0x0040, 0x0043, return_status[1]);
7037 write_byte(0x0040, 0x0044, return_status[2]);
7038 write_byte(0x0040, 0x0045, return_status[3]);
7039 write_byte(0x0040, 0x0046, return_status[4]);
7040 write_byte(0x0040, 0x0047, return_status[5]);
7041 write_byte(0x0040, 0x0048, return_status[6]);
7043 if ( (return_status[0] & 0xc0) != 0 ) {
7045 set_diskette_ret_status(0x20);
7046 SET_AL(0); // no sectors read
7047 SET_CF(); // error occurred
7051 // ??? should track be new val from return_status[3] ?
7052 set_diskette_current_cyl(drive, track);
7053 // AL = number of sectors read (same value as passed)
7054 SET_AH(0x00); // success
7055 CLEAR_CF(); // success
7058 else if (ah == 0x03) {
7059 // Write Diskette Sectors
7061 //-----------------------------------
7062 // set up DMA controller for transfer
7063 //-----------------------------------
7065 // es:bx = pointer to where to place information from diskette
7066 // port 04: DMA-1 base and current address, channel 2
7067 // port 05: DMA-1 base and current count, channel 2
7068 page = (ES >> 12); // upper 4 bits
7069 base_es = (ES << 4); // lower 16bits contributed by ES
7070 base_address = base_es + BX; // lower 16 bits of address
7071 // contributed by ES:BX
7072 if ( base_address < base_es ) {
7073 // in case of carry, adjust page by 1
7076 base_count = (num_sectors * 512) - 1;
7078 // check for 64K boundary overrun
7079 last_addr = base_address + base_count;
7080 if (last_addr < base_address) {
7082 set_diskette_ret_status(0x09);
7083 SET_AL(0); // no sectors read
7084 SET_CF(); // error occurred
7088 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7091 outb(0x000c, 0x00); // clear flip-flop
7092 outb(0x0004, base_address);
7093 outb(0x0004, base_address>>8);
7094 outb(0x000c, 0x00); // clear flip-flop
7095 outb(0x0005, base_count);
7096 outb(0x0005, base_count>>8);
7098 // port 0b: DMA-1 Mode Register
7099 mode_register = 0x4a; // single mode, increment, autoinit disable,
7100 // transfer type=read, channel 2
7101 outb(0x000b, mode_register);
7103 // port 81: DMA-1 Page Register, channel 2
7106 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7109 //--------------------------------------
7110 // set up floppy controller for transfer
7111 //--------------------------------------
7113 // set 40:3e bit 7 to 0
7114 val8 = read_byte(0x0000, 0x043e);
7116 write_byte(0x0000, 0x043e, val8);
7118 // turn on motor of selected drive, DMA & int enabled, normal operation
7127 // reset the disk motor timeout value of INT 08
7128 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7130 // check port 3f4 for drive readiness
7132 if ( (val8 & 0xf0) != 0x80 )
7133 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7135 // send read-normal-data command (9 bytes) to controller
7136 outb(0x03f5, 0xc5); // c5: write normal data
7137 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7138 outb(0x03f5, track);
7140 outb(0x03f5, sector);
7141 outb(0x03f5, 2); // 512 byte sector size
7142 outb(0x03f5, 0); // last sector number possible on track
7143 outb(0x03f5, 0); // Gap length
7144 outb(0x03f5, 0xff); // Gap length
7146 // turn on interrupts
7151 // wait on 40:3e bit 7 to become 1
7152 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7153 while ( val8 == 0 ) {
7154 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7157 val8 = 0; // separate asm from while() loop
7158 // turn off interrupts
7163 // set 40:3e bit 7 to 0
7164 val8 = read_byte(0x0000, 0x043e);
7166 write_byte(0x0000, 0x043e, val8);
7168 // check port 3f4 for accessibility to status bytes
7170 if ( (val8 & 0xc0) != 0xc0 )
7171 BX_PANIC("int13_diskette: ctrl not ready\n");
7173 // read 7 return status bytes from controller
7174 // using loop index broken, have to unroll...
7175 return_status[0] = inb(0x3f5);
7176 return_status[1] = inb(0x3f5);
7177 return_status[2] = inb(0x3f5);
7178 return_status[3] = inb(0x3f5);
7179 return_status[4] = inb(0x3f5);
7180 return_status[5] = inb(0x3f5);
7181 return_status[6] = inb(0x3f5);
7182 // record in BIOS Data Area
7183 write_byte(0x0040, 0x0042, return_status[0]);
7184 write_byte(0x0040, 0x0043, return_status[1]);
7185 write_byte(0x0040, 0x0044, return_status[2]);
7186 write_byte(0x0040, 0x0045, return_status[3]);
7187 write_byte(0x0040, 0x0046, return_status[4]);
7188 write_byte(0x0040, 0x0047, return_status[5]);
7189 write_byte(0x0040, 0x0048, return_status[6]);
7191 if ( (return_status[0] & 0xc0) != 0 ) {
7192 if ( (return_status[1] & 0x02) != 0 ) {
7193 // diskette not writable.
7194 // AH=status code=0x03 (tried to write on write-protected disk)
7195 // AL=number of sectors written=0
7200 BX_PANIC("int13_diskette_function: read error\n");
7204 // ??? should track be new val from return_status[3] ?
7205 set_diskette_current_cyl(drive, track);
7206 // AL = number of sectors read (same value as passed)
7207 SET_AH(0x00); // success
7208 CLEAR_CF(); // success
7211 else { // if (ah == 0x04)
7212 // Verify Diskette Sectors
7214 // ??? should track be new val from return_status[3] ?
7215 set_diskette_current_cyl(drive, track);
7216 // AL = number of sectors verified (same value as passed)
7217 CLEAR_CF(); // success
7218 SET_AH(0x00); // success
7223 case 0x05: // format diskette track
7224 BX_DEBUG_INT13_FL("floppy f05\n");
7226 num_sectors = GET_AL();
7231 if ((drive > 1) || (head > 1) || (track > 79) ||
7232 (num_sectors == 0) || (num_sectors > 18)) {
7234 set_diskette_ret_status(1);
7235 SET_CF(); // error occurred
7238 // see if drive exists
7239 if (floppy_drive_exists(drive) == 0) {
7240 SET_AH(0x80); // drive not responding
7241 set_diskette_ret_status(0x80);
7242 SET_CF(); // error occurred
7246 // see if media in drive, and type is known
7247 if (floppy_media_known(drive) == 0) {
7248 if (floppy_media_sense(drive) == 0) {
7249 SET_AH(0x0C); // Media type not found
7250 set_diskette_ret_status(0x0C);
7251 SET_AL(0); // no sectors read
7252 SET_CF(); // error occurred
7257 // set up DMA controller for transfer
7258 page = (ES >> 12); // upper 4 bits
7259 base_es = (ES << 4); // lower 16bits contributed by ES
7260 base_address = base_es + BX; // lower 16 bits of address
7261 // contributed by ES:BX
7262 if ( base_address < base_es ) {
7263 // in case of carry, adjust page by 1
7266 base_count = (num_sectors * 4) - 1;
7268 // check for 64K boundary overrun
7269 last_addr = base_address + base_count;
7270 if (last_addr < base_address) {
7272 set_diskette_ret_status(0x09);
7273 SET_AL(0); // no sectors read
7274 SET_CF(); // error occurred
7279 outb(0x000c, 0x00); // clear flip-flop
7280 outb(0x0004, base_address);
7281 outb(0x0004, base_address>>8);
7282 outb(0x000c, 0x00); // clear flip-flop
7283 outb(0x0005, base_count);
7284 outb(0x0005, base_count>>8);
7285 mode_register = 0x4a; // single mode, increment, autoinit disable,
7286 // transfer type=read, channel 2
7287 outb(0x000b, mode_register);
7288 // port 81: DMA-1 Page Register, channel 2
7292 // set up floppy controller for transfer
7293 val8 = read_byte(0x0000, 0x043e);
7295 write_byte(0x0000, 0x043e, val8);
7296 // turn on motor of selected drive, DMA & int enabled, normal operation
7305 // reset the disk motor timeout value of INT 08
7306 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7308 // check port 3f4 for drive readiness
7310 if ( (val8 & 0xf0) != 0x80 )
7311 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7313 // send read-normal-data command (6 bytes) to controller
7314 outb(0x03f5, 0x4d); // 4d: format track
7315 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7316 outb(0x03f5, 2); // 512 byte sector size
7317 outb(0x03f5, num_sectors); // number of sectors per track
7318 outb(0x03f5, 0); // Gap length
7319 outb(0x03f5, 0xf6); // Fill byte
7320 // turn on interrupts
7324 // wait on 40:3e bit 7 to become 1
7325 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7326 while ( val8 == 0 ) {
7327 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7329 val8 = 0; // separate asm from while() loop
7330 // turn off interrupts
7334 // set 40:3e bit 7 to 0
7335 val8 = read_byte(0x0000, 0x043e);
7337 write_byte(0x0000, 0x043e, val8);
7338 // check port 3f4 for accessibility to status bytes
7340 if ( (val8 & 0xc0) != 0xc0 )
7341 BX_PANIC("int13_diskette: ctrl not ready\n");
7343 // read 7 return status bytes from controller
7344 // using loop index broken, have to unroll...
7345 return_status[0] = inb(0x3f5);
7346 return_status[1] = inb(0x3f5);
7347 return_status[2] = inb(0x3f5);
7348 return_status[3] = inb(0x3f5);
7349 return_status[4] = inb(0x3f5);
7350 return_status[5] = inb(0x3f5);
7351 return_status[6] = inb(0x3f5);
7352 // record in BIOS Data Area
7353 write_byte(0x0040, 0x0042, return_status[0]);
7354 write_byte(0x0040, 0x0043, return_status[1]);
7355 write_byte(0x0040, 0x0044, return_status[2]);
7356 write_byte(0x0040, 0x0045, return_status[3]);
7357 write_byte(0x0040, 0x0046, return_status[4]);
7358 write_byte(0x0040, 0x0047, return_status[5]);
7359 write_byte(0x0040, 0x0048, return_status[6]);
7361 if ( (return_status[0] & 0xc0) != 0 ) {
7362 if ( (return_status[1] & 0x02) != 0 ) {
7363 // diskette not writable.
7364 // AH=status code=0x03 (tried to write on write-protected disk)
7365 // AL=number of sectors written=0
7370 BX_PANIC("int13_diskette_function: write error\n");
7375 set_diskette_ret_status(0);
7376 set_diskette_current_cyl(drive, 0);
7377 CLEAR_CF(); // successful
7381 case 0x08: // read diskette drive parameters
7382 BX_DEBUG_INT13_FL("floppy f08\n");
7392 SET_DL(num_floppies);
7397 drive_type = inb_cmos(0x10);
7399 if (drive_type & 0xf0)
7401 if (drive_type & 0x0f)
7413 SET_DL(num_floppies);
7415 switch (drive_type) {
7418 SET_DH(0); // max head #
7421 case 1: // 360KB, 5.25"
7422 CX = 0x2709; // 40 tracks, 9 sectors
7423 SET_DH(1); // max head #
7426 case 2: // 1.2MB, 5.25"
7427 CX = 0x4f0f; // 80 tracks, 15 sectors
7428 SET_DH(1); // max head #
7431 case 3: // 720KB, 3.5"
7432 CX = 0x4f09; // 80 tracks, 9 sectors
7433 SET_DH(1); // max head #
7436 case 4: // 1.44MB, 3.5"
7437 CX = 0x4f12; // 80 tracks, 18 sectors
7438 SET_DH(1); // max head #
7441 case 5: // 2.88MB, 3.5"
7442 CX = 0x4f24; // 80 tracks, 36 sectors
7443 SET_DH(1); // max head #
7446 case 6: // 160k, 5.25"
7447 CX = 0x2708; // 40 tracks, 8 sectors
7448 SET_DH(0); // max head #
7451 case 7: // 180k, 5.25"
7452 CX = 0x2709; // 40 tracks, 9 sectors
7453 SET_DH(0); // max head #
7456 case 8: // 320k, 5.25"
7457 CX = 0x2708; // 40 tracks, 8 sectors
7458 SET_DH(1); // max head #
7462 BX_PANIC("floppy: int13: bad floppy type\n");
7465 /* set es & di to point to 11 byte diskette param table in ROM */
7469 mov ax, #diskette_param_table2
7470 mov _int13_diskette_function.DI+2[bp], ax
7471 mov _int13_diskette_function.ES+2[bp], cs
7474 CLEAR_CF(); // success
7475 /* disk status not changed upon success */
7479 case 0x15: // read diskette drive type
7480 BX_DEBUG_INT13_FL("floppy f15\n");
7483 SET_AH(0); // only 2 drives supported
7484 // set_diskette_ret_status here ???
7488 drive_type = inb_cmos(0x10);
7494 CLEAR_CF(); // successful, not present
7495 if (drive_type==0) {
7496 SET_AH(0); // drive not present
7499 SET_AH(1); // drive present, does not support change line
7504 case 0x16: // get diskette change line status
7505 BX_DEBUG_INT13_FL("floppy f16\n");
7508 SET_AH(0x01); // invalid drive
7509 set_diskette_ret_status(0x01);
7514 SET_AH(0x06); // change line not supported
7515 set_diskette_ret_status(0x06);
7519 case 0x17: // set diskette type for format(old)
7520 BX_DEBUG_INT13_FL("floppy f17\n");
7521 /* not used for 1.44M floppies */
7522 SET_AH(0x01); // not supported
7523 set_diskette_ret_status(1); /* not supported */
7527 case 0x18: // set diskette type for format(new)
7528 BX_DEBUG_INT13_FL("floppy f18\n");
7529 SET_AH(0x01); // do later
7530 set_diskette_ret_status(1);
7535 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7537 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7538 SET_AH(0x01); // ???
7539 set_diskette_ret_status(1);
7545 #else // #if BX_SUPPORT_FLOPPY
7547 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7548 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7552 switch ( GET_AH() ) {
7554 case 0x01: // Read Diskette Status
7556 val8 = read_byte(0x0000, 0x0441);
7565 write_byte(0x0000, 0x0441, 0x01);
7569 #endif // #if BX_SUPPORT_FLOPPY
7572 set_diskette_ret_status(value)
7575 write_byte(0x0040, 0x0041, value);
7579 set_diskette_current_cyl(drive, cyl)
7584 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7585 write_byte(0x0040, 0x0094+drive, cyl);
7589 determine_floppy_media(drive)
7593 Bit8u val8, DOR, ctrl_info;
7595 ctrl_info = read_byte(0x0040, 0x008F);
7603 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7606 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7610 if ( (ctrl_info & 0x04) != 0x04 ) {
7611 // Drive not determined means no drive exists, done.
7616 // check Main Status Register for readiness
7617 val8 = inb(0x03f4) & 0x80; // Main Status Register
7619 BX_PANIC("d_f_m: MRQ bit not set\n");
7623 // existing BDA values
7625 // turn on drive motor
7626 outb(0x03f2, DOR); // Digital Output Register
7629 BX_PANIC("d_f_m: OK so far\n");
7634 int17_function(regs, ds, iret_addr)
7635 pusha_regs_t regs; // regs pushed from PUSHA instruction
7636 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7637 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7639 Bit16u addr,timeout;
7646 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7647 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7648 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7649 if (regs.u.r8.ah == 0) {
7650 outb(addr, regs.u.r8.al);
7652 outb(addr+2, val8 | 0x01); // send strobe
7656 outb(addr+2, val8 & ~0x01);
7657 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7661 if (regs.u.r8.ah == 1) {
7663 outb(addr+2, val8 & ~0x04); // send init
7667 outb(addr+2, val8 | 0x04);
7670 regs.u.r8.ah = (val8 ^ 0x48);
7671 if (!timeout) regs.u.r8.ah |= 0x01;
7672 ClearCF(iret_addr.flags);
7674 SetCF(iret_addr.flags); // Unsupported
7678 // returns bootsegment in ax, drive in bl
7680 int19_function(bseqnr)
7683 Bit16u ebda_seg=read_word(0x0040,0x000E);
7692 // BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7694 // if BX_ELTORITO_BOOT is not defined, old behavior
7695 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7696 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7697 // 0: system boot sequence, first drive C: then A:
7698 // 1: system boot sequence, first drive A: then C:
7699 // else BX_ELTORITO_BOOT is defined
7700 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7701 // CMOS reg 0x3D & 0x0f : 1st boot device
7702 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7703 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7704 // boot device codes:
7705 // 0x00 : not defined
7706 // 0x01 : first floppy
7707 // 0x02 : first harddrive
7708 // 0x03 : first cdrom
7709 // else : boot failure
7711 // Get the boot sequence
7712 #if BX_ELTORITO_BOOT
7713 bootseq=inb_cmos(0x3d);
7714 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7716 if (bseqnr==2) bootseq >>= 4;
7717 if (bseqnr==3) bootseq >>= 8;
7718 if (bootseq<0x10) lastdrive = 1;
7719 bootdrv=0x00; bootcd=0;
7720 switch(bootseq & 0x0f) {
7721 case 0x01: bootdrv=0x00; bootcd=0; break;
7722 case 0x02: bootdrv=0x80; bootcd=0; break;
7723 case 0x03: bootdrv=0x00; bootcd=1; break;
7724 default: return 0x00000000;
7727 bootseq=inb_cmos(0x2d);
7733 bootdrv=0x00; bootcd=0;
7734 if((bootseq&0x20)==0) bootdrv=0x80;
7735 #endif // BX_ELTORITO_BOOT
7737 #if BX_ELTORITO_BOOT
7738 // We have to boot from cd
7740 status = cdrom_boot();
7742 BX_DEBUG("CDBoot:%x\n",status);
7746 if ( (status & 0x00ff) !=0 ) {
7747 print_cdromboot_failure(status);
7748 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7752 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7753 bootdrv = (Bit8u)(status>>8);
7756 #endif // BX_ELTORITO_BOOT
7758 // We have to boot from harddisk or floppy
7769 mov _int19_function.status + 2[bp], ax
7770 mov dl, _int19_function.bootdrv + 2[bp]
7771 mov ax, _int19_function.bootseg + 2[bp]
7772 mov es, ax ;; segment
7773 mov bx, #0x0000 ;; offset
7774 mov ah, #0x02 ;; function 2, read diskette sector
7775 mov al, #0x01 ;; read 1 sector
7776 mov ch, #0x00 ;; track 0
7777 mov cl, #0x01 ;; sector 1
7778 mov dh, #0x00 ;; head 0
7779 int #0x13 ;; read sector
7782 mov _int19_function.status + 2[bp], ax
7790 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7795 // check signature if instructed by cmos reg 0x38, only for floppy
7796 // bootchk = 1 : signature check disabled
7797 // bootchk = 0 : signature check enabled
7798 if (bootdrv != 0) bootchk = 0;
7799 else bootchk = inb_cmos(0x38) & 0x01;
7801 #if BX_ELTORITO_BOOT
7802 // if boot from cd, no signature check
7805 #endif // BX_ELTORITO_BOOT
7808 if (read_word(bootseg,0x1fe) != 0xaa55) {
7809 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7814 #if BX_ELTORITO_BOOT
7815 // Print out the boot string
7816 BX_DEBUG("cdrom_boot: %x\n",status);
7817 print_boot_device(bootcd, bootdrv);
7818 #else // BX_ELTORITO_BOOT
7819 print_boot_device(0, bootdrv);
7820 #endif // BX_ELTORITO_BOOT
7822 BX_DEBUG("boot to %x\n", (((Bit32u)bootdrv) << 16) + bootseg);
7824 // return the boot segment
7825 return (((Bit32u)bootdrv) << 16) + bootseg;
7829 int1a_function(regs, ds, iret_addr)
7830 pusha_regs_t regs; // regs pushed from PUSHA instruction
7831 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7832 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7836 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);
7842 switch (regs.u.r8.ah) {
7843 case 0: // get current clock count
7847 regs.u.r16.cx = BiosData->ticks_high;
7848 regs.u.r16.dx = BiosData->ticks_low;
7849 regs.u.r8.al = BiosData->midnight_flag;
7850 BiosData->midnight_flag = 0; // reset flag
7855 ClearCF(iret_addr.flags); // OK
7858 case 1: // Set Current Clock Count
7862 BiosData->ticks_high = regs.u.r16.cx;
7863 BiosData->ticks_low = regs.u.r16.dx;
7864 BiosData->midnight_flag = 0; // reset flag
7869 ClearCF(iret_addr.flags); // OK
7873 case 2: // Read CMOS Time
7874 if (rtc_updating()) {
7875 SetCF(iret_addr.flags);
7879 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7880 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7881 regs.u.r8.ch = inb_cmos(0x04); // Hours
7882 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7884 regs.u.r8.al = regs.u.r8.ch;
7885 ClearCF(iret_addr.flags); // OK
7888 case 3: // Set CMOS Time
7889 // Using a debugger, I notice the following masking/setting
7890 // of bits in Status Register B, by setting Reg B to
7891 // a few values and getting its value after INT 1A was called.
7893 // try#1 try#2 try#3
7894 // before 1111 1101 0111 1101 0000 0000
7895 // after 0110 0010 0110 0010 0000 0010
7897 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7898 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7899 if (rtc_updating()) {
7901 // fall through as if an update were not in progress
7903 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7904 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7905 outb_cmos(0x04, regs.u.r8.ch); // Hours
7906 // Set Daylight Savings time enabled bit to requested value
7907 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7908 // (reg B already selected)
7909 outb_cmos(0x0b, val8);
7911 regs.u.r8.al = val8; // val last written to Reg B
7912 ClearCF(iret_addr.flags); // OK
7915 case 4: // Read CMOS Date
7917 if (rtc_updating()) {
7918 SetCF(iret_addr.flags);
7921 regs.u.r8.cl = inb_cmos(0x09); // Year
7922 regs.u.r8.dh = inb_cmos(0x08); // Month
7923 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7924 regs.u.r8.ch = inb_cmos(0x32); // Century
7925 regs.u.r8.al = regs.u.r8.ch;
7926 ClearCF(iret_addr.flags); // OK
7929 case 5: // Set CMOS Date
7930 // Using a debugger, I notice the following masking/setting
7931 // of bits in Status Register B, by setting Reg B to
7932 // a few values and getting its value after INT 1A was called.
7934 // try#1 try#2 try#3 try#4
7935 // before 1111 1101 0111 1101 0000 0010 0000 0000
7936 // after 0110 1101 0111 1101 0000 0010 0000 0000
7938 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7939 // My assumption: RegB = (RegB & 01111111b)
7940 if (rtc_updating()) {
7942 SetCF(iret_addr.flags);
7945 outb_cmos(0x09, regs.u.r8.cl); // Year
7946 outb_cmos(0x08, regs.u.r8.dh); // Month
7947 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7948 outb_cmos(0x32, regs.u.r8.ch); // Century
7949 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7950 outb_cmos(0x0b, val8);
7952 regs.u.r8.al = val8; // AL = val last written to Reg B
7953 ClearCF(iret_addr.flags); // OK
7956 case 6: // Set Alarm Time in CMOS
7957 // Using a debugger, I notice the following masking/setting
7958 // of bits in Status Register B, by setting Reg B to
7959 // a few values and getting its value after INT 1A was called.
7961 // try#1 try#2 try#3
7962 // before 1101 1111 0101 1111 0000 0000
7963 // after 0110 1111 0111 1111 0010 0000
7965 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7966 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7967 val8 = inb_cmos(0x0b); // Get Status Reg B
7970 // Alarm interrupt enabled already
7971 SetCF(iret_addr.flags); // Error: alarm in use
7974 if (rtc_updating()) {
7976 // fall through as if an update were not in progress
7978 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7979 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7980 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7981 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7982 // enable Status Reg B alarm bit, clear halt clock bit
7983 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7984 ClearCF(iret_addr.flags); // OK
7987 case 7: // Turn off Alarm
7988 // Using a debugger, I notice the following masking/setting
7989 // of bits in Status Register B, by setting Reg B to
7990 // a few values and getting its value after INT 1A was called.
7992 // try#1 try#2 try#3 try#4
7993 // before 1111 1101 0111 1101 0010 0000 0010 0010
7994 // after 0100 0101 0101 0101 0000 0000 0000 0010
7996 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7997 // My assumption: RegB = (RegB & 01010111b)
7998 val8 = inb_cmos(0x0b); // Get Status Reg B
7999 // clear clock-halt bit, disable alarm bit
8000 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8002 regs.u.r8.al = val8; // val last written to Reg B
8003 ClearCF(iret_addr.flags); // OK
8007 // real mode PCI BIOS functions now handled in assembler code
8008 // this C code handles the error code for information only
8009 if (regs.u.r8.bl == 0xff) {
8010 BX_INFO("PCI BIOS: PCI not present\n");
8011 } else if (regs.u.r8.bl == 0x81) {
8012 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8013 } else if (regs.u.r8.bl == 0x83) {
8014 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8015 } else if (regs.u.r8.bl == 0x86) {
8016 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
8018 regs.u.r8.ah = regs.u.r8.bl;
8019 SetCF(iret_addr.flags);
8024 SetCF(iret_addr.flags); // Unsupported
8029 int70_function(regs, ds, iret_addr)
8030 pusha_regs_t regs; // regs pushed from PUSHA instruction
8031 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8032 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8034 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8035 Bit8u registerB = 0, registerC = 0;
8037 // Check which modes are enabled and have occurred.
8038 registerB = inb_cmos( 0xB );
8039 registerC = inb_cmos( 0xC );
8041 if( ( registerB & 0x60 ) != 0 ) {
8042 if( ( registerC & 0x20 ) != 0 ) {
8043 // Handle Alarm Interrupt.
8050 if( ( registerC & 0x40 ) != 0 ) {
8051 // Handle Periodic Interrupt.
8053 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8054 // Wait Interval (Int 15, AH=83) active.
8055 Bit32u time, toggle;
8057 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8058 if( time < 0x3D1 ) {
8060 Bit16u segment, offset;
8062 offset = read_word( 0x40, 0x98 );
8063 segment = read_word( 0x40, 0x9A );
8064 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8065 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8066 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8068 // Continue waiting.
8070 write_dword( 0x40, 0x9C, time );
8083 ;------------------------------------------
8084 ;- INT74h : PS/2 mouse hardware interrupt -
8085 ;------------------------------------------
8090 push #0x00 ;; placeholder for status
8091 push #0x00 ;; placeholder for X
8092 push #0x00 ;; placeholder for Y
8093 push #0x00 ;; placeholder for Z
8094 push #0x00 ;; placeholder for make_far_call boolean
8095 call _int74_function
8096 pop cx ;; remove make_far_call from stack
8099 ;; make far call to EBDA:0022
8102 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8104 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8109 add sp, #8 ;; pop status, x, y, z
8111 pop ds ;; restore DS
8116 ;; This will perform an IRET, but will retain value of current CF
8117 ;; by altering flags on stack. Better than RETF #02.
8122 and BYTE [bp + 0x06], #0xfe
8128 or BYTE [bp + 0x06], #0x01
8133 ;----------------------
8134 ;- INT13h (relocated) -
8135 ;----------------------
8137 ; int13_relocated is a little bit messed up since I played with it
8138 ; I have to rewrite it:
8139 ; - call a function that detect which function to call
8140 ; - make all called C function get the same parameters list
8144 #if BX_ELTORITO_BOOT
8145 ;; check for an eltorito function
8147 jb int13_not_eltorito
8149 ja int13_not_eltorito
8158 jmp _int13_eltorito ;; ELDX not used
8166 ;; check if emulation active
8167 call _cdemu_isactive
8169 je int13_cdemu_inactive
8171 ;; check if access to the emulated drive
8172 call _cdemu_emulated_drive
8175 cmp al,dl ;; int13 on emulated drive
8190 jmp _int13_cdemu ;; ELDX not used
8193 and dl,#0xE0 ;; mask to get device class, including cdroms
8194 cmp al,dl ;; al is 0x00 or 0x80
8195 jne int13_cdemu_inactive ;; inactive for device class
8207 dec dl ;; real drive is dl - 1
8210 int13_cdemu_inactive:
8216 #endif // BX_ELTORITO_BOOT
8227 push dx ;; push eltorito value of dx instead of sp
8238 ;; now the 16-bit registers can be restored with:
8239 ;; pop ds; pop es; popa; iret
8240 ;; arguments passed to functions should be
8241 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8247 jmp _int13_diskette_function
8256 // ebx is modified: BSD 5.2.1 boot loader problem
8257 // someone should figure out which 32 bit register that actually are used
8274 call _int13_harddisk
8286 int18_handler: ;; Boot Failure routing
8287 call _int18_panic_msg
8294 int19_relocated: ;; Boot function, relocated
8296 ;; int19 was beginning to be really complex, so now it
8297 ;; just calls an C function, that does the work
8298 ;; it returns in BL the boot drive, and in AX the boot segment
8299 ;; the boot segment will be 0x0000 if something has failed
8311 call _int19_function
8314 ;; bl contains the boot drive
8315 ;; ax contains the boot segment or 0 if failure
8317 test ax, ax ;; if ax is 0 try next boot device
8323 call _int19_function
8326 test ax, ax ;; if ax is 0 try next boot device
8332 call _int19_function
8335 test ax, ax ;; if ax is 0 call int18
8339 mov dl, bl ;; set drive so guest os find it
8340 shl eax, #0x04 ;; convert seg to ip
8341 mov 2[bp], ax ;; set ip
8343 shr eax, #0x04 ;; get cs back
8344 and ax, #0xF000 ;; remove what went in ip
8345 mov 4[bp], ax ;; set cs
8347 mov es, ax ;; set es to zero fixes [ 549815 ]
8348 mov [bp], ax ;; set bp to zero
8349 mov ax, #0xaa55 ;; set ok flag
8354 iret ;; Beam me up Scotty
8359 int1c_handler: ;; User Timer Tick
8363 ;----------------------
8364 ;- POST: Floppy Drive -
8365 ;----------------------
8371 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8373 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8375 mov 0x0440, al ;; diskette motor timeout counter: not active
8376 mov 0x0441, al ;; diskette controller status return code
8378 mov 0x0442, al ;; disk & diskette controller status register 0
8379 mov 0x0443, al ;; diskette controller status register 1
8380 mov 0x0444, al ;; diskette controller status register 2
8381 mov 0x0445, al ;; diskette controller cylinder number
8382 mov 0x0446, al ;; diskette controller head number
8383 mov 0x0447, al ;; diskette controller sector number
8384 mov 0x0448, al ;; diskette controller bytes written
8386 mov 0x048b, al ;; diskette configuration data
8388 ;; -----------------------------------------------------------------
8389 ;; (048F) diskette controller information
8391 mov al, #0x10 ;; get CMOS diskette drive type
8394 mov ah, al ;; save byte to AH
8397 shr al, #4 ;; look at top 4 bits for drive 0
8398 jz f0_missing ;; jump if no drive0
8399 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8402 mov bl, #0x00 ;; no drive0
8405 mov al, ah ;; restore from AH
8406 and al, #0x0f ;; look at bottom 4 bits for drive 1
8407 jz f1_missing ;; jump if no drive1
8408 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8410 ;; leave high bits in BL zerod
8411 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8412 ;; -----------------------------------------------------------------
8415 mov 0x0490, al ;; diskette 0 media state
8416 mov 0x0491, al ;; diskette 1 media state
8418 ;; diskette 0,1 operational starting state
8419 ;; drive type has not been determined,
8420 ;; has no changed detection line
8424 mov 0x0494, al ;; diskette 0 current cylinder
8425 mov 0x0495, al ;; diskette 1 current cylinder
8428 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8430 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8431 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8432 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8437 ;--------------------
8438 ;- POST: HARD DRIVE -
8439 ;--------------------
8440 ; relocated here because the primary POST area isnt big enough.
8443 // INT 76h calls INT 15h function ax=9100
8445 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8451 mov 0x0474, al /* hard disk status of last operation */
8452 mov 0x0477, al /* hard disk port offset (XT only ???) */
8453 mov 0x048c, al /* hard disk status register */
8454 mov 0x048d, al /* hard disk error register */
8455 mov 0x048e, al /* hard disk task complete flag */
8457 mov 0x0475, al /* hard disk number attached */
8459 mov 0x0476, al /* hard disk control byte */
8460 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8461 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8462 ;; INT 41h: hard disk 0 configuration pointer
8463 ;; INT 46h: hard disk 1 configuration pointer
8464 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8465 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8467 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8479 cmp al, #47 ;; decimal 47 - user definable
8483 ;; CMOS purpose param table offset
8484 ;; 1b cylinders low 0
8485 ;; 1c cylinders high 1
8487 ;; 1e write pre-comp low 5
8488 ;; 1f write pre-comp high 6
8489 ;; 20 retries/bad map/heads>8 8
8490 ;; 21 landing zone low C
8491 ;; 22 landing zone high D
8492 ;; 23 sectors/track E
8497 ;;; Filling EBDA table for hard disk 0.
8505 mov (0x003d + 0x05), ax ;; write precomp word
8510 mov (0x003d + 0x08), al ;; drive control byte
8519 mov (0x003d + 0x0C), ax ;; landing zone word
8521 mov al, #0x1c ;; get cylinders word in AX
8523 in al, #0x71 ;; high byte
8527 in al, #0x71 ;; low byte
8528 mov bx, ax ;; BX = cylinders
8533 mov cl, al ;; CL = heads
8538 mov dl, al ;; DL = sectors
8541 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8543 hd0_post_physical_chs:
8544 ;; no logical CHS mapping used, just physical CHS
8545 ;; use Standard Fixed Disk Parameter Table (FDPT)
8546 mov (0x003d + 0x00), bx ;; number of physical cylinders
8547 mov (0x003d + 0x02), cl ;; number of physical heads
8548 mov (0x003d + 0x0E), dl ;; number of physical sectors
8551 hd0_post_logical_chs:
8552 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8553 mov (0x003d + 0x09), bx ;; number of physical cylinders
8554 mov (0x003d + 0x0b), cl ;; number of physical heads
8555 mov (0x003d + 0x04), dl ;; number of physical sectors
8556 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8558 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8561 jnbe hd0_post_above_2048
8562 ;; 1024 < c <= 2048 cylinders
8565 jmp hd0_post_store_logical
8567 hd0_post_above_2048:
8569 jnbe hd0_post_above_4096
8570 ;; 2048 < c <= 4096 cylinders
8573 jmp hd0_post_store_logical
8575 hd0_post_above_4096:
8577 jnbe hd0_post_above_8192
8578 ;; 4096 < c <= 8192 cylinders
8581 jmp hd0_post_store_logical
8583 hd0_post_above_8192:
8584 ;; 8192 < c <= 16384 cylinders
8588 hd0_post_store_logical:
8589 mov (0x003d + 0x00), bx ;; number of physical cylinders
8590 mov (0x003d + 0x02), cl ;; number of physical heads
8592 mov cl, #0x0f ;; repeat count
8593 mov si, #0x003d ;; offset to disk0 FDPT
8594 mov al, #0x00 ;; sum
8595 hd0_post_checksum_loop:
8599 jnz hd0_post_checksum_loop
8600 not al ;; now take 2s complement
8603 ;;; Done filling EBDA table for hard disk 0.
8607 ;; is there really a second hard disk? if not, return now
8615 ;; check that the hd type is really 0x0f.
8620 ;; check that the extended type is 47 - user definable
8624 cmp al, #47 ;; decimal 47 - user definable
8629 ;; CMOS purpose param table offset
8630 ;; 0x24 cylinders low 0
8631 ;; 0x25 cylinders high 1
8633 ;; 0x27 write pre-comp low 5
8634 ;; 0x28 write pre-comp high 6
8636 ;; 0x2a landing zone low C
8637 ;; 0x2b landing zone high D
8638 ;; 0x2c sectors/track E
8639 ;;; Fill EBDA table for hard disk 1.
8649 mov (0x004d + 0x05), ax ;; write precomp word
8654 mov (0x004d + 0x08), al ;; drive control byte
8663 mov (0x004d + 0x0C), ax ;; landing zone word
8665 mov al, #0x25 ;; get cylinders word in AX
8667 in al, #0x71 ;; high byte
8671 in al, #0x71 ;; low byte
8672 mov bx, ax ;; BX = cylinders
8677 mov cl, al ;; CL = heads
8682 mov dl, al ;; DL = sectors
8685 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8687 hd1_post_physical_chs:
8688 ;; no logical CHS mapping used, just physical CHS
8689 ;; use Standard Fixed Disk Parameter Table (FDPT)
8690 mov (0x004d + 0x00), bx ;; number of physical cylinders
8691 mov (0x004d + 0x02), cl ;; number of physical heads
8692 mov (0x004d + 0x0E), dl ;; number of physical sectors
8695 hd1_post_logical_chs:
8696 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8697 mov (0x004d + 0x09), bx ;; number of physical cylinders
8698 mov (0x004d + 0x0b), cl ;; number of physical heads
8699 mov (0x004d + 0x04), dl ;; number of physical sectors
8700 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8702 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8705 jnbe hd1_post_above_2048
8706 ;; 1024 < c <= 2048 cylinders
8709 jmp hd1_post_store_logical
8711 hd1_post_above_2048:
8713 jnbe hd1_post_above_4096
8714 ;; 2048 < c <= 4096 cylinders
8717 jmp hd1_post_store_logical
8719 hd1_post_above_4096:
8721 jnbe hd1_post_above_8192
8722 ;; 4096 < c <= 8192 cylinders
8725 jmp hd1_post_store_logical
8727 hd1_post_above_8192:
8728 ;; 8192 < c <= 16384 cylinders
8732 hd1_post_store_logical:
8733 mov (0x004d + 0x00), bx ;; number of physical cylinders
8734 mov (0x004d + 0x02), cl ;; number of physical heads
8736 mov cl, #0x0f ;; repeat count
8737 mov si, #0x004d ;; offset to disk0 FDPT
8738 mov al, #0x00 ;; sum
8739 hd1_post_checksum_loop:
8743 jnz hd1_post_checksum_loop
8744 not al ;; now take 2s complement
8747 ;;; Done filling EBDA table for hard disk 1.
8751 ;--------------------
8752 ;- POST: EBDA segment
8753 ;--------------------
8754 ; relocated here because the primary POST area isnt big enough.
8759 mov byte ptr [0x0], #EBDA_SIZE
8761 xor ax, ax ; mov EBDA seg into 40E
8763 mov word ptr [0x40E], #EBDA_SEG
8766 ;--------------------
8767 ;- POST: EOI + jmp via [0x40:67)
8768 ;--------------------
8769 ; relocated here because the primary POST area isnt big enough.
8779 ;--------------------
8782 out #0xA0, al ;; slave PIC EOI
8785 out #0x20, al ;; master PIC EOI
8788 ;--------------------
8790 ;; in: AL in BCD format
8791 ;; out: AL in binary format, AH will always be 0
8794 and bl, #0x0f ;; bl has low digit
8795 shr al, #4 ;; al has high digit
8797 mul al, bh ;; multiply high digit by 10 (result in AX)
8798 add al, bl ;; then add low digit
8801 ;--------------------
8803 ;; Setup the Timer Ticks Count (0x46C:dword) and
8804 ;; Timer Ticks Roller Flag (0x470:byte)
8805 ;; The Timer Ticks Count needs to be set according to
8806 ;; the current CMOS time, as if ticks have been occurring
8807 ;; at 18.2hz since midnight up to this point. Calculating
8808 ;; this is a little complicated. Here are the factors I gather
8809 ;; regarding this. 14,318,180 hz was the original clock speed,
8810 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8811 ;; at the time, or 4 to drive the CGA video adapter. The div3
8812 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8813 ;; the timer. With a maximum 16bit timer count, this is again
8814 ;; divided down by 65536 to 18.2hz.
8816 ;; 14,318,180 Hz clock
8817 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8818 ;; /4 = 1,193,181 Hz fed to timer
8819 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8820 ;; 1 second = 18.20650736 ticks
8821 ;; 1 minute = 1092.390442 ticks
8822 ;; 1 hour = 65543.42651 ticks
8824 ;; Given the values in the CMOS clock, one could calculate
8825 ;; the number of ticks by the following:
8826 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8827 ;; (BcdToBin(minutes) * 1092.3904)
8828 ;; (BcdToBin(hours) * 65543.427)
8829 ;; To get a little more accuracy, since Im using integer
8830 ;; arithmatic, I use:
8831 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8832 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8833 ;; (BcdToBin(hours) * 65543427) / 1000
8838 xor eax, eax ;; clear EAX
8841 in al, #0x71 ;; AL has CMOS seconds in BCD
8842 call BcdToBin ;; EAX now has seconds in binary
8848 mov ecx, eax ;; ECX will accumulate total ticks
8851 xor eax, eax ;; clear EAX
8854 in al, #0x71 ;; AL has CMOS minutes in BCD
8855 call BcdToBin ;; EAX now has minutes in binary
8861 add ecx, eax ;; add to total ticks
8864 xor eax, eax ;; clear EAX
8867 in al, #0x71 ;; AL has CMOS hours in BCD
8868 call BcdToBin ;; EAX now has hours in binary
8874 add ecx, eax ;; add to total ticks
8876 mov 0x46C, ecx ;; Timer Ticks Count
8878 mov 0x470, al ;; Timer Ticks Rollover Flag
8881 ;--------------------
8883 ;; record completion in BIOS task complete flag
8895 ;--------------------
8900 #include "apmbios.S"
8904 #include "apmbios.S"
8907 #include "apmbios.S"
8911 ;--------------------
8916 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8917 dw bios32_entry_point, 0xf ;; 32 bit physical address
8918 db 0 ;; revision level
8919 ;; length in paragraphs and checksum stored in a word to prevent errors
8920 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8921 & 0xff) << 8) + 0x01
8922 db 0,0,0,0,0 ;; reserved
8927 cmp eax, #0x49435024
8929 mov eax, #0x80000000
8934 cmp eax, #0x12378086
8936 mov ebx, #0x000f0000
8938 mov edx, #pcibios_protected
8953 cmp al, #0x01 ;; installation check
8957 mov edx, #0x20494350
8960 pci_pro_f02: ;; find pci device
8968 call pci_pro_select_reg
8982 pci_pro_f08: ;; read configuration byte
8985 call pci_pro_select_reg
8994 pci_pro_f09: ;; read configuration word
8997 call pci_pro_select_reg
9006 pci_pro_f0a: ;; read configuration dword
9009 call pci_pro_select_reg
9016 pci_pro_f0b: ;; write configuration byte
9019 call pci_pro_select_reg
9028 pci_pro_f0c: ;; write configuration word
9031 call pci_pro_select_reg
9040 pci_pro_f0d: ;; write configuration dword
9043 call pci_pro_select_reg
9086 mov eax, #0x80000000
9091 cmp eax, #0x12378086
9101 cmp al, #0x01 ;; installation check
9106 mov edx, #0x20494350
9108 mov di, #pcibios_protected
9111 pci_real_f02: ;; find pci device
9121 call pci_real_select_reg
9125 jne pci_real_nextdev
9132 jne pci_real_devloop
9137 pci_real_f08: ;; read configuration byte
9140 call pci_real_select_reg
9149 pci_real_f09: ;; read configuration word
9152 call pci_real_select_reg
9161 pci_real_f0a: ;; read configuration dword
9164 call pci_real_select_reg
9171 pci_real_f0b: ;; write configuration byte
9174 call pci_real_select_reg
9183 pci_real_f0c: ;; write configuration word
9186 call pci_real_select_reg
9195 pci_real_f0d: ;; write configuration dword
9197 jne pci_real_unknown
9198 call pci_real_select_reg
9219 pci_real_select_reg:
9233 pci_routing_table_structure:
9234 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9236 dw 32 + (6 * 16) ;; table size
9237 db 0 ;; PCI interrupt router bus
9238 db 0x08 ;; PCI interrupt router DevFunc
9239 dw 0x0000 ;; PCI exclusive IRQs
9240 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9241 dw 0x7000 ;; compatible PCI interrupt router device ID
9242 dw 0,0 ;; Miniport data
9243 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9245 ;; first slot entry PCI-to-ISA (embedded)
9246 db 0 ;; pci bus number
9247 db 0x08 ;; pci device number (bit 7-3)
9248 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9249 dw 0xdef8 ;; IRQ bitmap INTA#
9250 db 0x61 ;; link value INTB#
9251 dw 0xdef8 ;; IRQ bitmap INTB#
9252 db 0x62 ;; link value INTC#
9253 dw 0xdef8 ;; IRQ bitmap INTC#
9254 db 0x63 ;; link value INTD#
9255 dw 0xdef8 ;; IRQ bitmap INTD#
9256 db 0 ;; physical slot (0 = embedded)
9258 ;; second slot entry: 1st PCI slot
9259 db 0 ;; pci bus number
9260 db 0x10 ;; pci device number (bit 7-3)
9261 db 0x61 ;; link value INTA#
9262 dw 0xdef8 ;; IRQ bitmap INTA#
9263 db 0x62 ;; link value INTB#
9264 dw 0xdef8 ;; IRQ bitmap INTB#
9265 db 0x63 ;; link value INTC#
9266 dw 0xdef8 ;; IRQ bitmap INTC#
9267 db 0x60 ;; link value INTD#
9268 dw 0xdef8 ;; IRQ bitmap INTD#
9269 db 1 ;; physical slot (0 = embedded)
9271 ;; third slot entry: 2nd PCI slot
9272 db 0 ;; pci bus number
9273 db 0x18 ;; pci device number (bit 7-3)
9274 db 0x62 ;; link value INTA#
9275 dw 0xdef8 ;; IRQ bitmap INTA#
9276 db 0x63 ;; link value INTB#
9277 dw 0xdef8 ;; IRQ bitmap INTB#
9278 db 0x60 ;; link value INTC#
9279 dw 0xdef8 ;; IRQ bitmap INTC#
9280 db 0x61 ;; link value INTD#
9281 dw 0xdef8 ;; IRQ bitmap INTD#
9282 db 2 ;; physical slot (0 = embedded)
9284 ;; 4th slot entry: 3rd PCI slot
9285 db 0 ;; pci bus number
9286 db 0x20 ;; pci device number (bit 7-3)
9287 db 0x63 ;; link value INTA#
9288 dw 0xdef8 ;; IRQ bitmap INTA#
9289 db 0x60 ;; link value INTB#
9290 dw 0xdef8 ;; IRQ bitmap INTB#
9291 db 0x61 ;; link value INTC#
9292 dw 0xdef8 ;; IRQ bitmap INTC#
9293 db 0x62 ;; link value INTD#
9294 dw 0xdef8 ;; IRQ bitmap INTD#
9295 db 3 ;; physical slot (0 = embedded)
9297 ;; 5th slot entry: 4rd PCI slot
9298 db 0 ;; pci bus number
9299 db 0x28 ;; pci device number (bit 7-3)
9300 db 0x60 ;; link value INTA#
9301 dw 0xdef8 ;; IRQ bitmap INTA#
9302 db 0x61 ;; link value INTB#
9303 dw 0xdef8 ;; IRQ bitmap INTB#
9304 db 0x62 ;; link value INTC#
9305 dw 0xdef8 ;; IRQ bitmap INTC#
9306 db 0x63 ;; link value INTD#
9307 dw 0xdef8 ;; IRQ bitmap INTD#
9308 db 4 ;; physical slot (0 = embedded)
9310 ;; 6th slot entry: 5rd PCI slot
9311 db 0 ;; pci bus number
9312 db 0x30 ;; pci device number (bit 7-3)
9313 db 0x61 ;; link value INTA#
9314 dw 0xdef8 ;; IRQ bitmap INTA#
9315 db 0x62 ;; link value INTB#
9316 dw 0xdef8 ;; IRQ bitmap INTB#
9317 db 0x63 ;; link value INTC#
9318 dw 0xdef8 ;; IRQ bitmap INTC#
9319 db 0x60 ;; link value INTD#
9320 dw 0xdef8 ;; IRQ bitmap INTD#
9321 db 5 ;; physical slot (0 = embedded)
9327 pcibios_init_sel_reg:
9339 pcibios_init_set_elcr:
9363 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9368 mov si, #pci_routing_table_structure
9372 call pcibios_init_sel_reg
9375 cmp eax, [si+12] ;; check irq router
9378 call pcibios_init_sel_reg
9379 push bx ;; save irq router bus + devfunc
9382 out dx, ax ;; reset PIRQ route control
9390 add si, #0x20 ;; set pointer to 1st entry
9392 mov ax, #pci_irq_list
9401 call pcibios_init_sel_reg
9405 jnz pci_test_int_pin
9411 call pcibios_init_sel_reg
9416 dec al ;; determine pirq reg
9425 call pcibios_init_sel_reg
9432 mov bx, [bp-2] ;; pci irq list pointer
9437 call pcibios_init_set_elcr
9441 add bl, [bp-3] ;; pci function number
9443 call pcibios_init_sel_reg
9453 mov byte ptr[bp-3], #0x00
9461 #endif // BX_PCIBIOS
9463 ; parallel port detection: base address in DX, index in BX, timeout in CL
9468 and al, #0xdf ; clear input mode
9478 mov [bx+0x408], dx ; Parallel I/O address
9480 mov [bx+0x478], cl ; Parallel printer timeout
9485 ; serial port detection: base address in DX, index in BX, timeout in CL
9487 ; no serial port in the VM -PAD
9507 mov [bx+0x400], dx ; Serial I/O address
9509 mov [bx+0x47c], cl ; Serial timeout
9536 ;; Scan for existence of valid expansion ROMS.
9537 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9538 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9539 ;; System ROM: only 0xE0000
9545 ;; 2 ROM length in 512-byte blocks
9546 ;; 3 ROM initialization entry point (FAR CALL)
9551 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9552 cmp [0], #0xAA55 ;; look for signature
9553 jne rom_scan_increment
9555 jnz rom_scan_increment
9557 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9559 ;; We want our increment in 512-byte quantities, rounded to
9560 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9562 jz block_count_rounded
9563 and al, #0xfc ;; needs rounding up
9565 block_count_rounded:
9567 xor bx, bx ;; Restore DS back to 0000:
9570 ;; Push addr of ROM entry point
9572 push #0x0003 ;; Push offset
9573 mov bp, sp ;; Call ROM init routine using seg:off on stack
9574 db 0xff ;; call_far ss:[bp+0]
9577 cli ;; In case expansion ROM BIOS turns IF on
9578 add sp, #2 ;; Pop offset value
9579 pop cx ;; Pop seg value (restore CX)
9580 pop ax ;; Restore AX
9582 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9583 ;; because the segment selector is shifted left 4 bits.
9588 xor ax, ax ;; Restore DS back to 0000:
9594 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9595 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9596 ; but the tables themeselves can be elsewhere.
9605 mov cx, #0x001f ; 0x1f bytes to copy
9607 mov es, ax ; destination segment is 0xf0000
9608 mov di, #smbios_entry_point ; destination offset
9610 mov ds, ax ; source segment is 0x9f000
9611 mov si, #0x0000 ; source offset is 0
9629 ;; for 'C' strings and other data, insert them here with
9630 ;; a the following hack:
9631 ;; DATA_SEG_DEFS_HERE
9637 .org 0xe05b ; POST Entry Point
9642 ;; first reset the DMA controllers
9646 ;; then initialize the DMA controllers
9648 out 0xD6, al ; cascade mode of channel 4 enabled
9650 out 0xD4, al ; unmask channel 4
9652 ;; Examine CMOS shutdown status.
9660 ;; Reset CMOS shutdown status.
9662 out 0x70, AL ; select CMOS register Fh
9664 out 0x71, AL ; set shutdown action to normal
9666 ;; Examine CMOS shutdown status.
9669 ;; 0x00, 0x09, 0x0D+ = normal startup
9677 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9681 ;; Examine CMOS shutdown status.
9682 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9684 call _shutdown_status_panic
9690 ; 0xb0, 0x20, /* mov al, #0x20 */
9691 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9701 ; case 0: normal startup
9710 ;; zero out BIOS data area (40:00..40:ff)
9712 mov cx, #0x0080 ;; 128 words
9718 call _log_bios_start
9720 ;; set all interrupts to default handler
9721 mov bx, #0x0000 ;; offset index
9722 mov cx, #0x0100 ;; counter (256 interrupts)
9723 mov ax, #dummy_iret_handler
9733 loop post_default_ints
9735 ;; set vector 0x79 to zero
9736 ;; this is used by 'gardian angel' protection system
9737 SET_INT_VECTOR(0x79, #0, #0)
9739 ;; base memory in K 40:13 (word)
9740 mov ax, #BASE_MEM_IN_K
9744 ;; Manufacturing Test 40:12
9747 ;; Warm Boot Flag 0040:0072
9748 ;; value of 1234h = skip memory checks
9752 ;; Printer Services vector
9753 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9755 ;; Bootstrap failure vector
9756 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9758 ;; Bootstrap Loader vector
9759 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9761 ;; User Timer Tick vector
9762 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9764 ;; Memory Size Check vector
9765 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9767 ;; Equipment Configuration Check vector
9768 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9771 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9777 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9778 ;; int 1C already points at dummy_iret_handler (above)
9779 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9782 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9787 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9793 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9794 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9798 mov 0x0417, al /* keyboard shift flags, set 1 */
9799 mov 0x0418, al /* keyboard shift flags, set 2 */
9800 mov 0x0419, al /* keyboard alt-numpad work area */
9801 mov 0x0471, al /* keyboard ctrl-break flag */
9802 mov 0x0497, al /* keyboard status flags 4 */
9804 mov 0x0496, al /* keyboard status flags 3 */
9807 /* keyboard head of buffer pointer */
9811 /* keyboard end of buffer pointer */
9814 /* keyboard pointer to start of buffer */
9818 /* keyboard pointer to end of buffer */
9822 /* init the keyboard */
9825 ;; mov CMOS Equipment Byte to BDA Equipment Word
9834 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9838 mov cl, #0x14 ; timeout value
9839 mov dx, #0x378 ; Parallel I/O address, port 1
9841 mov dx, #0x278 ; Parallel I/O address, port 2
9844 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9846 or ax, bx ; set number of parallel ports
9850 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9851 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9853 mov cl, #0x0a ; timeout value
9854 mov dx, #0x03f8 ; Serial I/O address, port 1
9856 mov dx, #0x02f8 ; Serial I/O address, port 2
9858 mov dx, #0x03e8 ; Serial I/O address, port 3
9860 mov dx, #0x02e8 ; Serial I/O address, port 4
9863 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9865 or ax, bx ; set number of serial port
9869 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9870 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9871 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9872 ;; BIOS DATA AREA 0x4CE ???
9873 call timer_tick_post
9876 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9878 ;; IRQ13 (FPU exception) setup
9879 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9882 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9887 mov al, #0x11 ; send initialisation commands
9902 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9903 #if BX_USE_PS2_MOUSE
9908 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9911 call _copy_e820_table
9930 call _print_bios_banner
9935 call floppy_drive_post
9942 call hard_drive_post
9945 ;; ATA/ATAPI driver setup
9950 #else // BX_USE_ATADRV
9955 call hard_drive_post
9957 #endif // BX_USE_ATADRV
9959 #if BX_ELTORITO_BOOT
9961 ;; eltorito floppy/harddisk emulation from cd
9965 #endif // BX_ELTORITO_BOOT
9968 //JMP_EP(0x0064) ; INT 19h location
9971 .org 0xe2c3 ; NMI Handler Entry Point
9973 ;; FIXME the NMI handler should not panic
9974 ;; but iret when called from int75 (fpu exception)
9975 call _nmi_handler_msg
9979 out 0xf0, al // clear irq13
9980 call eoi_both_pics // clear interrupt
9981 int 2 // legacy nmi call
9984 ;-------------------------------------------
9985 ;- INT 13h Fixed Disk Services Entry Point -
9986 ;-------------------------------------------
9987 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9989 //JMPL(int13_relocated)
9992 .org 0xe401 ; Fixed Disk Parameter Table
9997 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
10000 jmp int19_relocated
10001 ;-------------------------------------------
10002 ;- System BIOS Configuration Data Table
10003 ;-------------------------------------------
10004 .org BIOS_CONFIG_TABLE
10005 db 0x08 ; Table size (bytes) -Lo
10006 db 0x00 ; Table size (bytes) -Hi
10011 ; b7: 1=DMA channel 3 used by hard disk
10012 ; b6: 1=2 interrupt controllers present
10013 ; b5: 1=RTC present
10014 ; b4: 1=BIOS calls int 15h/4Fh every key
10015 ; b3: 1=wait for extern event supported (Int 15h/41h)
10016 ; b2: 1=extended BIOS data area used
10017 ; b1: 0=AT or ESDI bus, 1=MicroChannel
10018 ; b0: 1=Dual bus (MicroChannel + ISA)
10022 (BX_CALL_INT15_4F << 4) | \
10024 (BX_USE_EBDA << 2) | \
10028 ; b7: 1=32-bit DMA supported
10029 ; b6: 1=int16h, function 9 supported
10030 ; b5: 1=int15h/C6h (get POS data) supported
10031 ; b4: 1=int15h/C7h (get mem map info) supported
10032 ; b3: 1=int15h/C8h (en/dis CPU) supported
10033 ; b2: 1=non-8042 kb controller
10034 ; b1: 1=data streaming supported
10048 ; b4: POST supports ROM-to-RAM enable/disable
10049 ; b3: SCSI on system board
10050 ; b2: info panel installed
10051 ; b1: Initial Machine Load (IML) system - BIOS on disk
10052 ; b0: SCSI supported in IML
10056 ; b6: EEPROM present
10057 ; b5-3: ABIOS presence (011 = not supported)
10059 ; b1: memory split above 16Mb supported
10060 ; b0: POSTEXT directly supported by POST
10062 ; Feature byte 5 (IBM)
10063 ; b1: enhanced mouse
10069 .org 0xe729 ; Baud Rate Generator Table
10074 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10080 call _int14_function
10086 ;----------------------------------------
10087 ;- INT 16h Keyboard Service Entry Point -
10088 ;----------------------------------------
10104 call _int16_function
10114 and BYTE [bp + 0x06], #0xbf
10122 or BYTE [bp + 0x06], #0x40
10130 int16_wait_for_key:
10134 jne int16_key_found
10138 /* no key yet, call int 15h, function AX=9002 */
10139 0x50, /* push AX */
10140 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10141 0xcd, 0x15, /* int 15h */
10143 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10145 jmp int16_wait_for_key
10150 call _int16_function
10155 /* notify int16 complete w/ int 15h, function AX=9102 */
10156 0x50, /* push AX */
10157 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10158 0xcd, 0x15, /* int 15h */
10165 ;-------------------------------------------------
10166 ;- INT09h : Keyboard Hardware Service Entry Point -
10167 ;-------------------------------------------------
10173 mov al, #0xAD ;;disable keyboard
10182 in al, #0x60 ;;read key from keyboard controller
10183 //test al, #0x80 ;;look for key release
10184 //jnz int09_process_key ;; dont pass releases to intercept?
10186 ;; check for extended key
10188 jne int09_call_int15_4f
10193 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10195 mov BYTE [0x496], al
10198 in al, #0x60 ;;read another key from keyboard controller
10202 int09_call_int15_4f:
10205 #ifdef BX_CALL_INT15_4F
10206 mov ah, #0x4f ;; allow for keyboard intercept
10213 //int09_process_key:
10216 call _int09_function
10222 call eoi_master_pic
10225 mov al, #0xAE ;;enable keyboard
10233 ;----------------------------------------
10234 ;- INT 13h Diskette Service Entry Point -
10235 ;----------------------------------------
10238 jmp int13_noeltorito
10240 ;---------------------------------------------
10241 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10242 ;---------------------------------------------
10243 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10253 mov al, #0x08 ; sense interrupt status
10271 mov ax, #0x0000 ;; segment 0000
10273 call eoi_master_pic
10275 or al, #0x80 ;; diskette interrupt has occurred
10283 .org 0xefc7 ; Diskette Controller Parameter Table
10284 diskette_param_table:
10285 ;; Since no provisions are made for multiple drive types, most
10286 ;; values in this table are ignored. I set parameters for 1.44M
10289 db 0x02 ;; head load time 0000001, DMA used
10301 ;----------------------------------------
10302 ;- INT17h : Printer Service Entry Point -
10303 ;----------------------------------------
10310 call _int17_function
10315 diskette_param_table2:
10316 ;; New diskette parameter table adding 3 parameters from IBM
10317 ;; Since no provisions are made for multiple drive types, most
10318 ;; values in this table are ignored. I set parameters for 1.44M
10321 db 0x02 ;; head load time 0000001, DMA used
10331 db 79 ;; maximum track
10332 db 0 ;; data transfer rate
10333 db 4 ;; drive type in cmos
10335 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10342 .org 0xf065 ; INT 10h Video Support Service Entry Point
10344 ;; dont do anything, since the VGA BIOS handles int10h requests
10347 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10352 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10353 ; ??? different for Pentium (machine check)?
10365 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10377 .org 0xf859 ; INT 15h System Services Entry Point
10391 #if BX_USE_PS2_MOUSE
10393 je int15_handler_mouse
10395 call _int15_function
10396 int15_handler_mouse_ret:
10398 int15_handler32_ret:
10408 #if BX_USE_PS2_MOUSE
10409 int15_handler_mouse:
10410 call _int15_function_mouse
10411 jmp int15_handler_mouse_ret
10416 call _int15_function32
10418 jmp int15_handler32_ret
10420 ;; Protected mode IDT descriptor
10422 ;; I just make the limit 0, so the machine will shutdown
10423 ;; if an exception occurs during protected mode memory
10426 ;; Set base to f0000 to correspond to beginning of BIOS,
10427 ;; in case I actually define an IDT later
10431 dw 0x0000 ;; limit 15:00
10432 dw 0x0000 ;; base 15:00
10433 db 0x0f ;; base 23:16
10435 ;; Real mode IDT descriptor
10437 ;; Set to typical real-mode values.
10442 dw 0x03ff ;; limit 15:00
10443 dw 0x0000 ;; base 15:00
10444 db 0x00 ;; base 23:16
10450 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10463 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10464 mov ds, ax ; on 16bit protected mode.
10465 jmp int1a_callfunction
10472 int1a_callfunction:
10473 call _int1a_function
10479 ;; int70h: IRQ8 - CMOS RTC
10486 call _int70_function
10494 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10502 ;; time to turn off drive(s)?
10505 jz int08_floppy_off
10508 jnz int08_floppy_off
10509 ;; turn motor(s) off
10518 mov eax, 0x046c ;; get ticks dword
10521 ;; compare eax to one days worth of timer ticks at 18.2 hz
10522 cmp eax, #0x001800B0
10523 jb int08_store_ticks
10524 ;; there has been a midnight rollover at this point
10525 xor eax, eax ;; zero out counter
10526 inc BYTE 0x0470 ;; increment rollover flag
10529 mov 0x046c, eax ;; store new ticks dword
10530 ;; chain to user timer tick INT #0x1c
10532 //;; call_ep [ds:loc]
10533 //CALL_EP( 0x1c << 2 )
10536 call eoi_master_pic
10541 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10545 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10547 ;------------------------------------------------
10548 ;- IRET Instruction for Dummy Interrupt Handler -
10549 ;------------------------------------------------
10550 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10551 dummy_iret_handler:
10554 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10563 .org 0xfff0 ; Power-up Entry Point
10570 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10571 .ascii BIOS_BUILD_DATE
10573 .org 0xfffe ; System Model ID
10577 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10580 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10581 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10582 * This font is public domain
10584 static Bit8u vgafont8[128*8]=
10586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10587 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10588 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10589 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10590 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10591 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10592 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10593 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10594 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10595 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10596 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10597 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10598 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10599 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10600 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10601 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10602 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10603 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10604 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10605 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10606 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10607 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10608 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10609 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10610 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10611 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10612 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10613 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10614 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10615 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10616 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10617 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10619 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10620 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10621 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10622 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10623 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10624 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10625 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10626 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10627 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10628 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10629 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10630 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10631 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10632 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10633 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10634 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10635 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10636 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10637 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10638 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10639 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10640 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10641 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10642 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10643 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10644 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10645 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10646 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10647 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10648 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10649 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10650 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10651 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10652 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10653 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10654 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10655 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10656 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10657 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10658 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10659 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10660 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10661 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10662 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10663 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10664 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10665 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10666 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10667 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10668 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10669 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10670 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10671 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10672 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10673 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10674 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10675 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10676 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10677 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10678 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10679 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10680 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10682 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10683 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10684 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10685 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10686 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10687 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10688 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10689 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10690 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10691 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10692 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10693 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10694 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10695 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10696 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10697 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10698 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10699 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10700 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10701 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10702 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10703 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10704 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10705 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10706 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10707 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10708 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10709 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10710 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10711 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10712 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10713 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10719 // just carve out some blank space for HVMLOADER to write the MP tables to
10721 // NOTE: There should be enough space for a 32 processor entry MP table
10725 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10726 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
10727 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
10728 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
10729 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
10730 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
10731 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
10732 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
10733 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
10734 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
10735 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
10736 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
10737 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
10738 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
10739 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
10742 smbios_entry_point:
10743 db 0,0,0,0,0,0,0,0 ; 8 bytes
10744 db 0,0,0,0,0,0,0,0 ; 16 bytes
10745 db 0,0,0,0,0,0,0,0 ; 24 bytes
10746 db 0,0,0,0,0,0,0 ; 31 bytes
10749 #else // !HVMASSIST
10753 // bcc-generated data will be placed here
10755 // For documentation of this config structure, look on developer.intel.com and
10756 // search for multiprocessor specification. Note that when you change anything
10757 // you must update the checksum (a pain!). It would be better to construct this
10758 // with C structures, or at least fill in the checksum automatically.
10760 // Maybe this structs could be moved elsewhere than d000
10762 #if (BX_SMP_PROCESSORS==1)
10763 // no structure necessary.
10764 #elif (BX_SMP_PROCESSORS==2)
10765 // define the Intel MP Configuration Structure for 2 processors at
10766 // APIC ID 0,1. I/O APIC at ID=2.
10769 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10770 dw (mp_config_end-mp_config_table) ;; table length
10772 db 0x65 ;; checksum
10773 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10774 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10775 db 0x20, 0x20, 0x20, 0x20
10776 db 0x20, 0x20, 0x20, 0x20
10777 dw 0,0 ;; oem table ptr
10778 dw 0 ;; oem table size
10779 dw 20 ;; entry count
10780 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10781 dw 0 ;; extended table length
10782 db 0 ;; extended table checksum
10785 db 0 ;; entry type=processor
10786 db 0 ;; local APIC id
10787 db 0x11 ;; local APIC version number
10788 db 3 ;; cpu flags: enabled, bootstrap processor
10789 db 0,6,0,0 ;; cpu signature
10790 dw 0x201,0 ;; feature flags
10794 db 0 ;; entry type=processor
10795 db 1 ;; local APIC id
10796 db 0x11 ;; local APIC version number
10797 db 1 ;; cpu flags: enabled
10798 db 0,6,0,0 ;; cpu signature
10799 dw 0x201,0 ;; feature flags
10803 db 1 ;; entry type=bus
10805 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10807 db 2 ;; entry type=I/O APIC
10808 db 2 ;; apic id=2. linux will set.
10809 db 0x11 ;; I/O APIC version number
10810 db 1 ;; flags=1=enabled
10811 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10813 db 3 ;; entry type=I/O interrupt
10814 db 0 ;; interrupt type=vectored interrupt
10815 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10816 db 0 ;; source bus ID is ISA
10817 db 0 ;; source bus IRQ
10818 db 2 ;; destination I/O APIC ID
10819 db 0 ;; destination I/O APIC interrrupt in
10820 ;; repeat pattern for interrupts 0-15
10830 db 3,0,0,0,0,10,2,10
10831 db 3,0,0,0,0,11,2,11
10832 db 3,0,0,0,0,12,2,12
10833 db 3,0,0,0,0,13,2,13
10834 db 3,0,0,0,0,14,2,14
10835 db 3,0,0,0,0,15,2,15
10836 #elif (BX_SMP_PROCESSORS==4)
10837 // define the Intel MP Configuration Structure for 4 processors at
10838 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10841 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10842 dw (mp_config_end-mp_config_table) ;; table length
10844 db 0xdd ;; checksum
10845 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10846 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10847 db 0x20, 0x20, 0x20, 0x20
10848 db 0x20, 0x20, 0x20, 0x20
10849 dw 0,0 ;; oem table ptr
10850 dw 0 ;; oem table size
10851 dw 22 ;; entry count
10852 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10853 dw 0 ;; extended table length
10854 db 0 ;; extended table checksum
10857 db 0 ;; entry type=processor
10858 db 0 ;; local APIC id
10859 db 0x11 ;; local APIC version number
10860 db 3 ;; cpu flags: enabled, bootstrap processor
10861 db 0,6,0,0 ;; cpu signature
10862 dw 0x201,0 ;; feature flags
10866 db 0 ;; entry type=processor
10867 db 1 ;; local APIC id
10868 db 0x11 ;; local APIC version number
10869 db 1 ;; cpu flags: enabled
10870 db 0,6,0,0 ;; cpu signature
10871 dw 0x201,0 ;; feature flags
10875 db 0 ;; entry type=processor
10876 db 2 ;; local APIC id
10877 db 0x11 ;; local APIC version number
10878 db 1 ;; cpu flags: enabled
10879 db 0,6,0,0 ;; cpu signature
10880 dw 0x201,0 ;; feature flags
10884 db 0 ;; entry type=processor
10885 db 3 ;; local APIC id
10886 db 0x11 ;; local APIC version number
10887 db 1 ;; cpu flags: enabled
10888 db 0,6,0,0 ;; cpu signature
10889 dw 0x201,0 ;; feature flags
10893 db 1 ;; entry type=bus
10895 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10897 db 2 ;; entry type=I/O APIC
10898 db 4 ;; apic id=4. linux will set.
10899 db 0x11 ;; I/O APIC version number
10900 db 1 ;; flags=1=enabled
10901 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10903 db 3 ;; entry type=I/O interrupt
10904 db 0 ;; interrupt type=vectored interrupt
10905 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10906 db 0 ;; source bus ID is ISA
10907 db 0 ;; source bus IRQ
10908 db 4 ;; destination I/O APIC ID
10909 db 0 ;; destination I/O APIC interrrupt in
10910 ;; repeat pattern for interrupts 0-15
10920 db 3,0,0,0,0,10,4,10
10921 db 3,0,0,0,0,11,4,11
10922 db 3,0,0,0,0,12,4,12
10923 db 3,0,0,0,0,13,4,13
10924 db 3,0,0,0,0,14,4,14
10925 db 3,0,0,0,0,15,4,15
10926 #elif (BX_SMP_PROCESSORS==8)
10927 // define the Intel MP Configuration Structure for 8 processors at
10928 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10931 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10932 dw (mp_config_end-mp_config_table) ;; table length
10934 db 0xc3 ;; checksum
10935 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10936 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10937 db 0x20, 0x20, 0x20, 0x20
10938 db 0x20, 0x20, 0x20, 0x20
10939 dw 0,0 ;; oem table ptr
10940 dw 0 ;; oem table size
10941 dw 26 ;; entry count
10942 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10943 dw 0 ;; extended table length
10944 db 0 ;; extended table checksum
10947 db 0 ;; entry type=processor
10948 db 0 ;; local APIC id
10949 db 0x11 ;; local APIC version number
10950 db 3 ;; cpu flags: enabled, bootstrap processor
10951 db 0,6,0,0 ;; cpu signature
10952 dw 0x201,0 ;; feature flags
10956 db 0 ;; entry type=processor
10957 db 1 ;; local APIC id
10958 db 0x11 ;; local APIC version number
10959 db 1 ;; cpu flags: enabled
10960 db 0,6,0,0 ;; cpu signature
10961 dw 0x201,0 ;; feature flags
10965 db 0 ;; entry type=processor
10966 db 2 ;; local APIC id
10967 db 0x11 ;; local APIC version number
10968 db 1 ;; cpu flags: enabled
10969 db 0,6,0,0 ;; cpu signature
10970 dw 0x201,0 ;; feature flags
10974 db 0 ;; entry type=processor
10975 db 3 ;; local APIC id
10976 db 0x11 ;; local APIC version number
10977 db 1 ;; cpu flags: enabled
10978 db 0,6,0,0 ;; cpu signature
10979 dw 0x201,0 ;; feature flags
10983 db 0 ;; entry type=processor
10984 db 4 ;; local APIC id
10985 db 0x11 ;; local APIC version number
10986 db 1 ;; cpu flags: enabled
10987 db 0,6,0,0 ;; cpu signature
10988 dw 0x201,0 ;; feature flags
10992 db 0 ;; entry type=processor
10993 db 5 ;; local APIC id
10994 db 0x11 ;; local APIC version number
10995 db 1 ;; cpu flags: enabled
10996 db 0,6,0,0 ;; cpu signature
10997 dw 0x201,0 ;; feature flags
11001 db 0 ;; entry type=processor
11002 db 6 ;; local APIC id
11003 db 0x11 ;; local APIC version number
11004 db 1 ;; cpu flags: enabled
11005 db 0,6,0,0 ;; cpu signature
11006 dw 0x201,0 ;; feature flags
11010 db 0 ;; entry type=processor
11011 db 7 ;; local APIC id
11012 db 0x11 ;; local APIC version number
11013 db 1 ;; cpu flags: enabled
11014 db 0,6,0,0 ;; cpu signature
11015 dw 0x201,0 ;; feature flags
11019 db 1 ;; entry type=bus
11021 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
11023 db 2 ;; entry type=I/O APIC
11025 db 0x11 ;; I/O APIC version number
11026 db 1 ;; flags=1=enabled
11027 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11029 db 3 ;; entry type=I/O interrupt
11030 db 0 ;; interrupt type=vectored interrupt
11031 db 0,0 ;; flags po=0, el=0 (linux uses as default)
11032 db 0 ;; source bus ID is ISA
11033 db 0 ;; source bus IRQ
11034 db 8 ;; destination I/O APIC ID
11035 db 0 ;; destination I/O APIC interrrupt in
11036 ;; repeat pattern for interrupts 0-15
11046 db 3,0,0,0,0,10,8,10
11047 db 3,0,0,0,0,11,8,11
11048 db 3,0,0,0,0,12,8,12
11049 db 3,0,0,0,0,13,8,13
11050 db 3,0,0,0,0,14,8,14
11051 db 3,0,0,0,0,15,8,15
11053 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11054 #endif // if (BX_SMP_PROCESSORS==...)
11056 mp_config_end: // this label used to find length of mp structure
11059 #if (BX_SMP_PROCESSORS>1)
11061 mp_floating_pointer_structure:
11062 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
11063 dw mp_config_table, 0xf ;; pointer to MP configuration table
11064 db 1 ;; length of this struct in 16-bit byte chunks
11065 db 4 ;; MP spec revision
11066 db 0xc1 ;; checksum
11067 db 0 ;; MP feature byte 1. value 0 means look at the config table
11068 db 0,0,0,0 ;; MP feature bytes 2-5.
11073 #endif // HVMASSIST