2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.5 2008/05/12 00:21:17 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.5 $";
949 static char bios_date_string[] = "$Date: 2008/05/12 00:21:17 $";
951 static char CVSID[] = "$Id: rombios.c,v 1.5 2008/05/12 00:21:17 pdinda Exp $";
953 /* Offset to skip the CVS $Id: prefix */
954 #define bios_version_string (CVSID + 4)
956 #define BIOS_PRINTF_HALT 1
957 #define BIOS_PRINTF_SCREEN 2
958 #define BIOS_PRINTF_INFO 4
959 #define BIOS_PRINTF_DEBUG 8
960 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
961 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
963 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
965 // Defines the output macros.
966 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
967 // per-device basis. Debug info are sent only in debug mode
969 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_ALL, format, ##p)
971 # define BX_DEBUG(format, p...)
973 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
974 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
977 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
979 # define BX_DEBUG_ATA(a...)
982 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
984 # define BX_DEBUG_INT13_HD(a...)
987 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
989 # define BX_DEBUG_INT13_CD(a...)
992 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
994 # define BX_DEBUG_INT13_ET(a...)
997 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
999 # define BX_DEBUG_INT13_FL(a...)
1002 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1004 # define BX_DEBUG_INT15(a...)
1007 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1009 # define BX_DEBUG_INT16(a...)
1012 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1014 # define BX_DEBUG_INT1A(a...)
1017 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1019 # define BX_DEBUG_INT74(a...)
1022 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1023 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1024 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1025 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1026 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1027 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1028 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1029 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1031 #define GET_AL() ( AX & 0x00ff )
1032 #define GET_BL() ( BX & 0x00ff )
1033 #define GET_CL() ( CX & 0x00ff )
1034 #define GET_DL() ( DX & 0x00ff )
1035 #define GET_AH() ( AX >> 8 )
1036 #define GET_BH() ( BX >> 8 )
1037 #define GET_CH() ( CX >> 8 )
1038 #define GET_DH() ( DX >> 8 )
1040 #define GET_ELDL() ( ELDX & 0x00ff )
1041 #define GET_ELDH() ( ELDX >> 8 )
1043 #define SET_CF() FLAGS |= 0x0001
1044 #define CLEAR_CF() FLAGS &= 0xfffe
1045 #define GET_CF() (FLAGS & 0x0001)
1047 #define SET_ZF() FLAGS |= 0x0040
1048 #define CLEAR_ZF() FLAGS &= 0xffbf
1049 #define GET_ZF() (FLAGS & 0x0040)
1051 #define UNSUPPORTED_FUNCTION 0x86
1054 #define MAX_SCAN_CODE 0x53
1062 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1063 { none, none, none, none, none },
1064 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1065 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1066 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1067 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1068 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1069 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1070 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1071 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1072 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1073 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1074 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1075 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1076 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1077 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1078 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1079 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1080 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1081 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1082 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1083 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1084 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1085 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1086 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1087 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1088 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1089 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1090 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1091 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1092 { none, none, none, none, none }, /* L Ctrl */
1093 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1094 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1095 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1096 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1097 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1098 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1099 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1100 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1101 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1102 { 0x273b, 0x273a, none, none, none }, /* ;: */
1103 { 0x2827, 0x2822, none, none, none }, /* '" */
1104 { 0x2960, 0x297e, none, none, none }, /* `~ */
1105 { none, none, none, none, none }, /* L shift */
1106 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1107 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1108 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1109 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1110 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1111 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1112 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1113 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1114 { 0x332c, 0x333c, none, none, none }, /* ,< */
1115 { 0x342e, 0x343e, none, none, none }, /* .> */
1116 { 0x352f, 0x353f, none, none, none }, /* /? */
1117 { none, none, none, none, none }, /* R Shift */
1118 { 0x372a, 0x372a, none, none, none }, /* * */
1119 { none, none, none, none, none }, /* L Alt */
1120 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1121 { none, none, none, none, none }, /* caps lock */
1122 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1123 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1124 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1125 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1126 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1127 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1128 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1129 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1130 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1131 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1132 { none, none, none, none, none }, /* Num Lock */
1133 { none, none, none, none, none }, /* Scroll Lock */
1134 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1135 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1136 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1137 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1138 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1139 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1140 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1141 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1142 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1143 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1144 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1145 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1146 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1230 outb_cmos(cmos_reg, val)
1238 mov al, 4[bp] ;; cmos_reg
1240 mov al, 6[bp] ;; val
1255 mov al, 4[bp] ;; cmos_reg
1266 printf("rombios: init_rtc()\n");
1267 outb_cmos(0x0a, 0x26);
1268 outb_cmos(0x0b, 0x02);
1276 // This function checks to see if the update-in-progress bit
1277 // is set in CMOS Status Register A. If not, it returns 0.
1278 // If it is set, it tries to wait until there is a transition
1279 // to 0, and will return 0 if such a transition occurs. A 1
1280 // is returned only after timing out. The maximum period
1281 // that this bit should be set is constrained to 244useconds.
1282 // The count I use below guarantees coverage or more than
1283 // this time, with any reasonable IPS setting.
1288 while (--count != 0) {
1289 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1292 return(1); // update-in-progress never transitioned to 0
1297 read_byte(seg, offset)
1307 mov ax, 4[bp] ; segment
1309 mov bx, 6[bp] ; offset
1311 ;; al = return value (byte)
1320 read_word(seg, offset)
1330 mov ax, 4[bp] ; segment
1332 mov bx, 6[bp] ; offset
1334 ;; ax = return value (word)
1343 write_byte(seg, offset, data)
1355 mov ax, 4[bp] ; segment
1357 mov bx, 6[bp] ; offset
1358 mov al, 8[bp] ; data byte
1359 mov [bx], al ; write data byte
1369 write_word(seg, offset, data)
1381 mov ax, 4[bp] ; segment
1383 mov bx, 6[bp] ; offset
1384 mov ax, 8[bp] ; data word
1385 mov [bx], ax ; write data word
1411 //set_DS(ds_selector)
1412 // Bit16u ds_selector;
1419 // mov ax, 4[bp] ; ds_selector
1439 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1440 if (nr_entries > 32)
1442 write_word(0xe000, 0x8, nr_entries);
1443 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1445 #endif /* HVMASSIST */
1448 /* serial debug port*/
1449 #define BX_DEBUG_PORT 0x03f8
1452 #define UART_RBR 0x00
1453 #define UART_THR 0x00
1456 #define UART_IER 0x01
1457 #define UART_IIR 0x02
1458 #define UART_FCR 0x02
1459 #define UART_LCR 0x03
1460 #define UART_MCR 0x04
1461 #define UART_DLL 0x00
1462 #define UART_DLM 0x01
1465 #define UART_LSR 0x05
1466 #define UART_MSR 0x06
1467 #define UART_SCR 0x07
1469 int uart_can_tx_byte(base_port)
1472 return inb(base_port + UART_LSR) & 0x20;
1475 void uart_wait_to_tx_byte(base_port)
1478 while (!uart_can_tx_byte(base_port));
1481 void uart_wait_until_sent(base_port)
1484 while (!(inb(base_port + UART_LSR) & 0x40));
1487 void uart_tx_byte(base_port, data)
1491 uart_wait_to_tx_byte(base_port);
1492 outb(base_port + UART_THR, data);
1493 uart_wait_until_sent(base_port);
1522 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1523 uart_tx_byte(BX_DEBUG_PORT, c);
1528 #if BX_VIRTUAL_PORTS
1529 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1530 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1532 if (action & BIOS_PRINTF_SCREEN) {
1533 if (c == '\n') wrch('\r');
1539 put_int(action, val, width, neg)
1544 short nval = val / 10;
1546 put_int(action, nval, width - 1, neg);
1548 while (--width > 0) send(action, ' ');
1549 if (neg) send(action, '-');
1551 send(action, val - (nval * 10) + '0');
1555 put_uint(action, val, width, neg)
1561 unsigned short nval = val / 10;
1563 put_uint(action, nval, width - 1, neg);
1565 while (--width > 0) send(action, ' ');
1566 if (neg) send(action, '-');
1568 send(action, val - (nval * 10) + '0');
1571 //--------------------------------------------------------------------------
1573 // A compact variable argument printf function which prints its output via
1574 // an I/O port so that it can be logged by Bochs/Plex.
1575 // Currently, only %x is supported (or %02x, %04x, etc).
1577 // Supports %[format_width][format]
1578 // where format can be d,x,c,s
1579 //--------------------------------------------------------------------------
1581 bios_printf(action, s)
1585 Bit8u c, format_char;
1589 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1597 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1598 #if BX_VIRTUAL_PORTS
1599 outb(PANIC_PORT2, 0x00);
1601 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1604 while (c = read_byte(get_CS(), s)) {
1609 else if (in_format) {
1610 if ( (c>='0') && (c<='9') ) {
1611 format_width = (format_width * 10) + (c - '0');
1614 arg_ptr++; // increment to next arg
1615 arg = read_word(arg_seg, arg_ptr);
1617 if (format_width == 0)
1619 for (i=format_width-1; i>=0; i--) {
1620 nibble = (arg >> (4 * i)) & 0x000f;
1621 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1624 else if (c == 'u') {
1625 put_uint(action, arg, format_width, 0);
1627 else if (c == 'd') {
1629 put_int(action, -arg, format_width - 1, 1);
1631 put_int(action, arg, format_width, 0);
1633 else if (c == 's') {
1634 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1636 else if (c == 'c') {
1640 BX_PANIC("bios_printf: unknown format\n");
1650 if (action & BIOS_PRINTF_HALT) {
1651 // freeze in a busy loop.
1661 //--------------------------------------------------------------------------
1663 //--------------------------------------------------------------------------
1664 // this file is based on LinuxBIOS implementation of keyboard.c
1665 // could convert to #asm to gain space
1672 BX_DEBUG("rombios: keyboard_init\n");
1674 /* printf("Assuming keyboard already inited and returning\n");
1677 /* ------------------- Flush buffers ------------------------*/
1678 /* Wait until buffer is empty */
1680 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1682 /* flush incoming keys */
1686 if (inb(0x64) & 0x01) {
1692 // Due to timer issues, and if the IPS setting is > 15000000,
1693 // the incoming keys might not be flushed here. That will
1694 // cause a panic a few lines below. See sourceforge bug report :
1695 // [ 642031 ] FATAL: Keyboard RESET error:993
1697 /* ------------------- controller side ----------------------*/
1698 /* send cmd = 0xAA, self test 8042 */
1701 /* Wait until buffer is empty */
1703 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1704 if (max==0x0) keyboard_panic(00);
1708 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1709 if (max==0x0) keyboard_panic(01);
1711 /* read self-test result, 0x55 should be returned from 0x60 */
1712 if ((inb(0x60) != 0x55)){
1713 keyboard_panic(991);
1716 /* send cmd = 0xAB, keyboard interface test */
1719 /* Wait until buffer is empty */
1721 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1722 if (max==0x0) keyboard_panic(10);
1726 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1727 if (max==0x0) keyboard_panic(11);
1729 /* read keyboard interface test result, */
1730 /* 0x00 should be returned form 0x60 */
1731 if ((inb(0x60) != 0x00)) {
1732 keyboard_panic(992);
1735 /* Enable Keyboard clock */
1739 /* ------------------- keyboard side ------------------------*/
1740 /* reset kerboard and self test (keyboard side) */
1743 /* Wait until buffer is empty */
1745 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1746 if (max==0x0) keyboard_panic(20);
1750 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1751 if (max==0x0) keyboard_panic(21);
1753 /* keyboard should return ACK */
1754 if ((inb(0x60) != 0xfa)) {
1755 keyboard_panic(993);
1760 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1761 if (max==0x0) keyboard_panic(31);
1763 if ((inb(0x60) != 0xaa)) {
1764 keyboard_panic(994);
1767 /* Disable keyboard */
1770 /* Wait until buffer is empty */
1772 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1773 if (max==0x0) keyboard_panic(40);
1777 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1778 if (max==0x0) keyboard_panic(41);
1780 /* keyboard should return ACK */
1783 printf("rc=0x%x\n",rc);
1784 keyboard_panic(995);
1787 /* Write Keyboard Mode */
1790 /* Wait until buffer is empty */
1792 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1793 if (max==0x0) keyboard_panic(50);
1795 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1798 /* Wait until buffer is empty */
1800 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1801 if (max==0x0) keyboard_panic(60);
1803 /* Enable keyboard */
1806 /* Wait until buffer is empty */
1808 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1809 if (max==0x0) keyboard_panic(70);
1813 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1814 if (max==0x0) keyboard_panic(70);
1816 /* keyboard should return ACK */
1817 if ((inb(0x60) != 0xfa)) {
1818 keyboard_panic(996);
1822 printf("keyboard init done.\n");
1825 //--------------------------------------------------------------------------
1827 //--------------------------------------------------------------------------
1829 keyboard_panic(status)
1832 // If you're getting a 993 keyboard panic here,
1833 // please see the comment in keyboard_init
1834 printf("Keyboard error:%u CONTINUING\n",status); return;
1835 BX_PANIC("Keyboard error:%u\n",status);
1838 //--------------------------------------------------------------------------
1839 // shutdown_status_panic
1840 // called when the shutdown statsu is not implemented, displays the status
1841 //--------------------------------------------------------------------------
1843 shutdown_status_panic(status)
1846 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1849 //--------------------------------------------------------------------------
1850 // print_bios_banner
1851 // displays a the bios version
1852 //--------------------------------------------------------------------------
1856 printf("Hi from peter's modified bios\n");
1857 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1858 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1862 //--------------------------------------------------------------------------
1863 // print_boot_device
1864 // displays the boot device
1865 //--------------------------------------------------------------------------
1867 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1870 print_boot_device(cdboot, drive)
1871 Bit8u cdboot; Bit16u drive;
1875 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1876 // drive contains real/emulated boot drive
1878 if(cdboot)i=2; // CD-Rom
1879 else if((drive&0x0080)==0x00)i=0; // Floppy
1880 else if((drive&0x0080)==0x80)i=1; // Hard drive
1883 printf("Booting from %s...\n",drivetypes[i]);
1886 //--------------------------------------------------------------------------
1887 // print_boot_failure
1888 // displays the reason why boot failed
1889 //--------------------------------------------------------------------------
1891 print_boot_failure(cdboot, drive, reason, lastdrive)
1892 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1894 Bit16u drivenum = drive&0x7f;
1896 // cdboot: 1 if boot from cd, 0 otherwise
1897 // drive : drive number
1898 // reason: 0 signature check failed, 1 read error
1899 // lastdrive: 1 boot drive is the last one in boot sequence
1902 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1903 else if (drive & 0x80)
1904 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1906 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1910 BX_PANIC("Not a bootable disk\n");
1912 BX_PANIC("Could not read the boot disk\n");
1916 //--------------------------------------------------------------------------
1917 // print_cdromboot_failure
1918 // displays the reason why boot failed
1919 //--------------------------------------------------------------------------
1921 print_cdromboot_failure( code )
1924 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1932 BX_PANIC("NMI Handler called\n");
1938 BX_PANIC("INT18: BOOT FAILURE\n");
1945 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1947 BX_INFO("%s\n", bios_version_string);
1956 // Use PS2 System Control port A to set A20 enable
1958 // get current setting first
1961 // change A20 status
1963 outb(0x92, oldval | 0x02);
1965 outb(0x92, oldval & 0xfd);
1967 return((oldval & 0x02) != 0);
1984 // ---------------------------------------------------------------------------
1985 // Start of ATA/ATAPI Driver
1986 // ---------------------------------------------------------------------------
1988 // Global defines -- ATA register and register bits.
1989 // command block & control block regs
1990 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1991 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1992 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1993 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1994 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1995 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1996 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1997 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1998 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1999 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2000 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2001 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2002 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2004 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2005 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2006 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2007 #define ATA_CB_ER_MC 0x20 // ATA media change
2008 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2009 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2010 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2011 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2012 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2014 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2015 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2016 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2017 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2018 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2020 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2021 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2022 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2023 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2024 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2026 // bits 7-4 of the device/head (CB_DH) reg
2027 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2028 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2030 // status reg (CB_STAT and CB_ASTAT) bits
2031 #define ATA_CB_STAT_BSY 0x80 // busy
2032 #define ATA_CB_STAT_RDY 0x40 // ready
2033 #define ATA_CB_STAT_DF 0x20 // device fault
2034 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2035 #define ATA_CB_STAT_SKC 0x10 // seek complete
2036 #define ATA_CB_STAT_SERV 0x10 // service
2037 #define ATA_CB_STAT_DRQ 0x08 // data request
2038 #define ATA_CB_STAT_CORR 0x04 // corrected
2039 #define ATA_CB_STAT_IDX 0x02 // index
2040 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2041 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2043 // device control reg (CB_DC) bits
2044 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2045 #define ATA_CB_DC_SRST 0x04 // soft reset
2046 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2048 // Most mandtory and optional ATA commands (from ATA-3),
2049 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2050 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2051 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2052 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2053 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2054 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2055 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2056 #define ATA_CMD_DEVICE_RESET 0x08
2057 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2058 #define ATA_CMD_FLUSH_CACHE 0xE7
2059 #define ATA_CMD_FORMAT_TRACK 0x50
2060 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2061 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2062 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2063 #define ATA_CMD_IDLE1 0xE3
2064 #define ATA_CMD_IDLE2 0x97
2065 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2066 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2067 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2068 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2069 #define ATA_CMD_NOP 0x00
2070 #define ATA_CMD_PACKET 0xA0
2071 #define ATA_CMD_READ_BUFFER 0xE4
2072 #define ATA_CMD_READ_DMA 0xC8
2073 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2074 #define ATA_CMD_READ_MULTIPLE 0xC4
2075 #define ATA_CMD_READ_SECTORS 0x20
2076 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2077 #define ATA_CMD_RECALIBRATE 0x10
2078 #define ATA_CMD_SEEK 0x70
2079 #define ATA_CMD_SET_FEATURES 0xEF
2080 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2081 #define ATA_CMD_SLEEP1 0xE6
2082 #define ATA_CMD_SLEEP2 0x99
2083 #define ATA_CMD_STANDBY1 0xE2
2084 #define ATA_CMD_STANDBY2 0x96
2085 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2086 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2087 #define ATA_CMD_WRITE_BUFFER 0xE8
2088 #define ATA_CMD_WRITE_DMA 0xCA
2089 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2090 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2091 #define ATA_CMD_WRITE_SECTORS 0x30
2092 #define ATA_CMD_WRITE_VERIFY 0x3C
2094 #define ATA_IFACE_NONE 0x00
2095 #define ATA_IFACE_ISA 0x00
2096 #define ATA_IFACE_PCI 0x01
2098 #define ATA_TYPE_NONE 0x00
2099 #define ATA_TYPE_UNKNOWN 0x01
2100 #define ATA_TYPE_ATA 0x02
2101 #define ATA_TYPE_ATAPI 0x03
2103 #define ATA_DEVICE_NONE 0x00
2104 #define ATA_DEVICE_HD 0xFF
2105 #define ATA_DEVICE_CDROM 0x05
2107 #define ATA_MODE_NONE 0x00
2108 #define ATA_MODE_PIO16 0x00
2109 #define ATA_MODE_PIO32 0x01
2110 #define ATA_MODE_ISADMA 0x02
2111 #define ATA_MODE_PCIDMA 0x03
2112 #define ATA_MODE_USEIRQ 0x10
2114 #define ATA_TRANSLATION_NONE 0
2115 #define ATA_TRANSLATION_LBA 1
2116 #define ATA_TRANSLATION_LARGE 2
2117 #define ATA_TRANSLATION_RECHS 3
2119 #define ATA_DATA_NO 0x00
2120 #define ATA_DATA_IN 0x01
2121 #define ATA_DATA_OUT 0x02
2123 // ---------------------------------------------------------------------------
2124 // ATA/ATAPI driver : initialization
2125 // ---------------------------------------------------------------------------
2128 Bit16u ebda_seg=read_word(0x0040,0x000E);
2129 Bit8u channel, device;
2131 //BX_DEBUG("rombios: ata_init\n");
2133 // Channels info init.
2134 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2135 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2136 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2137 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2138 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2141 // Devices info init.
2142 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2143 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2144 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2145 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2146 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2147 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2148 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2149 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2150 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2151 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2152 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2153 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2154 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2155 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2157 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2160 // hdidmap and cdidmap init.
2161 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2162 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2163 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2166 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2167 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2170 // ---------------------------------------------------------------------------
2171 // ATA/ATAPI driver : device detection
2172 // ---------------------------------------------------------------------------
2176 Bit16u ebda_seg=read_word(0x0040,0x000E);
2177 Bit8u hdcount, cdcount, device, type;
2178 Bit8u buffer[0x0200];
2180 //BX_DEBUG("rombios: ata_detect\n");
2182 #if BX_MAX_ATA_INTERFACES > 0
2183 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2184 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2185 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2186 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2188 #if BX_MAX_ATA_INTERFACES > 1
2189 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2190 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2191 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2192 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2194 #if BX_MAX_ATA_INTERFACES > 2
2195 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2196 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2197 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2198 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2200 #if BX_MAX_ATA_INTERFACES > 3
2201 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2202 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2203 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2204 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2206 #if BX_MAX_ATA_INTERFACES > 4
2207 #error Please fill the ATA interface informations
2213 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2214 Bit16u iobase1, iobase2;
2215 Bit8u channel, slave, shift;
2216 Bit8u sc, sn, cl, ch, st;
2218 channel = device / 2;
2221 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2222 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2224 // Disable interrupts
2225 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2228 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2229 outb(iobase1+ATA_CB_SC, 0x55);
2230 outb(iobase1+ATA_CB_SN, 0xaa);
2231 outb(iobase1+ATA_CB_SC, 0xaa);
2232 outb(iobase1+ATA_CB_SN, 0x55);
2233 outb(iobase1+ATA_CB_SC, 0x55);
2234 outb(iobase1+ATA_CB_SN, 0xaa);
2236 // If we found something
2237 sc = inb(iobase1+ATA_CB_SC);
2238 sn = inb(iobase1+ATA_CB_SN);
2240 if ( (sc == 0x55) && (sn == 0xaa) ) {
2241 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2243 // reset the channel
2246 // check for ATA or ATAPI
2247 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2248 sc = inb(iobase1+ATA_CB_SC);
2249 sn = inb(iobase1+ATA_CB_SN);
2250 if ( (sc==0x01) && (sn==0x01) ) {
2251 cl = inb(iobase1+ATA_CB_CL);
2252 ch = inb(iobase1+ATA_CB_CH);
2253 st = inb(iobase1+ATA_CB_STAT);
2255 if ( (cl==0x14) && (ch==0xeb) ) {
2256 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2258 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2259 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2264 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2266 // Now we send a IDENTIFY command to ATA device
2267 if(type == ATA_TYPE_ATA) {
2269 Bit16u cylinders, heads, spt, blksize;
2270 Bit8u translation, removable, mode;
2272 // default mode to PIO16
2273 mode = ATA_MODE_PIO16;
2275 //Temporary values to do the transfer
2276 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2277 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2279 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2280 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2282 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2284 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2287 blksize = read_word(get_SS(),buffer+10);
2289 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2290 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2291 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2293 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2295 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2296 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2297 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2298 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2299 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2300 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2301 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2302 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2303 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2305 translation = inb_cmos(0x39 + channel/2);
2306 for (shift=device%4; shift>0; shift--) translation >>= 2;
2307 translation &= 0x03;
2309 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2311 switch (translation) {
2312 case ATA_TRANSLATION_NONE:
2315 case ATA_TRANSLATION_LBA:
2318 case ATA_TRANSLATION_LARGE:
2321 case ATA_TRANSLATION_RECHS:
2325 switch (translation) {
2326 case ATA_TRANSLATION_NONE:
2328 case ATA_TRANSLATION_LBA:
2331 heads = sectors / 1024;
2332 if (heads>128) heads = 255;
2333 else if (heads>64) heads = 128;
2334 else if (heads>32) heads = 64;
2335 else if (heads>16) heads = 32;
2337 cylinders = sectors / heads;
2339 case ATA_TRANSLATION_RECHS:
2340 // Take care not to overflow
2342 if(cylinders>61439) cylinders=61439;
2344 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2346 // then go through the large bitshift process
2347 case ATA_TRANSLATION_LARGE:
2348 while(cylinders > 1024) {
2352 // If we max out the head count
2353 if (heads > 127) break;
2357 // clip to 1024 cylinders in lchs
2358 if (cylinders > 1024) cylinders=1024;
2359 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2361 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2362 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2363 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2366 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2370 // Now we send a IDENTIFY command to ATAPI device
2371 if(type == ATA_TYPE_ATAPI) {
2373 Bit8u type, removable, mode;
2376 // default mode to PIO16
2377 mode = ATA_MODE_PIO16;
2379 //Temporary values to do the transfer
2380 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2381 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2383 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2384 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2386 type = read_byte(get_SS(),buffer+1) & 0x1f;
2387 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2389 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2393 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2394 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2395 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2396 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2399 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2406 Bit8u c, i, version, model[41];
2410 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2412 case ATA_TYPE_ATAPI:
2413 // Read ATA/ATAPI version
2414 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2415 for(version=15;version>0;version--) {
2416 if((ataversion&(1<<version))!=0)
2422 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2423 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2427 write_byte(get_SS(),model+40,0x00);
2429 if(read_byte(get_SS(),model+i)==0x20)
2430 write_byte(get_SS(),model+i,0x00);
2438 printf("ata%d %s: ",channel,slave?" slave":"master");
2439 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2440 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2442 case ATA_TYPE_ATAPI:
2443 printf("ata%d %s: ",channel,slave?" slave":"master");
2444 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2445 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2446 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2448 printf(" ATAPI-%d Device\n",version);
2450 case ATA_TYPE_UNKNOWN:
2451 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2457 // Store the devices counts
2458 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2459 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2460 write_byte(0x40,0x75, hdcount);
2464 // FIXME : should use bios=cmos|auto|disable bits
2465 // FIXME : should know about translation bits
2466 // FIXME : move hard_drive_post here
2470 // ---------------------------------------------------------------------------
2471 // ATA/ATAPI driver : software reset
2472 // ---------------------------------------------------------------------------
2474 // 8.2.1 Software reset - Device 0
2476 void ata_reset(device)
2479 Bit16u ebda_seg=read_word(0x0040,0x000E);
2480 Bit16u iobase1, iobase2;
2481 Bit8u channel, slave, sn, sc;
2484 channel = device / 2;
2487 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2488 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2492 // 8.2.1 (a) -- set SRST in DC
2493 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2495 // 8.2.1 (b) -- wait for BSY
2498 Bit8u status = inb(iobase1+ATA_CB_STAT);
2499 if ((status & ATA_CB_STAT_BSY) != 0) break;
2502 // 8.2.1 (f) -- clear SRST
2503 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2505 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2507 // 8.2.1 (g) -- check for sc==sn==0x01
2509 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2510 sc = inb(iobase1+ATA_CB_SC);
2511 sn = inb(iobase1+ATA_CB_SN);
2513 if ( (sc==0x01) && (sn==0x01) ) {
2515 // 8.2.1 (h) -- wait for not BSY
2518 Bit8u status = inb(iobase1+ATA_CB_STAT);
2519 if ((status & ATA_CB_STAT_BSY) == 0) break;
2524 // 8.2.1 (i) -- wait for DRDY
2527 Bit8u status = inb(iobase1+ATA_CB_STAT);
2528 if ((status & ATA_CB_STAT_RDY) != 0) break;
2531 // Enable interrupts
2532 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2535 // ---------------------------------------------------------------------------
2536 // ATA/ATAPI driver : execute a non data command
2537 // ---------------------------------------------------------------------------
2539 Bit16u ata_cmd_non_data()
2542 // ---------------------------------------------------------------------------
2543 // ATA/ATAPI driver : execute a data-in command
2544 // ---------------------------------------------------------------------------
2549 // 3 : expected DRQ=1
2550 // 4 : no sectors left to read/verify
2551 // 5 : more sectors to read/verify
2552 // 6 : no sectors left to write
2553 // 7 : more sectors to write
2554 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2555 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2558 Bit16u ebda_seg=read_word(0x0040,0x000E);
2559 Bit16u iobase1, iobase2, blksize;
2560 Bit8u channel, slave;
2561 Bit8u status, current, mode;
2563 channel = device / 2;
2566 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2567 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2568 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2569 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2570 if (mode == ATA_MODE_PIO32) blksize>>=2;
2573 // sector will be 0 only on lba access. Convert to lba-chs
2575 sector = (Bit16u) (lba & 0x000000ffL);
2577 cylinder = (Bit16u) (lba & 0x0000ffffL);
2579 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2582 // Reset count of transferred data
2583 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2584 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2587 status = inb(iobase1 + ATA_CB_STAT);
2588 if (status & ATA_CB_STAT_BSY) return 1;
2590 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2591 outb(iobase1 + ATA_CB_FR, 0x00);
2592 outb(iobase1 + ATA_CB_SC, count);
2593 outb(iobase1 + ATA_CB_SN, sector);
2594 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2595 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2596 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2597 outb(iobase1 + ATA_CB_CMD, command);
2600 status = inb(iobase1 + ATA_CB_STAT);
2601 if ( !(status & ATA_CB_STAT_BSY) ) break;
2604 if (status & ATA_CB_STAT_ERR) {
2605 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2607 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2608 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2612 // FIXME : move seg/off translation here
2615 sti ;; enable higher priority interrupts
2623 mov di, _ata_cmd_data_in.offset + 2[bp]
2624 mov ax, _ata_cmd_data_in.segment + 2[bp]
2625 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2627 ;; adjust if there will be an overrun. 2K max sector size
2629 jbe ata_in_no_adjust
2632 sub di, #0x0800 ;; sub 2 kbytes from offset
2633 add ax, #0x0080 ;; add 2 Kbytes to segment
2636 mov es, ax ;; segment in es
2638 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2640 mov ah, _ata_cmd_data_in.mode + 2[bp]
2641 cmp ah, #ATA_MODE_PIO32
2646 insw ;; CX words transfered from port(DX) to ES:[DI]
2651 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2654 mov _ata_cmd_data_in.offset + 2[bp], di
2655 mov _ata_cmd_data_in.segment + 2[bp], es
2660 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2662 status = inb(iobase1 + ATA_CB_STAT);
2664 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2665 != ATA_CB_STAT_RDY ) {
2666 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2672 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2673 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2674 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2680 // Enable interrupts
2681 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2685 // ---------------------------------------------------------------------------
2686 // ATA/ATAPI driver : execute a data-out command
2687 // ---------------------------------------------------------------------------
2692 // 3 : expected DRQ=1
2693 // 4 : no sectors left to read/verify
2694 // 5 : more sectors to read/verify
2695 // 6 : no sectors left to write
2696 // 7 : more sectors to write
2697 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2698 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2701 Bit16u ebda_seg=read_word(0x0040,0x000E);
2702 Bit16u iobase1, iobase2, blksize;
2703 Bit8u channel, slave;
2704 Bit8u status, current, mode;
2706 channel = device / 2;
2709 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2710 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2711 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2712 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2713 if (mode == ATA_MODE_PIO32) blksize>>=2;
2716 // sector will be 0 only on lba access. Convert to lba-chs
2718 sector = (Bit16u) (lba & 0x000000ffL);
2720 cylinder = (Bit16u) (lba & 0x0000ffffL);
2722 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2725 // Reset count of transferred data
2726 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2727 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2730 status = inb(iobase1 + ATA_CB_STAT);
2731 if (status & ATA_CB_STAT_BSY) return 1;
2733 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2734 outb(iobase1 + ATA_CB_FR, 0x00);
2735 outb(iobase1 + ATA_CB_SC, count);
2736 outb(iobase1 + ATA_CB_SN, sector);
2737 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2738 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2739 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2740 outb(iobase1 + ATA_CB_CMD, command);
2743 status = inb(iobase1 + ATA_CB_STAT);
2744 if ( !(status & ATA_CB_STAT_BSY) ) break;
2747 if (status & ATA_CB_STAT_ERR) {
2748 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2750 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2751 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2755 // FIXME : move seg/off translation here
2758 sti ;; enable higher priority interrupts
2766 mov si, _ata_cmd_data_out.offset + 2[bp]
2767 mov ax, _ata_cmd_data_out.segment + 2[bp]
2768 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2770 ;; adjust if there will be an overrun. 2K max sector size
2772 jbe ata_out_no_adjust
2775 sub si, #0x0800 ;; sub 2 kbytes from offset
2776 add ax, #0x0080 ;; add 2 Kbytes to segment
2779 mov es, ax ;; segment in es
2781 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2783 mov ah, _ata_cmd_data_out.mode + 2[bp]
2784 cmp ah, #ATA_MODE_PIO32
2790 outsw ;; CX words transfered from port(DX) to ES:[SI]
2796 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2799 mov _ata_cmd_data_out.offset + 2[bp], si
2800 mov _ata_cmd_data_out.segment + 2[bp], es
2805 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2807 status = inb(iobase1 + ATA_CB_STAT);
2809 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2810 != ATA_CB_STAT_RDY ) {
2811 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2817 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2818 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2819 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2825 // Enable interrupts
2826 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2830 // ---------------------------------------------------------------------------
2831 // ATA/ATAPI driver : execute a packet command
2832 // ---------------------------------------------------------------------------
2835 // 1 : error in parameters
2839 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2841 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2845 Bit16u ebda_seg=read_word(0x0040,0x000E);
2846 Bit16u iobase1, iobase2;
2847 Bit16u lcount, lbefore, lafter, count;
2848 Bit8u channel, slave;
2849 Bit8u status, mode, lmode;
2850 Bit32u total, transfer;
2852 channel = device / 2;
2855 // Data out is not supported yet
2856 if (inout == ATA_DATA_OUT) {
2857 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2861 // The header length must be even
2863 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2867 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2868 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2869 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2872 if (cmdlen < 12) cmdlen=12;
2873 if (cmdlen > 12) cmdlen=16;
2876 // Reset count of transferred data
2877 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2878 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2880 // Device should not be busy yet
2885 // wait for device to be ready
2887 status = inb(iobase1 + ATA_CB_STAT);
2888 // BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2889 } while (status & ATA_CB_STAT_BSY);
2891 status = inb(iobase1 + ATA_CB_STAT);
2892 if (status & ATA_CB_STAT_BSY) return 2;
2896 // set "noninterruptable"
2897 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2899 //outb(iobase1 + ATA_CB_FR, 0x00);
2900 //outb(iobase1 + ATA_CB_SC, 0x00);
2901 //outb(iobase1 + ATA_CB_SN, 0x00);
2903 // Set cylinders ?? - Why? And why not sector
2904 // This is all embedded in cmd_packet, anyway...
2905 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2906 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2908 // select master or slave
2909 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2911 // Tell it we are sending a command packet
2912 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2915 // Now wait for 400 ns
2918 for (i=0;i<0xffff; i++)
2923 // Device should ok to receive command
2924 // wait until we get
2927 status = inb(iobase1 + ATA_CB_STAT);
2930 if (!(status & ATA_CB_STAT_BSY)) break;
2932 // Shouldn't this be ATA_CB_STAT_RDY? -PAD - NO, it's OK
2933 if ( !(status & ATA_CB_STAT_BSY) ) break;
2938 if (status & ATA_CB_STAT_ERR) {
2939 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2941 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2942 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2946 // Normalize address
2947 cmdseg += (cmdoff / 16);
2950 // Send command to device
2952 sti ;; enable higher priority interrupts
2957 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2958 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2959 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2960 mov es, ax ;; segment in es
2962 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2966 outsw ;; CX words transfered from port(DX) to ES:[SI]
2971 // issue read of alternative status - claimed to be in spec
2972 //inb(iobase2+ATA_CB_ASTAT);
2975 if (inout == ATA_DATA_NO) {
2976 status = inb(iobase1 + ATA_CB_STAT);
2979 // Wait for completion
2982 status=inb(iobase1+ATA_CB_STAT);
2983 BX_DEBUG_ATA("ata_cmd_packet: wait (%2x)\n",status);
2984 } while ((status & ATA_CB_STAT_BSY));
2988 status = inb(iobase1 + ATA_CB_STAT);
2990 // Check if command completed
2991 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2993 if (status & ATA_CB_STAT_ERR) {
2994 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2998 // If we get here, we are ready and should have DRQ
2999 // and so data is available
3000 // Device must be ready to send data
3001 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3002 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3003 BX_DEBUG_ATA("ata_cmd_packet 1: not ready (status %02x)\n", status);
3007 // Normalize address
3008 bufseg += (bufoff / 16);
3011 // Get the byte count
3012 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3014 // adjust to read what we want
3027 lafter=lcount-length;
3039 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3040 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3042 // If counts not dividable by 4, use 16bits mode
3044 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3045 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3046 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3048 // adds an extra byte if count are odd. before is always even
3049 if (lcount & 0x01) {
3051 if ((lafter > 0) && (lafter & 0x01)) {
3056 if (lmode == ATA_MODE_PIO32) {
3057 lcount>>=2; lbefore>>=2; lafter>>=2;
3060 lcount>>=1; lbefore>>=1; lafter>>=1;
3069 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3071 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3072 jcxz ata_packet_no_before
3074 mov ah, _ata_cmd_packet.lmode + 2[bp]
3075 cmp ah, #ATA_MODE_PIO32
3076 je ata_packet_in_before_32
3078 ata_packet_in_before_16:
3080 loop ata_packet_in_before_16
3081 jmp ata_packet_no_before
3083 ata_packet_in_before_32:
3085 ata_packet_in_before_32_loop:
3087 loop ata_packet_in_before_32_loop
3090 ata_packet_no_before:
3091 mov cx, _ata_cmd_packet.lcount + 2[bp]
3092 jcxz ata_packet_after
3094 mov di, _ata_cmd_packet.bufoff + 2[bp]
3095 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3098 mov ah, _ata_cmd_packet.lmode + 2[bp]
3099 cmp ah, #ATA_MODE_PIO32
3104 insw ;; CX words transfered tp port(DX) to ES:[DI]
3105 jmp ata_packet_after
3109 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3112 mov cx, _ata_cmd_packet.lafter + 2[bp]
3113 jcxz ata_packet_done
3115 mov ah, _ata_cmd_packet.lmode + 2[bp]
3116 cmp ah, #ATA_MODE_PIO32
3117 je ata_packet_in_after_32
3119 ata_packet_in_after_16:
3121 loop ata_packet_in_after_16
3124 ata_packet_in_after_32:
3126 ata_packet_in_after_32_loop:
3128 loop ata_packet_in_after_32_loop
3135 // Compute new buffer address
3138 // Save transferred bytes count
3140 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3144 // Final check, device must be ready
3145 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3146 != ATA_CB_STAT_RDY ) {
3147 BX_DEBUG_ATA("ata_cmd_packet 2 : not ready (status %02x)\n", (unsigned) status);
3151 // Enable interrupts
3152 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3156 // ---------------------------------------------------------------------------
3157 // End of ATA/ATAPI Driver
3158 // ---------------------------------------------------------------------------
3161 // ---------------------------------------------------------------------------
3162 // Start of ATA/ATAPI generic functions
3163 // ---------------------------------------------------------------------------
3166 atapi_get_sense(device)
3173 memsetb(get_SS(),atacmd,0,12);
3178 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3181 if ((buffer[0] & 0x7e) == 0x70) {
3182 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3189 atapi_is_ready(device)
3195 memsetb(get_SS(),atacmd,0,12);
3198 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3201 if (atapi_get_sense(device) !=0 ) {
3202 memsetb(get_SS(),atacmd,0,12);
3204 // try to send Test Unit Ready again
3205 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3208 return atapi_get_sense(device);
3214 atapi_is_cdrom(device)
3217 Bit16u ebda_seg=read_word(0x0040,0x000E);
3219 if (device >= BX_MAX_ATA_DEVICES)
3222 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3225 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3231 // ---------------------------------------------------------------------------
3232 // End of ATA/ATAPI generic functions
3233 // ---------------------------------------------------------------------------
3235 #endif // BX_USE_ATADRV
3237 #if BX_ELTORITO_BOOT
3239 // ---------------------------------------------------------------------------
3240 // Start of El-Torito boot functions
3241 // ---------------------------------------------------------------------------
3246 Bit16u ebda_seg=read_word(0x0040,0x000E);
3248 //BX_DEBUG("rombios: cdemu_init\n");
3250 // the only important data is this one for now
3251 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3257 Bit16u ebda_seg=read_word(0x0040,0x000E);
3259 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3263 cdemu_emulated_drive()
3265 Bit16u ebda_seg=read_word(0x0040,0x000E);
3267 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3270 static char isotag[6]="CD001";
3271 static char eltorito[24]="EL TORITO SPECIFICATION";
3273 // Returns ah: emulated drive, al: error code
3278 Bit16u ebda_seg=read_word(0x0040,0x000E);
3279 Bit8u atacmd[12], buffer[2048];
3281 Bit16u boot_segment, nbsectors, i, error;
3285 // Find out the first cdrom
3286 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3287 if (atapi_is_cdrom(device)) break;
3291 if(device >= BX_MAX_ATA_DEVICES) return 2;
3293 // Read the Boot Record Volume Descriptor
3294 memsetb(get_SS(),atacmd,0,12);
3295 atacmd[0]=0x28; // READ command
3296 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3297 atacmd[8]=(0x01 & 0x00ff); // Sectors
3298 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3299 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3300 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3301 atacmd[5]=(0x11 & 0x000000ff);
3302 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3307 if(buffer[0]!=0)return 4;
3309 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3312 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3314 // ok, now we calculate the Boot catalog address
3315 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3317 // And we read the Boot Catalog
3318 memsetb(get_SS(),atacmd,0,12);
3319 atacmd[0]=0x28; // READ command
3320 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3321 atacmd[8]=(0x01 & 0x00ff); // Sectors
3322 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3323 atacmd[3]=(lba & 0x00ff0000) >> 16;
3324 atacmd[4]=(lba & 0x0000ff00) >> 8;
3325 atacmd[5]=(lba & 0x000000ff);
3326 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3332 if(buffer[0x00]!=0x01)return 8; // Header
3333 if(buffer[0x01]!=0x00)return 9; // Platform
3334 if(buffer[0x1E]!=0x55)return 10; // key 1
3335 if(buffer[0x1F]!=0xAA)return 10; // key 2
3337 // Initial/Default Entry
3338 if(buffer[0x20]!=0x88)return 11; // Bootable
3340 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3341 if(buffer[0x21]==0){
3342 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3343 // Win2000 cd boot needs to know it booted from cd
3344 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3346 else if(buffer[0x21]<4)
3347 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3349 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3351 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3352 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3354 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3355 if(boot_segment==0x0000)boot_segment=0x07C0;
3357 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3358 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3360 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3361 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3363 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3364 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3366 // And we read the image in memory
3367 memsetb(get_SS(),atacmd,0,12);
3368 atacmd[0]=0x28; // READ command
3369 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3370 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3371 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3372 atacmd[3]=(lba & 0x00ff0000) >> 16;
3373 atacmd[4]=(lba & 0x0000ff00) >> 8;
3374 atacmd[5]=(lba & 0x000000ff);
3375 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3379 // Remember the media type
3380 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3381 case 0x01: // 1.2M floppy
3382 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3383 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3384 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3386 case 0x02: // 1.44M floppy
3387 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3388 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3389 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3391 case 0x03: // 2.88M floppy
3392 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3393 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3394 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3396 case 0x04: // Harddrive
3397 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3398 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3399 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3400 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3404 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3405 // Increase bios installed hardware number of devices
3406 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3407 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3409 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3413 // everything is ok, so from now on, the emulation is active
3414 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3415 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3417 // return the boot drive + no error
3418 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3421 // ---------------------------------------------------------------------------
3422 // End of El-Torito boot functions
3423 // ---------------------------------------------------------------------------
3424 #endif // BX_ELTORITO_BOOT
3427 int14_function(regs, ds, iret_addr)
3428 pusha_regs_t regs; // regs pushed from PUSHA instruction
3429 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3430 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3432 Bit16u addr,timer,val16;
3439 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3440 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3441 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3442 switch (regs.u.r8.ah) {
3444 outb(addr+3, inb(addr+3) | 0x80);
3445 if (regs.u.r8.al & 0xE0 == 0) {
3449 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3450 outb(addr, val16 & 0xFF);
3451 outb(addr+1, val16 >> 8);
3453 outb(addr+3, regs.u.r8.al & 0x1F);
3454 regs.u.r8.ah = inb(addr+5);
3455 regs.u.r8.al = inb(addr+6);
3456 ClearCF(iret_addr.flags);
3459 timer = read_word(0x0040, 0x006C);
3460 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3461 val16 = read_word(0x0040, 0x006C);
3462 if (val16 != timer) {
3467 if (timeout) outb(addr, regs.u.r8.al);
3468 regs.u.r8.ah = inb(addr+5);
3469 if (!timeout) regs.u.r8.ah |= 0x80;
3470 ClearCF(iret_addr.flags);
3473 timer = read_word(0x0040, 0x006C);
3474 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3475 val16 = read_word(0x0040, 0x006C);
3476 if (val16 != timer) {
3483 regs.u.r8.al = inb(addr);
3485 regs.u.r8.ah = inb(addr+5);
3487 ClearCF(iret_addr.flags);
3490 regs.u.r8.ah = inb(addr+5);
3491 regs.u.r8.al = inb(addr+6);
3492 ClearCF(iret_addr.flags);
3495 SetCF(iret_addr.flags); // Unsupported
3498 SetCF(iret_addr.flags); // Unsupported
3503 int15_function(regs, ES, DS, FLAGS)
3504 pusha_regs_t regs; // REGS pushed via pusha
3505 Bit16u ES, DS, FLAGS;
3507 Bit16u ebda_seg=read_word(0x0040,0x000E);
3508 bx_bool prev_a20_enable;
3517 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3519 switch (regs.u.r8.ah) {
3520 case 0x24: /* A20 Control */
3521 switch (regs.u.r8.al) {
3533 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3543 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3545 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3551 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3555 /* keyboard intercept */
3557 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3564 case 0x52: // removable media eject
3566 regs.u.r8.ah = 0; // "ok ejection may proceed"
3570 if( regs.u.r8.al == 0 ) {
3571 // Set Interval requested.
3572 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3573 // Interval not already set.
3574 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3575 write_word( 0x40, 0x98, ES ); // Byte location, segment
3576 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3577 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3578 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3580 irqDisable = inb( 0xA1 );
3581 outb( 0xA1, irqDisable & 0xFE );
3582 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3583 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3585 // Interval already set.
3586 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3588 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3590 } else if( regs.u.r8.al == 1 ) {
3591 // Clear Interval requested
3592 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3594 bRegister = inb_cmos( 0xB );
3595 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3597 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3599 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3608 # error "Int15 function 87h not supported on < 80386"
3610 // +++ should probably have descriptor checks
3611 // +++ should have exception handlers
3613 // turn off interrupts
3618 prev_a20_enable = set_enable_a20(1); // enable A20 line
3620 // 128K max of transfer on 386+ ???
3621 // source == destination ???
3623 // ES:SI points to descriptor table
3624 // offset use initially comments
3625 // ==============================================
3626 // 00..07 Unused zeros Null descriptor
3627 // 08..0f GDT zeros filled in by BIOS
3628 // 10..17 source ssssssss source of data
3629 // 18..1f dest dddddddd destination of data
3630 // 20..27 CS zeros filled in by BIOS
3631 // 28..2f SS zeros filled in by BIOS
3638 // check for access rights of source & dest here
3640 // Initialize GDT descriptor
3641 base15_00 = (ES << 4) + regs.u.r16.si;
3642 base23_16 = ES >> 12;
3643 if (base15_00 < (ES<<4))
3645 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3646 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3647 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3648 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3649 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3651 // Initialize CS descriptor
3652 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3653 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3654 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3655 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3656 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3658 // Initialize SS descriptor
3660 base15_00 = ss << 4;
3661 base23_16 = ss >> 12;
3662 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3663 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3664 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3665 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3666 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3670 // Compile generates locals offset info relative to SP.
3671 // Get CX (word count) from stack.
3674 mov cx, _int15_function.CX [bx]
3676 // since we need to set SS:SP, save them to the BDA
3677 // for future restore
3687 lidt [pmode_IDT_info]
3688 ;; perhaps do something with IDT here
3690 ;; set PE bit in CR0
3694 ;; far jump to flush CPU queue after transition to protected mode
3695 JMP_AP(0x0020, protected_mode)
3698 ;; GDT points to valid descriptor table, now load SS, DS, ES
3699 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3701 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3703 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3709 movsw ;; move CX words from DS:SI to ES:DI
3711 ;; make sure DS and ES limits are 64KB
3716 ;; reset PG bit in CR0 ???
3721 ;; far jump to flush CPU queue after transition to real mode
3722 JMP_AP(0xf000, real_mode)
3725 ;; restore IDT to normal real-mode defaults
3727 lidt [rmode_IDT_info]
3729 // restore SS:SP from the BDA
3737 set_enable_a20(prev_a20_enable);
3739 // turn back on interrupts
3750 // Get the amount of extended memory (above 1M)
3752 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3755 regs.u.r8.al = inb_cmos(0x30);
3756 regs.u.r8.ah = inb_cmos(0x31);
3759 if(regs.u.r16.ax > 0x3c00)
3760 regs.u.r16.ax = 0x3c00;
3767 /* Device busy interrupt. Called by Int 16h when no key available */
3771 /* Interrupt complete. Called by Int 16h when key becomes available */
3775 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3777 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3783 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3788 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3798 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3800 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3804 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3805 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3807 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3812 #if BX_USE_PS2_MOUSE
3814 int15_function_mouse(regs, ES, DS, FLAGS)
3815 pusha_regs_t regs; // REGS pushed via pusha
3816 Bit16u ES, DS, FLAGS;
3818 Bit16u ebda_seg=read_word(0x0040,0x000E);
3819 Bit8u mouse_flags_1, mouse_flags_2;
3820 Bit16u mouse_driver_seg;
3821 Bit16u mouse_driver_offset;
3822 Bit8u comm_byte, prev_command_byte;
3823 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3825 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3827 switch (regs.u.r8.ah) {
3829 // Return Codes status in AH
3830 // =========================
3832 // 01: invalid subfunction (AL > 7)
3833 // 02: invalid input value (out of allowable range)
3834 // 03: interface error
3835 // 04: resend command received from mouse controller,
3836 // device driver should attempt command again
3837 // 05: cannot enable mouse, since no far call has been installed
3838 // 80/86: mouse service not implemented
3840 switch (regs.u.r8.al) {
3841 case 0: // Disable/Enable Mouse
3842 BX_DEBUG_INT15("case 0:\n");
3843 switch (regs.u.r8.bh) {
3844 case 0: // Disable Mouse
3845 BX_DEBUG_INT15("case 0: disable mouse\n");
3846 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3847 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3849 ret = get_mouse_data(&mouse_data1);
3850 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3863 case 1: // Enable Mouse
3864 BX_DEBUG_INT15("case 1: enable mouse\n");
3865 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3866 if ( (mouse_flags_2 & 0x80) == 0 ) {
3867 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3869 regs.u.r8.ah = 5; // no far call installed
3872 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3873 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3875 ret = get_mouse_data(&mouse_data1);
3876 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3877 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3887 default: // invalid subfunction
3888 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3890 regs.u.r8.ah = 1; // invalid subfunction
3895 case 1: // Reset Mouse
3896 case 5: // Initialize Mouse
3897 BX_DEBUG_INT15("case 1 or 5:\n");
3898 if (regs.u.r8.al == 5) {
3899 if (regs.u.r8.bh != 3) {
3901 regs.u.r8.ah = 0x02; // invalid input
3904 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3905 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3906 mouse_flags_1 = 0x00;
3907 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3908 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3911 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3912 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3914 ret = get_mouse_data(&mouse_data3);
3915 // if no mouse attached, it will return RESEND
3916 if (mouse_data3 == 0xfe) {
3920 if (mouse_data3 != 0xfa)
3921 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3923 ret = get_mouse_data(&mouse_data1);
3925 ret = get_mouse_data(&mouse_data2);
3927 // turn IRQ12 and packet generation on
3928 enable_mouse_int_and_events();
3931 regs.u.r8.bl = mouse_data1;
3932 regs.u.r8.bh = mouse_data2;
3944 case 2: // Set Sample Rate
3945 BX_DEBUG_INT15("case 2:\n");
3946 switch (regs.u.r8.bh) {
3947 case 0: mouse_data1 = 10; break; // 10 reports/sec
3948 case 1: mouse_data1 = 20; break; // 20 reports/sec
3949 case 2: mouse_data1 = 40; break; // 40 reports/sec
3950 case 3: mouse_data1 = 60; break; // 60 reports/sec
3951 case 4: mouse_data1 = 80; break; // 80 reports/sec
3952 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3953 case 6: mouse_data1 = 200; break; // 200 reports/sec
3954 default: mouse_data1 = 0;
3956 if (mouse_data1 > 0) {
3957 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3959 ret = get_mouse_data(&mouse_data2);
3960 ret = send_to_mouse_ctrl(mouse_data1);
3961 ret = get_mouse_data(&mouse_data2);
3967 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3972 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3976 case 3: // Set Resolution
3977 BX_DEBUG_INT15("case 3:\n");
3979 // 0 = 25 dpi, 1 count per millimeter
3980 // 1 = 50 dpi, 2 counts per millimeter
3981 // 2 = 100 dpi, 4 counts per millimeter
3982 // 3 = 200 dpi, 8 counts per millimeter
3987 case 4: // Get Device ID
3988 BX_DEBUG_INT15("case 4:\n");
3989 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3990 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3992 ret = get_mouse_data(&mouse_data1);
3993 ret = get_mouse_data(&mouse_data2);
3996 regs.u.r8.bh = mouse_data2;
4000 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4004 case 6: // Return Status & Set Scaling Factor...
4005 BX_DEBUG_INT15("case 6:\n");
4006 switch (regs.u.r8.bh) {
4007 case 0: // Return Status
4008 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4009 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4011 ret = get_mouse_data(&mouse_data1);
4012 if (mouse_data1 != 0xfa)
4013 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4015 ret = get_mouse_data(&mouse_data1);
4017 ret = get_mouse_data(&mouse_data2);
4019 ret = get_mouse_data(&mouse_data3);
4023 regs.u.r8.bl = mouse_data1;
4024 regs.u.r8.cl = mouse_data2;
4025 regs.u.r8.dl = mouse_data3;
4026 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4037 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4040 case 1: // Set Scaling Factor to 1:1
4041 case 2: // Set Scaling Factor to 2:1
4042 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4043 if (regs.u.r8.bh == 1) {
4044 ret = send_to_mouse_ctrl(0xE6);
4046 ret = send_to_mouse_ctrl(0xE7);
4049 get_mouse_data(&mouse_data1);
4050 ret = (mouse_data1 != 0xFA);
4058 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4060 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4064 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4068 case 7: // Set Mouse Handler Address
4069 BX_DEBUG_INT15("case 7:\n");
4070 mouse_driver_seg = ES;
4071 mouse_driver_offset = regs.u.r16.bx;
4072 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4073 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4074 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4075 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4076 /* remove handler */
4077 if ( (mouse_flags_2 & 0x80) != 0 ) {
4078 mouse_flags_2 &= ~0x80;
4079 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4083 /* install handler */
4084 mouse_flags_2 |= 0x80;
4086 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4092 BX_DEBUG_INT15("case default:\n");
4093 regs.u.r8.ah = 1; // invalid function
4099 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4100 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4102 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4109 int15_function32(regs, ES, DS, FLAGS)
4110 pushad_regs_t regs; // REGS pushed via pushad
4111 Bit16u ES, DS, FLAGS;
4113 Bit32u extended_memory_size=0; // 64bits long
4116 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4118 switch (regs.u.r8.ah) {
4120 // Wait for CX:DX microseconds. currently using the
4121 // refresh request port 0x61 bit4, toggling every 15usec
4129 ;; Get the count in eax
4132 mov ax, _int15_function.CX [bx]
4135 mov ax, _int15_function.DX [bx]
4137 ;; convert to numbers of 15usec ticks
4143 ;; wait for ecx number of refresh requests
4164 switch(regs.u.r8.al)
4166 case 0x20: // coded by osmaker aka K.J.
4167 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4170 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4171 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4173 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4174 memcpyb(ES, regs.u.r16.di,
4175 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4177 regs.u.r32.ebx += 0x14;
4178 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4180 regs.u.r32.eax = 0x534D4150;
4181 regs.u.r32.ecx = 0x14;
4184 } else if (regs.u.r16.bx == 1) {
4185 extended_memory_size = inb_cmos(0x35);
4186 extended_memory_size <<= 8;
4187 extended_memory_size |= inb_cmos(0x34);
4188 extended_memory_size *= 64;
4189 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4191 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4193 extended_memory_size *= 1024;
4194 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4196 if (extended_memory_size <= 15728640)
4198 extended_memory_size = inb_cmos(0x31);
4199 extended_memory_size <<= 8;
4200 extended_memory_size |= inb_cmos(0x30);
4201 extended_memory_size *= 1024;
4204 write_word(ES, regs.u.r16.di, 0x0000);
4205 write_word(ES, regs.u.r16.di+2, 0x0010);
4206 write_word(ES, regs.u.r16.di+4, 0x0000);
4207 write_word(ES, regs.u.r16.di+6, 0x0000);
4209 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4210 extended_memory_size >>= 16;
4211 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4212 extended_memory_size >>= 16;
4213 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4214 extended_memory_size >>= 16;
4215 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4217 write_word(ES, regs.u.r16.di+16, 0x1);
4218 write_word(ES, regs.u.r16.di+18, 0x0);
4221 regs.u.r32.eax = 0x534D4150;
4222 regs.u.r32.ecx = 0x14;
4225 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4226 goto int15_unimplemented;
4229 switch(regs.u.r16.bx)
4232 write_word(ES, regs.u.r16.di, 0x00);
4233 write_word(ES, regs.u.r16.di+2, 0x00);
4234 write_word(ES, regs.u.r16.di+4, 0x00);
4235 write_word(ES, regs.u.r16.di+6, 0x00);
4237 write_word(ES, regs.u.r16.di+8, 0xFC00);
4238 write_word(ES, regs.u.r16.di+10, 0x0009);
4239 write_word(ES, regs.u.r16.di+12, 0x0000);
4240 write_word(ES, regs.u.r16.di+14, 0x0000);
4242 write_word(ES, regs.u.r16.di+16, 0x1);
4243 write_word(ES, regs.u.r16.di+18, 0x0);
4247 regs.u.r32.eax = 0x534D4150;
4248 regs.u.r32.ecx = 0x14;
4253 extended_memory_size = inb_cmos(0x35);
4254 extended_memory_size <<= 8;
4255 extended_memory_size |= inb_cmos(0x34);
4256 extended_memory_size *= 64;
4257 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4259 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4261 extended_memory_size *= 1024;
4262 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4264 if(extended_memory_size <= 15728640)
4266 extended_memory_size = inb_cmos(0x31);
4267 extended_memory_size <<= 8;
4268 extended_memory_size |= inb_cmos(0x30);
4269 extended_memory_size *= 1024;
4272 write_word(ES, regs.u.r16.di, 0x0000);
4273 write_word(ES, regs.u.r16.di+2, 0x0010);
4274 write_word(ES, regs.u.r16.di+4, 0x0000);
4275 write_word(ES, regs.u.r16.di+6, 0x0000);
4277 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4278 extended_memory_size >>= 16;
4279 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4280 extended_memory_size >>= 16;
4281 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4282 extended_memory_size >>= 16;
4283 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4285 write_word(ES, regs.u.r16.di+16, 0x1);
4286 write_word(ES, regs.u.r16.di+18, 0x0);
4289 regs.u.r32.eax = 0x534D4150;
4290 regs.u.r32.ecx = 0x14;
4294 default: /* AX=E820, DX=534D4150, BX unrecognized */
4295 goto int15_unimplemented;
4300 // if DX != 0x534D4150)
4301 goto int15_unimplemented;
4306 // do we have any reason to fail here ?
4309 // my real system sets ax and bx to 0
4310 // this is confirmed by Ralph Brown list
4311 // but syslinux v1.48 is known to behave
4312 // strangely if ax is set to 0
4313 // regs.u.r16.ax = 0;
4314 // regs.u.r16.bx = 0;
4316 // Get the amount of extended memory (above 1M)
4317 regs.u.r8.cl = inb_cmos(0x30);
4318 regs.u.r8.ch = inb_cmos(0x31);
4321 if(regs.u.r16.cx > 0x3c00)
4323 regs.u.r16.cx = 0x3c00;
4326 // Get the amount of extended memory above 16M in 64k blocs
4327 regs.u.r8.dl = inb_cmos(0x34);
4328 regs.u.r8.dh = inb_cmos(0x35);
4330 // Set configured memory equal to extended memory
4331 regs.u.r16.ax = regs.u.r16.cx;
4332 regs.u.r16.bx = regs.u.r16.dx;
4334 default: /* AH=0xE8?? but not implemented */
4335 goto int15_unimplemented;
4338 int15_unimplemented:
4339 // fall into the default
4341 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4342 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4344 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4350 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4351 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4353 Bit8u scan_code, ascii_code, shift_flags, count;
4354 Bit16u kbd_code, max;
4356 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4359 case 0x00: /* read keyboard input */
4361 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4362 BX_PANIC("KBD: int16h: out of keyboard input\n");
4364 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4365 else if (ascii_code == 0xE0) ascii_code = 0;
4366 AX = (scan_code << 8) | ascii_code;
4369 case 0x01: /* check keyboard status */
4370 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4374 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4375 else if (ascii_code == 0xE0) ascii_code = 0;
4376 AX = (scan_code << 8) | ascii_code;
4380 case 0x02: /* get shift flag status */
4381 shift_flags = read_byte(0x0040, 0x17);
4382 SET_AL(shift_flags);
4385 case 0x05: /* store key-stroke into buffer */
4386 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4394 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4395 // bit Bochs Description
4397 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4398 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4399 // 4 1 INT 16/AH=0Ah supported
4400 // 3 0 INT 16/AX=0306h supported
4401 // 2 0 INT 16/AX=0305h supported
4402 // 1 0 INT 16/AX=0304h supported
4403 // 0 0 INT 16/AX=0300h supported
4408 case 0x0A: /* GET KEYBOARD ID */
4414 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4416 if ((inb(0x60) == 0xfa)) {
4419 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4422 kbd_code |= (inb(0x60) << 8);
4424 } while (--count>0);
4430 case 0x10: /* read MF-II keyboard input */
4432 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4433 BX_PANIC("KBD: int16h: out of keyboard input\n");
4435 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4436 AX = (scan_code << 8) | ascii_code;
4439 case 0x11: /* check MF-II keyboard status */
4440 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4444 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4445 AX = (scan_code << 8) | ascii_code;
4449 case 0x12: /* get extended keyboard status */
4450 shift_flags = read_byte(0x0040, 0x17);
4451 SET_AL(shift_flags);
4452 shift_flags = read_byte(0x0040, 0x18);
4453 SET_AH(shift_flags);
4454 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4457 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4458 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4461 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4462 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4466 if (GET_AL() == 0x08)
4467 SET_AH(0x02); // unsupported, aka normal keyboard
4470 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4475 dequeue_key(scan_code, ascii_code, incr)
4480 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4485 buffer_start = 0x001E;
4486 buffer_end = 0x003E;
4488 buffer_start = read_word(0x0040, 0x0080);
4489 buffer_end = read_word(0x0040, 0x0082);
4492 buffer_head = read_word(0x0040, 0x001a);
4493 buffer_tail = read_word(0x0040, 0x001c);
4495 if (buffer_head != buffer_tail) {
4497 acode = read_byte(0x0040, buffer_head);
4498 scode = read_byte(0x0040, buffer_head+1);
4499 write_byte(ss, ascii_code, acode);
4500 write_byte(ss, scan_code, scode);
4504 if (buffer_head >= buffer_end)
4505 buffer_head = buffer_start;
4506 write_word(0x0040, 0x001a, buffer_head);
4515 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4518 inhibit_mouse_int_and_events()
4520 Bit8u command_byte, prev_command_byte;
4522 // Turn off IRQ generation and aux data line
4523 if ( inb(0x64) & 0x02 )
4524 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4525 outb(0x64, 0x20); // get command byte
4526 while ( (inb(0x64) & 0x01) != 0x01 );
4527 prev_command_byte = inb(0x60);
4528 command_byte = prev_command_byte;
4529 //while ( (inb(0x64) & 0x02) );
4530 if ( inb(0x64) & 0x02 )
4531 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4532 command_byte &= 0xfd; // turn off IRQ 12 generation
4533 command_byte |= 0x20; // disable mouse serial clock line
4534 outb(0x64, 0x60); // write command byte
4535 outb(0x60, command_byte);
4536 return(prev_command_byte);
4540 enable_mouse_int_and_events()
4544 // Turn on IRQ generation and aux data line
4545 if ( inb(0x64) & 0x02 )
4546 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4547 outb(0x64, 0x20); // get command byte
4548 while ( (inb(0x64) & 0x01) != 0x01 );
4549 command_byte = inb(0x60);
4550 //while ( (inb(0x64) & 0x02) );
4551 if ( inb(0x64) & 0x02 )
4552 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4553 command_byte |= 0x02; // turn on IRQ 12 generation
4554 command_byte &= 0xdf; // enable mouse serial clock line
4555 outb(0x64, 0x60); // write command byte
4556 outb(0x60, command_byte);
4560 send_to_mouse_ctrl(sendbyte)
4565 // wait for chance to write to ctrl
4566 if ( inb(0x64) & 0x02 )
4567 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4569 outb(0x60, sendbyte);
4575 get_mouse_data(data)
4581 while ( (inb(0x64) & 0x21) != 0x21 ) {
4584 response = inb(0x60);
4587 write_byte(ss, data, response);
4592 set_kbd_command_byte(command_byte)
4595 if ( inb(0x64) & 0x02 )
4596 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4599 outb(0x64, 0x60); // write command byte
4600 outb(0x60, command_byte);
4604 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4605 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4607 Bit8u scancode, asciicode, shift_flags;
4608 Bit8u mf2_flags, mf2_state, led_flags;
4611 // DS has been set to F000 before call
4615 scancode = GET_AL();
4617 if (scancode == 0) {
4618 BX_INFO("KBD: int09 handler: AL=0\n");
4623 shift_flags = read_byte(0x0040, 0x17);
4624 mf2_flags = read_byte(0x0040, 0x18);
4625 mf2_state = read_byte(0x0040, 0x96);
4626 led_flags = read_byte(0x0040, 0x97);
4630 case 0x3a: /* Caps Lock press */
4631 shift_flags ^= 0x40;
4632 write_byte(0x0040, 0x17, shift_flags);
4634 write_byte(0x0040, 0x18, mf2_flags);
4636 write_byte(0x0040, 0x97, led_flags);
4638 case 0xba: /* Caps Lock release */
4640 write_byte(0x0040, 0x18, mf2_flags);
4643 case 0x2a: /* L Shift press */
4644 /*shift_flags &= ~0x40;*/
4645 shift_flags |= 0x02;
4646 write_byte(0x0040, 0x17, shift_flags);
4648 write_byte(0x0040, 0x97, led_flags);
4650 case 0xaa: /* L Shift release */
4651 shift_flags &= ~0x02;
4652 write_byte(0x0040, 0x17, shift_flags);
4655 case 0x36: /* R Shift press */
4656 /*shift_flags &= ~0x40;*/
4657 shift_flags |= 0x01;
4658 write_byte(0x0040, 0x17, shift_flags);
4660 write_byte(0x0040, 0x97, led_flags);
4662 case 0xb6: /* R Shift release */
4663 shift_flags &= ~0x01;
4664 write_byte(0x0040, 0x17, shift_flags);
4667 case 0x1d: /* Ctrl press */
4668 shift_flags |= 0x04;
4669 write_byte(0x0040, 0x17, shift_flags);
4670 if (mf2_state & 0x01) {
4675 write_byte(0x0040, 0x18, mf2_flags);
4677 case 0x9d: /* Ctrl release */
4678 shift_flags &= ~0x04;
4679 write_byte(0x0040, 0x17, shift_flags);
4680 if (mf2_state & 0x01) {
4685 write_byte(0x0040, 0x18, mf2_flags);
4688 case 0x38: /* Alt press */
4689 shift_flags |= 0x08;
4690 write_byte(0x0040, 0x17, shift_flags);
4691 if (mf2_state & 0x01) {
4696 write_byte(0x0040, 0x18, mf2_flags);
4698 case 0xb8: /* Alt release */
4699 shift_flags &= ~0x08;
4700 write_byte(0x0040, 0x17, shift_flags);
4701 if (mf2_state & 0x01) {
4706 write_byte(0x0040, 0x18, mf2_flags);
4709 case 0x45: /* Num Lock press */
4710 if ((mf2_state & 0x01) == 0) {
4712 write_byte(0x0040, 0x18, mf2_flags);
4713 shift_flags ^= 0x20;
4715 write_byte(0x0040, 0x17, shift_flags);
4716 write_byte(0x0040, 0x97, led_flags);
4719 case 0xc5: /* Num Lock release */
4720 if ((mf2_state & 0x01) == 0) {
4722 write_byte(0x0040, 0x18, mf2_flags);
4726 case 0x46: /* Scroll Lock press */
4728 write_byte(0x0040, 0x18, mf2_flags);
4729 shift_flags ^= 0x10;
4731 write_byte(0x0040, 0x17, shift_flags);
4732 write_byte(0x0040, 0x97, led_flags);
4735 case 0xc6: /* Scroll Lock release */
4737 write_byte(0x0040, 0x18, mf2_flags);
4741 if (scancode & 0x80) return; /* toss key releases ... */
4742 if (scancode > MAX_SCAN_CODE) {
4743 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4746 if (shift_flags & 0x08) { /* ALT */
4747 asciicode = scan_to_scanascii[scancode].alt;
4748 scancode = scan_to_scanascii[scancode].alt >> 8;
4750 else if (shift_flags & 0x04) { /* CONTROL */
4751 asciicode = scan_to_scanascii[scancode].control;
4752 scancode = scan_to_scanascii[scancode].control >> 8;
4754 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4755 /* check if lock state should be ignored
4756 * because a SHIFT key are pressed */
4758 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4759 asciicode = scan_to_scanascii[scancode].normal;
4760 scancode = scan_to_scanascii[scancode].normal >> 8;
4763 asciicode = scan_to_scanascii[scancode].shift;
4764 scancode = scan_to_scanascii[scancode].shift >> 8;
4768 /* check if lock is on */
4769 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4770 asciicode = scan_to_scanascii[scancode].shift;
4771 scancode = scan_to_scanascii[scancode].shift >> 8;
4774 asciicode = scan_to_scanascii[scancode].normal;
4775 scancode = scan_to_scanascii[scancode].normal >> 8;
4778 if (scancode==0 && asciicode==0) {
4779 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4781 enqueue_key(scancode, asciicode);
4788 enqueue_key(scan_code, ascii_code)
4789 Bit8u scan_code, ascii_code;
4791 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4793 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4794 // scan_code, ascii_code);
4797 buffer_start = 0x001E;
4798 buffer_end = 0x003E;
4800 buffer_start = read_word(0x0040, 0x0080);
4801 buffer_end = read_word(0x0040, 0x0082);
4804 buffer_head = read_word(0x0040, 0x001A);
4805 buffer_tail = read_word(0x0040, 0x001C);
4807 temp_tail = buffer_tail;
4809 if (buffer_tail >= buffer_end)
4810 buffer_tail = buffer_start;
4812 if (buffer_tail == buffer_head) {
4816 write_byte(0x0040, temp_tail, ascii_code);
4817 write_byte(0x0040, temp_tail+1, scan_code);
4818 write_word(0x0040, 0x001C, buffer_tail);
4824 int74_function(make_farcall, Z, Y, X, status)
4825 Bit16u make_farcall, Z, Y, X, status;
4827 Bit16u ebda_seg=read_word(0x0040,0x000E);
4828 Bit8u in_byte, index, package_count;
4829 Bit8u mouse_flags_1, mouse_flags_2;
4831 BX_DEBUG_INT74("entering int74_function\n");
4834 in_byte = inb(0x64);
4835 if ( (in_byte & 0x21) != 0x21 ) {
4838 in_byte = inb(0x60);
4839 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4841 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4842 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4844 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4845 // BX_PANIC("int74_function:\n");
4849 package_count = mouse_flags_2 & 0x07;
4850 index = mouse_flags_1 & 0x07;
4851 write_byte(ebda_seg, 0x28 + index, in_byte);
4853 if ( (index+1) >= package_count ) {
4854 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4855 status = read_byte(ebda_seg, 0x0028 + 0);
4856 X = read_byte(ebda_seg, 0x0028 + 1);
4857 Y = read_byte(ebda_seg, 0x0028 + 2);
4860 // check if far call handler installed
4861 if (mouse_flags_2 & 0x80)
4867 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4870 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4875 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4876 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4879 Bit16u ebda_seg=read_word(0x0040,0x000E);
4880 Bit16u cylinder, head, sector;
4881 Bit16u segment, offset;
4882 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4884 Bit8u device, status;
4886 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4888 write_byte(0x0040, 0x008e, 0); // clear completion flag
4890 // basic check : device has to be defined
4891 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4892 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4896 // Get the ata channel
4897 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4899 // basic check : device has to be valid
4900 if (device >= BX_MAX_ATA_DEVICES) {
4901 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4907 case 0x00: /* disk controller reset */
4912 case 0x01: /* read disk status */
4913 status = read_byte(0x0040, 0x0074);
4915 SET_DISK_RET_STATUS(0);
4916 /* set CF if error status read */
4917 if (status) goto int13_fail_nostatus;
4918 else goto int13_success_noah;
4921 case 0x02: // read disk sectors
4922 case 0x03: // write disk sectors
4923 case 0x04: // verify disk sectors
4926 cylinder = GET_CH();
4927 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4928 sector = (GET_CL() & 0x3f);
4934 if ( (count > 128) || (count == 0) ) {
4935 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4939 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4940 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4941 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4943 // sanity check on cyl heads, sec
4944 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4945 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4950 if ( GET_AH() == 0x04 ) goto int13_success;
4952 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4953 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4955 // if needed, translate lchs to lba, and execute command
4956 if ( (nph != nlh) || (npspt != nlspt)) {
4957 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4958 sector = 0; // this forces the command to be lba
4961 if ( GET_AH() == 0x02 )
4962 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4964 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4966 // Set nb of sector transferred
4967 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4970 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4972 goto int13_fail_noah;
4978 case 0x05: /* format disk track */
4979 BX_INFO("format disk track called\n");
4984 case 0x08: /* read disk drive parameters */
4986 // Get logical geometry from table
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);
4990 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4992 nlc = nlc - 2; /* 0 based , last sector not used */
4995 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4997 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4999 // FIXME should set ES & DI
5004 case 0x10: /* check drive ready */
5005 // should look at 40:8E also???
5007 // Read the status from controller
5008 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5009 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5014 goto int13_fail_noah;
5018 case 0x15: /* read disk drive size */
5020 // Get physical geometry from table
5021 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5022 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5023 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5025 // Compute sector count seen by int13
5026 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5030 SET_AH(3); // hard disk accessible
5031 goto int13_success_noah;
5034 case 0x41: // IBM/MS installation check
5035 BX=0xaa55; // install check
5036 SET_AH(0x30); // EDD 3.0
5037 CX=0x0007; // ext disk access and edd, removable supported
5038 goto int13_success_noah;
5041 case 0x42: // IBM/MS extended read
5042 case 0x43: // IBM/MS extended write
5043 case 0x44: // IBM/MS verify
5044 case 0x47: // IBM/MS extended seek
5046 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5047 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5048 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5050 // Can't use 64 bits lba
5051 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5053 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5057 // Get 32 bits lba and check
5058 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5059 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5060 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5064 // If verify or seek
5065 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5068 // Execute the command
5069 if ( GET_AH() == 0x42 )
5070 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5072 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5074 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5075 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5078 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5080 goto int13_fail_noah;
5086 case 0x45: // IBM/MS lock/unlock drive
5087 case 0x49: // IBM/MS extended media change
5088 goto int13_success; // Always success for HD
5091 case 0x46: // IBM/MS eject media
5092 SET_AH(0xb2); // Volume Not Removable
5093 goto int13_fail_noah; // Always fail for HD
5096 case 0x48: // IBM/MS get drive parameters
5097 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5099 // Buffer is too small
5107 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5108 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5109 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5110 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5111 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5113 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5114 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5115 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5116 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5117 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5118 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5119 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5120 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5125 Bit8u channel, dev, irq, mode, checksum, i, translation;
5126 Bit16u iobase1, iobase2, options;
5128 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5130 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5131 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5134 channel = device / 2;
5135 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5136 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5137 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5138 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5139 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5141 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5142 options |= (1<<4); // lba translation
5143 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5144 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5145 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5147 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5148 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5149 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5150 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5151 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5152 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5153 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5154 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5155 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5156 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5157 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5160 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5161 checksum = ~checksum;
5162 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5167 Bit8u channel, iface, checksum, i;
5170 channel = device / 2;
5171 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5172 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5174 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5175 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5176 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5177 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5178 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5180 if (iface==ATA_IFACE_ISA) {
5181 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5182 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5183 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5184 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5189 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5190 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5191 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5192 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5194 if (iface==ATA_IFACE_ISA) {
5195 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5196 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5197 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5202 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5203 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5204 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5205 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5208 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5209 checksum = ~checksum;
5210 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5216 case 0x4e: // // IBM/MS set hardware configuration
5217 // DMA, prefetch, PIO maximum not supported
5230 case 0x09: /* initialize drive parameters */
5231 case 0x0c: /* seek to specified cylinder */
5232 case 0x0d: /* alternate disk reset */
5233 case 0x11: /* recalibrate */
5234 case 0x14: /* controller internal diagnostic */
5235 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5239 case 0x0a: /* read disk sectors with ECC */
5240 case 0x0b: /* write disk sectors with ECC */
5241 case 0x18: // set media type for format
5242 case 0x50: // IBM/MS send packet command
5244 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5250 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5252 SET_DISK_RET_STATUS(GET_AH());
5253 int13_fail_nostatus:
5254 SET_CF(); // error occurred
5258 SET_AH(0x00); // no error
5260 SET_DISK_RET_STATUS(0x00);
5261 CLEAR_CF(); // no error
5265 // ---------------------------------------------------------------------------
5266 // Start of int13 for cdrom
5267 // ---------------------------------------------------------------------------
5270 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5271 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5273 Bit16u ebda_seg=read_word(0x0040,0x000E);
5274 Bit8u device, status, locks;
5277 Bit16u count, segment, offset, i, size;
5279 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5280 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5282 SET_DISK_RET_STATUS(0x00);
5284 /* basic check : device should be 0xE0+ */
5285 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5286 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5290 // Get the ata channel
5291 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5293 /* basic check : device has to be valid */
5294 if (device >= BX_MAX_ATA_DEVICES) {
5295 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5301 // all those functions return SUCCESS
5302 case 0x00: /* disk controller reset */
5303 case 0x09: /* initialize drive parameters */
5304 case 0x0c: /* seek to specified cylinder */
5305 case 0x0d: /* alternate disk reset */
5306 case 0x10: /* check drive ready */
5307 case 0x11: /* recalibrate */
5308 case 0x14: /* controller internal diagnostic */
5309 case 0x16: /* detect disk change */
5313 // all those functions return disk write-protected
5314 case 0x03: /* write disk sectors */
5315 case 0x05: /* format disk track */
5316 case 0x43: // IBM/MS extended write
5318 goto int13_fail_noah;
5321 case 0x01: /* read disk status */
5322 status = read_byte(0x0040, 0x0074);
5324 SET_DISK_RET_STATUS(0);
5326 /* set CF if error status read */
5327 if (status) goto int13_fail_nostatus;
5328 else goto int13_success_noah;
5331 case 0x15: /* read disk drive size */
5333 goto int13_fail_noah;
5336 case 0x41: // IBM/MS installation check
5337 BX=0xaa55; // install check
5338 SET_AH(0x30); // EDD 2.1
5339 CX=0x0007; // ext disk access, removable and edd
5340 goto int13_success_noah;
5343 case 0x42: // IBM/MS extended read
5344 case 0x44: // IBM/MS verify sectors
5345 case 0x47: // IBM/MS extended seek
5347 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5348 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5349 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5351 // Can't use 64 bits lba
5352 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5354 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5359 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5361 // If verify or seek
5362 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5365 memsetb(get_SS(),atacmd,0,12);
5366 atacmd[0]=0x28; // READ command
5367 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5368 atacmd[8]=(count & 0x00ff); // Sectors
5369 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5370 atacmd[3]=(lba & 0x00ff0000) >> 16;
5371 atacmd[4]=(lba & 0x0000ff00) >> 8;
5372 atacmd[5]=(lba & 0x000000ff);
5373 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5375 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5376 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5379 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5381 goto int13_fail_noah;
5387 case 0x45: // IBM/MS lock/unlock drive
5388 if (GET_AL() > 2) goto int13_fail;
5390 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5394 if (locks == 0xff) {
5397 goto int13_fail_noah;
5399 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5403 if (locks == 0x00) {
5406 goto int13_fail_noah;
5408 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5409 SET_AL(locks==0?0:1);
5412 SET_AL(locks==0?0:1);
5418 case 0x46: // IBM/MS eject media
5419 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5422 SET_AH(0xb1); // media locked
5423 goto int13_fail_noah;
5425 // FIXME should handle 0x31 no media in device
5426 // FIXME should handle 0xb5 valid request failed
5428 // Call removable media eject
5435 mov _int13_cdrom.status + 2[bp], ah
5436 jnc int13_cdrom_rme_end
5437 mov _int13_cdrom.status, #1
5438 int13_cdrom_rme_end:
5443 SET_AH(0xb1); // media locked
5444 goto int13_fail_noah;
5450 case 0x48: // IBM/MS get drive parameters
5451 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5453 // Buffer is too small
5459 Bit16u cylinders, heads, spt, blksize;
5461 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5463 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5464 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5465 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5466 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5467 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5468 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5469 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5470 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5475 Bit8u channel, dev, irq, mode, checksum, i;
5476 Bit16u iobase1, iobase2, options;
5478 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5480 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5481 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5484 channel = device / 2;
5485 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5486 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5487 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5488 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5490 // FIXME atapi device
5491 options = (1<<4); // lba translation
5492 options |= (1<<5); // removable device
5493 options |= (1<<6); // atapi device
5494 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5496 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5497 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5498 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5499 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5500 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5501 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5502 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5503 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5504 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5505 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5506 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5509 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5510 checksum = ~checksum;
5511 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5516 Bit8u channel, iface, checksum, i;
5519 channel = device / 2;
5520 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5521 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5523 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5524 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5525 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5526 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5527 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5529 if (iface==ATA_IFACE_ISA) {
5530 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5531 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5532 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5533 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5538 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5539 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5540 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5541 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5543 if (iface==ATA_IFACE_ISA) {
5544 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5545 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5546 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5551 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5552 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5553 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5554 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5557 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5558 checksum = ~checksum;
5559 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5565 case 0x49: // IBM/MS extended media change
5566 // always send changed ??
5568 goto int13_fail_nostatus;
5571 case 0x4e: // // IBM/MS set hardware configuration
5572 // DMA, prefetch, PIO maximum not supported
5585 // all those functions return unimplemented
5586 case 0x02: /* read sectors */
5587 case 0x04: /* verify sectors */
5588 case 0x08: /* read disk drive parameters */
5589 case 0x0a: /* read disk sectors with ECC */
5590 case 0x0b: /* write disk sectors with ECC */
5591 case 0x18: /* set media type for format */
5592 case 0x50: // ? - send packet command
5594 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5600 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5602 SET_DISK_RET_STATUS(GET_AH());
5603 int13_fail_nostatus:
5604 SET_CF(); // error occurred
5608 SET_AH(0x00); // no error
5610 SET_DISK_RET_STATUS(0x00);
5611 CLEAR_CF(); // no error
5615 // ---------------------------------------------------------------------------
5616 // End of int13 for cdrom
5617 // ---------------------------------------------------------------------------
5619 #if BX_ELTORITO_BOOT
5620 // ---------------------------------------------------------------------------
5621 // Start of int13 for eltorito functions
5622 // ---------------------------------------------------------------------------
5625 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5626 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5628 Bit16u ebda_seg=read_word(0x0040,0x000E);
5630 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5631 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5635 // FIXME ElTorito Various. Should be implemented
5636 case 0x4a: // ElTorito - Initiate disk emu
5637 case 0x4c: // ElTorito - Initiate disk emu and boot
5638 case 0x4d: // ElTorito - Return Boot catalog
5639 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5643 case 0x4b: // ElTorito - Terminate disk emu
5644 // FIXME ElTorito Hardcoded
5645 write_byte(DS,SI+0x00,0x13);
5646 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5647 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5648 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5649 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5650 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5651 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5652 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5653 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5654 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5655 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5656 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5658 // If we have to terminate emulation
5659 if(GET_AL() == 0x00) {
5660 // FIXME ElTorito Various. Should be handled accordingly to spec
5661 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5668 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5674 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5675 SET_DISK_RET_STATUS(GET_AH());
5676 SET_CF(); // error occurred
5680 SET_AH(0x00); // no error
5681 SET_DISK_RET_STATUS(0x00);
5682 CLEAR_CF(); // no error
5686 // ---------------------------------------------------------------------------
5687 // End of int13 for eltorito functions
5688 // ---------------------------------------------------------------------------
5690 // ---------------------------------------------------------------------------
5691 // Start of int13 when emulating a device from the cd
5692 // ---------------------------------------------------------------------------
5695 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5696 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5698 Bit16u ebda_seg=read_word(0x0040,0x000E);
5699 Bit8u device, status;
5700 Bit16u vheads, vspt, vcylinders;
5701 Bit16u head, sector, cylinder, nbsectors;
5702 Bit32u vlba, ilba, slba, elba;
5703 Bit16u before, segment, offset;
5706 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5707 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5709 /* at this point, we are emulating a floppy/harddisk */
5711 // Recompute the device number
5712 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5713 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5715 SET_DISK_RET_STATUS(0x00);
5717 /* basic checks : emulation should be active, dl should equal the emulated drive */
5718 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5719 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5720 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5726 // all those functions return SUCCESS
5727 case 0x00: /* disk controller reset */
5728 case 0x09: /* initialize drive parameters */
5729 case 0x0c: /* seek to specified cylinder */
5730 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5731 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5732 case 0x11: /* recalibrate */
5733 case 0x14: /* controller internal diagnostic */
5734 case 0x16: /* detect disk change */
5738 // all those functions return disk write-protected
5739 case 0x03: /* write disk sectors */
5740 case 0x05: /* format disk track */
5742 goto int13_fail_noah;
5745 case 0x01: /* read disk status */
5746 status=read_byte(0x0040, 0x0074);
5748 SET_DISK_RET_STATUS(0);
5750 /* set CF if error status read */
5751 if (status) goto int13_fail_nostatus;
5752 else goto int13_success_noah;
5755 case 0x02: // read disk sectors
5756 case 0x04: // verify disk sectors
5757 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5758 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5759 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5761 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5763 sector = GET_CL() & 0x003f;
5764 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5766 nbsectors = GET_AL();
5770 // no sector to read ?
5771 if(nbsectors==0) goto int13_success;
5773 // sanity checks sco openserver needs this!
5775 || (cylinder >= vcylinders)
5776 || (head >= vheads)) {
5780 // After controls, verify do nothing
5781 if (GET_AH() == 0x04) goto int13_success;
5783 segment = ES+(BX / 16);
5786 // calculate the virtual lba inside the image
5787 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5789 // In advance so we don't loose the count
5793 slba = (Bit32u)vlba/4;
5794 before= (Bit16u)vlba%4;
5797 elba = (Bit32u)(vlba+nbsectors-1)/4;
5799 memsetb(get_SS(),atacmd,0,12);
5800 atacmd[0]=0x28; // READ command
5801 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5802 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5803 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5804 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5805 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5806 atacmd[5]=(ilba+slba & 0x000000ff);
5807 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5808 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5811 goto int13_fail_noah;
5817 case 0x08: /* read disk drive parameters */
5818 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5819 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5820 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5824 SET_CH( vcylinders & 0xff );
5825 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5827 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5828 // FIXME ElTorito Harddisk. should send the HD count
5830 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5831 case 0x01: SET_BL( 0x02 ); break;
5832 case 0x02: SET_BL( 0x04 ); break;
5833 case 0x03: SET_BL( 0x06 ); break;
5839 mov ax, #diskette_param_table2
5840 mov _int13_cdemu.DI+2[bp], ax
5841 mov _int13_cdemu.ES+2[bp], cs
5847 case 0x15: /* read disk drive size */
5848 // FIXME ElTorito Harddisk. What geometry to send ?
5850 goto int13_success_noah;
5853 // all those functions return unimplemented
5854 case 0x0a: /* read disk sectors with ECC */
5855 case 0x0b: /* write disk sectors with ECC */
5856 case 0x18: /* set media type for format */
5857 case 0x41: // IBM/MS installation check
5858 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5859 case 0x42: // IBM/MS extended read
5860 case 0x43: // IBM/MS extended write
5861 case 0x44: // IBM/MS verify sectors
5862 case 0x45: // IBM/MS lock/unlock drive
5863 case 0x46: // IBM/MS eject media
5864 case 0x47: // IBM/MS extended seek
5865 case 0x48: // IBM/MS get drive parameters
5866 case 0x49: // IBM/MS extended media change
5867 case 0x4e: // ? - set hardware configuration
5868 case 0x50: // ? - send packet command
5870 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5876 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5878 SET_DISK_RET_STATUS(GET_AH());
5879 int13_fail_nostatus:
5880 SET_CF(); // error occurred
5884 SET_AH(0x00); // no error
5886 SET_DISK_RET_STATUS(0x00);
5887 CLEAR_CF(); // no error
5891 // ---------------------------------------------------------------------------
5892 // End of int13 when emulating a device from the cd
5893 // ---------------------------------------------------------------------------
5895 #endif // BX_ELTORITO_BOOT
5897 #else //BX_USE_ATADRV
5900 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5915 mov ax,4[bp] // cylinder
5917 mov bl,6[bp] // hd_heads
5920 mov bl,8[bp] // head
5922 mov bl,10[bp] // hd_sectors
5924 mov bl,12[bp] // sector
5953 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5954 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5956 Bit8u drive, num_sectors, sector, head, status, mod;
5960 Bit16u max_cylinder, cylinder, total_sectors;
5961 Bit16u hd_cylinders;
5962 Bit8u hd_heads, hd_sectors;
5969 Bit16u count, segment, offset;
5973 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5975 write_byte(0x0040, 0x008e, 0); // clear completion flag
5977 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5979 /* check how many disks first (cmos reg 0x12), return an error if
5980 drive not present */
5981 drive_map = inb_cmos(0x12);
5982 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5983 (((drive_map & 0x0f)==0) ? 0 : 2);
5984 n_drives = (drive_map==0) ? 0 :
5985 ((drive_map==3) ? 2 : 1);
5987 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5989 SET_DISK_RET_STATUS(0x01);
5990 SET_CF(); /* error occurred */
5996 case 0x00: /* disk controller reset */
5997 BX_DEBUG_INT13_HD("int13_f00\n");
6000 SET_DISK_RET_STATUS(0);
6001 set_diskette_ret_status(0);
6002 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6003 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6004 CLEAR_CF(); /* successful */
6008 case 0x01: /* read disk status */
6009 BX_DEBUG_INT13_HD("int13_f01\n");
6010 status = read_byte(0x0040, 0x0074);
6012 SET_DISK_RET_STATUS(0);
6013 /* set CF if error status read */
6014 if (status) SET_CF();
6019 case 0x04: // verify disk sectors
6020 case 0x02: // read disk sectors
6022 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6024 num_sectors = GET_AL();
6025 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6026 sector = (GET_CL() & 0x3f);
6030 if (hd_cylinders > 1024) {
6031 if (hd_cylinders <= 2048) {
6034 else if (hd_cylinders <= 4096) {
6037 else if (hd_cylinders <= 8192) {
6040 else { // hd_cylinders <= 16384
6044 ax = head / hd_heads;
6045 cyl_mod = ax & 0xff;
6047 cylinder |= cyl_mod;
6050 if ( (cylinder >= hd_cylinders) ||
6051 (sector > hd_sectors) ||
6052 (head >= hd_heads) ) {
6054 SET_DISK_RET_STATUS(1);
6055 SET_CF(); /* error occurred */
6059 if ( (num_sectors > 128) || (num_sectors == 0) )
6060 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6063 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6065 if ( GET_AH() == 0x04 ) {
6067 SET_DISK_RET_STATUS(0);
6072 status = inb(0x1f7);
6073 if (status & 0x80) {
6074 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6076 outb(0x01f2, num_sectors);
6077 /* activate LBA? (tomv) */
6078 if (hd_heads > 16) {
6079 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6080 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6083 outb(0x01f3, sector);
6084 outb(0x01f4, cylinder & 0x00ff);
6085 outb(0x01f5, cylinder >> 8);
6086 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6091 status = inb(0x1f7);
6092 if ( !(status & 0x80) ) break;
6095 if (status & 0x01) {
6096 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6097 } else if ( !(status & 0x08) ) {
6098 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6099 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6106 sti ;; enable higher priority interrupts
6111 ;; store temp bx in real DI register
6114 mov di, _int13_harddisk.tempbx + 2 [bp]
6117 ;; adjust if there will be an overrun
6119 jbe i13_f02_no_adjust
6121 sub di, #0x0200 ; sub 512 bytes from offset
6123 add ax, #0x0020 ; add 512 to segment
6127 mov cx, #0x0100 ;; counter (256 words = 512b)
6128 mov dx, #0x01f0 ;; AT data read port
6131 insw ;; CX words transfered from port(DX) to ES:[DI]
6134 ;; store real DI register back to temp bx
6137 mov _int13_harddisk.tempbx + 2 [bp], di
6143 if (num_sectors == 0) {
6144 status = inb(0x1f7);
6145 if ( (status & 0xc9) != 0x40 )
6146 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6150 status = inb(0x1f7);
6151 if ( (status & 0xc9) != 0x48 )
6152 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6158 SET_DISK_RET_STATUS(0);
6159 SET_AL(sector_count);
6160 CLEAR_CF(); /* successful */
6165 case 0x03: /* write disk sectors */
6166 BX_DEBUG_INT13_HD("int13_f03\n");
6167 drive = GET_ELDL ();
6168 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6170 num_sectors = GET_AL();
6171 cylinder = GET_CH();
6172 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6173 sector = (GET_CL() & 0x3f);
6176 if (hd_cylinders > 1024) {
6177 if (hd_cylinders <= 2048) {
6180 else if (hd_cylinders <= 4096) {
6183 else if (hd_cylinders <= 8192) {
6186 else { // hd_cylinders <= 16384
6190 ax = head / hd_heads;
6191 cyl_mod = ax & 0xff;
6193 cylinder |= cyl_mod;
6196 if ( (cylinder >= hd_cylinders) ||
6197 (sector > hd_sectors) ||
6198 (head >= hd_heads) ) {
6200 SET_DISK_RET_STATUS(1);
6201 SET_CF(); /* error occurred */
6205 if ( (num_sectors > 128) || (num_sectors == 0) )
6206 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6209 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6211 status = inb(0x1f7);
6212 if (status & 0x80) {
6213 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6215 // should check for Drive Ready Bit also in status reg
6216 outb(0x01f2, num_sectors);
6218 /* activate LBA? (tomv) */
6219 if (hd_heads > 16) {
6220 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6221 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6224 outb(0x01f3, sector);
6225 outb(0x01f4, cylinder & 0x00ff);
6226 outb(0x01f5, cylinder >> 8);
6227 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6231 // wait for busy bit to turn off after seeking
6233 status = inb(0x1f7);
6234 if ( !(status & 0x80) ) break;
6237 if ( !(status & 0x08) ) {
6238 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6239 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6246 sti ;; enable higher priority interrupts
6251 ;; store temp bx in real SI register
6254 mov si, _int13_harddisk.tempbx + 2 [bp]
6257 ;; adjust if there will be an overrun
6259 jbe i13_f03_no_adjust
6261 sub si, #0x0200 ; sub 512 bytes from offset
6263 add ax, #0x0020 ; add 512 to segment
6267 mov cx, #0x0100 ;; counter (256 words = 512b)
6268 mov dx, #0x01f0 ;; AT data read port
6272 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6274 ;; store real SI register back to temp bx
6277 mov _int13_harddisk.tempbx + 2 [bp], si
6283 if (num_sectors == 0) {
6284 status = inb(0x1f7);
6285 if ( (status & 0xe9) != 0x40 )
6286 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6290 status = inb(0x1f7);
6291 if ( (status & 0xc9) != 0x48 )
6292 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6298 SET_DISK_RET_STATUS(0);
6299 SET_AL(sector_count);
6300 CLEAR_CF(); /* successful */
6304 case 0x05: /* format disk track */
6305 BX_DEBUG_INT13_HD("int13_f05\n");
6306 BX_PANIC("format disk track called\n");
6309 SET_DISK_RET_STATUS(0);
6310 CLEAR_CF(); /* successful */
6314 case 0x08: /* read disk drive parameters */
6315 BX_DEBUG_INT13_HD("int13_f08\n");
6317 drive = GET_ELDL ();
6318 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6322 if (hd_cylinders <= 1024) {
6323 // hd_cylinders >>= 0;
6326 else if (hd_cylinders <= 2048) {
6330 else if (hd_cylinders <= 4096) {
6334 else if (hd_cylinders <= 8192) {
6338 else { // hd_cylinders <= 16384
6343 max_cylinder = hd_cylinders - 2; /* 0 based */
6345 SET_CH(max_cylinder & 0xff);
6346 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6347 SET_DH(hd_heads - 1);
6348 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6350 SET_DISK_RET_STATUS(0);
6351 CLEAR_CF(); /* successful */
6356 case 0x09: /* initialize drive parameters */
6357 BX_DEBUG_INT13_HD("int13_f09\n");
6359 SET_DISK_RET_STATUS(0);
6360 CLEAR_CF(); /* successful */
6364 case 0x0a: /* read disk sectors with ECC */
6365 BX_DEBUG_INT13_HD("int13_f0a\n");
6366 case 0x0b: /* write disk sectors with ECC */
6367 BX_DEBUG_INT13_HD("int13_f0b\n");
6368 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6372 case 0x0c: /* seek to specified cylinder */
6373 BX_DEBUG_INT13_HD("int13_f0c\n");
6374 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6376 SET_DISK_RET_STATUS(0);
6377 CLEAR_CF(); /* successful */
6381 case 0x0d: /* alternate disk reset */
6382 BX_DEBUG_INT13_HD("int13_f0d\n");
6384 SET_DISK_RET_STATUS(0);
6385 CLEAR_CF(); /* successful */
6389 case 0x10: /* check drive ready */
6390 BX_DEBUG_INT13_HD("int13_f10\n");
6392 //SET_DISK_RET_STATUS(0);
6393 //CLEAR_CF(); /* successful */
6397 // should look at 40:8E also???
6398 status = inb(0x01f7);
6399 if ( (status & 0xc0) == 0x40 ) {
6401 SET_DISK_RET_STATUS(0);
6402 CLEAR_CF(); // drive ready
6407 SET_DISK_RET_STATUS(0xAA);
6408 SET_CF(); // not ready
6413 case 0x11: /* recalibrate */
6414 BX_DEBUG_INT13_HD("int13_f11\n");
6416 SET_DISK_RET_STATUS(0);
6417 CLEAR_CF(); /* successful */
6421 case 0x14: /* controller internal diagnostic */
6422 BX_DEBUG_INT13_HD("int13_f14\n");
6424 SET_DISK_RET_STATUS(0);
6425 CLEAR_CF(); /* successful */
6430 case 0x15: /* read disk drive size */
6432 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6436 mov al, _int13_harddisk.hd_heads + 2 [bp]
6437 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6438 mul al, ah ;; ax = heads * sectors
6439 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6440 dec bx ;; use (cylinders - 1) ???
6441 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6442 ;; now we need to move the 32bit result dx:ax to what the
6443 ;; BIOS wants which is cx:dx.
6444 ;; and then into CX:DX on the stack
6445 mov _int13_harddisk.CX + 2 [bp], dx
6446 mov _int13_harddisk.DX + 2 [bp], ax
6449 SET_AH(3); // hard disk accessible
6450 SET_DISK_RET_STATUS(0); // ??? should this be 0
6451 CLEAR_CF(); // successful
6455 case 0x18: // set media type for format
6456 case 0x41: // IBM/MS
6457 case 0x42: // IBM/MS
6458 case 0x43: // IBM/MS
6459 case 0x44: // IBM/MS
6460 case 0x45: // IBM/MS lock/unlock drive
6461 case 0x46: // IBM/MS eject media
6462 case 0x47: // IBM/MS extended seek
6463 case 0x49: // IBM/MS extended media change
6464 case 0x50: // IBM/MS send packet command
6466 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6468 SET_AH(1); // code=invalid function in AH or invalid parameter
6469 SET_DISK_RET_STATUS(1);
6470 SET_CF(); /* unsuccessful */
6476 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6477 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6480 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6482 Bit16u *hd_cylinders;
6492 if (drive == 0x80) {
6493 hd_type = inb_cmos(0x12) & 0xf0;
6494 if (hd_type != 0xf0)
6495 BX_INFO(panic_msg_reg12h,0);
6496 hd_type = inb_cmos(0x19); // HD0: extended type
6498 BX_INFO(panic_msg_reg19h,0,0x19);
6501 hd_type = inb_cmos(0x12) & 0x0f;
6502 if (hd_type != 0x0f)
6503 BX_INFO(panic_msg_reg12h,1);
6504 hd_type = inb_cmos(0x1a); // HD0: extended type
6506 BX_INFO(panic_msg_reg19h,0,0x1a);
6511 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6512 write_word(ss, hd_cylinders, cylinders);
6515 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6517 // sectors per track
6518 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6521 #endif //else BX_USE_ATADRV
6524 //////////////////////
6525 // FLOPPY functions //
6526 //////////////////////
6529 floppy_media_known(drive)
6533 Bit16u media_state_offset;
6535 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6542 media_state_offset = 0x0090;
6544 media_state_offset += 1;
6546 val8 = read_byte(0x0040, media_state_offset);
6547 val8 = (val8 >> 4) & 0x01;
6551 // check pass, return KNOWN
6556 floppy_media_sense(drive)
6560 Bit16u media_state_offset;
6561 Bit8u drive_type, config_data, media_state;
6563 if (floppy_drive_recal(drive) == 0) {
6567 // for now cheat and get drive type from CMOS,
6568 // assume media is same as drive type
6570 // ** config_data **
6571 // Bitfields for diskette media control:
6572 // Bit(s) Description (Table M0028)
6573 // 7-6 last data rate set by controller
6574 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6575 // 5-4 last diskette drive step rate selected
6576 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6577 // 3-2 {data rate at start of operation}
6580 // ** media_state **
6581 // Bitfields for diskette drive media state:
6582 // Bit(s) Description (Table M0030)
6584 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6585 // 5 double stepping required (e.g. 360kB in 1.2MB)
6586 // 4 media type established
6587 // 3 drive capable of supporting 4MB media
6588 // 2-0 on exit from BIOS, contains
6589 // 000 trying 360kB in 360kB
6590 // 001 trying 360kB in 1.2MB
6591 // 010 trying 1.2MB in 1.2MB
6592 // 011 360kB in 360kB established
6593 // 100 360kB in 1.2MB established
6594 // 101 1.2MB in 1.2MB established
6596 // 111 all other formats/drives
6598 drive_type = inb_cmos(0x10);
6603 if ( drive_type == 1 ) {
6605 config_data = 0x00; // 0000 0000
6606 media_state = 0x25; // 0010 0101
6609 else if ( drive_type == 2 ) {
6610 // 1.2 MB 5.25" drive
6611 config_data = 0x00; // 0000 0000
6612 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6615 else if ( drive_type == 3 ) {
6617 config_data = 0x00; // 0000 0000 ???
6618 media_state = 0x17; // 0001 0111
6621 else if ( drive_type == 4 ) {
6622 // 1.44 MB 3.5" drive
6623 config_data = 0x00; // 0000 0000
6624 media_state = 0x17; // 0001 0111
6627 else if ( drive_type == 5 ) {
6628 // 2.88 MB 3.5" drive
6629 config_data = 0xCC; // 1100 1100
6630 media_state = 0xD7; // 1101 0111
6634 // Extended floppy size uses special cmos setting
6635 else if ( drive_type == 6 ) {
6637 config_data = 0x00; // 0000 0000
6638 media_state = 0x27; // 0010 0111
6641 else if ( drive_type == 7 ) {
6643 config_data = 0x00; // 0000 0000
6644 media_state = 0x27; // 0010 0111
6647 else if ( drive_type == 8 ) {
6649 config_data = 0x00; // 0000 0000
6650 media_state = 0x27; // 0010 0111
6656 config_data = 0x00; // 0000 0000
6657 media_state = 0x00; // 0000 0000
6662 media_state_offset = 0x90;
6664 media_state_offset = 0x91;
6665 write_byte(0x0040, 0x008B, config_data);
6666 write_byte(0x0040, media_state_offset, media_state);
6672 floppy_drive_recal(drive)
6676 Bit16u curr_cyl_offset;
6678 // set 40:3e bit 7 to 0
6679 val8 = read_byte(0x0000, 0x043e);
6681 write_byte(0x0000, 0x043e, val8);
6683 // turn on motor of selected drive, DMA & int enabled, normal operation
6692 // reset the disk motor timeout value of INT 08
6693 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6695 // check port 3f4 for drive readiness
6697 if ( (val8 & 0xf0) != 0x80 )
6698 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6700 // send Recalibrate command (2 bytes) to controller
6701 outb(0x03f5, 0x07); // 07: Recalibrate
6702 outb(0x03f5, drive); // 0=drive0, 1=drive1
6704 // turn on interrupts
6709 // wait on 40:3e bit 7 to become 1
6710 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6711 while ( val8 == 0 ) {
6712 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6715 val8 = 0; // separate asm from while() loop
6716 // turn off interrupts
6721 // set 40:3e bit 7 to 0, and calibrated bit
6722 val8 = read_byte(0x0000, 0x043e);
6725 val8 |= 0x02; // Drive 1 calibrated
6726 curr_cyl_offset = 0x0095;
6729 val8 |= 0x01; // Drive 0 calibrated
6730 curr_cyl_offset = 0x0094;
6732 write_byte(0x0040, 0x003e, val8);
6733 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6741 floppy_drive_exists(drive)
6746 // just tell it both drives exist - PAD
6749 // check CMOS to see if drive exists
6750 drive_type = inb_cmos(0x10);
6755 if ( drive_type == 0 )
6761 #if BX_SUPPORT_FLOPPY
6763 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6764 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6766 Bit8u drive, num_sectors, track, sector, head, status;
6767 Bit16u base_address, base_count, base_es;
6768 Bit8u page, mode_register, val8, dor;
6769 Bit8u return_status[7];
6770 Bit8u drive_type, num_floppies, ah;
6771 Bit16u es, last_addr;
6773 printf("In int13_diskette\n");
6775 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6776 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6781 case 0x00: // diskette controller reset
6782 BX_DEBUG_INT13_FL("floppy f00\n");
6785 SET_AH(1); // invalid param
6786 set_diskette_ret_status(1);
6790 drive_type = inb_cmos(0x10);
6796 if (drive_type == 0) {
6797 SET_AH(0x80); // drive not responding
6798 set_diskette_ret_status(0x80);
6803 set_diskette_ret_status(0);
6804 CLEAR_CF(); // successful
6805 set_diskette_current_cyl(drive, 0); // current cylinder
6808 case 0x01: // Read Diskette Status
6810 val8 = read_byte(0x0000, 0x0441);
6817 case 0x02: // Read Diskette Sectors
6818 case 0x03: // Write Diskette Sectors
6819 case 0x04: // Verify Diskette Sectors
6820 num_sectors = GET_AL();
6826 if ( (drive > 1) || (head > 1) ||
6827 (num_sectors == 0) || (num_sectors > 72) ) {
6828 BX_INFO("floppy: drive>1 || head>1 ...\n");
6830 set_diskette_ret_status(1);
6831 SET_AL(0); // no sectors read
6832 SET_CF(); // error occurred
6836 // see if drive exists
6837 if (floppy_drive_exists(drive) == 0) {
6838 SET_AH(0x80); // not responding
6839 set_diskette_ret_status(0x80);
6840 SET_AL(0); // no sectors read
6841 SET_CF(); // error occurred
6845 // see if media in drive, and type is known
6846 if (floppy_media_known(drive) == 0) {
6847 if (floppy_media_sense(drive) == 0) {
6848 SET_AH(0x0C); // Media type not found
6849 set_diskette_ret_status(0x0C);
6850 SET_AL(0); // no sectors read
6851 SET_CF(); // error occurred
6857 // Read Diskette Sectors
6859 //-----------------------------------
6860 // set up DMA controller for transfer
6861 //-----------------------------------
6863 // es:bx = pointer to where to place information from diskette
6864 // port 04: DMA-1 base and current address, channel 2
6865 // port 05: DMA-1 base and current count, channel 2
6866 page = (ES >> 12); // upper 4 bits
6867 base_es = (ES << 4); // lower 16bits contributed by ES
6868 base_address = base_es + BX; // lower 16 bits of address
6869 // contributed by ES:BX
6870 if ( base_address < base_es ) {
6871 // in case of carry, adjust page by 1
6874 base_count = (num_sectors * 512) - 1;
6876 // check for 64K boundary overrun
6877 last_addr = base_address + base_count;
6878 if (last_addr < base_address) {
6880 set_diskette_ret_status(0x09);
6881 SET_AL(0); // no sectors read
6882 SET_CF(); // error occurred
6886 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6889 BX_DEBUG_INT13_FL("clear flip-flop\n");
6890 outb(0x000c, 0x00); // clear flip-flop
6891 outb(0x0004, base_address);
6892 outb(0x0004, base_address>>8);
6893 BX_DEBUG_INT13_FL("clear flip-flop\n");
6894 outb(0x000c, 0x00); // clear flip-flop
6895 outb(0x0005, base_count);
6896 outb(0x0005, base_count>>8);
6898 // port 0b: DMA-1 Mode Register
6899 mode_register = 0x46; // single mode, increment, autoinit disable,
6900 // transfer type=write, channel 2
6901 BX_DEBUG_INT13_FL("setting mode register\n");
6902 outb(0x000b, mode_register);
6904 BX_DEBUG_INT13_FL("setting page register\n");
6905 // port 81: DMA-1 Page Register, channel 2
6908 BX_DEBUG_INT13_FL("unmask chan 2\n");
6909 outb(0x000a, 0x02); // unmask channel 2
6911 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6914 //--------------------------------------
6915 // set up floppy controller for transfer
6916 //--------------------------------------
6918 // set 40:3e bit 7 to 0
6919 val8 = read_byte(0x0000, 0x043e);
6921 write_byte(0x0000, 0x043e, val8);
6923 // turn on motor of selected drive, DMA & int enabled, normal operation
6932 // reset the disk motor timeout value of INT 08
6933 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6935 // check port 3f4 for drive readiness
6937 if ( (val8 & 0xf0) != 0x80 )
6938 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6940 // send read-normal-data command (9 bytes) to controller
6941 outb(0x03f5, 0xe6); // e6: read normal data
6942 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6943 outb(0x03f5, track);
6945 outb(0x03f5, sector);
6946 outb(0x03f5, 2); // 512 byte sector size
6947 outb(0x03f5, 0); // last sector number possible on track
6948 outb(0x03f5, 0); // Gap length
6949 outb(0x03f5, 0xff); // Gap length
6951 // turn on interrupts
6956 // wait on 40:3e bit 7 to become 1
6957 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6958 while ( val8 == 0 ) {
6959 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6962 val8 = 0; // separate asm from while() loop
6963 // turn off interrupts
6968 // set 40:3e bit 7 to 0
6969 val8 = read_byte(0x0000, 0x043e);
6971 write_byte(0x0000, 0x043e, val8);
6973 // check port 3f4 for accessibility to status bytes
6975 if ( (val8 & 0xc0) != 0xc0 )
6976 BX_PANIC("int13_diskette: ctrl not ready\n");
6978 // read 7 return status bytes from controller
6979 // using loop index broken, have to unroll...
6980 return_status[0] = inb(0x3f5);
6981 return_status[1] = inb(0x3f5);
6982 return_status[2] = inb(0x3f5);
6983 return_status[3] = inb(0x3f5);
6984 return_status[4] = inb(0x3f5);
6985 return_status[5] = inb(0x3f5);
6986 return_status[6] = inb(0x3f5);
6987 // record in BIOS Data Area
6988 write_byte(0x0040, 0x0042, return_status[0]);
6989 write_byte(0x0040, 0x0043, return_status[1]);
6990 write_byte(0x0040, 0x0044, return_status[2]);
6991 write_byte(0x0040, 0x0045, return_status[3]);
6992 write_byte(0x0040, 0x0046, return_status[4]);
6993 write_byte(0x0040, 0x0047, return_status[5]);
6994 write_byte(0x0040, 0x0048, return_status[6]);
6996 if ( (return_status[0] & 0xc0) != 0 ) {
6998 set_diskette_ret_status(0x20);
6999 SET_AL(0); // no sectors read
7000 SET_CF(); // error occurred
7004 // ??? should track be new val from return_status[3] ?
7005 set_diskette_current_cyl(drive, track);
7006 // AL = number of sectors read (same value as passed)
7007 SET_AH(0x00); // success
7008 CLEAR_CF(); // success
7011 else if (ah == 0x03) {
7012 // Write Diskette Sectors
7014 //-----------------------------------
7015 // set up DMA controller for transfer
7016 //-----------------------------------
7018 // es:bx = pointer to where to place information from diskette
7019 // port 04: DMA-1 base and current address, channel 2
7020 // port 05: DMA-1 base and current count, channel 2
7021 page = (ES >> 12); // upper 4 bits
7022 base_es = (ES << 4); // lower 16bits contributed by ES
7023 base_address = base_es + BX; // lower 16 bits of address
7024 // contributed by ES:BX
7025 if ( base_address < base_es ) {
7026 // in case of carry, adjust page by 1
7029 base_count = (num_sectors * 512) - 1;
7031 // check for 64K boundary overrun
7032 last_addr = base_address + base_count;
7033 if (last_addr < base_address) {
7035 set_diskette_ret_status(0x09);
7036 SET_AL(0); // no sectors read
7037 SET_CF(); // error occurred
7041 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7044 outb(0x000c, 0x00); // clear flip-flop
7045 outb(0x0004, base_address);
7046 outb(0x0004, base_address>>8);
7047 outb(0x000c, 0x00); // clear flip-flop
7048 outb(0x0005, base_count);
7049 outb(0x0005, base_count>>8);
7051 // port 0b: DMA-1 Mode Register
7052 mode_register = 0x4a; // single mode, increment, autoinit disable,
7053 // transfer type=read, channel 2
7054 outb(0x000b, mode_register);
7056 // port 81: DMA-1 Page Register, channel 2
7059 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7062 //--------------------------------------
7063 // set up floppy controller for transfer
7064 //--------------------------------------
7066 // set 40:3e bit 7 to 0
7067 val8 = read_byte(0x0000, 0x043e);
7069 write_byte(0x0000, 0x043e, val8);
7071 // turn on motor of selected drive, DMA & int enabled, normal operation
7080 // reset the disk motor timeout value of INT 08
7081 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7083 // check port 3f4 for drive readiness
7085 if ( (val8 & 0xf0) != 0x80 )
7086 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7088 // send read-normal-data command (9 bytes) to controller
7089 outb(0x03f5, 0xc5); // c5: write normal data
7090 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7091 outb(0x03f5, track);
7093 outb(0x03f5, sector);
7094 outb(0x03f5, 2); // 512 byte sector size
7095 outb(0x03f5, 0); // last sector number possible on track
7096 outb(0x03f5, 0); // Gap length
7097 outb(0x03f5, 0xff); // Gap length
7099 // turn on interrupts
7104 // wait on 40:3e bit 7 to become 1
7105 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7106 while ( val8 == 0 ) {
7107 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7110 val8 = 0; // separate asm from while() loop
7111 // turn off interrupts
7116 // set 40:3e bit 7 to 0
7117 val8 = read_byte(0x0000, 0x043e);
7119 write_byte(0x0000, 0x043e, val8);
7121 // check port 3f4 for accessibility to status bytes
7123 if ( (val8 & 0xc0) != 0xc0 )
7124 BX_PANIC("int13_diskette: ctrl not ready\n");
7126 // read 7 return status bytes from controller
7127 // using loop index broken, have to unroll...
7128 return_status[0] = inb(0x3f5);
7129 return_status[1] = inb(0x3f5);
7130 return_status[2] = inb(0x3f5);
7131 return_status[3] = inb(0x3f5);
7132 return_status[4] = inb(0x3f5);
7133 return_status[5] = inb(0x3f5);
7134 return_status[6] = inb(0x3f5);
7135 // record in BIOS Data Area
7136 write_byte(0x0040, 0x0042, return_status[0]);
7137 write_byte(0x0040, 0x0043, return_status[1]);
7138 write_byte(0x0040, 0x0044, return_status[2]);
7139 write_byte(0x0040, 0x0045, return_status[3]);
7140 write_byte(0x0040, 0x0046, return_status[4]);
7141 write_byte(0x0040, 0x0047, return_status[5]);
7142 write_byte(0x0040, 0x0048, return_status[6]);
7144 if ( (return_status[0] & 0xc0) != 0 ) {
7145 if ( (return_status[1] & 0x02) != 0 ) {
7146 // diskette not writable.
7147 // AH=status code=0x03 (tried to write on write-protected disk)
7148 // AL=number of sectors written=0
7153 BX_PANIC("int13_diskette_function: read error\n");
7157 // ??? should track be new val from return_status[3] ?
7158 set_diskette_current_cyl(drive, track);
7159 // AL = number of sectors read (same value as passed)
7160 SET_AH(0x00); // success
7161 CLEAR_CF(); // success
7164 else { // if (ah == 0x04)
7165 // Verify Diskette Sectors
7167 // ??? should track be new val from return_status[3] ?
7168 set_diskette_current_cyl(drive, track);
7169 // AL = number of sectors verified (same value as passed)
7170 CLEAR_CF(); // success
7171 SET_AH(0x00); // success
7176 case 0x05: // format diskette track
7177 BX_DEBUG_INT13_FL("floppy f05\n");
7179 num_sectors = GET_AL();
7184 if ((drive > 1) || (head > 1) || (track > 79) ||
7185 (num_sectors == 0) || (num_sectors > 18)) {
7187 set_diskette_ret_status(1);
7188 SET_CF(); // error occurred
7191 // see if drive exists
7192 if (floppy_drive_exists(drive) == 0) {
7193 SET_AH(0x80); // drive not responding
7194 set_diskette_ret_status(0x80);
7195 SET_CF(); // error occurred
7199 // see if media in drive, and type is known
7200 if (floppy_media_known(drive) == 0) {
7201 if (floppy_media_sense(drive) == 0) {
7202 SET_AH(0x0C); // Media type not found
7203 set_diskette_ret_status(0x0C);
7204 SET_AL(0); // no sectors read
7205 SET_CF(); // error occurred
7210 // set up DMA controller for transfer
7211 page = (ES >> 12); // upper 4 bits
7212 base_es = (ES << 4); // lower 16bits contributed by ES
7213 base_address = base_es + BX; // lower 16 bits of address
7214 // contributed by ES:BX
7215 if ( base_address < base_es ) {
7216 // in case of carry, adjust page by 1
7219 base_count = (num_sectors * 4) - 1;
7221 // check for 64K boundary overrun
7222 last_addr = base_address + base_count;
7223 if (last_addr < base_address) {
7225 set_diskette_ret_status(0x09);
7226 SET_AL(0); // no sectors read
7227 SET_CF(); // error occurred
7232 outb(0x000c, 0x00); // clear flip-flop
7233 outb(0x0004, base_address);
7234 outb(0x0004, base_address>>8);
7235 outb(0x000c, 0x00); // clear flip-flop
7236 outb(0x0005, base_count);
7237 outb(0x0005, base_count>>8);
7238 mode_register = 0x4a; // single mode, increment, autoinit disable,
7239 // transfer type=read, channel 2
7240 outb(0x000b, mode_register);
7241 // port 81: DMA-1 Page Register, channel 2
7245 // set up floppy controller for transfer
7246 val8 = read_byte(0x0000, 0x043e);
7248 write_byte(0x0000, 0x043e, val8);
7249 // turn on motor of selected drive, DMA & int enabled, normal operation
7258 // reset the disk motor timeout value of INT 08
7259 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7261 // check port 3f4 for drive readiness
7263 if ( (val8 & 0xf0) != 0x80 )
7264 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7266 // send read-normal-data command (6 bytes) to controller
7267 outb(0x03f5, 0x4d); // 4d: format track
7268 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7269 outb(0x03f5, 2); // 512 byte sector size
7270 outb(0x03f5, num_sectors); // number of sectors per track
7271 outb(0x03f5, 0); // Gap length
7272 outb(0x03f5, 0xf6); // Fill byte
7273 // turn on interrupts
7277 // wait on 40:3e bit 7 to become 1
7278 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7279 while ( val8 == 0 ) {
7280 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7282 val8 = 0; // separate asm from while() loop
7283 // turn off interrupts
7287 // set 40:3e bit 7 to 0
7288 val8 = read_byte(0x0000, 0x043e);
7290 write_byte(0x0000, 0x043e, val8);
7291 // check port 3f4 for accessibility to status bytes
7293 if ( (val8 & 0xc0) != 0xc0 )
7294 BX_PANIC("int13_diskette: ctrl not ready\n");
7296 // read 7 return status bytes from controller
7297 // using loop index broken, have to unroll...
7298 return_status[0] = inb(0x3f5);
7299 return_status[1] = inb(0x3f5);
7300 return_status[2] = inb(0x3f5);
7301 return_status[3] = inb(0x3f5);
7302 return_status[4] = inb(0x3f5);
7303 return_status[5] = inb(0x3f5);
7304 return_status[6] = inb(0x3f5);
7305 // record in BIOS Data Area
7306 write_byte(0x0040, 0x0042, return_status[0]);
7307 write_byte(0x0040, 0x0043, return_status[1]);
7308 write_byte(0x0040, 0x0044, return_status[2]);
7309 write_byte(0x0040, 0x0045, return_status[3]);
7310 write_byte(0x0040, 0x0046, return_status[4]);
7311 write_byte(0x0040, 0x0047, return_status[5]);
7312 write_byte(0x0040, 0x0048, return_status[6]);
7314 if ( (return_status[0] & 0xc0) != 0 ) {
7315 if ( (return_status[1] & 0x02) != 0 ) {
7316 // diskette not writable.
7317 // AH=status code=0x03 (tried to write on write-protected disk)
7318 // AL=number of sectors written=0
7323 BX_PANIC("int13_diskette_function: write error\n");
7328 set_diskette_ret_status(0);
7329 set_diskette_current_cyl(drive, 0);
7330 CLEAR_CF(); // successful
7334 case 0x08: // read diskette drive parameters
7335 BX_DEBUG_INT13_FL("floppy f08\n");
7345 SET_DL(num_floppies);
7350 drive_type = inb_cmos(0x10);
7352 if (drive_type & 0xf0)
7354 if (drive_type & 0x0f)
7366 SET_DL(num_floppies);
7368 switch (drive_type) {
7371 SET_DH(0); // max head #
7374 case 1: // 360KB, 5.25"
7375 CX = 0x2709; // 40 tracks, 9 sectors
7376 SET_DH(1); // max head #
7379 case 2: // 1.2MB, 5.25"
7380 CX = 0x4f0f; // 80 tracks, 15 sectors
7381 SET_DH(1); // max head #
7384 case 3: // 720KB, 3.5"
7385 CX = 0x4f09; // 80 tracks, 9 sectors
7386 SET_DH(1); // max head #
7389 case 4: // 1.44MB, 3.5"
7390 CX = 0x4f12; // 80 tracks, 18 sectors
7391 SET_DH(1); // max head #
7394 case 5: // 2.88MB, 3.5"
7395 CX = 0x4f24; // 80 tracks, 36 sectors
7396 SET_DH(1); // max head #
7399 case 6: // 160k, 5.25"
7400 CX = 0x2708; // 40 tracks, 8 sectors
7401 SET_DH(0); // max head #
7404 case 7: // 180k, 5.25"
7405 CX = 0x2709; // 40 tracks, 9 sectors
7406 SET_DH(0); // max head #
7409 case 8: // 320k, 5.25"
7410 CX = 0x2708; // 40 tracks, 8 sectors
7411 SET_DH(1); // max head #
7415 BX_PANIC("floppy: int13: bad floppy type\n");
7418 /* set es & di to point to 11 byte diskette param table in ROM */
7422 mov ax, #diskette_param_table2
7423 mov _int13_diskette_function.DI+2[bp], ax
7424 mov _int13_diskette_function.ES+2[bp], cs
7427 CLEAR_CF(); // success
7428 /* disk status not changed upon success */
7432 case 0x15: // read diskette drive type
7433 BX_DEBUG_INT13_FL("floppy f15\n");
7436 SET_AH(0); // only 2 drives supported
7437 // set_diskette_ret_status here ???
7441 drive_type = inb_cmos(0x10);
7447 CLEAR_CF(); // successful, not present
7448 if (drive_type==0) {
7449 SET_AH(0); // drive not present
7452 SET_AH(1); // drive present, does not support change line
7457 case 0x16: // get diskette change line status
7458 BX_DEBUG_INT13_FL("floppy f16\n");
7461 SET_AH(0x01); // invalid drive
7462 set_diskette_ret_status(0x01);
7467 SET_AH(0x06); // change line not supported
7468 set_diskette_ret_status(0x06);
7472 case 0x17: // set diskette type for format(old)
7473 BX_DEBUG_INT13_FL("floppy f17\n");
7474 /* not used for 1.44M floppies */
7475 SET_AH(0x01); // not supported
7476 set_diskette_ret_status(1); /* not supported */
7480 case 0x18: // set diskette type for format(new)
7481 BX_DEBUG_INT13_FL("floppy f18\n");
7482 SET_AH(0x01); // do later
7483 set_diskette_ret_status(1);
7488 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7490 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7491 SET_AH(0x01); // ???
7492 set_diskette_ret_status(1);
7498 #else // #if BX_SUPPORT_FLOPPY
7500 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7501 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7505 switch ( GET_AH() ) {
7507 case 0x01: // Read Diskette Status
7509 val8 = read_byte(0x0000, 0x0441);
7518 write_byte(0x0000, 0x0441, 0x01);
7522 #endif // #if BX_SUPPORT_FLOPPY
7525 set_diskette_ret_status(value)
7528 write_byte(0x0040, 0x0041, value);
7532 set_diskette_current_cyl(drive, cyl)
7537 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7538 write_byte(0x0040, 0x0094+drive, cyl);
7542 determine_floppy_media(drive)
7546 Bit8u val8, DOR, ctrl_info;
7548 ctrl_info = read_byte(0x0040, 0x008F);
7556 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7559 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7563 if ( (ctrl_info & 0x04) != 0x04 ) {
7564 // Drive not determined means no drive exists, done.
7569 // check Main Status Register for readiness
7570 val8 = inb(0x03f4) & 0x80; // Main Status Register
7572 BX_PANIC("d_f_m: MRQ bit not set\n");
7576 // existing BDA values
7578 // turn on drive motor
7579 outb(0x03f2, DOR); // Digital Output Register
7582 BX_PANIC("d_f_m: OK so far\n");
7587 int17_function(regs, ds, iret_addr)
7588 pusha_regs_t regs; // regs pushed from PUSHA instruction
7589 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7590 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7592 Bit16u addr,timeout;
7599 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7600 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7601 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7602 if (regs.u.r8.ah == 0) {
7603 outb(addr, regs.u.r8.al);
7605 outb(addr+2, val8 | 0x01); // send strobe
7609 outb(addr+2, val8 & ~0x01);
7610 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7614 if (regs.u.r8.ah == 1) {
7616 outb(addr+2, val8 & ~0x04); // send init
7620 outb(addr+2, val8 | 0x04);
7623 regs.u.r8.ah = (val8 ^ 0x48);
7624 if (!timeout) regs.u.r8.ah |= 0x01;
7625 ClearCF(iret_addr.flags);
7627 SetCF(iret_addr.flags); // Unsupported
7631 // returns bootsegment in ax, drive in bl
7633 int19_function(bseqnr)
7636 Bit16u ebda_seg=read_word(0x0040,0x000E);
7645 // BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7647 // if BX_ELTORITO_BOOT is not defined, old behavior
7648 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7649 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7650 // 0: system boot sequence, first drive C: then A:
7651 // 1: system boot sequence, first drive A: then C:
7652 // else BX_ELTORITO_BOOT is defined
7653 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7654 // CMOS reg 0x3D & 0x0f : 1st boot device
7655 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7656 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7657 // boot device codes:
7658 // 0x00 : not defined
7659 // 0x01 : first floppy
7660 // 0x02 : first harddrive
7661 // 0x03 : first cdrom
7662 // else : boot failure
7664 // Get the boot sequence
7665 #if BX_ELTORITO_BOOT
7666 bootseq=inb_cmos(0x3d);
7667 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7669 if (bseqnr==2) bootseq >>= 4;
7670 if (bseqnr==3) bootseq >>= 8;
7671 if (bootseq<0x10) lastdrive = 1;
7672 bootdrv=0x00; bootcd=0;
7673 switch(bootseq & 0x0f) {
7674 case 0x01: bootdrv=0x00; bootcd=0; break;
7675 case 0x02: bootdrv=0x80; bootcd=0; break;
7676 case 0x03: bootdrv=0x00; bootcd=1; break;
7677 default: return 0x00000000;
7680 bootseq=inb_cmos(0x2d);
7686 bootdrv=0x00; bootcd=0;
7687 if((bootseq&0x20)==0) bootdrv=0x80;
7688 #endif // BX_ELTORITO_BOOT
7690 #if BX_ELTORITO_BOOT
7691 // We have to boot from cd
7693 status = cdrom_boot();
7695 BX_DEBUG("CDBoot:%x\n",status);
7699 if ( (status & 0x00ff) !=0 ) {
7700 print_cdromboot_failure(status);
7701 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7705 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7706 bootdrv = (Bit8u)(status>>8);
7709 #endif // BX_ELTORITO_BOOT
7711 // We have to boot from harddisk or floppy
7722 mov _int19_function.status + 2[bp], ax
7723 mov dl, _int19_function.bootdrv + 2[bp]
7724 mov ax, _int19_function.bootseg + 2[bp]
7725 mov es, ax ;; segment
7726 mov bx, #0x0000 ;; offset
7727 mov ah, #0x02 ;; function 2, read diskette sector
7728 mov al, #0x01 ;; read 1 sector
7729 mov ch, #0x00 ;; track 0
7730 mov cl, #0x01 ;; sector 1
7731 mov dh, #0x00 ;; head 0
7732 int #0x13 ;; read sector
7735 mov _int19_function.status + 2[bp], ax
7743 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7748 // check signature if instructed by cmos reg 0x38, only for floppy
7749 // bootchk = 1 : signature check disabled
7750 // bootchk = 0 : signature check enabled
7751 if (bootdrv != 0) bootchk = 0;
7752 else bootchk = inb_cmos(0x38) & 0x01;
7754 #if BX_ELTORITO_BOOT
7755 // if boot from cd, no signature check
7758 #endif // BX_ELTORITO_BOOT
7761 if (read_word(bootseg,0x1fe) != 0xaa55) {
7762 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7767 #if BX_ELTORITO_BOOT
7768 // Print out the boot string
7769 BX_DEBUG("cdrom_boot: %x\n",status);
7770 print_boot_device(bootcd, bootdrv);
7771 #else // BX_ELTORITO_BOOT
7772 print_boot_device(0, bootdrv);
7773 #endif // BX_ELTORITO_BOOT
7775 // return the boot segment
7776 return (((Bit32u)bootdrv) << 16) + bootseg;
7780 int1a_function(regs, ds, iret_addr)
7781 pusha_regs_t regs; // regs pushed from PUSHA instruction
7782 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7783 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7787 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);
7793 switch (regs.u.r8.ah) {
7794 case 0: // get current clock count
7798 regs.u.r16.cx = BiosData->ticks_high;
7799 regs.u.r16.dx = BiosData->ticks_low;
7800 regs.u.r8.al = BiosData->midnight_flag;
7801 BiosData->midnight_flag = 0; // reset flag
7806 ClearCF(iret_addr.flags); // OK
7809 case 1: // Set Current Clock Count
7813 BiosData->ticks_high = regs.u.r16.cx;
7814 BiosData->ticks_low = regs.u.r16.dx;
7815 BiosData->midnight_flag = 0; // reset flag
7820 ClearCF(iret_addr.flags); // OK
7824 case 2: // Read CMOS Time
7825 if (rtc_updating()) {
7826 SetCF(iret_addr.flags);
7830 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7831 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7832 regs.u.r8.ch = inb_cmos(0x04); // Hours
7833 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7835 regs.u.r8.al = regs.u.r8.ch;
7836 ClearCF(iret_addr.flags); // OK
7839 case 3: // Set CMOS Time
7840 // Using a debugger, I notice the following masking/setting
7841 // of bits in Status Register B, by setting Reg B to
7842 // a few values and getting its value after INT 1A was called.
7844 // try#1 try#2 try#3
7845 // before 1111 1101 0111 1101 0000 0000
7846 // after 0110 0010 0110 0010 0000 0010
7848 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7849 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7850 if (rtc_updating()) {
7852 // fall through as if an update were not in progress
7854 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7855 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7856 outb_cmos(0x04, regs.u.r8.ch); // Hours
7857 // Set Daylight Savings time enabled bit to requested value
7858 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7859 // (reg B already selected)
7860 outb_cmos(0x0b, val8);
7862 regs.u.r8.al = val8; // val last written to Reg B
7863 ClearCF(iret_addr.flags); // OK
7866 case 4: // Read CMOS Date
7868 if (rtc_updating()) {
7869 SetCF(iret_addr.flags);
7872 regs.u.r8.cl = inb_cmos(0x09); // Year
7873 regs.u.r8.dh = inb_cmos(0x08); // Month
7874 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7875 regs.u.r8.ch = inb_cmos(0x32); // Century
7876 regs.u.r8.al = regs.u.r8.ch;
7877 ClearCF(iret_addr.flags); // OK
7880 case 5: // Set CMOS Date
7881 // Using a debugger, I notice the following masking/setting
7882 // of bits in Status Register B, by setting Reg B to
7883 // a few values and getting its value after INT 1A was called.
7885 // try#1 try#2 try#3 try#4
7886 // before 1111 1101 0111 1101 0000 0010 0000 0000
7887 // after 0110 1101 0111 1101 0000 0010 0000 0000
7889 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7890 // My assumption: RegB = (RegB & 01111111b)
7891 if (rtc_updating()) {
7893 SetCF(iret_addr.flags);
7896 outb_cmos(0x09, regs.u.r8.cl); // Year
7897 outb_cmos(0x08, regs.u.r8.dh); // Month
7898 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7899 outb_cmos(0x32, regs.u.r8.ch); // Century
7900 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7901 outb_cmos(0x0b, val8);
7903 regs.u.r8.al = val8; // AL = val last written to Reg B
7904 ClearCF(iret_addr.flags); // OK
7907 case 6: // Set Alarm Time in CMOS
7908 // Using a debugger, I notice the following masking/setting
7909 // of bits in Status Register B, by setting Reg B to
7910 // a few values and getting its value after INT 1A was called.
7912 // try#1 try#2 try#3
7913 // before 1101 1111 0101 1111 0000 0000
7914 // after 0110 1111 0111 1111 0010 0000
7916 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7917 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7918 val8 = inb_cmos(0x0b); // Get Status Reg B
7921 // Alarm interrupt enabled already
7922 SetCF(iret_addr.flags); // Error: alarm in use
7925 if (rtc_updating()) {
7927 // fall through as if an update were not in progress
7929 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7930 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7931 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7932 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7933 // enable Status Reg B alarm bit, clear halt clock bit
7934 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7935 ClearCF(iret_addr.flags); // OK
7938 case 7: // Turn off Alarm
7939 // Using a debugger, I notice the following masking/setting
7940 // of bits in Status Register B, by setting Reg B to
7941 // a few values and getting its value after INT 1A was called.
7943 // try#1 try#2 try#3 try#4
7944 // before 1111 1101 0111 1101 0010 0000 0010 0010
7945 // after 0100 0101 0101 0101 0000 0000 0000 0010
7947 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7948 // My assumption: RegB = (RegB & 01010111b)
7949 val8 = inb_cmos(0x0b); // Get Status Reg B
7950 // clear clock-halt bit, disable alarm bit
7951 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7953 regs.u.r8.al = val8; // val last written to Reg B
7954 ClearCF(iret_addr.flags); // OK
7958 // real mode PCI BIOS functions now handled in assembler code
7959 // this C code handles the error code for information only
7960 if (regs.u.r8.bl == 0xff) {
7961 BX_INFO("PCI BIOS: PCI not present\n");
7962 } else if (regs.u.r8.bl == 0x81) {
7963 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7964 } else if (regs.u.r8.bl == 0x83) {
7965 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7966 } else if (regs.u.r8.bl == 0x86) {
7967 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7969 regs.u.r8.ah = regs.u.r8.bl;
7970 SetCF(iret_addr.flags);
7975 SetCF(iret_addr.flags); // Unsupported
7980 int70_function(regs, ds, iret_addr)
7981 pusha_regs_t regs; // regs pushed from PUSHA instruction
7982 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7983 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7985 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7986 Bit8u registerB = 0, registerC = 0;
7988 // Check which modes are enabled and have occurred.
7989 registerB = inb_cmos( 0xB );
7990 registerC = inb_cmos( 0xC );
7992 if( ( registerB & 0x60 ) != 0 ) {
7993 if( ( registerC & 0x20 ) != 0 ) {
7994 // Handle Alarm Interrupt.
8001 if( ( registerC & 0x40 ) != 0 ) {
8002 // Handle Periodic Interrupt.
8004 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8005 // Wait Interval (Int 15, AH=83) active.
8006 Bit32u time, toggle;
8008 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8009 if( time < 0x3D1 ) {
8011 Bit16u segment, offset;
8013 offset = read_word( 0x40, 0x98 );
8014 segment = read_word( 0x40, 0x9A );
8015 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8016 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8017 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8019 // Continue waiting.
8021 write_dword( 0x40, 0x9C, time );
8034 ;------------------------------------------
8035 ;- INT74h : PS/2 mouse hardware interrupt -
8036 ;------------------------------------------
8041 push #0x00 ;; placeholder for status
8042 push #0x00 ;; placeholder for X
8043 push #0x00 ;; placeholder for Y
8044 push #0x00 ;; placeholder for Z
8045 push #0x00 ;; placeholder for make_far_call boolean
8046 call _int74_function
8047 pop cx ;; remove make_far_call from stack
8050 ;; make far call to EBDA:0022
8053 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8055 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8060 add sp, #8 ;; pop status, x, y, z
8062 pop ds ;; restore DS
8067 ;; This will perform an IRET, but will retain value of current CF
8068 ;; by altering flags on stack. Better than RETF #02.
8073 and BYTE [bp + 0x06], #0xfe
8079 or BYTE [bp + 0x06], #0x01
8084 ;----------------------
8085 ;- INT13h (relocated) -
8086 ;----------------------
8088 ; int13_relocated is a little bit messed up since I played with it
8089 ; I have to rewrite it:
8090 ; - call a function that detect which function to call
8091 ; - make all called C function get the same parameters list
8095 #if BX_ELTORITO_BOOT
8096 ;; check for an eltorito function
8098 jb int13_not_eltorito
8100 ja int13_not_eltorito
8109 jmp _int13_eltorito ;; ELDX not used
8117 ;; check if emulation active
8118 call _cdemu_isactive
8120 je int13_cdemu_inactive
8122 ;; check if access to the emulated drive
8123 call _cdemu_emulated_drive
8126 cmp al,dl ;; int13 on emulated drive
8141 jmp _int13_cdemu ;; ELDX not used
8144 and dl,#0xE0 ;; mask to get device class, including cdroms
8145 cmp al,dl ;; al is 0x00 or 0x80
8146 jne int13_cdemu_inactive ;; inactive for device class
8158 dec dl ;; real drive is dl - 1
8161 int13_cdemu_inactive:
8167 #endif // BX_ELTORITO_BOOT
8178 push dx ;; push eltorito value of dx instead of sp
8189 ;; now the 16-bit registers can be restored with:
8190 ;; pop ds; pop es; popa; iret
8191 ;; arguments passed to functions should be
8192 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8198 jmp _int13_diskette_function
8207 // ebx is modified: BSD 5.2.1 boot loader problem
8208 // someone should figure out which 32 bit register that actually are used
8225 call _int13_harddisk
8237 int18_handler: ;; Boot Failure routing
8238 call _int18_panic_msg
8245 int19_relocated: ;; Boot function, relocated
8247 ;; int19 was beginning to be really complex, so now it
8248 ;; just calls an C function, that does the work
8249 ;; it returns in BL the boot drive, and in AX the boot segment
8250 ;; the boot segment will be 0x0000 if something has failed
8262 call _int19_function
8265 ;; bl contains the boot drive
8266 ;; ax contains the boot segment or 0 if failure
8268 test ax, ax ;; if ax is 0 try next boot device
8274 call _int19_function
8277 test ax, ax ;; if ax is 0 try next boot device
8283 call _int19_function
8286 test ax, ax ;; if ax is 0 call int18
8290 mov dl, bl ;; set drive so guest os find it
8291 shl eax, #0x04 ;; convert seg to ip
8292 mov 2[bp], ax ;; set ip
8294 shr eax, #0x04 ;; get cs back
8295 and ax, #0xF000 ;; remove what went in ip
8296 mov 4[bp], ax ;; set cs
8298 mov es, ax ;; set es to zero fixes [ 549815 ]
8299 mov [bp], ax ;; set bp to zero
8300 mov ax, #0xaa55 ;; set ok flag
8303 iret ;; Beam me up Scotty
8308 int1c_handler: ;; User Timer Tick
8312 ;----------------------
8313 ;- POST: Floppy Drive -
8314 ;----------------------
8320 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8322 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8324 mov 0x0440, al ;; diskette motor timeout counter: not active
8325 mov 0x0441, al ;; diskette controller status return code
8327 mov 0x0442, al ;; disk & diskette controller status register 0
8328 mov 0x0443, al ;; diskette controller status register 1
8329 mov 0x0444, al ;; diskette controller status register 2
8330 mov 0x0445, al ;; diskette controller cylinder number
8331 mov 0x0446, al ;; diskette controller head number
8332 mov 0x0447, al ;; diskette controller sector number
8333 mov 0x0448, al ;; diskette controller bytes written
8335 mov 0x048b, al ;; diskette configuration data
8337 ;; -----------------------------------------------------------------
8338 ;; (048F) diskette controller information
8340 mov al, #0x10 ;; get CMOS diskette drive type
8343 mov ah, al ;; save byte to AH
8346 shr al, #4 ;; look at top 4 bits for drive 0
8347 jz f0_missing ;; jump if no drive0
8348 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8351 mov bl, #0x00 ;; no drive0
8354 mov al, ah ;; restore from AH
8355 and al, #0x0f ;; look at bottom 4 bits for drive 1
8356 jz f1_missing ;; jump if no drive1
8357 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8359 ;; leave high bits in BL zerod
8360 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8361 ;; -----------------------------------------------------------------
8364 mov 0x0490, al ;; diskette 0 media state
8365 mov 0x0491, al ;; diskette 1 media state
8367 ;; diskette 0,1 operational starting state
8368 ;; drive type has not been determined,
8369 ;; has no changed detection line
8373 mov 0x0494, al ;; diskette 0 current cylinder
8374 mov 0x0495, al ;; diskette 1 current cylinder
8377 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8379 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8380 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8381 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8386 ;--------------------
8387 ;- POST: HARD DRIVE -
8388 ;--------------------
8389 ; relocated here because the primary POST area isnt big enough.
8392 // INT 76h calls INT 15h function ax=9100
8394 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8400 mov 0x0474, al /* hard disk status of last operation */
8401 mov 0x0477, al /* hard disk port offset (XT only ???) */
8402 mov 0x048c, al /* hard disk status register */
8403 mov 0x048d, al /* hard disk error register */
8404 mov 0x048e, al /* hard disk task complete flag */
8406 mov 0x0475, al /* hard disk number attached */
8408 mov 0x0476, al /* hard disk control byte */
8409 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8410 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8411 ;; INT 41h: hard disk 0 configuration pointer
8412 ;; INT 46h: hard disk 1 configuration pointer
8413 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8414 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8416 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8428 cmp al, #47 ;; decimal 47 - user definable
8432 ;; CMOS purpose param table offset
8433 ;; 1b cylinders low 0
8434 ;; 1c cylinders high 1
8436 ;; 1e write pre-comp low 5
8437 ;; 1f write pre-comp high 6
8438 ;; 20 retries/bad map/heads>8 8
8439 ;; 21 landing zone low C
8440 ;; 22 landing zone high D
8441 ;; 23 sectors/track E
8446 ;;; Filling EBDA table for hard disk 0.
8454 mov (0x003d + 0x05), ax ;; write precomp word
8459 mov (0x003d + 0x08), al ;; drive control byte
8468 mov (0x003d + 0x0C), ax ;; landing zone word
8470 mov al, #0x1c ;; get cylinders word in AX
8472 in al, #0x71 ;; high byte
8476 in al, #0x71 ;; low byte
8477 mov bx, ax ;; BX = cylinders
8482 mov cl, al ;; CL = heads
8487 mov dl, al ;; DL = sectors
8490 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8492 hd0_post_physical_chs:
8493 ;; no logical CHS mapping used, just physical CHS
8494 ;; use Standard Fixed Disk Parameter Table (FDPT)
8495 mov (0x003d + 0x00), bx ;; number of physical cylinders
8496 mov (0x003d + 0x02), cl ;; number of physical heads
8497 mov (0x003d + 0x0E), dl ;; number of physical sectors
8500 hd0_post_logical_chs:
8501 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8502 mov (0x003d + 0x09), bx ;; number of physical cylinders
8503 mov (0x003d + 0x0b), cl ;; number of physical heads
8504 mov (0x003d + 0x04), dl ;; number of physical sectors
8505 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8507 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8510 jnbe hd0_post_above_2048
8511 ;; 1024 < c <= 2048 cylinders
8514 jmp hd0_post_store_logical
8516 hd0_post_above_2048:
8518 jnbe hd0_post_above_4096
8519 ;; 2048 < c <= 4096 cylinders
8522 jmp hd0_post_store_logical
8524 hd0_post_above_4096:
8526 jnbe hd0_post_above_8192
8527 ;; 4096 < c <= 8192 cylinders
8530 jmp hd0_post_store_logical
8532 hd0_post_above_8192:
8533 ;; 8192 < c <= 16384 cylinders
8537 hd0_post_store_logical:
8538 mov (0x003d + 0x00), bx ;; number of physical cylinders
8539 mov (0x003d + 0x02), cl ;; number of physical heads
8541 mov cl, #0x0f ;; repeat count
8542 mov si, #0x003d ;; offset to disk0 FDPT
8543 mov al, #0x00 ;; sum
8544 hd0_post_checksum_loop:
8548 jnz hd0_post_checksum_loop
8549 not al ;; now take 2s complement
8552 ;;; Done filling EBDA table for hard disk 0.
8556 ;; is there really a second hard disk? if not, return now
8564 ;; check that the hd type is really 0x0f.
8569 ;; check that the extended type is 47 - user definable
8573 cmp al, #47 ;; decimal 47 - user definable
8578 ;; CMOS purpose param table offset
8579 ;; 0x24 cylinders low 0
8580 ;; 0x25 cylinders high 1
8582 ;; 0x27 write pre-comp low 5
8583 ;; 0x28 write pre-comp high 6
8585 ;; 0x2a landing zone low C
8586 ;; 0x2b landing zone high D
8587 ;; 0x2c sectors/track E
8588 ;;; Fill EBDA table for hard disk 1.
8598 mov (0x004d + 0x05), ax ;; write precomp word
8603 mov (0x004d + 0x08), al ;; drive control byte
8612 mov (0x004d + 0x0C), ax ;; landing zone word
8614 mov al, #0x25 ;; get cylinders word in AX
8616 in al, #0x71 ;; high byte
8620 in al, #0x71 ;; low byte
8621 mov bx, ax ;; BX = cylinders
8626 mov cl, al ;; CL = heads
8631 mov dl, al ;; DL = sectors
8634 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8636 hd1_post_physical_chs:
8637 ;; no logical CHS mapping used, just physical CHS
8638 ;; use Standard Fixed Disk Parameter Table (FDPT)
8639 mov (0x004d + 0x00), bx ;; number of physical cylinders
8640 mov (0x004d + 0x02), cl ;; number of physical heads
8641 mov (0x004d + 0x0E), dl ;; number of physical sectors
8644 hd1_post_logical_chs:
8645 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8646 mov (0x004d + 0x09), bx ;; number of physical cylinders
8647 mov (0x004d + 0x0b), cl ;; number of physical heads
8648 mov (0x004d + 0x04), dl ;; number of physical sectors
8649 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8651 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8654 jnbe hd1_post_above_2048
8655 ;; 1024 < c <= 2048 cylinders
8658 jmp hd1_post_store_logical
8660 hd1_post_above_2048:
8662 jnbe hd1_post_above_4096
8663 ;; 2048 < c <= 4096 cylinders
8666 jmp hd1_post_store_logical
8668 hd1_post_above_4096:
8670 jnbe hd1_post_above_8192
8671 ;; 4096 < c <= 8192 cylinders
8674 jmp hd1_post_store_logical
8676 hd1_post_above_8192:
8677 ;; 8192 < c <= 16384 cylinders
8681 hd1_post_store_logical:
8682 mov (0x004d + 0x00), bx ;; number of physical cylinders
8683 mov (0x004d + 0x02), cl ;; number of physical heads
8685 mov cl, #0x0f ;; repeat count
8686 mov si, #0x004d ;; offset to disk0 FDPT
8687 mov al, #0x00 ;; sum
8688 hd1_post_checksum_loop:
8692 jnz hd1_post_checksum_loop
8693 not al ;; now take 2s complement
8696 ;;; Done filling EBDA table for hard disk 1.
8700 ;--------------------
8701 ;- POST: EBDA segment
8702 ;--------------------
8703 ; relocated here because the primary POST area isnt big enough.
8708 mov byte ptr [0x0], #EBDA_SIZE
8710 xor ax, ax ; mov EBDA seg into 40E
8712 mov word ptr [0x40E], #EBDA_SEG
8715 ;--------------------
8716 ;- POST: EOI + jmp via [0x40:67)
8717 ;--------------------
8718 ; relocated here because the primary POST area isnt big enough.
8728 ;--------------------
8731 out #0xA0, al ;; slave PIC EOI
8734 out #0x20, al ;; master PIC EOI
8737 ;--------------------
8739 ;; in: AL in BCD format
8740 ;; out: AL in binary format, AH will always be 0
8743 and bl, #0x0f ;; bl has low digit
8744 shr al, #4 ;; al has high digit
8746 mul al, bh ;; multiply high digit by 10 (result in AX)
8747 add al, bl ;; then add low digit
8750 ;--------------------
8752 ;; Setup the Timer Ticks Count (0x46C:dword) and
8753 ;; Timer Ticks Roller Flag (0x470:byte)
8754 ;; The Timer Ticks Count needs to be set according to
8755 ;; the current CMOS time, as if ticks have been occurring
8756 ;; at 18.2hz since midnight up to this point. Calculating
8757 ;; this is a little complicated. Here are the factors I gather
8758 ;; regarding this. 14,318,180 hz was the original clock speed,
8759 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8760 ;; at the time, or 4 to drive the CGA video adapter. The div3
8761 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8762 ;; the timer. With a maximum 16bit timer count, this is again
8763 ;; divided down by 65536 to 18.2hz.
8765 ;; 14,318,180 Hz clock
8766 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8767 ;; /4 = 1,193,181 Hz fed to timer
8768 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8769 ;; 1 second = 18.20650736 ticks
8770 ;; 1 minute = 1092.390442 ticks
8771 ;; 1 hour = 65543.42651 ticks
8773 ;; Given the values in the CMOS clock, one could calculate
8774 ;; the number of ticks by the following:
8775 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8776 ;; (BcdToBin(minutes) * 1092.3904)
8777 ;; (BcdToBin(hours) * 65543.427)
8778 ;; To get a little more accuracy, since Im using integer
8779 ;; arithmatic, I use:
8780 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8781 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8782 ;; (BcdToBin(hours) * 65543427) / 1000
8787 xor eax, eax ;; clear EAX
8790 in al, #0x71 ;; AL has CMOS seconds in BCD
8791 call BcdToBin ;; EAX now has seconds in binary
8797 mov ecx, eax ;; ECX will accumulate total ticks
8800 xor eax, eax ;; clear EAX
8803 in al, #0x71 ;; AL has CMOS minutes in BCD
8804 call BcdToBin ;; EAX now has minutes in binary
8810 add ecx, eax ;; add to total ticks
8813 xor eax, eax ;; clear EAX
8816 in al, #0x71 ;; AL has CMOS hours in BCD
8817 call BcdToBin ;; EAX now has hours in binary
8823 add ecx, eax ;; add to total ticks
8825 mov 0x46C, ecx ;; Timer Ticks Count
8827 mov 0x470, al ;; Timer Ticks Rollover Flag
8830 ;--------------------
8832 ;; record completion in BIOS task complete flag
8844 ;--------------------
8849 #include "apmbios.S"
8853 #include "apmbios.S"
8856 #include "apmbios.S"
8860 ;--------------------
8865 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8866 dw bios32_entry_point, 0xf ;; 32 bit physical address
8867 db 0 ;; revision level
8868 ;; length in paragraphs and checksum stored in a word to prevent errors
8869 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8870 & 0xff) << 8) + 0x01
8871 db 0,0,0,0,0 ;; reserved
8876 cmp eax, #0x49435024
8878 mov eax, #0x80000000
8883 cmp eax, #0x12378086
8885 mov ebx, #0x000f0000
8887 mov edx, #pcibios_protected
8902 cmp al, #0x01 ;; installation check
8906 mov edx, #0x20494350
8909 pci_pro_f02: ;; find pci device
8917 call pci_pro_select_reg
8931 pci_pro_f08: ;; read configuration byte
8934 call pci_pro_select_reg
8943 pci_pro_f09: ;; read configuration word
8946 call pci_pro_select_reg
8955 pci_pro_f0a: ;; read configuration dword
8958 call pci_pro_select_reg
8965 pci_pro_f0b: ;; write configuration byte
8968 call pci_pro_select_reg
8977 pci_pro_f0c: ;; write configuration word
8980 call pci_pro_select_reg
8989 pci_pro_f0d: ;; write configuration dword
8992 call pci_pro_select_reg
9035 mov eax, #0x80000000
9040 cmp eax, #0x12378086
9050 cmp al, #0x01 ;; installation check
9055 mov edx, #0x20494350
9057 mov di, #pcibios_protected
9060 pci_real_f02: ;; find pci device
9070 call pci_real_select_reg
9074 jne pci_real_nextdev
9081 jne pci_real_devloop
9086 pci_real_f08: ;; read configuration byte
9089 call pci_real_select_reg
9098 pci_real_f09: ;; read configuration word
9101 call pci_real_select_reg
9110 pci_real_f0a: ;; read configuration dword
9113 call pci_real_select_reg
9120 pci_real_f0b: ;; write configuration byte
9123 call pci_real_select_reg
9132 pci_real_f0c: ;; write configuration word
9135 call pci_real_select_reg
9144 pci_real_f0d: ;; write configuration dword
9146 jne pci_real_unknown
9147 call pci_real_select_reg
9168 pci_real_select_reg:
9182 pci_routing_table_structure:
9183 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9185 dw 32 + (6 * 16) ;; table size
9186 db 0 ;; PCI interrupt router bus
9187 db 0x08 ;; PCI interrupt router DevFunc
9188 dw 0x0000 ;; PCI exclusive IRQs
9189 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9190 dw 0x7000 ;; compatible PCI interrupt router device ID
9191 dw 0,0 ;; Miniport data
9192 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9194 ;; first slot entry PCI-to-ISA (embedded)
9195 db 0 ;; pci bus number
9196 db 0x08 ;; pci device number (bit 7-3)
9197 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9198 dw 0xdef8 ;; IRQ bitmap INTA#
9199 db 0x61 ;; link value INTB#
9200 dw 0xdef8 ;; IRQ bitmap INTB#
9201 db 0x62 ;; link value INTC#
9202 dw 0xdef8 ;; IRQ bitmap INTC#
9203 db 0x63 ;; link value INTD#
9204 dw 0xdef8 ;; IRQ bitmap INTD#
9205 db 0 ;; physical slot (0 = embedded)
9207 ;; second slot entry: 1st PCI slot
9208 db 0 ;; pci bus number
9209 db 0x10 ;; pci device number (bit 7-3)
9210 db 0x61 ;; link value INTA#
9211 dw 0xdef8 ;; IRQ bitmap INTA#
9212 db 0x62 ;; link value INTB#
9213 dw 0xdef8 ;; IRQ bitmap INTB#
9214 db 0x63 ;; link value INTC#
9215 dw 0xdef8 ;; IRQ bitmap INTC#
9216 db 0x60 ;; link value INTD#
9217 dw 0xdef8 ;; IRQ bitmap INTD#
9218 db 1 ;; physical slot (0 = embedded)
9220 ;; third slot entry: 2nd PCI slot
9221 db 0 ;; pci bus number
9222 db 0x18 ;; pci device number (bit 7-3)
9223 db 0x62 ;; link value INTA#
9224 dw 0xdef8 ;; IRQ bitmap INTA#
9225 db 0x63 ;; link value INTB#
9226 dw 0xdef8 ;; IRQ bitmap INTB#
9227 db 0x60 ;; link value INTC#
9228 dw 0xdef8 ;; IRQ bitmap INTC#
9229 db 0x61 ;; link value INTD#
9230 dw 0xdef8 ;; IRQ bitmap INTD#
9231 db 2 ;; physical slot (0 = embedded)
9233 ;; 4th slot entry: 3rd PCI slot
9234 db 0 ;; pci bus number
9235 db 0x20 ;; pci device number (bit 7-3)
9236 db 0x63 ;; link value INTA#
9237 dw 0xdef8 ;; IRQ bitmap INTA#
9238 db 0x60 ;; link value INTB#
9239 dw 0xdef8 ;; IRQ bitmap INTB#
9240 db 0x61 ;; link value INTC#
9241 dw 0xdef8 ;; IRQ bitmap INTC#
9242 db 0x62 ;; link value INTD#
9243 dw 0xdef8 ;; IRQ bitmap INTD#
9244 db 3 ;; physical slot (0 = embedded)
9246 ;; 5th slot entry: 4rd PCI slot
9247 db 0 ;; pci bus number
9248 db 0x28 ;; pci device number (bit 7-3)
9249 db 0x60 ;; link value INTA#
9250 dw 0xdef8 ;; IRQ bitmap INTA#
9251 db 0x61 ;; link value INTB#
9252 dw 0xdef8 ;; IRQ bitmap INTB#
9253 db 0x62 ;; link value INTC#
9254 dw 0xdef8 ;; IRQ bitmap INTC#
9255 db 0x63 ;; link value INTD#
9256 dw 0xdef8 ;; IRQ bitmap INTD#
9257 db 4 ;; physical slot (0 = embedded)
9259 ;; 6th slot entry: 5rd PCI slot
9260 db 0 ;; pci bus number
9261 db 0x30 ;; pci device number (bit 7-3)
9262 db 0x61 ;; link value INTA#
9263 dw 0xdef8 ;; IRQ bitmap INTA#
9264 db 0x62 ;; link value INTB#
9265 dw 0xdef8 ;; IRQ bitmap INTB#
9266 db 0x63 ;; link value INTC#
9267 dw 0xdef8 ;; IRQ bitmap INTC#
9268 db 0x60 ;; link value INTD#
9269 dw 0xdef8 ;; IRQ bitmap INTD#
9270 db 5 ;; physical slot (0 = embedded)
9276 pcibios_init_sel_reg:
9288 pcibios_init_set_elcr:
9312 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9317 mov si, #pci_routing_table_structure
9321 call pcibios_init_sel_reg
9324 cmp eax, [si+12] ;; check irq router
9327 call pcibios_init_sel_reg
9328 push bx ;; save irq router bus + devfunc
9331 out dx, ax ;; reset PIRQ route control
9339 add si, #0x20 ;; set pointer to 1st entry
9341 mov ax, #pci_irq_list
9350 call pcibios_init_sel_reg
9354 jnz pci_test_int_pin
9360 call pcibios_init_sel_reg
9365 dec al ;; determine pirq reg
9374 call pcibios_init_sel_reg
9381 mov bx, [bp-2] ;; pci irq list pointer
9386 call pcibios_init_set_elcr
9390 add bl, [bp-3] ;; pci function number
9392 call pcibios_init_sel_reg
9402 mov byte ptr[bp-3], #0x00
9410 #endif // BX_PCIBIOS
9412 ; parallel port detection: base address in DX, index in BX, timeout in CL
9417 and al, #0xdf ; clear input mode
9427 mov [bx+0x408], dx ; Parallel I/O address
9429 mov [bx+0x478], cl ; Parallel printer timeout
9434 ; serial port detection: base address in DX, index in BX, timeout in CL
9436 ; no serial port in the VM -PAD
9456 mov [bx+0x400], dx ; Serial I/O address
9458 mov [bx+0x47c], cl ; Serial timeout
9485 ;; Scan for existence of valid expansion ROMS.
9486 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9487 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9488 ;; System ROM: only 0xE0000
9494 ;; 2 ROM length in 512-byte blocks
9495 ;; 3 ROM initialization entry point (FAR CALL)
9500 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9501 cmp [0], #0xAA55 ;; look for signature
9502 jne rom_scan_increment
9504 jnz rom_scan_increment
9505 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9507 ;; We want our increment in 512-byte quantities, rounded to
9508 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9510 jz block_count_rounded
9511 and al, #0xfc ;; needs rounding up
9513 block_count_rounded:
9515 xor bx, bx ;; Restore DS back to 0000:
9518 ;; Push addr of ROM entry point
9520 push #0x0003 ;; Push offset
9521 mov bp, sp ;; Call ROM init routine using seg:off on stack
9522 db 0xff ;; call_far ss:[bp+0]
9525 cli ;; In case expansion ROM BIOS turns IF on
9526 add sp, #2 ;; Pop offset value
9527 pop cx ;; Pop seg value (restore CX)
9528 pop ax ;; Restore AX
9530 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9531 ;; because the segment selector is shifted left 4 bits.
9536 xor ax, ax ;; Restore DS back to 0000:
9542 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9543 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9544 ; but the tables themeselves can be elsewhere.
9553 mov cx, #0x001f ; 0x1f bytes to copy
9555 mov es, ax ; destination segment is 0xf0000
9556 mov di, #smbios_entry_point ; destination offset
9558 mov ds, ax ; source segment is 0x9f000
9559 mov si, #0x0000 ; source offset is 0
9577 ;; for 'C' strings and other data, insert them here with
9578 ;; a the following hack:
9579 ;; DATA_SEG_DEFS_HERE
9585 .org 0xe05b ; POST Entry Point
9590 ;; first reset the DMA controllers
9594 ;; then initialize the DMA controllers
9596 out 0xD6, al ; cascade mode of channel 4 enabled
9598 out 0xD4, al ; unmask channel 4
9600 ;; Examine CMOS shutdown status.
9608 ;; Reset CMOS shutdown status.
9610 out 0x70, AL ; select CMOS register Fh
9612 out 0x71, AL ; set shutdown action to normal
9614 ;; Examine CMOS shutdown status.
9617 ;; 0x00, 0x09, 0x0D+ = normal startup
9625 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9629 ;; Examine CMOS shutdown status.
9630 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9632 call _shutdown_status_panic
9638 ; 0xb0, 0x20, /* mov al, #0x20 */
9639 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9649 ; case 0: normal startup
9658 ;; zero out BIOS data area (40:00..40:ff)
9660 mov cx, #0x0080 ;; 128 words
9666 call _log_bios_start
9668 ;; set all interrupts to default handler
9669 mov bx, #0x0000 ;; offset index
9670 mov cx, #0x0100 ;; counter (256 interrupts)
9671 mov ax, #dummy_iret_handler
9681 loop post_default_ints
9683 ;; set vector 0x79 to zero
9684 ;; this is used by 'gardian angel' protection system
9685 SET_INT_VECTOR(0x79, #0, #0)
9687 ;; base memory in K 40:13 (word)
9688 mov ax, #BASE_MEM_IN_K
9692 ;; Manufacturing Test 40:12
9695 ;; Warm Boot Flag 0040:0072
9696 ;; value of 1234h = skip memory checks
9700 ;; Printer Services vector
9701 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9703 ;; Bootstrap failure vector
9704 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9706 ;; Bootstrap Loader vector
9707 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9709 ;; User Timer Tick vector
9710 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9712 ;; Memory Size Check vector
9713 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9715 ;; Equipment Configuration Check vector
9716 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9719 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9725 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9726 ;; int 1C already points at dummy_iret_handler (above)
9727 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9730 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9735 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9741 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9742 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9746 mov 0x0417, al /* keyboard shift flags, set 1 */
9747 mov 0x0418, al /* keyboard shift flags, set 2 */
9748 mov 0x0419, al /* keyboard alt-numpad work area */
9749 mov 0x0471, al /* keyboard ctrl-break flag */
9750 mov 0x0497, al /* keyboard status flags 4 */
9752 mov 0x0496, al /* keyboard status flags 3 */
9755 /* keyboard head of buffer pointer */
9759 /* keyboard end of buffer pointer */
9762 /* keyboard pointer to start of buffer */
9766 /* keyboard pointer to end of buffer */
9770 /* init the keyboard */
9773 ;; mov CMOS Equipment Byte to BDA Equipment Word
9782 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9786 mov cl, #0x14 ; timeout value
9787 mov dx, #0x378 ; Parallel I/O address, port 1
9789 mov dx, #0x278 ; Parallel I/O address, port 2
9792 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9794 or ax, bx ; set number of parallel ports
9798 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9799 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9801 mov cl, #0x0a ; timeout value
9802 mov dx, #0x03f8 ; Serial I/O address, port 1
9804 mov dx, #0x02f8 ; Serial I/O address, port 2
9806 mov dx, #0x03e8 ; Serial I/O address, port 3
9808 mov dx, #0x02e8 ; Serial I/O address, port 4
9811 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9813 or ax, bx ; set number of serial port
9817 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9818 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9819 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9820 ;; BIOS DATA AREA 0x4CE ???
9821 call timer_tick_post
9824 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9826 ;; IRQ13 (FPU exception) setup
9827 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9830 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9835 mov al, #0x11 ; send initialisation commands
9850 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9851 #if BX_USE_PS2_MOUSE
9856 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9859 call _copy_e820_table
9878 call _print_bios_banner
9883 call floppy_drive_post
9890 call hard_drive_post
9893 ;; ATA/ATAPI driver setup
9898 #else // BX_USE_ATADRV
9903 call hard_drive_post
9905 #endif // BX_USE_ATADRV
9907 #if BX_ELTORITO_BOOT
9909 ;; eltorito floppy/harddisk emulation from cd
9913 #endif // BX_ELTORITO_BOOT
9916 //JMP_EP(0x0064) ; INT 19h location
9919 .org 0xe2c3 ; NMI Handler Entry Point
9921 ;; FIXME the NMI handler should not panic
9922 ;; but iret when called from int75 (fpu exception)
9923 call _nmi_handler_msg
9927 out 0xf0, al // clear irq13
9928 call eoi_both_pics // clear interrupt
9929 int 2 // legacy nmi call
9932 ;-------------------------------------------
9933 ;- INT 13h Fixed Disk Services Entry Point -
9934 ;-------------------------------------------
9935 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9937 //JMPL(int13_relocated)
9940 .org 0xe401 ; Fixed Disk Parameter Table
9945 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9949 ;-------------------------------------------
9950 ;- System BIOS Configuration Data Table
9951 ;-------------------------------------------
9952 .org BIOS_CONFIG_TABLE
9953 db 0x08 ; Table size (bytes) -Lo
9954 db 0x00 ; Table size (bytes) -Hi
9959 ; b7: 1=DMA channel 3 used by hard disk
9960 ; b6: 1=2 interrupt controllers present
9962 ; b4: 1=BIOS calls int 15h/4Fh every key
9963 ; b3: 1=wait for extern event supported (Int 15h/41h)
9964 ; b2: 1=extended BIOS data area used
9965 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9966 ; b0: 1=Dual bus (MicroChannel + ISA)
9970 (BX_CALL_INT15_4F << 4) | \
9972 (BX_USE_EBDA << 2) | \
9976 ; b7: 1=32-bit DMA supported
9977 ; b6: 1=int16h, function 9 supported
9978 ; b5: 1=int15h/C6h (get POS data) supported
9979 ; b4: 1=int15h/C7h (get mem map info) supported
9980 ; b3: 1=int15h/C8h (en/dis CPU) supported
9981 ; b2: 1=non-8042 kb controller
9982 ; b1: 1=data streaming supported
9996 ; b4: POST supports ROM-to-RAM enable/disable
9997 ; b3: SCSI on system board
9998 ; b2: info panel installed
9999 ; b1: Initial Machine Load (IML) system - BIOS on disk
10000 ; b0: SCSI supported in IML
10004 ; b6: EEPROM present
10005 ; b5-3: ABIOS presence (011 = not supported)
10007 ; b1: memory split above 16Mb supported
10008 ; b0: POSTEXT directly supported by POST
10010 ; Feature byte 5 (IBM)
10011 ; b1: enhanced mouse
10017 .org 0xe729 ; Baud Rate Generator Table
10022 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10028 call _int14_function
10034 ;----------------------------------------
10035 ;- INT 16h Keyboard Service Entry Point -
10036 ;----------------------------------------
10052 call _int16_function
10062 and BYTE [bp + 0x06], #0xbf
10070 or BYTE [bp + 0x06], #0x40
10078 int16_wait_for_key:
10082 jne int16_key_found
10086 /* no key yet, call int 15h, function AX=9002 */
10087 0x50, /* push AX */
10088 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10089 0xcd, 0x15, /* int 15h */
10091 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10093 jmp int16_wait_for_key
10098 call _int16_function
10103 /* notify int16 complete w/ int 15h, function AX=9102 */
10104 0x50, /* push AX */
10105 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10106 0xcd, 0x15, /* int 15h */
10113 ;-------------------------------------------------
10114 ;- INT09h : Keyboard Hardware Service Entry Point -
10115 ;-------------------------------------------------
10121 mov al, #0xAD ;;disable keyboard
10130 in al, #0x60 ;;read key from keyboard controller
10131 //test al, #0x80 ;;look for key release
10132 //jnz int09_process_key ;; dont pass releases to intercept?
10134 ;; check for extended key
10136 jne int09_call_int15_4f
10141 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10143 mov BYTE [0x496], al
10146 in al, #0x60 ;;read another key from keyboard controller
10150 int09_call_int15_4f:
10153 #ifdef BX_CALL_INT15_4F
10154 mov ah, #0x4f ;; allow for keyboard intercept
10161 //int09_process_key:
10164 call _int09_function
10170 call eoi_master_pic
10173 mov al, #0xAE ;;enable keyboard
10181 ;----------------------------------------
10182 ;- INT 13h Diskette Service Entry Point -
10183 ;----------------------------------------
10186 jmp int13_noeltorito
10188 ;---------------------------------------------
10189 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10190 ;---------------------------------------------
10191 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10201 mov al, #0x08 ; sense interrupt status
10219 mov ax, #0x0000 ;; segment 0000
10221 call eoi_master_pic
10223 or al, #0x80 ;; diskette interrupt has occurred
10231 .org 0xefc7 ; Diskette Controller Parameter Table
10232 diskette_param_table:
10233 ;; Since no provisions are made for multiple drive types, most
10234 ;; values in this table are ignored. I set parameters for 1.44M
10237 db 0x02 ;; head load time 0000001, DMA used
10249 ;----------------------------------------
10250 ;- INT17h : Printer Service Entry Point -
10251 ;----------------------------------------
10258 call _int17_function
10263 diskette_param_table2:
10264 ;; New diskette parameter table adding 3 parameters from IBM
10265 ;; Since no provisions are made for multiple drive types, most
10266 ;; values in this table are ignored. I set parameters for 1.44M
10269 db 0x02 ;; head load time 0000001, DMA used
10279 db 79 ;; maximum track
10280 db 0 ;; data transfer rate
10281 db 4 ;; drive type in cmos
10283 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10290 .org 0xf065 ; INT 10h Video Support Service Entry Point
10292 ;; dont do anything, since the VGA BIOS handles int10h requests
10295 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10300 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10301 ; ??? different for Pentium (machine check)?
10313 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10325 .org 0xf859 ; INT 15h System Services Entry Point
10339 #if BX_USE_PS2_MOUSE
10341 je int15_handler_mouse
10343 call _int15_function
10344 int15_handler_mouse_ret:
10346 int15_handler32_ret:
10356 #if BX_USE_PS2_MOUSE
10357 int15_handler_mouse:
10358 call _int15_function_mouse
10359 jmp int15_handler_mouse_ret
10364 call _int15_function32
10366 jmp int15_handler32_ret
10368 ;; Protected mode IDT descriptor
10370 ;; I just make the limit 0, so the machine will shutdown
10371 ;; if an exception occurs during protected mode memory
10374 ;; Set base to f0000 to correspond to beginning of BIOS,
10375 ;; in case I actually define an IDT later
10379 dw 0x0000 ;; limit 15:00
10380 dw 0x0000 ;; base 15:00
10381 db 0x0f ;; base 23:16
10383 ;; Real mode IDT descriptor
10385 ;; Set to typical real-mode values.
10390 dw 0x03ff ;; limit 15:00
10391 dw 0x0000 ;; base 15:00
10392 db 0x00 ;; base 23:16
10398 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10411 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10412 mov ds, ax ; on 16bit protected mode.
10413 jmp int1a_callfunction
10420 int1a_callfunction:
10421 call _int1a_function
10427 ;; int70h: IRQ8 - CMOS RTC
10434 call _int70_function
10442 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10450 ;; time to turn off drive(s)?
10453 jz int08_floppy_off
10456 jnz int08_floppy_off
10457 ;; turn motor(s) off
10466 mov eax, 0x046c ;; get ticks dword
10469 ;; compare eax to one days worth of timer ticks at 18.2 hz
10470 cmp eax, #0x001800B0
10471 jb int08_store_ticks
10472 ;; there has been a midnight rollover at this point
10473 xor eax, eax ;; zero out counter
10474 inc BYTE 0x0470 ;; increment rollover flag
10477 mov 0x046c, eax ;; store new ticks dword
10478 ;; chain to user timer tick INT #0x1c
10480 //;; call_ep [ds:loc]
10481 //CALL_EP( 0x1c << 2 )
10484 call eoi_master_pic
10489 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10493 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10495 ;------------------------------------------------
10496 ;- IRET Instruction for Dummy Interrupt Handler -
10497 ;------------------------------------------------
10498 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10499 dummy_iret_handler:
10502 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10511 .org 0xfff0 ; Power-up Entry Point
10518 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10519 .ascii BIOS_BUILD_DATE
10521 .org 0xfffe ; System Model ID
10525 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10528 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10529 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10530 * This font is public domain
10532 static Bit8u vgafont8[128*8]=
10534 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10535 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10536 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10537 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10538 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10539 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10540 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10541 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10542 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10543 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10544 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10545 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10546 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10547 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10548 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10549 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10550 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10551 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10552 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10553 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10554 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10555 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10556 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10557 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10558 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10559 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10560 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10561 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10562 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10563 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10564 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10565 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10567 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10568 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10569 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10570 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10571 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10572 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10573 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10574 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10575 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10576 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10577 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10578 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10579 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10580 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10581 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10582 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10583 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10584 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10585 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10586 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10587 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10588 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10589 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10590 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10591 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10592 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10593 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10594 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10595 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10596 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10597 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10598 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10599 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10600 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10601 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10602 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10603 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10604 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10605 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10606 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10607 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10608 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10609 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10610 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10611 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10612 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10613 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10614 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10615 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10616 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10617 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10618 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10619 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10620 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10621 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10622 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10623 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10624 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10625 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10626 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10627 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10628 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10630 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10631 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10632 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10633 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10634 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10635 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10636 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10637 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10638 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10639 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10640 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10641 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10642 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10643 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10644 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10645 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10646 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10647 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10648 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10649 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10650 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10651 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10652 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10653 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10654 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10655 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10656 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10657 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10658 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10659 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10660 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10661 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10667 // just carve out some blank space for HVMLOADER to write the MP tables to
10669 // NOTE: There should be enough space for a 32 processor entry MP table
10673 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10674 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 64 bytes
10675 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 128 bytes
10676 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 192 bytes
10677 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 256 bytes
10678 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 320 bytes
10679 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 384 bytes
10680 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 448 bytes
10681 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 512 bytes
10682 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 576 bytes
10683 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 640 bytes
10684 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 704 bytes
10685 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 768 bytes
10686 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 832 bytes
10687 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 896 bytes
10690 smbios_entry_point:
10691 db 0,0,0,0,0,0,0,0 ; 8 bytes
10692 db 0,0,0,0,0,0,0,0 ; 16 bytes
10693 db 0,0,0,0,0,0,0,0 ; 24 bytes
10694 db 0,0,0,0,0,0,0 ; 31 bytes
10697 #else // !HVMASSIST
10701 // bcc-generated data will be placed here
10703 // For documentation of this config structure, look on developer.intel.com and
10704 // search for multiprocessor specification. Note that when you change anything
10705 // you must update the checksum (a pain!). It would be better to construct this
10706 // with C structures, or at least fill in the checksum automatically.
10708 // Maybe this structs could be moved elsewhere than d000
10710 #if (BX_SMP_PROCESSORS==1)
10711 // no structure necessary.
10712 #elif (BX_SMP_PROCESSORS==2)
10713 // define the Intel MP Configuration Structure for 2 processors at
10714 // APIC ID 0,1. I/O APIC at ID=2.
10717 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10718 dw (mp_config_end-mp_config_table) ;; table length
10720 db 0x65 ;; checksum
10721 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10722 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10723 db 0x20, 0x20, 0x20, 0x20
10724 db 0x20, 0x20, 0x20, 0x20
10725 dw 0,0 ;; oem table ptr
10726 dw 0 ;; oem table size
10727 dw 20 ;; entry count
10728 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10729 dw 0 ;; extended table length
10730 db 0 ;; extended table checksum
10733 db 0 ;; entry type=processor
10734 db 0 ;; local APIC id
10735 db 0x11 ;; local APIC version number
10736 db 3 ;; cpu flags: enabled, bootstrap processor
10737 db 0,6,0,0 ;; cpu signature
10738 dw 0x201,0 ;; feature flags
10742 db 0 ;; entry type=processor
10743 db 1 ;; local APIC id
10744 db 0x11 ;; local APIC version number
10745 db 1 ;; cpu flags: enabled
10746 db 0,6,0,0 ;; cpu signature
10747 dw 0x201,0 ;; feature flags
10751 db 1 ;; entry type=bus
10753 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10755 db 2 ;; entry type=I/O APIC
10756 db 2 ;; apic id=2. linux will set.
10757 db 0x11 ;; I/O APIC version number
10758 db 1 ;; flags=1=enabled
10759 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10761 db 3 ;; entry type=I/O interrupt
10762 db 0 ;; interrupt type=vectored interrupt
10763 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10764 db 0 ;; source bus ID is ISA
10765 db 0 ;; source bus IRQ
10766 db 2 ;; destination I/O APIC ID
10767 db 0 ;; destination I/O APIC interrrupt in
10768 ;; repeat pattern for interrupts 0-15
10778 db 3,0,0,0,0,10,2,10
10779 db 3,0,0,0,0,11,2,11
10780 db 3,0,0,0,0,12,2,12
10781 db 3,0,0,0,0,13,2,13
10782 db 3,0,0,0,0,14,2,14
10783 db 3,0,0,0,0,15,2,15
10784 #elif (BX_SMP_PROCESSORS==4)
10785 // define the Intel MP Configuration Structure for 4 processors at
10786 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10789 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10790 dw (mp_config_end-mp_config_table) ;; table length
10792 db 0xdd ;; checksum
10793 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10794 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10795 db 0x20, 0x20, 0x20, 0x20
10796 db 0x20, 0x20, 0x20, 0x20
10797 dw 0,0 ;; oem table ptr
10798 dw 0 ;; oem table size
10799 dw 22 ;; entry count
10800 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10801 dw 0 ;; extended table length
10802 db 0 ;; extended table checksum
10805 db 0 ;; entry type=processor
10806 db 0 ;; local APIC id
10807 db 0x11 ;; local APIC version number
10808 db 3 ;; cpu flags: enabled, bootstrap processor
10809 db 0,6,0,0 ;; cpu signature
10810 dw 0x201,0 ;; feature flags
10814 db 0 ;; entry type=processor
10815 db 1 ;; local APIC id
10816 db 0x11 ;; local APIC version number
10817 db 1 ;; cpu flags: enabled
10818 db 0,6,0,0 ;; cpu signature
10819 dw 0x201,0 ;; feature flags
10823 db 0 ;; entry type=processor
10824 db 2 ;; local APIC id
10825 db 0x11 ;; local APIC version number
10826 db 1 ;; cpu flags: enabled
10827 db 0,6,0,0 ;; cpu signature
10828 dw 0x201,0 ;; feature flags
10832 db 0 ;; entry type=processor
10833 db 3 ;; local APIC id
10834 db 0x11 ;; local APIC version number
10835 db 1 ;; cpu flags: enabled
10836 db 0,6,0,0 ;; cpu signature
10837 dw 0x201,0 ;; feature flags
10841 db 1 ;; entry type=bus
10843 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10845 db 2 ;; entry type=I/O APIC
10846 db 4 ;; apic id=4. linux will set.
10847 db 0x11 ;; I/O APIC version number
10848 db 1 ;; flags=1=enabled
10849 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10851 db 3 ;; entry type=I/O interrupt
10852 db 0 ;; interrupt type=vectored interrupt
10853 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10854 db 0 ;; source bus ID is ISA
10855 db 0 ;; source bus IRQ
10856 db 4 ;; destination I/O APIC ID
10857 db 0 ;; destination I/O APIC interrrupt in
10858 ;; repeat pattern for interrupts 0-15
10868 db 3,0,0,0,0,10,4,10
10869 db 3,0,0,0,0,11,4,11
10870 db 3,0,0,0,0,12,4,12
10871 db 3,0,0,0,0,13,4,13
10872 db 3,0,0,0,0,14,4,14
10873 db 3,0,0,0,0,15,4,15
10874 #elif (BX_SMP_PROCESSORS==8)
10875 // define the Intel MP Configuration Structure for 8 processors at
10876 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10879 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10880 dw (mp_config_end-mp_config_table) ;; table length
10882 db 0xc3 ;; checksum
10883 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10884 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10885 db 0x20, 0x20, 0x20, 0x20
10886 db 0x20, 0x20, 0x20, 0x20
10887 dw 0,0 ;; oem table ptr
10888 dw 0 ;; oem table size
10889 dw 26 ;; entry count
10890 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10891 dw 0 ;; extended table length
10892 db 0 ;; extended table checksum
10895 db 0 ;; entry type=processor
10896 db 0 ;; local APIC id
10897 db 0x11 ;; local APIC version number
10898 db 3 ;; cpu flags: enabled, bootstrap processor
10899 db 0,6,0,0 ;; cpu signature
10900 dw 0x201,0 ;; feature flags
10904 db 0 ;; entry type=processor
10905 db 1 ;; local APIC id
10906 db 0x11 ;; local APIC version number
10907 db 1 ;; cpu flags: enabled
10908 db 0,6,0,0 ;; cpu signature
10909 dw 0x201,0 ;; feature flags
10913 db 0 ;; entry type=processor
10914 db 2 ;; local APIC id
10915 db 0x11 ;; local APIC version number
10916 db 1 ;; cpu flags: enabled
10917 db 0,6,0,0 ;; cpu signature
10918 dw 0x201,0 ;; feature flags
10922 db 0 ;; entry type=processor
10923 db 3 ;; local APIC id
10924 db 0x11 ;; local APIC version number
10925 db 1 ;; cpu flags: enabled
10926 db 0,6,0,0 ;; cpu signature
10927 dw 0x201,0 ;; feature flags
10931 db 0 ;; entry type=processor
10932 db 4 ;; local APIC id
10933 db 0x11 ;; local APIC version number
10934 db 1 ;; cpu flags: enabled
10935 db 0,6,0,0 ;; cpu signature
10936 dw 0x201,0 ;; feature flags
10940 db 0 ;; entry type=processor
10941 db 5 ;; local APIC id
10942 db 0x11 ;; local APIC version number
10943 db 1 ;; cpu flags: enabled
10944 db 0,6,0,0 ;; cpu signature
10945 dw 0x201,0 ;; feature flags
10949 db 0 ;; entry type=processor
10950 db 6 ;; local APIC id
10951 db 0x11 ;; local APIC version number
10952 db 1 ;; cpu flags: enabled
10953 db 0,6,0,0 ;; cpu signature
10954 dw 0x201,0 ;; feature flags
10958 db 0 ;; entry type=processor
10959 db 7 ;; local APIC id
10960 db 0x11 ;; local APIC version number
10961 db 1 ;; cpu flags: enabled
10962 db 0,6,0,0 ;; cpu signature
10963 dw 0x201,0 ;; feature flags
10967 db 1 ;; entry type=bus
10969 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10971 db 2 ;; entry type=I/O APIC
10973 db 0x11 ;; I/O APIC version number
10974 db 1 ;; flags=1=enabled
10975 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10977 db 3 ;; entry type=I/O interrupt
10978 db 0 ;; interrupt type=vectored interrupt
10979 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10980 db 0 ;; source bus ID is ISA
10981 db 0 ;; source bus IRQ
10982 db 8 ;; destination I/O APIC ID
10983 db 0 ;; destination I/O APIC interrrupt in
10984 ;; repeat pattern for interrupts 0-15
10994 db 3,0,0,0,0,10,8,10
10995 db 3,0,0,0,0,11,8,11
10996 db 3,0,0,0,0,12,8,12
10997 db 3,0,0,0,0,13,8,13
10998 db 3,0,0,0,0,14,8,14
10999 db 3,0,0,0,0,15,8,15
11001 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11002 #endif // if (BX_SMP_PROCESSORS==...)
11004 mp_config_end: // this label used to find length of mp structure
11007 #if (BX_SMP_PROCESSORS>1)
11009 mp_floating_pointer_structure:
11010 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
11011 dw mp_config_table, 0xf ;; pointer to MP configuration table
11012 db 1 ;; length of this struct in 16-bit byte chunks
11013 db 4 ;; MP spec revision
11014 db 0xc1 ;; checksum
11015 db 0 ;; MP feature byte 1. value 0 means look at the config table
11016 db 0,0,0,0 ;; MP feature bytes 2-5.
11021 #endif // HVMASSIST