2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.2 2008/04/11 19:12:59 jarusl 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 0
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.2 $";
949 static char bios_date_string[] = "$Date: 2008/04/11 19:12:59 $";
951 static char CVSID[] = "$Id: rombios.c,v 1.2 2008/04/11 19:12:59 jarusl 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_INFO, 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 printf("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 printf("rom_bios: 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 #if BX_MAX_ATA_INTERFACES > 0
2181 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2182 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2183 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2184 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2186 #if BX_MAX_ATA_INTERFACES > 1
2187 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2188 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2189 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2190 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2192 #if BX_MAX_ATA_INTERFACES > 2
2193 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2194 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2195 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2196 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2198 #if BX_MAX_ATA_INTERFACES > 3
2199 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2200 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2201 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2202 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2204 #if BX_MAX_ATA_INTERFACES > 4
2205 #error Please fill the ATA interface informations
2211 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2212 Bit16u iobase1, iobase2;
2213 Bit8u channel, slave, shift;
2214 Bit8u sc, sn, cl, ch, st;
2216 channel = device / 2;
2219 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2220 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2222 // Disable interrupts
2223 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2226 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2227 outb(iobase1+ATA_CB_SC, 0x55);
2228 outb(iobase1+ATA_CB_SN, 0xaa);
2229 outb(iobase1+ATA_CB_SC, 0xaa);
2230 outb(iobase1+ATA_CB_SN, 0x55);
2231 outb(iobase1+ATA_CB_SC, 0x55);
2232 outb(iobase1+ATA_CB_SN, 0xaa);
2234 // If we found something
2235 sc = inb(iobase1+ATA_CB_SC);
2236 sn = inb(iobase1+ATA_CB_SN);
2238 if ( (sc == 0x55) && (sn == 0xaa) ) {
2239 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2241 // reset the channel
2244 // check for ATA or ATAPI
2245 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2246 sc = inb(iobase1+ATA_CB_SC);
2247 sn = inb(iobase1+ATA_CB_SN);
2248 if ( (sc==0x01) && (sn==0x01) ) {
2249 cl = inb(iobase1+ATA_CB_CL);
2250 ch = inb(iobase1+ATA_CB_CH);
2251 st = inb(iobase1+ATA_CB_STAT);
2253 if ( (cl==0x14) && (ch==0xeb) ) {
2254 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2256 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2257 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2262 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2264 // Now we send a IDENTIFY command to ATA device
2265 if(type == ATA_TYPE_ATA) {
2267 Bit16u cylinders, heads, spt, blksize;
2268 Bit8u translation, removable, mode;
2270 // default mode to PIO16
2271 mode = ATA_MODE_PIO16;
2273 //Temporary values to do the transfer
2274 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2275 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2277 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2278 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2280 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2282 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2285 blksize = read_word(get_SS(),buffer+10);
2287 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2288 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2289 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2291 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2293 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2294 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2295 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2296 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2297 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2298 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2299 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2300 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2301 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2303 translation = inb_cmos(0x39 + channel/2);
2304 for (shift=device%4; shift>0; shift--) translation >>= 2;
2305 translation &= 0x03;
2307 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2309 switch (translation) {
2310 case ATA_TRANSLATION_NONE:
2313 case ATA_TRANSLATION_LBA:
2316 case ATA_TRANSLATION_LARGE:
2319 case ATA_TRANSLATION_RECHS:
2323 switch (translation) {
2324 case ATA_TRANSLATION_NONE:
2326 case ATA_TRANSLATION_LBA:
2329 heads = sectors / 1024;
2330 if (heads>128) heads = 255;
2331 else if (heads>64) heads = 128;
2332 else if (heads>32) heads = 64;
2333 else if (heads>16) heads = 32;
2335 cylinders = sectors / heads;
2337 case ATA_TRANSLATION_RECHS:
2338 // Take care not to overflow
2340 if(cylinders>61439) cylinders=61439;
2342 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2344 // then go through the large bitshift process
2345 case ATA_TRANSLATION_LARGE:
2346 while(cylinders > 1024) {
2350 // If we max out the head count
2351 if (heads > 127) break;
2355 // clip to 1024 cylinders in lchs
2356 if (cylinders > 1024) cylinders=1024;
2357 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2359 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2360 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2361 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2364 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2368 // Now we send a IDENTIFY command to ATAPI device
2369 if(type == ATA_TYPE_ATAPI) {
2371 Bit8u type, removable, mode;
2374 // default mode to PIO16
2375 mode = ATA_MODE_PIO16;
2377 //Temporary values to do the transfer
2378 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2379 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2381 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2382 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2384 type = read_byte(get_SS(),buffer+1) & 0x1f;
2385 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2387 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2391 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2392 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2393 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2394 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2397 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2404 Bit8u c, i, version, model[41];
2408 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2410 case ATA_TYPE_ATAPI:
2411 // Read ATA/ATAPI version
2412 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2413 for(version=15;version>0;version--) {
2414 if((ataversion&(1<<version))!=0)
2420 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2421 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2425 write_byte(get_SS(),model+40,0x00);
2427 if(read_byte(get_SS(),model+i)==0x20)
2428 write_byte(get_SS(),model+i,0x00);
2436 printf("ata%d %s: ",channel,slave?" slave":"master");
2437 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2438 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2440 case ATA_TYPE_ATAPI:
2441 printf("ata%d %s: ",channel,slave?" slave":"master");
2442 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2443 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2444 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2446 printf(" ATAPI-%d Device\n",version);
2448 case ATA_TYPE_UNKNOWN:
2449 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2455 // Store the devices counts
2456 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2457 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2458 write_byte(0x40,0x75, hdcount);
2462 // FIXME : should use bios=cmos|auto|disable bits
2463 // FIXME : should know about translation bits
2464 // FIXME : move hard_drive_post here
2468 // ---------------------------------------------------------------------------
2469 // ATA/ATAPI driver : software reset
2470 // ---------------------------------------------------------------------------
2472 // 8.2.1 Software reset - Device 0
2474 void ata_reset(device)
2477 Bit16u ebda_seg=read_word(0x0040,0x000E);
2478 Bit16u iobase1, iobase2;
2479 Bit8u channel, slave, sn, sc;
2482 channel = device / 2;
2485 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2486 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2490 // 8.2.1 (a) -- set SRST in DC
2491 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2493 // 8.2.1 (b) -- wait for BSY
2496 Bit8u status = inb(iobase1+ATA_CB_STAT);
2497 if ((status & ATA_CB_STAT_BSY) != 0) break;
2500 // 8.2.1 (f) -- clear SRST
2501 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2503 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2505 // 8.2.1 (g) -- check for sc==sn==0x01
2507 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2508 sc = inb(iobase1+ATA_CB_SC);
2509 sn = inb(iobase1+ATA_CB_SN);
2511 if ( (sc==0x01) && (sn==0x01) ) {
2513 // 8.2.1 (h) -- wait for not BSY
2516 Bit8u status = inb(iobase1+ATA_CB_STAT);
2517 if ((status & ATA_CB_STAT_BSY) == 0) break;
2522 // 8.2.1 (i) -- wait for DRDY
2525 Bit8u status = inb(iobase1+ATA_CB_STAT);
2526 if ((status & ATA_CB_STAT_RDY) != 0) break;
2529 // Enable interrupts
2530 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2533 // ---------------------------------------------------------------------------
2534 // ATA/ATAPI driver : execute a non data command
2535 // ---------------------------------------------------------------------------
2537 Bit16u ata_cmd_non_data()
2540 // ---------------------------------------------------------------------------
2541 // ATA/ATAPI driver : execute a data-in command
2542 // ---------------------------------------------------------------------------
2547 // 3 : expected DRQ=1
2548 // 4 : no sectors left to read/verify
2549 // 5 : more sectors to read/verify
2550 // 6 : no sectors left to write
2551 // 7 : more sectors to write
2552 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2553 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2556 Bit16u ebda_seg=read_word(0x0040,0x000E);
2557 Bit16u iobase1, iobase2, blksize;
2558 Bit8u channel, slave;
2559 Bit8u status, current, mode;
2561 channel = device / 2;
2564 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2565 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2566 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2567 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2568 if (mode == ATA_MODE_PIO32) blksize>>=2;
2571 // sector will be 0 only on lba access. Convert to lba-chs
2573 sector = (Bit16u) (lba & 0x000000ffL);
2575 cylinder = (Bit16u) (lba & 0x0000ffffL);
2577 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2580 // Reset count of transferred data
2581 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2582 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2585 status = inb(iobase1 + ATA_CB_STAT);
2586 if (status & ATA_CB_STAT_BSY) return 1;
2588 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2589 outb(iobase1 + ATA_CB_FR, 0x00);
2590 outb(iobase1 + ATA_CB_SC, count);
2591 outb(iobase1 + ATA_CB_SN, sector);
2592 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2593 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2594 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2595 outb(iobase1 + ATA_CB_CMD, command);
2598 status = inb(iobase1 + ATA_CB_STAT);
2599 if ( !(status & ATA_CB_STAT_BSY) ) break;
2602 if (status & ATA_CB_STAT_ERR) {
2603 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2605 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2606 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2610 // FIXME : move seg/off translation here
2613 sti ;; enable higher priority interrupts
2621 mov di, _ata_cmd_data_in.offset + 2[bp]
2622 mov ax, _ata_cmd_data_in.segment + 2[bp]
2623 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2625 ;; adjust if there will be an overrun. 2K max sector size
2627 jbe ata_in_no_adjust
2630 sub di, #0x0800 ;; sub 2 kbytes from offset
2631 add ax, #0x0080 ;; add 2 Kbytes to segment
2634 mov es, ax ;; segment in es
2636 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2638 mov ah, _ata_cmd_data_in.mode + 2[bp]
2639 cmp ah, #ATA_MODE_PIO32
2644 insw ;; CX words transfered from port(DX) to ES:[DI]
2649 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2652 mov _ata_cmd_data_in.offset + 2[bp], di
2653 mov _ata_cmd_data_in.segment + 2[bp], es
2658 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2660 status = inb(iobase1 + ATA_CB_STAT);
2662 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2663 != ATA_CB_STAT_RDY ) {
2664 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2670 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2671 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2672 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2678 // Enable interrupts
2679 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2683 // ---------------------------------------------------------------------------
2684 // ATA/ATAPI driver : execute a data-out command
2685 // ---------------------------------------------------------------------------
2690 // 3 : expected DRQ=1
2691 // 4 : no sectors left to read/verify
2692 // 5 : more sectors to read/verify
2693 // 6 : no sectors left to write
2694 // 7 : more sectors to write
2695 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2696 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2699 Bit16u ebda_seg=read_word(0x0040,0x000E);
2700 Bit16u iobase1, iobase2, blksize;
2701 Bit8u channel, slave;
2702 Bit8u status, current, mode;
2704 channel = device / 2;
2707 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2708 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2709 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2710 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2711 if (mode == ATA_MODE_PIO32) blksize>>=2;
2714 // sector will be 0 only on lba access. Convert to lba-chs
2716 sector = (Bit16u) (lba & 0x000000ffL);
2718 cylinder = (Bit16u) (lba & 0x0000ffffL);
2720 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2723 // Reset count of transferred data
2724 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2725 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2728 status = inb(iobase1 + ATA_CB_STAT);
2729 if (status & ATA_CB_STAT_BSY) return 1;
2731 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2732 outb(iobase1 + ATA_CB_FR, 0x00);
2733 outb(iobase1 + ATA_CB_SC, count);
2734 outb(iobase1 + ATA_CB_SN, sector);
2735 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2736 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2737 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2738 outb(iobase1 + ATA_CB_CMD, command);
2741 status = inb(iobase1 + ATA_CB_STAT);
2742 if ( !(status & ATA_CB_STAT_BSY) ) break;
2745 if (status & ATA_CB_STAT_ERR) {
2746 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2748 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2749 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2753 // FIXME : move seg/off translation here
2756 sti ;; enable higher priority interrupts
2764 mov si, _ata_cmd_data_out.offset + 2[bp]
2765 mov ax, _ata_cmd_data_out.segment + 2[bp]
2766 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2768 ;; adjust if there will be an overrun. 2K max sector size
2770 jbe ata_out_no_adjust
2773 sub si, #0x0800 ;; sub 2 kbytes from offset
2774 add ax, #0x0080 ;; add 2 Kbytes to segment
2777 mov es, ax ;; segment in es
2779 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2781 mov ah, _ata_cmd_data_out.mode + 2[bp]
2782 cmp ah, #ATA_MODE_PIO32
2788 outsw ;; CX words transfered from port(DX) to ES:[SI]
2794 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2797 mov _ata_cmd_data_out.offset + 2[bp], si
2798 mov _ata_cmd_data_out.segment + 2[bp], es
2803 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2805 status = inb(iobase1 + ATA_CB_STAT);
2807 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2808 != ATA_CB_STAT_RDY ) {
2809 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2815 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2816 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2817 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2823 // Enable interrupts
2824 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2828 // ---------------------------------------------------------------------------
2829 // ATA/ATAPI driver : execute a packet command
2830 // ---------------------------------------------------------------------------
2833 // 1 : error in parameters
2837 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2839 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2843 Bit16u ebda_seg=read_word(0x0040,0x000E);
2844 Bit16u iobase1, iobase2;
2845 Bit16u lcount, lbefore, lafter, count;
2846 Bit8u channel, slave;
2847 Bit8u status, mode, lmode;
2848 Bit32u total, transfer;
2850 channel = device / 2;
2853 // Data out is not supported yet
2854 if (inout == ATA_DATA_OUT) {
2855 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2859 // The header length must be even
2861 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2865 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2866 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2867 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2870 if (cmdlen < 12) cmdlen=12;
2871 if (cmdlen > 12) cmdlen=16;
2874 // Reset count of transferred data
2875 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2876 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2878 status = inb(iobase1 + ATA_CB_STAT);
2879 if (status & ATA_CB_STAT_BSY) return 2;
2881 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2882 // outb(iobase1 + ATA_CB_FR, 0x00);
2883 // outb(iobase1 + ATA_CB_SC, 0x00);
2884 // outb(iobase1 + ATA_CB_SN, 0x00);
2885 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2886 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2887 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2888 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2890 // Device should ok to receive command
2892 status = inb(iobase1 + ATA_CB_STAT);
2893 if ( !(status & ATA_CB_STAT_BSY) ) break;
2896 if (status & ATA_CB_STAT_ERR) {
2897 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2899 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2900 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2904 // Normalize address
2905 cmdseg += (cmdoff / 16);
2908 // Send command to device
2910 sti ;; enable higher priority interrupts
2915 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2916 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2917 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2918 mov es, ax ;; segment in es
2920 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2924 outsw ;; CX words transfered from port(DX) to ES:[SI]
2929 if (inout == ATA_DATA_NO) {
2930 status = inb(iobase1 + ATA_CB_STAT);
2935 status = inb(iobase1 + ATA_CB_STAT);
2937 // Check if command completed
2938 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2940 if (status & ATA_CB_STAT_ERR) {
2941 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2945 // Device must be ready to send data
2946 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2947 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2948 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
2952 // Normalize address
2953 bufseg += (bufoff / 16);
2956 // Get the byte count
2957 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
2959 // adjust to read what we want
2972 lafter=lcount-length;
2984 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
2985 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
2987 // If counts not dividable by 4, use 16bits mode
2989 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
2990 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
2991 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
2993 // adds an extra byte if count are odd. before is always even
2994 if (lcount & 0x01) {
2996 if ((lafter > 0) && (lafter & 0x01)) {
3001 if (lmode == ATA_MODE_PIO32) {
3002 lcount>>=2; lbefore>>=2; lafter>>=2;
3005 lcount>>=1; lbefore>>=1; lafter>>=1;
3014 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3016 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3017 jcxz ata_packet_no_before
3019 mov ah, _ata_cmd_packet.lmode + 2[bp]
3020 cmp ah, #ATA_MODE_PIO32
3021 je ata_packet_in_before_32
3023 ata_packet_in_before_16:
3025 loop ata_packet_in_before_16
3026 jmp ata_packet_no_before
3028 ata_packet_in_before_32:
3030 ata_packet_in_before_32_loop:
3032 loop ata_packet_in_before_32_loop
3035 ata_packet_no_before:
3036 mov cx, _ata_cmd_packet.lcount + 2[bp]
3037 jcxz ata_packet_after
3039 mov di, _ata_cmd_packet.bufoff + 2[bp]
3040 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3043 mov ah, _ata_cmd_packet.lmode + 2[bp]
3044 cmp ah, #ATA_MODE_PIO32
3049 insw ;; CX words transfered tp port(DX) to ES:[DI]
3050 jmp ata_packet_after
3054 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3057 mov cx, _ata_cmd_packet.lafter + 2[bp]
3058 jcxz ata_packet_done
3060 mov ah, _ata_cmd_packet.lmode + 2[bp]
3061 cmp ah, #ATA_MODE_PIO32
3062 je ata_packet_in_after_32
3064 ata_packet_in_after_16:
3066 loop ata_packet_in_after_16
3069 ata_packet_in_after_32:
3071 ata_packet_in_after_32_loop:
3073 loop ata_packet_in_after_32_loop
3080 // Compute new buffer address
3083 // Save transferred bytes count
3085 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3089 // Final check, device must be ready
3090 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3091 != ATA_CB_STAT_RDY ) {
3092 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3096 // Enable interrupts
3097 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3101 // ---------------------------------------------------------------------------
3102 // End of ATA/ATAPI Driver
3103 // ---------------------------------------------------------------------------
3105 // ---------------------------------------------------------------------------
3106 // Start of ATA/ATAPI generic functions
3107 // ---------------------------------------------------------------------------
3110 atapi_get_sense(device)
3117 memsetb(get_SS(),atacmd,0,12);
3122 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3125 if ((buffer[0] & 0x7e) == 0x70) {
3126 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3133 atapi_is_ready(device)
3139 memsetb(get_SS(),atacmd,0,12);
3142 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3145 if (atapi_get_sense(device) !=0 ) {
3146 memsetb(get_SS(),atacmd,0,12);
3148 // try to send Test Unit Ready again
3149 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3152 return atapi_get_sense(device);
3158 atapi_is_cdrom(device)
3161 Bit16u ebda_seg=read_word(0x0040,0x000E);
3163 if (device >= BX_MAX_ATA_DEVICES)
3166 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3169 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3175 // ---------------------------------------------------------------------------
3176 // End of ATA/ATAPI generic functions
3177 // ---------------------------------------------------------------------------
3179 #endif // BX_USE_ATADRV
3181 #if BX_ELTORITO_BOOT
3183 // ---------------------------------------------------------------------------
3184 // Start of El-Torito boot functions
3185 // ---------------------------------------------------------------------------
3190 Bit16u ebda_seg=read_word(0x0040,0x000E);
3192 printf("rombios: cdemu_init\n");
3194 // the only important data is this one for now
3195 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3201 Bit16u ebda_seg=read_word(0x0040,0x000E);
3203 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3207 cdemu_emulated_drive()
3209 Bit16u ebda_seg=read_word(0x0040,0x000E);
3211 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3214 static char isotag[6]="CD001";
3215 static char eltorito[24]="EL TORITO SPECIFICATION";
3217 // Returns ah: emulated drive, al: error code
3222 Bit16u ebda_seg=read_word(0x0040,0x000E);
3223 Bit8u atacmd[12], buffer[2048];
3225 Bit16u boot_segment, nbsectors, i, error;
3228 // Find out the first cdrom
3229 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3230 if (atapi_is_cdrom(device)) break;
3234 if(device >= BX_MAX_ATA_DEVICES) return 2;
3236 // Read the Boot Record Volume Descriptor
3237 memsetb(get_SS(),atacmd,0,12);
3238 atacmd[0]=0x28; // READ command
3239 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3240 atacmd[8]=(0x01 & 0x00ff); // Sectors
3241 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3242 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3243 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3244 atacmd[5]=(0x11 & 0x000000ff);
3245 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3249 if(buffer[0]!=0)return 4;
3251 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3254 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3256 // ok, now we calculate the Boot catalog address
3257 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3259 // And we read the Boot Catalog
3260 memsetb(get_SS(),atacmd,0,12);
3261 atacmd[0]=0x28; // READ command
3262 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3263 atacmd[8]=(0x01 & 0x00ff); // Sectors
3264 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3265 atacmd[3]=(lba & 0x00ff0000) >> 16;
3266 atacmd[4]=(lba & 0x0000ff00) >> 8;
3267 atacmd[5]=(lba & 0x000000ff);
3268 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3272 if(buffer[0x00]!=0x01)return 8; // Header
3273 if(buffer[0x01]!=0x00)return 9; // Platform
3274 if(buffer[0x1E]!=0x55)return 10; // key 1
3275 if(buffer[0x1F]!=0xAA)return 10; // key 2
3277 // Initial/Default Entry
3278 if(buffer[0x20]!=0x88)return 11; // Bootable
3280 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3281 if(buffer[0x21]==0){
3282 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3283 // Win2000 cd boot needs to know it booted from cd
3284 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3286 else if(buffer[0x21]<4)
3287 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3289 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3291 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3292 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3294 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3295 if(boot_segment==0x0000)boot_segment=0x07C0;
3297 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3298 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3300 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3301 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3303 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3304 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3306 // And we read the image in memory
3307 memsetb(get_SS(),atacmd,0,12);
3308 atacmd[0]=0x28; // READ command
3309 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3310 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3311 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3312 atacmd[3]=(lba & 0x00ff0000) >> 16;
3313 atacmd[4]=(lba & 0x0000ff00) >> 8;
3314 atacmd[5]=(lba & 0x000000ff);
3315 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3318 // Remember the media type
3319 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3320 case 0x01: // 1.2M floppy
3321 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3322 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3323 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3325 case 0x02: // 1.44M floppy
3326 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3327 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3328 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3330 case 0x03: // 2.88M floppy
3331 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3332 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3333 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3335 case 0x04: // Harddrive
3336 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3337 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3338 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3339 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3343 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3344 // Increase bios installed hardware number of devices
3345 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3346 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3348 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3352 // everything is ok, so from now on, the emulation is active
3353 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3354 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3356 // return the boot drive + no error
3357 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3360 // ---------------------------------------------------------------------------
3361 // End of El-Torito boot functions
3362 // ---------------------------------------------------------------------------
3363 #endif // BX_ELTORITO_BOOT
3366 int14_function(regs, ds, iret_addr)
3367 pusha_regs_t regs; // regs pushed from PUSHA instruction
3368 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3369 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3371 Bit16u addr,timer,val16;
3378 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3379 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3380 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3381 switch (regs.u.r8.ah) {
3383 outb(addr+3, inb(addr+3) | 0x80);
3384 if (regs.u.r8.al & 0xE0 == 0) {
3388 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3389 outb(addr, val16 & 0xFF);
3390 outb(addr+1, val16 >> 8);
3392 outb(addr+3, regs.u.r8.al & 0x1F);
3393 regs.u.r8.ah = inb(addr+5);
3394 regs.u.r8.al = inb(addr+6);
3395 ClearCF(iret_addr.flags);
3398 timer = read_word(0x0040, 0x006C);
3399 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3400 val16 = read_word(0x0040, 0x006C);
3401 if (val16 != timer) {
3406 if (timeout) outb(addr, regs.u.r8.al);
3407 regs.u.r8.ah = inb(addr+5);
3408 if (!timeout) regs.u.r8.ah |= 0x80;
3409 ClearCF(iret_addr.flags);
3412 timer = read_word(0x0040, 0x006C);
3413 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3414 val16 = read_word(0x0040, 0x006C);
3415 if (val16 != timer) {
3422 regs.u.r8.al = inb(addr);
3424 regs.u.r8.ah = inb(addr+5);
3426 ClearCF(iret_addr.flags);
3429 regs.u.r8.ah = inb(addr+5);
3430 regs.u.r8.al = inb(addr+6);
3431 ClearCF(iret_addr.flags);
3434 SetCF(iret_addr.flags); // Unsupported
3437 SetCF(iret_addr.flags); // Unsupported
3442 int15_function(regs, ES, DS, FLAGS)
3443 pusha_regs_t regs; // REGS pushed via pusha
3444 Bit16u ES, DS, FLAGS;
3446 Bit16u ebda_seg=read_word(0x0040,0x000E);
3447 bx_bool prev_a20_enable;
3456 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3458 switch (regs.u.r8.ah) {
3459 case 0x24: /* A20 Control */
3460 switch (regs.u.r8.al) {
3472 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3482 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3484 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3490 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3494 /* keyboard intercept */
3496 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3503 case 0x52: // removable media eject
3505 regs.u.r8.ah = 0; // "ok ejection may proceed"
3509 if( regs.u.r8.al == 0 ) {
3510 // Set Interval requested.
3511 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3512 // Interval not already set.
3513 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3514 write_word( 0x40, 0x98, ES ); // Byte location, segment
3515 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3516 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3517 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3519 irqDisable = inb( 0xA1 );
3520 outb( 0xA1, irqDisable & 0xFE );
3521 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3522 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3524 // Interval already set.
3525 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3527 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3529 } else if( regs.u.r8.al == 1 ) {
3530 // Clear Interval requested
3531 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3533 bRegister = inb_cmos( 0xB );
3534 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3536 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3538 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3547 # error "Int15 function 87h not supported on < 80386"
3549 // +++ should probably have descriptor checks
3550 // +++ should have exception handlers
3552 // turn off interrupts
3557 prev_a20_enable = set_enable_a20(1); // enable A20 line
3559 // 128K max of transfer on 386+ ???
3560 // source == destination ???
3562 // ES:SI points to descriptor table
3563 // offset use initially comments
3564 // ==============================================
3565 // 00..07 Unused zeros Null descriptor
3566 // 08..0f GDT zeros filled in by BIOS
3567 // 10..17 source ssssssss source of data
3568 // 18..1f dest dddddddd destination of data
3569 // 20..27 CS zeros filled in by BIOS
3570 // 28..2f SS zeros filled in by BIOS
3577 // check for access rights of source & dest here
3579 // Initialize GDT descriptor
3580 base15_00 = (ES << 4) + regs.u.r16.si;
3581 base23_16 = ES >> 12;
3582 if (base15_00 < (ES<<4))
3584 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3585 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3586 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3587 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3588 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3590 // Initialize CS descriptor
3591 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3592 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3593 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3594 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3595 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3597 // Initialize SS descriptor
3599 base15_00 = ss << 4;
3600 base23_16 = ss >> 12;
3601 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3602 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3603 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3604 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3605 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3609 // Compile generates locals offset info relative to SP.
3610 // Get CX (word count) from stack.
3613 mov cx, _int15_function.CX [bx]
3615 // since we need to set SS:SP, save them to the BDA
3616 // for future restore
3626 lidt [pmode_IDT_info]
3627 ;; perhaps do something with IDT here
3629 ;; set PE bit in CR0
3633 ;; far jump to flush CPU queue after transition to protected mode
3634 JMP_AP(0x0020, protected_mode)
3637 ;; GDT points to valid descriptor table, now load SS, DS, ES
3638 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3640 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3642 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3648 movsw ;; move CX words from DS:SI to ES:DI
3650 ;; make sure DS and ES limits are 64KB
3655 ;; reset PG bit in CR0 ???
3660 ;; far jump to flush CPU queue after transition to real mode
3661 JMP_AP(0xf000, real_mode)
3664 ;; restore IDT to normal real-mode defaults
3666 lidt [rmode_IDT_info]
3668 // restore SS:SP from the BDA
3676 set_enable_a20(prev_a20_enable);
3678 // turn back on interrupts
3689 // Get the amount of extended memory (above 1M)
3691 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3694 regs.u.r8.al = inb_cmos(0x30);
3695 regs.u.r8.ah = inb_cmos(0x31);
3698 if(regs.u.r16.ax > 0x3c00)
3699 regs.u.r16.ax = 0x3c00;
3706 /* Device busy interrupt. Called by Int 16h when no key available */
3710 /* Interrupt complete. Called by Int 16h when key becomes available */
3714 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3716 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3722 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3727 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3737 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3739 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3743 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3744 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3746 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3751 #if BX_USE_PS2_MOUSE
3753 int15_function_mouse(regs, ES, DS, FLAGS)
3754 pusha_regs_t regs; // REGS pushed via pusha
3755 Bit16u ES, DS, FLAGS;
3757 Bit16u ebda_seg=read_word(0x0040,0x000E);
3758 Bit8u mouse_flags_1, mouse_flags_2;
3759 Bit16u mouse_driver_seg;
3760 Bit16u mouse_driver_offset;
3761 Bit8u comm_byte, prev_command_byte;
3762 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3764 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3766 switch (regs.u.r8.ah) {
3768 // Return Codes status in AH
3769 // =========================
3771 // 01: invalid subfunction (AL > 7)
3772 // 02: invalid input value (out of allowable range)
3773 // 03: interface error
3774 // 04: resend command received from mouse controller,
3775 // device driver should attempt command again
3776 // 05: cannot enable mouse, since no far call has been installed
3777 // 80/86: mouse service not implemented
3779 switch (regs.u.r8.al) {
3780 case 0: // Disable/Enable Mouse
3781 BX_DEBUG_INT15("case 0:\n");
3782 switch (regs.u.r8.bh) {
3783 case 0: // Disable Mouse
3784 BX_DEBUG_INT15("case 0: disable mouse\n");
3785 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3786 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3788 ret = get_mouse_data(&mouse_data1);
3789 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3802 case 1: // Enable Mouse
3803 BX_DEBUG_INT15("case 1: enable mouse\n");
3804 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3805 if ( (mouse_flags_2 & 0x80) == 0 ) {
3806 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3808 regs.u.r8.ah = 5; // no far call installed
3811 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3812 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3814 ret = get_mouse_data(&mouse_data1);
3815 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3816 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3826 default: // invalid subfunction
3827 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3829 regs.u.r8.ah = 1; // invalid subfunction
3834 case 1: // Reset Mouse
3835 case 5: // Initialize Mouse
3836 BX_DEBUG_INT15("case 1 or 5:\n");
3837 if (regs.u.r8.al == 5) {
3838 if (regs.u.r8.bh != 3) {
3840 regs.u.r8.ah = 0x02; // invalid input
3843 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3844 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3845 mouse_flags_1 = 0x00;
3846 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3847 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3850 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3851 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3853 ret = get_mouse_data(&mouse_data3);
3854 // if no mouse attached, it will return RESEND
3855 if (mouse_data3 == 0xfe) {
3859 if (mouse_data3 != 0xfa)
3860 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3862 ret = get_mouse_data(&mouse_data1);
3864 ret = get_mouse_data(&mouse_data2);
3866 // turn IRQ12 and packet generation on
3867 enable_mouse_int_and_events();
3870 regs.u.r8.bl = mouse_data1;
3871 regs.u.r8.bh = mouse_data2;
3883 case 2: // Set Sample Rate
3884 BX_DEBUG_INT15("case 2:\n");
3885 switch (regs.u.r8.bh) {
3886 case 0: mouse_data1 = 10; break; // 10 reports/sec
3887 case 1: mouse_data1 = 20; break; // 20 reports/sec
3888 case 2: mouse_data1 = 40; break; // 40 reports/sec
3889 case 3: mouse_data1 = 60; break; // 60 reports/sec
3890 case 4: mouse_data1 = 80; break; // 80 reports/sec
3891 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3892 case 6: mouse_data1 = 200; break; // 200 reports/sec
3893 default: mouse_data1 = 0;
3895 if (mouse_data1 > 0) {
3896 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3898 ret = get_mouse_data(&mouse_data2);
3899 ret = send_to_mouse_ctrl(mouse_data1);
3900 ret = get_mouse_data(&mouse_data2);
3906 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3911 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3915 case 3: // Set Resolution
3916 BX_DEBUG_INT15("case 3:\n");
3918 // 0 = 25 dpi, 1 count per millimeter
3919 // 1 = 50 dpi, 2 counts per millimeter
3920 // 2 = 100 dpi, 4 counts per millimeter
3921 // 3 = 200 dpi, 8 counts per millimeter
3926 case 4: // Get Device ID
3927 BX_DEBUG_INT15("case 4:\n");
3928 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3929 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3931 ret = get_mouse_data(&mouse_data1);
3932 ret = get_mouse_data(&mouse_data2);
3935 regs.u.r8.bh = mouse_data2;
3939 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3943 case 6: // Return Status & Set Scaling Factor...
3944 BX_DEBUG_INT15("case 6:\n");
3945 switch (regs.u.r8.bh) {
3946 case 0: // Return Status
3947 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3948 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
3950 ret = get_mouse_data(&mouse_data1);
3951 if (mouse_data1 != 0xfa)
3952 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
3954 ret = get_mouse_data(&mouse_data1);
3956 ret = get_mouse_data(&mouse_data2);
3958 ret = get_mouse_data(&mouse_data3);
3962 regs.u.r8.bl = mouse_data1;
3963 regs.u.r8.cl = mouse_data2;
3964 regs.u.r8.dl = mouse_data3;
3965 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3976 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3979 case 1: // Set Scaling Factor to 1:1
3980 case 2: // Set Scaling Factor to 2:1
3981 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3982 if (regs.u.r8.bh == 1) {
3983 ret = send_to_mouse_ctrl(0xE6);
3985 ret = send_to_mouse_ctrl(0xE7);
3988 get_mouse_data(&mouse_data1);
3989 ret = (mouse_data1 != 0xFA);
3997 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3999 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4003 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4007 case 7: // Set Mouse Handler Address
4008 BX_DEBUG_INT15("case 7:\n");
4009 mouse_driver_seg = ES;
4010 mouse_driver_offset = regs.u.r16.bx;
4011 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4012 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4013 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4014 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4015 /* remove handler */
4016 if ( (mouse_flags_2 & 0x80) != 0 ) {
4017 mouse_flags_2 &= ~0x80;
4018 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4022 /* install handler */
4023 mouse_flags_2 |= 0x80;
4025 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4031 BX_DEBUG_INT15("case default:\n");
4032 regs.u.r8.ah = 1; // invalid function
4038 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4039 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4041 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4048 int15_function32(regs, ES, DS, FLAGS)
4049 pushad_regs_t regs; // REGS pushed via pushad
4050 Bit16u ES, DS, FLAGS;
4052 Bit32u extended_memory_size=0; // 64bits long
4055 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4057 switch (regs.u.r8.ah) {
4059 // Wait for CX:DX microseconds. currently using the
4060 // refresh request port 0x61 bit4, toggling every 15usec
4068 ;; Get the count in eax
4071 mov ax, _int15_function.CX [bx]
4074 mov ax, _int15_function.DX [bx]
4076 ;; convert to numbers of 15usec ticks
4082 ;; wait for ecx number of refresh requests
4103 switch(regs.u.r8.al)
4105 case 0x20: // coded by osmaker aka K.J.
4106 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4109 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4110 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4112 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4113 memcpyb(ES, regs.u.r16.di,
4114 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4116 regs.u.r32.ebx += 0x14;
4117 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4119 regs.u.r32.eax = 0x534D4150;
4120 regs.u.r32.ecx = 0x14;
4123 } else if (regs.u.r16.bx == 1) {
4124 extended_memory_size = inb_cmos(0x35);
4125 extended_memory_size <<= 8;
4126 extended_memory_size |= inb_cmos(0x34);
4127 extended_memory_size *= 64;
4128 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4130 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4132 extended_memory_size *= 1024;
4133 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4135 if (extended_memory_size <= 15728640)
4137 extended_memory_size = inb_cmos(0x31);
4138 extended_memory_size <<= 8;
4139 extended_memory_size |= inb_cmos(0x30);
4140 extended_memory_size *= 1024;
4143 write_word(ES, regs.u.r16.di, 0x0000);
4144 write_word(ES, regs.u.r16.di+2, 0x0010);
4145 write_word(ES, regs.u.r16.di+4, 0x0000);
4146 write_word(ES, regs.u.r16.di+6, 0x0000);
4148 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4149 extended_memory_size >>= 16;
4150 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4151 extended_memory_size >>= 16;
4152 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4153 extended_memory_size >>= 16;
4154 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4156 write_word(ES, regs.u.r16.di+16, 0x1);
4157 write_word(ES, regs.u.r16.di+18, 0x0);
4160 regs.u.r32.eax = 0x534D4150;
4161 regs.u.r32.ecx = 0x14;
4164 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4165 goto int15_unimplemented;
4168 switch(regs.u.r16.bx)
4171 write_word(ES, regs.u.r16.di, 0x00);
4172 write_word(ES, regs.u.r16.di+2, 0x00);
4173 write_word(ES, regs.u.r16.di+4, 0x00);
4174 write_word(ES, regs.u.r16.di+6, 0x00);
4176 write_word(ES, regs.u.r16.di+8, 0xFC00);
4177 write_word(ES, regs.u.r16.di+10, 0x0009);
4178 write_word(ES, regs.u.r16.di+12, 0x0000);
4179 write_word(ES, regs.u.r16.di+14, 0x0000);
4181 write_word(ES, regs.u.r16.di+16, 0x1);
4182 write_word(ES, regs.u.r16.di+18, 0x0);
4186 regs.u.r32.eax = 0x534D4150;
4187 regs.u.r32.ecx = 0x14;
4192 extended_memory_size = inb_cmos(0x35);
4193 extended_memory_size <<= 8;
4194 extended_memory_size |= inb_cmos(0x34);
4195 extended_memory_size *= 64;
4196 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4198 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4200 extended_memory_size *= 1024;
4201 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4203 if(extended_memory_size <= 15728640)
4205 extended_memory_size = inb_cmos(0x31);
4206 extended_memory_size <<= 8;
4207 extended_memory_size |= inb_cmos(0x30);
4208 extended_memory_size *= 1024;
4211 write_word(ES, regs.u.r16.di, 0x0000);
4212 write_word(ES, regs.u.r16.di+2, 0x0010);
4213 write_word(ES, regs.u.r16.di+4, 0x0000);
4214 write_word(ES, regs.u.r16.di+6, 0x0000);
4216 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4217 extended_memory_size >>= 16;
4218 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4219 extended_memory_size >>= 16;
4220 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4221 extended_memory_size >>= 16;
4222 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4224 write_word(ES, regs.u.r16.di+16, 0x1);
4225 write_word(ES, regs.u.r16.di+18, 0x0);
4228 regs.u.r32.eax = 0x534D4150;
4229 regs.u.r32.ecx = 0x14;
4233 default: /* AX=E820, DX=534D4150, BX unrecognized */
4234 goto int15_unimplemented;
4239 // if DX != 0x534D4150)
4240 goto int15_unimplemented;
4245 // do we have any reason to fail here ?
4248 // my real system sets ax and bx to 0
4249 // this is confirmed by Ralph Brown list
4250 // but syslinux v1.48 is known to behave
4251 // strangely if ax is set to 0
4252 // regs.u.r16.ax = 0;
4253 // regs.u.r16.bx = 0;
4255 // Get the amount of extended memory (above 1M)
4256 regs.u.r8.cl = inb_cmos(0x30);
4257 regs.u.r8.ch = inb_cmos(0x31);
4260 if(regs.u.r16.cx > 0x3c00)
4262 regs.u.r16.cx = 0x3c00;
4265 // Get the amount of extended memory above 16M in 64k blocs
4266 regs.u.r8.dl = inb_cmos(0x34);
4267 regs.u.r8.dh = inb_cmos(0x35);
4269 // Set configured memory equal to extended memory
4270 regs.u.r16.ax = regs.u.r16.cx;
4271 regs.u.r16.bx = regs.u.r16.dx;
4273 default: /* AH=0xE8?? but not implemented */
4274 goto int15_unimplemented;
4277 int15_unimplemented:
4278 // fall into the default
4280 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4281 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4283 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4289 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4290 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4292 Bit8u scan_code, ascii_code, shift_flags, count;
4293 Bit16u kbd_code, max;
4295 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4298 case 0x00: /* read keyboard input */
4300 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4301 BX_PANIC("KBD: int16h: out of keyboard input\n");
4303 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4304 else if (ascii_code == 0xE0) ascii_code = 0;
4305 AX = (scan_code << 8) | ascii_code;
4308 case 0x01: /* check keyboard status */
4309 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4313 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4314 else if (ascii_code == 0xE0) ascii_code = 0;
4315 AX = (scan_code << 8) | ascii_code;
4319 case 0x02: /* get shift flag status */
4320 shift_flags = read_byte(0x0040, 0x17);
4321 SET_AL(shift_flags);
4324 case 0x05: /* store key-stroke into buffer */
4325 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4333 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4334 // bit Bochs Description
4336 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4337 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4338 // 4 1 INT 16/AH=0Ah supported
4339 // 3 0 INT 16/AX=0306h supported
4340 // 2 0 INT 16/AX=0305h supported
4341 // 1 0 INT 16/AX=0304h supported
4342 // 0 0 INT 16/AX=0300h supported
4347 case 0x0A: /* GET KEYBOARD ID */
4353 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4355 if ((inb(0x60) == 0xfa)) {
4358 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4361 kbd_code |= (inb(0x60) << 8);
4363 } while (--count>0);
4369 case 0x10: /* read MF-II keyboard input */
4371 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4372 BX_PANIC("KBD: int16h: out of keyboard input\n");
4374 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4375 AX = (scan_code << 8) | ascii_code;
4378 case 0x11: /* check MF-II keyboard status */
4379 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4383 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4384 AX = (scan_code << 8) | ascii_code;
4388 case 0x12: /* get extended keyboard status */
4389 shift_flags = read_byte(0x0040, 0x17);
4390 SET_AL(shift_flags);
4391 shift_flags = read_byte(0x0040, 0x18);
4392 SET_AH(shift_flags);
4393 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4396 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4397 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4400 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4401 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4405 if (GET_AL() == 0x08)
4406 SET_AH(0x02); // unsupported, aka normal keyboard
4409 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4414 dequeue_key(scan_code, ascii_code, incr)
4419 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4424 buffer_start = 0x001E;
4425 buffer_end = 0x003E;
4427 buffer_start = read_word(0x0040, 0x0080);
4428 buffer_end = read_word(0x0040, 0x0082);
4431 buffer_head = read_word(0x0040, 0x001a);
4432 buffer_tail = read_word(0x0040, 0x001c);
4434 if (buffer_head != buffer_tail) {
4436 acode = read_byte(0x0040, buffer_head);
4437 scode = read_byte(0x0040, buffer_head+1);
4438 write_byte(ss, ascii_code, acode);
4439 write_byte(ss, scan_code, scode);
4443 if (buffer_head >= buffer_end)
4444 buffer_head = buffer_start;
4445 write_word(0x0040, 0x001a, buffer_head);
4454 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4457 inhibit_mouse_int_and_events()
4459 Bit8u command_byte, prev_command_byte;
4461 // Turn off IRQ generation and aux data line
4462 if ( inb(0x64) & 0x02 )
4463 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4464 outb(0x64, 0x20); // get command byte
4465 while ( (inb(0x64) & 0x01) != 0x01 );
4466 prev_command_byte = inb(0x60);
4467 command_byte = prev_command_byte;
4468 //while ( (inb(0x64) & 0x02) );
4469 if ( inb(0x64) & 0x02 )
4470 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4471 command_byte &= 0xfd; // turn off IRQ 12 generation
4472 command_byte |= 0x20; // disable mouse serial clock line
4473 outb(0x64, 0x60); // write command byte
4474 outb(0x60, command_byte);
4475 return(prev_command_byte);
4479 enable_mouse_int_and_events()
4483 // Turn on IRQ generation and aux data line
4484 if ( inb(0x64) & 0x02 )
4485 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4486 outb(0x64, 0x20); // get command byte
4487 while ( (inb(0x64) & 0x01) != 0x01 );
4488 command_byte = inb(0x60);
4489 //while ( (inb(0x64) & 0x02) );
4490 if ( inb(0x64) & 0x02 )
4491 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4492 command_byte |= 0x02; // turn on IRQ 12 generation
4493 command_byte &= 0xdf; // enable mouse serial clock line
4494 outb(0x64, 0x60); // write command byte
4495 outb(0x60, command_byte);
4499 send_to_mouse_ctrl(sendbyte)
4504 // wait for chance to write to ctrl
4505 if ( inb(0x64) & 0x02 )
4506 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4508 outb(0x60, sendbyte);
4514 get_mouse_data(data)
4520 while ( (inb(0x64) & 0x21) != 0x21 ) {
4523 response = inb(0x60);
4526 write_byte(ss, data, response);
4531 set_kbd_command_byte(command_byte)
4534 if ( inb(0x64) & 0x02 )
4535 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4538 outb(0x64, 0x60); // write command byte
4539 outb(0x60, command_byte);
4543 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4544 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4546 Bit8u scancode, asciicode, shift_flags;
4547 Bit8u mf2_flags, mf2_state, led_flags;
4550 // DS has been set to F000 before call
4554 scancode = GET_AL();
4556 if (scancode == 0) {
4557 BX_INFO("KBD: int09 handler: AL=0\n");
4562 shift_flags = read_byte(0x0040, 0x17);
4563 mf2_flags = read_byte(0x0040, 0x18);
4564 mf2_state = read_byte(0x0040, 0x96);
4565 led_flags = read_byte(0x0040, 0x97);
4569 case 0x3a: /* Caps Lock press */
4570 shift_flags ^= 0x40;
4571 write_byte(0x0040, 0x17, shift_flags);
4573 write_byte(0x0040, 0x18, mf2_flags);
4575 write_byte(0x0040, 0x97, led_flags);
4577 case 0xba: /* Caps Lock release */
4579 write_byte(0x0040, 0x18, mf2_flags);
4582 case 0x2a: /* L Shift press */
4583 /*shift_flags &= ~0x40;*/
4584 shift_flags |= 0x02;
4585 write_byte(0x0040, 0x17, shift_flags);
4587 write_byte(0x0040, 0x97, led_flags);
4589 case 0xaa: /* L Shift release */
4590 shift_flags &= ~0x02;
4591 write_byte(0x0040, 0x17, shift_flags);
4594 case 0x36: /* R Shift press */
4595 /*shift_flags &= ~0x40;*/
4596 shift_flags |= 0x01;
4597 write_byte(0x0040, 0x17, shift_flags);
4599 write_byte(0x0040, 0x97, led_flags);
4601 case 0xb6: /* R Shift release */
4602 shift_flags &= ~0x01;
4603 write_byte(0x0040, 0x17, shift_flags);
4606 case 0x1d: /* Ctrl press */
4607 shift_flags |= 0x04;
4608 write_byte(0x0040, 0x17, shift_flags);
4609 if (mf2_state & 0x01) {
4614 write_byte(0x0040, 0x18, mf2_flags);
4616 case 0x9d: /* Ctrl release */
4617 shift_flags &= ~0x04;
4618 write_byte(0x0040, 0x17, shift_flags);
4619 if (mf2_state & 0x01) {
4624 write_byte(0x0040, 0x18, mf2_flags);
4627 case 0x38: /* Alt press */
4628 shift_flags |= 0x08;
4629 write_byte(0x0040, 0x17, shift_flags);
4630 if (mf2_state & 0x01) {
4635 write_byte(0x0040, 0x18, mf2_flags);
4637 case 0xb8: /* Alt release */
4638 shift_flags &= ~0x08;
4639 write_byte(0x0040, 0x17, shift_flags);
4640 if (mf2_state & 0x01) {
4645 write_byte(0x0040, 0x18, mf2_flags);
4648 case 0x45: /* Num Lock press */
4649 if ((mf2_state & 0x01) == 0) {
4651 write_byte(0x0040, 0x18, mf2_flags);
4652 shift_flags ^= 0x20;
4654 write_byte(0x0040, 0x17, shift_flags);
4655 write_byte(0x0040, 0x97, led_flags);
4658 case 0xc5: /* Num Lock release */
4659 if ((mf2_state & 0x01) == 0) {
4661 write_byte(0x0040, 0x18, mf2_flags);
4665 case 0x46: /* Scroll Lock press */
4667 write_byte(0x0040, 0x18, mf2_flags);
4668 shift_flags ^= 0x10;
4670 write_byte(0x0040, 0x17, shift_flags);
4671 write_byte(0x0040, 0x97, led_flags);
4674 case 0xc6: /* Scroll Lock release */
4676 write_byte(0x0040, 0x18, mf2_flags);
4680 if (scancode & 0x80) return; /* toss key releases ... */
4681 if (scancode > MAX_SCAN_CODE) {
4682 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4685 if (shift_flags & 0x08) { /* ALT */
4686 asciicode = scan_to_scanascii[scancode].alt;
4687 scancode = scan_to_scanascii[scancode].alt >> 8;
4689 else if (shift_flags & 0x04) { /* CONTROL */
4690 asciicode = scan_to_scanascii[scancode].control;
4691 scancode = scan_to_scanascii[scancode].control >> 8;
4693 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4694 /* check if lock state should be ignored
4695 * because a SHIFT key are pressed */
4697 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4698 asciicode = scan_to_scanascii[scancode].normal;
4699 scancode = scan_to_scanascii[scancode].normal >> 8;
4702 asciicode = scan_to_scanascii[scancode].shift;
4703 scancode = scan_to_scanascii[scancode].shift >> 8;
4707 /* check if lock is on */
4708 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4709 asciicode = scan_to_scanascii[scancode].shift;
4710 scancode = scan_to_scanascii[scancode].shift >> 8;
4713 asciicode = scan_to_scanascii[scancode].normal;
4714 scancode = scan_to_scanascii[scancode].normal >> 8;
4717 if (scancode==0 && asciicode==0) {
4718 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4720 enqueue_key(scancode, asciicode);
4727 enqueue_key(scan_code, ascii_code)
4728 Bit8u scan_code, ascii_code;
4730 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4732 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4733 // scan_code, ascii_code);
4736 buffer_start = 0x001E;
4737 buffer_end = 0x003E;
4739 buffer_start = read_word(0x0040, 0x0080);
4740 buffer_end = read_word(0x0040, 0x0082);
4743 buffer_head = read_word(0x0040, 0x001A);
4744 buffer_tail = read_word(0x0040, 0x001C);
4746 temp_tail = buffer_tail;
4748 if (buffer_tail >= buffer_end)
4749 buffer_tail = buffer_start;
4751 if (buffer_tail == buffer_head) {
4755 write_byte(0x0040, temp_tail, ascii_code);
4756 write_byte(0x0040, temp_tail+1, scan_code);
4757 write_word(0x0040, 0x001C, buffer_tail);
4763 int74_function(make_farcall, Z, Y, X, status)
4764 Bit16u make_farcall, Z, Y, X, status;
4766 Bit16u ebda_seg=read_word(0x0040,0x000E);
4767 Bit8u in_byte, index, package_count;
4768 Bit8u mouse_flags_1, mouse_flags_2;
4770 BX_DEBUG_INT74("entering int74_function\n");
4773 in_byte = inb(0x64);
4774 if ( (in_byte & 0x21) != 0x21 ) {
4777 in_byte = inb(0x60);
4778 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4780 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4781 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4783 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4784 // BX_PANIC("int74_function:\n");
4788 package_count = mouse_flags_2 & 0x07;
4789 index = mouse_flags_1 & 0x07;
4790 write_byte(ebda_seg, 0x28 + index, in_byte);
4792 if ( (index+1) >= package_count ) {
4793 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4794 status = read_byte(ebda_seg, 0x0028 + 0);
4795 X = read_byte(ebda_seg, 0x0028 + 1);
4796 Y = read_byte(ebda_seg, 0x0028 + 2);
4799 // check if far call handler installed
4800 if (mouse_flags_2 & 0x80)
4806 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4809 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4814 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4815 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4818 Bit16u ebda_seg=read_word(0x0040,0x000E);
4819 Bit16u cylinder, head, sector;
4820 Bit16u segment, offset;
4821 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4823 Bit8u device, status;
4825 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4827 write_byte(0x0040, 0x008e, 0); // clear completion flag
4829 // basic check : device has to be defined
4830 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4831 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4835 // Get the ata channel
4836 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4838 // basic check : device has to be valid
4839 if (device >= BX_MAX_ATA_DEVICES) {
4840 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4846 case 0x00: /* disk controller reset */
4851 case 0x01: /* read disk status */
4852 status = read_byte(0x0040, 0x0074);
4854 SET_DISK_RET_STATUS(0);
4855 /* set CF if error status read */
4856 if (status) goto int13_fail_nostatus;
4857 else goto int13_success_noah;
4860 case 0x02: // read disk sectors
4861 case 0x03: // write disk sectors
4862 case 0x04: // verify disk sectors
4865 cylinder = GET_CH();
4866 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4867 sector = (GET_CL() & 0x3f);
4873 if ( (count > 128) || (count == 0) ) {
4874 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4878 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4879 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4880 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4882 // sanity check on cyl heads, sec
4883 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4884 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4889 if ( GET_AH() == 0x04 ) goto int13_success;
4891 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4892 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4894 // if needed, translate lchs to lba, and execute command
4895 if ( (nph != nlh) || (npspt != nlspt)) {
4896 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4897 sector = 0; // this forces the command to be lba
4900 if ( GET_AH() == 0x02 )
4901 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4903 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4905 // Set nb of sector transferred
4906 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4909 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4911 goto int13_fail_noah;
4917 case 0x05: /* format disk track */
4918 BX_INFO("format disk track called\n");
4923 case 0x08: /* read disk drive parameters */
4925 // Get logical geometry from table
4926 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4927 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4928 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4929 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4931 nlc = nlc - 2; /* 0 based , last sector not used */
4934 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4936 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4938 // FIXME should set ES & DI
4943 case 0x10: /* check drive ready */
4944 // should look at 40:8E also???
4946 // Read the status from controller
4947 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
4948 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
4953 goto int13_fail_noah;
4957 case 0x15: /* read disk drive size */
4959 // Get physical geometry from table
4960 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4961 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4962 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4964 // Compute sector count seen by int13
4965 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
4969 SET_AH(3); // hard disk accessible
4970 goto int13_success_noah;
4973 case 0x41: // IBM/MS installation check
4974 BX=0xaa55; // install check
4975 SET_AH(0x30); // EDD 3.0
4976 CX=0x0007; // ext disk access and edd, removable supported
4977 goto int13_success_noah;
4980 case 0x42: // IBM/MS extended read
4981 case 0x43: // IBM/MS extended write
4982 case 0x44: // IBM/MS verify
4983 case 0x47: // IBM/MS extended seek
4985 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
4986 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
4987 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
4989 // Can't use 64 bits lba
4990 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
4992 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4996 // Get 32 bits lba and check
4997 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
4998 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
4999 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5003 // If verify or seek
5004 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5007 // Execute the command
5008 if ( GET_AH() == 0x42 )
5009 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5011 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5013 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5014 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5017 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5019 goto int13_fail_noah;
5025 case 0x45: // IBM/MS lock/unlock drive
5026 case 0x49: // IBM/MS extended media change
5027 goto int13_success; // Always success for HD
5030 case 0x46: // IBM/MS eject media
5031 SET_AH(0xb2); // Volume Not Removable
5032 goto int13_fail_noah; // Always fail for HD
5035 case 0x48: // IBM/MS get drive parameters
5036 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5038 // Buffer is too small
5046 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5047 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5048 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5049 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5050 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5052 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5053 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5054 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5055 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5056 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5057 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5058 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5059 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5064 Bit8u channel, dev, irq, mode, checksum, i, translation;
5065 Bit16u iobase1, iobase2, options;
5067 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5069 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5070 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5073 channel = device / 2;
5074 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5075 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5076 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5077 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5078 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5080 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5081 options |= (1<<4); // lba translation
5082 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5083 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5084 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5086 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5087 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5088 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5089 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5090 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5091 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5092 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5093 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5094 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5095 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5096 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5099 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5100 checksum = ~checksum;
5101 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5106 Bit8u channel, iface, checksum, i;
5109 channel = device / 2;
5110 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5111 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5113 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5114 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5115 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5116 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5117 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5119 if (iface==ATA_IFACE_ISA) {
5120 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5121 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5122 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5123 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5128 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5129 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5130 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5131 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5133 if (iface==ATA_IFACE_ISA) {
5134 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5135 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5136 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5141 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5142 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5143 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5144 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5147 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5148 checksum = ~checksum;
5149 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5155 case 0x4e: // // IBM/MS set hardware configuration
5156 // DMA, prefetch, PIO maximum not supported
5169 case 0x09: /* initialize drive parameters */
5170 case 0x0c: /* seek to specified cylinder */
5171 case 0x0d: /* alternate disk reset */
5172 case 0x11: /* recalibrate */
5173 case 0x14: /* controller internal diagnostic */
5174 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5178 case 0x0a: /* read disk sectors with ECC */
5179 case 0x0b: /* write disk sectors with ECC */
5180 case 0x18: // set media type for format
5181 case 0x50: // IBM/MS send packet command
5183 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5189 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5191 SET_DISK_RET_STATUS(GET_AH());
5192 int13_fail_nostatus:
5193 SET_CF(); // error occurred
5197 SET_AH(0x00); // no error
5199 SET_DISK_RET_STATUS(0x00);
5200 CLEAR_CF(); // no error
5204 // ---------------------------------------------------------------------------
5205 // Start of int13 for cdrom
5206 // ---------------------------------------------------------------------------
5209 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5210 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5212 Bit16u ebda_seg=read_word(0x0040,0x000E);
5213 Bit8u device, status, locks;
5216 Bit16u count, segment, offset, i, size;
5218 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5219 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5221 SET_DISK_RET_STATUS(0x00);
5223 /* basic check : device should be 0xE0+ */
5224 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5225 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5229 // Get the ata channel
5230 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5232 /* basic check : device has to be valid */
5233 if (device >= BX_MAX_ATA_DEVICES) {
5234 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5240 // all those functions return SUCCESS
5241 case 0x00: /* disk controller reset */
5242 case 0x09: /* initialize drive parameters */
5243 case 0x0c: /* seek to specified cylinder */
5244 case 0x0d: /* alternate disk reset */
5245 case 0x10: /* check drive ready */
5246 case 0x11: /* recalibrate */
5247 case 0x14: /* controller internal diagnostic */
5248 case 0x16: /* detect disk change */
5252 // all those functions return disk write-protected
5253 case 0x03: /* write disk sectors */
5254 case 0x05: /* format disk track */
5255 case 0x43: // IBM/MS extended write
5257 goto int13_fail_noah;
5260 case 0x01: /* read disk status */
5261 status = read_byte(0x0040, 0x0074);
5263 SET_DISK_RET_STATUS(0);
5265 /* set CF if error status read */
5266 if (status) goto int13_fail_nostatus;
5267 else goto int13_success_noah;
5270 case 0x15: /* read disk drive size */
5272 goto int13_fail_noah;
5275 case 0x41: // IBM/MS installation check
5276 BX=0xaa55; // install check
5277 SET_AH(0x30); // EDD 2.1
5278 CX=0x0007; // ext disk access, removable and edd
5279 goto int13_success_noah;
5282 case 0x42: // IBM/MS extended read
5283 case 0x44: // IBM/MS verify sectors
5284 case 0x47: // IBM/MS extended seek
5286 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5287 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5288 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5290 // Can't use 64 bits lba
5291 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5293 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5298 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5300 // If verify or seek
5301 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5304 memsetb(get_SS(),atacmd,0,12);
5305 atacmd[0]=0x28; // READ command
5306 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5307 atacmd[8]=(count & 0x00ff); // Sectors
5308 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5309 atacmd[3]=(lba & 0x00ff0000) >> 16;
5310 atacmd[4]=(lba & 0x0000ff00) >> 8;
5311 atacmd[5]=(lba & 0x000000ff);
5312 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5314 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5315 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5318 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5320 goto int13_fail_noah;
5326 case 0x45: // IBM/MS lock/unlock drive
5327 if (GET_AL() > 2) goto int13_fail;
5329 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5333 if (locks == 0xff) {
5336 goto int13_fail_noah;
5338 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5342 if (locks == 0x00) {
5345 goto int13_fail_noah;
5347 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5348 SET_AL(locks==0?0:1);
5351 SET_AL(locks==0?0:1);
5357 case 0x46: // IBM/MS eject media
5358 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5361 SET_AH(0xb1); // media locked
5362 goto int13_fail_noah;
5364 // FIXME should handle 0x31 no media in device
5365 // FIXME should handle 0xb5 valid request failed
5367 // Call removable media eject
5374 mov _int13_cdrom.status + 2[bp], ah
5375 jnc int13_cdrom_rme_end
5376 mov _int13_cdrom.status, #1
5377 int13_cdrom_rme_end:
5382 SET_AH(0xb1); // media locked
5383 goto int13_fail_noah;
5389 case 0x48: // IBM/MS get drive parameters
5390 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5392 // Buffer is too small
5398 Bit16u cylinders, heads, spt, blksize;
5400 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5402 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5403 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5404 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5405 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5406 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5407 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5408 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5409 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5414 Bit8u channel, dev, irq, mode, checksum, i;
5415 Bit16u iobase1, iobase2, options;
5417 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5419 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5420 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5423 channel = device / 2;
5424 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5425 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5426 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5427 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5429 // FIXME atapi device
5430 options = (1<<4); // lba translation
5431 options |= (1<<5); // removable device
5432 options |= (1<<6); // atapi device
5433 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5435 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5436 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5437 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5438 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5439 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5440 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5441 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5442 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5443 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5444 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5445 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5448 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5449 checksum = ~checksum;
5450 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5455 Bit8u channel, iface, checksum, i;
5458 channel = device / 2;
5459 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5460 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5462 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5463 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5464 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5465 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5466 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5468 if (iface==ATA_IFACE_ISA) {
5469 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5470 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5471 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5472 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5477 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5478 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5479 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5480 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5482 if (iface==ATA_IFACE_ISA) {
5483 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5484 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5485 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5490 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5491 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5492 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5493 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5496 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5497 checksum = ~checksum;
5498 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5504 case 0x49: // IBM/MS extended media change
5505 // always send changed ??
5507 goto int13_fail_nostatus;
5510 case 0x4e: // // IBM/MS set hardware configuration
5511 // DMA, prefetch, PIO maximum not supported
5524 // all those functions return unimplemented
5525 case 0x02: /* read sectors */
5526 case 0x04: /* verify sectors */
5527 case 0x08: /* read disk drive parameters */
5528 case 0x0a: /* read disk sectors with ECC */
5529 case 0x0b: /* write disk sectors with ECC */
5530 case 0x18: /* set media type for format */
5531 case 0x50: // ? - send packet command
5533 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5539 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5541 SET_DISK_RET_STATUS(GET_AH());
5542 int13_fail_nostatus:
5543 SET_CF(); // error occurred
5547 SET_AH(0x00); // no error
5549 SET_DISK_RET_STATUS(0x00);
5550 CLEAR_CF(); // no error
5554 // ---------------------------------------------------------------------------
5555 // End of int13 for cdrom
5556 // ---------------------------------------------------------------------------
5558 #if BX_ELTORITO_BOOT
5559 // ---------------------------------------------------------------------------
5560 // Start of int13 for eltorito functions
5561 // ---------------------------------------------------------------------------
5564 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5565 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5567 Bit16u ebda_seg=read_word(0x0040,0x000E);
5569 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5570 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5574 // FIXME ElTorito Various. Should be implemented
5575 case 0x4a: // ElTorito - Initiate disk emu
5576 case 0x4c: // ElTorito - Initiate disk emu and boot
5577 case 0x4d: // ElTorito - Return Boot catalog
5578 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5582 case 0x4b: // ElTorito - Terminate disk emu
5583 // FIXME ElTorito Hardcoded
5584 write_byte(DS,SI+0x00,0x13);
5585 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5586 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5587 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5588 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5589 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5590 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5591 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5592 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5593 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5594 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5595 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5597 // If we have to terminate emulation
5598 if(GET_AL() == 0x00) {
5599 // FIXME ElTorito Various. Should be handled accordingly to spec
5600 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5607 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5613 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5614 SET_DISK_RET_STATUS(GET_AH());
5615 SET_CF(); // error occurred
5619 SET_AH(0x00); // no error
5620 SET_DISK_RET_STATUS(0x00);
5621 CLEAR_CF(); // no error
5625 // ---------------------------------------------------------------------------
5626 // End of int13 for eltorito functions
5627 // ---------------------------------------------------------------------------
5629 // ---------------------------------------------------------------------------
5630 // Start of int13 when emulating a device from the cd
5631 // ---------------------------------------------------------------------------
5634 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5635 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5637 Bit16u ebda_seg=read_word(0x0040,0x000E);
5638 Bit8u device, status;
5639 Bit16u vheads, vspt, vcylinders;
5640 Bit16u head, sector, cylinder, nbsectors;
5641 Bit32u vlba, ilba, slba, elba;
5642 Bit16u before, segment, offset;
5645 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5646 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5648 /* at this point, we are emulating a floppy/harddisk */
5650 // Recompute the device number
5651 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5652 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5654 SET_DISK_RET_STATUS(0x00);
5656 /* basic checks : emulation should be active, dl should equal the emulated drive */
5657 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5658 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5659 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5665 // all those functions return SUCCESS
5666 case 0x00: /* disk controller reset */
5667 case 0x09: /* initialize drive parameters */
5668 case 0x0c: /* seek to specified cylinder */
5669 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5670 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5671 case 0x11: /* recalibrate */
5672 case 0x14: /* controller internal diagnostic */
5673 case 0x16: /* detect disk change */
5677 // all those functions return disk write-protected
5678 case 0x03: /* write disk sectors */
5679 case 0x05: /* format disk track */
5681 goto int13_fail_noah;
5684 case 0x01: /* read disk status */
5685 status=read_byte(0x0040, 0x0074);
5687 SET_DISK_RET_STATUS(0);
5689 /* set CF if error status read */
5690 if (status) goto int13_fail_nostatus;
5691 else goto int13_success_noah;
5694 case 0x02: // read disk sectors
5695 case 0x04: // verify disk sectors
5696 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5697 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5698 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5700 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5702 sector = GET_CL() & 0x003f;
5703 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5705 nbsectors = GET_AL();
5709 // no sector to read ?
5710 if(nbsectors==0) goto int13_success;
5712 // sanity checks sco openserver needs this!
5714 || (cylinder >= vcylinders)
5715 || (head >= vheads)) {
5719 // After controls, verify do nothing
5720 if (GET_AH() == 0x04) goto int13_success;
5722 segment = ES+(BX / 16);
5725 // calculate the virtual lba inside the image
5726 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5728 // In advance so we don't loose the count
5732 slba = (Bit32u)vlba/4;
5733 before= (Bit16u)vlba%4;
5736 elba = (Bit32u)(vlba+nbsectors-1)/4;
5738 memsetb(get_SS(),atacmd,0,12);
5739 atacmd[0]=0x28; // READ command
5740 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5741 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5742 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5743 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5744 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5745 atacmd[5]=(ilba+slba & 0x000000ff);
5746 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5747 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5750 goto int13_fail_noah;
5756 case 0x08: /* read disk drive parameters */
5757 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5758 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5759 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5763 SET_CH( vcylinders & 0xff );
5764 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5766 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5767 // FIXME ElTorito Harddisk. should send the HD count
5769 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5770 case 0x01: SET_BL( 0x02 ); break;
5771 case 0x02: SET_BL( 0x04 ); break;
5772 case 0x03: SET_BL( 0x06 ); break;
5778 mov ax, #diskette_param_table2
5779 mov _int13_cdemu.DI+2[bp], ax
5780 mov _int13_cdemu.ES+2[bp], cs
5786 case 0x15: /* read disk drive size */
5787 // FIXME ElTorito Harddisk. What geometry to send ?
5789 goto int13_success_noah;
5792 // all those functions return unimplemented
5793 case 0x0a: /* read disk sectors with ECC */
5794 case 0x0b: /* write disk sectors with ECC */
5795 case 0x18: /* set media type for format */
5796 case 0x41: // IBM/MS installation check
5797 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5798 case 0x42: // IBM/MS extended read
5799 case 0x43: // IBM/MS extended write
5800 case 0x44: // IBM/MS verify sectors
5801 case 0x45: // IBM/MS lock/unlock drive
5802 case 0x46: // IBM/MS eject media
5803 case 0x47: // IBM/MS extended seek
5804 case 0x48: // IBM/MS get drive parameters
5805 case 0x49: // IBM/MS extended media change
5806 case 0x4e: // ? - set hardware configuration
5807 case 0x50: // ? - send packet command
5809 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5815 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5817 SET_DISK_RET_STATUS(GET_AH());
5818 int13_fail_nostatus:
5819 SET_CF(); // error occurred
5823 SET_AH(0x00); // no error
5825 SET_DISK_RET_STATUS(0x00);
5826 CLEAR_CF(); // no error
5830 // ---------------------------------------------------------------------------
5831 // End of int13 when emulating a device from the cd
5832 // ---------------------------------------------------------------------------
5834 #endif // BX_ELTORITO_BOOT
5836 #else //BX_USE_ATADRV
5839 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5854 mov ax,4[bp] // cylinder
5856 mov bl,6[bp] // hd_heads
5859 mov bl,8[bp] // head
5861 mov bl,10[bp] // hd_sectors
5863 mov bl,12[bp] // sector
5892 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5893 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5895 Bit8u drive, num_sectors, sector, head, status, mod;
5899 Bit16u max_cylinder, cylinder, total_sectors;
5900 Bit16u hd_cylinders;
5901 Bit8u hd_heads, hd_sectors;
5908 Bit16u count, segment, offset;
5912 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5914 write_byte(0x0040, 0x008e, 0); // clear completion flag
5916 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5918 /* check how many disks first (cmos reg 0x12), return an error if
5919 drive not present */
5920 drive_map = inb_cmos(0x12);
5921 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5922 (((drive_map & 0x0f)==0) ? 0 : 2);
5923 n_drives = (drive_map==0) ? 0 :
5924 ((drive_map==3) ? 2 : 1);
5926 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5928 SET_DISK_RET_STATUS(0x01);
5929 SET_CF(); /* error occurred */
5935 case 0x00: /* disk controller reset */
5936 BX_DEBUG_INT13_HD("int13_f00\n");
5939 SET_DISK_RET_STATUS(0);
5940 set_diskette_ret_status(0);
5941 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5942 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5943 CLEAR_CF(); /* successful */
5947 case 0x01: /* read disk status */
5948 BX_DEBUG_INT13_HD("int13_f01\n");
5949 status = read_byte(0x0040, 0x0074);
5951 SET_DISK_RET_STATUS(0);
5952 /* set CF if error status read */
5953 if (status) SET_CF();
5958 case 0x04: // verify disk sectors
5959 case 0x02: // read disk sectors
5961 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5963 num_sectors = GET_AL();
5964 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5965 sector = (GET_CL() & 0x3f);
5969 if (hd_cylinders > 1024) {
5970 if (hd_cylinders <= 2048) {
5973 else if (hd_cylinders <= 4096) {
5976 else if (hd_cylinders <= 8192) {
5979 else { // hd_cylinders <= 16384
5983 ax = head / hd_heads;
5984 cyl_mod = ax & 0xff;
5986 cylinder |= cyl_mod;
5989 if ( (cylinder >= hd_cylinders) ||
5990 (sector > hd_sectors) ||
5991 (head >= hd_heads) ) {
5993 SET_DISK_RET_STATUS(1);
5994 SET_CF(); /* error occurred */
5998 if ( (num_sectors > 128) || (num_sectors == 0) )
5999 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6002 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6004 if ( GET_AH() == 0x04 ) {
6006 SET_DISK_RET_STATUS(0);
6011 status = inb(0x1f7);
6012 if (status & 0x80) {
6013 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6015 outb(0x01f2, num_sectors);
6016 /* activate LBA? (tomv) */
6017 if (hd_heads > 16) {
6018 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6019 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6022 outb(0x01f3, sector);
6023 outb(0x01f4, cylinder & 0x00ff);
6024 outb(0x01f5, cylinder >> 8);
6025 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6030 status = inb(0x1f7);
6031 if ( !(status & 0x80) ) break;
6034 if (status & 0x01) {
6035 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6036 } else if ( !(status & 0x08) ) {
6037 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6038 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6045 sti ;; enable higher priority interrupts
6050 ;; store temp bx in real DI register
6053 mov di, _int13_harddisk.tempbx + 2 [bp]
6056 ;; adjust if there will be an overrun
6058 jbe i13_f02_no_adjust
6060 sub di, #0x0200 ; sub 512 bytes from offset
6062 add ax, #0x0020 ; add 512 to segment
6066 mov cx, #0x0100 ;; counter (256 words = 512b)
6067 mov dx, #0x01f0 ;; AT data read port
6070 insw ;; CX words transfered from port(DX) to ES:[DI]
6073 ;; store real DI register back to temp bx
6076 mov _int13_harddisk.tempbx + 2 [bp], di
6082 if (num_sectors == 0) {
6083 status = inb(0x1f7);
6084 if ( (status & 0xc9) != 0x40 )
6085 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6089 status = inb(0x1f7);
6090 if ( (status & 0xc9) != 0x48 )
6091 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6097 SET_DISK_RET_STATUS(0);
6098 SET_AL(sector_count);
6099 CLEAR_CF(); /* successful */
6104 case 0x03: /* write disk sectors */
6105 BX_DEBUG_INT13_HD("int13_f03\n");
6106 drive = GET_ELDL ();
6107 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6109 num_sectors = GET_AL();
6110 cylinder = GET_CH();
6111 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6112 sector = (GET_CL() & 0x3f);
6115 if (hd_cylinders > 1024) {
6116 if (hd_cylinders <= 2048) {
6119 else if (hd_cylinders <= 4096) {
6122 else if (hd_cylinders <= 8192) {
6125 else { // hd_cylinders <= 16384
6129 ax = head / hd_heads;
6130 cyl_mod = ax & 0xff;
6132 cylinder |= cyl_mod;
6135 if ( (cylinder >= hd_cylinders) ||
6136 (sector > hd_sectors) ||
6137 (head >= hd_heads) ) {
6139 SET_DISK_RET_STATUS(1);
6140 SET_CF(); /* error occurred */
6144 if ( (num_sectors > 128) || (num_sectors == 0) )
6145 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6148 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6150 status = inb(0x1f7);
6151 if (status & 0x80) {
6152 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6154 // should check for Drive Ready Bit also in status reg
6155 outb(0x01f2, num_sectors);
6157 /* activate LBA? (tomv) */
6158 if (hd_heads > 16) {
6159 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6160 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6163 outb(0x01f3, sector);
6164 outb(0x01f4, cylinder & 0x00ff);
6165 outb(0x01f5, cylinder >> 8);
6166 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6170 // wait for busy bit to turn off after seeking
6172 status = inb(0x1f7);
6173 if ( !(status & 0x80) ) break;
6176 if ( !(status & 0x08) ) {
6177 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6178 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6185 sti ;; enable higher priority interrupts
6190 ;; store temp bx in real SI register
6193 mov si, _int13_harddisk.tempbx + 2 [bp]
6196 ;; adjust if there will be an overrun
6198 jbe i13_f03_no_adjust
6200 sub si, #0x0200 ; sub 512 bytes from offset
6202 add ax, #0x0020 ; add 512 to segment
6206 mov cx, #0x0100 ;; counter (256 words = 512b)
6207 mov dx, #0x01f0 ;; AT data read port
6211 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6213 ;; store real SI register back to temp bx
6216 mov _int13_harddisk.tempbx + 2 [bp], si
6222 if (num_sectors == 0) {
6223 status = inb(0x1f7);
6224 if ( (status & 0xe9) != 0x40 )
6225 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6229 status = inb(0x1f7);
6230 if ( (status & 0xc9) != 0x48 )
6231 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6237 SET_DISK_RET_STATUS(0);
6238 SET_AL(sector_count);
6239 CLEAR_CF(); /* successful */
6243 case 0x05: /* format disk track */
6244 BX_DEBUG_INT13_HD("int13_f05\n");
6245 BX_PANIC("format disk track called\n");
6248 SET_DISK_RET_STATUS(0);
6249 CLEAR_CF(); /* successful */
6253 case 0x08: /* read disk drive parameters */
6254 BX_DEBUG_INT13_HD("int13_f08\n");
6256 drive = GET_ELDL ();
6257 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6261 if (hd_cylinders <= 1024) {
6262 // hd_cylinders >>= 0;
6265 else if (hd_cylinders <= 2048) {
6269 else if (hd_cylinders <= 4096) {
6273 else if (hd_cylinders <= 8192) {
6277 else { // hd_cylinders <= 16384
6282 max_cylinder = hd_cylinders - 2; /* 0 based */
6284 SET_CH(max_cylinder & 0xff);
6285 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6286 SET_DH(hd_heads - 1);
6287 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6289 SET_DISK_RET_STATUS(0);
6290 CLEAR_CF(); /* successful */
6295 case 0x09: /* initialize drive parameters */
6296 BX_DEBUG_INT13_HD("int13_f09\n");
6298 SET_DISK_RET_STATUS(0);
6299 CLEAR_CF(); /* successful */
6303 case 0x0a: /* read disk sectors with ECC */
6304 BX_DEBUG_INT13_HD("int13_f0a\n");
6305 case 0x0b: /* write disk sectors with ECC */
6306 BX_DEBUG_INT13_HD("int13_f0b\n");
6307 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6311 case 0x0c: /* seek to specified cylinder */
6312 BX_DEBUG_INT13_HD("int13_f0c\n");
6313 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6315 SET_DISK_RET_STATUS(0);
6316 CLEAR_CF(); /* successful */
6320 case 0x0d: /* alternate disk reset */
6321 BX_DEBUG_INT13_HD("int13_f0d\n");
6323 SET_DISK_RET_STATUS(0);
6324 CLEAR_CF(); /* successful */
6328 case 0x10: /* check drive ready */
6329 BX_DEBUG_INT13_HD("int13_f10\n");
6331 //SET_DISK_RET_STATUS(0);
6332 //CLEAR_CF(); /* successful */
6336 // should look at 40:8E also???
6337 status = inb(0x01f7);
6338 if ( (status & 0xc0) == 0x40 ) {
6340 SET_DISK_RET_STATUS(0);
6341 CLEAR_CF(); // drive ready
6346 SET_DISK_RET_STATUS(0xAA);
6347 SET_CF(); // not ready
6352 case 0x11: /* recalibrate */
6353 BX_DEBUG_INT13_HD("int13_f11\n");
6355 SET_DISK_RET_STATUS(0);
6356 CLEAR_CF(); /* successful */
6360 case 0x14: /* controller internal diagnostic */
6361 BX_DEBUG_INT13_HD("int13_f14\n");
6363 SET_DISK_RET_STATUS(0);
6364 CLEAR_CF(); /* successful */
6369 case 0x15: /* read disk drive size */
6371 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6375 mov al, _int13_harddisk.hd_heads + 2 [bp]
6376 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6377 mul al, ah ;; ax = heads * sectors
6378 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6379 dec bx ;; use (cylinders - 1) ???
6380 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6381 ;; now we need to move the 32bit result dx:ax to what the
6382 ;; BIOS wants which is cx:dx.
6383 ;; and then into CX:DX on the stack
6384 mov _int13_harddisk.CX + 2 [bp], dx
6385 mov _int13_harddisk.DX + 2 [bp], ax
6388 SET_AH(3); // hard disk accessible
6389 SET_DISK_RET_STATUS(0); // ??? should this be 0
6390 CLEAR_CF(); // successful
6394 case 0x18: // set media type for format
6395 case 0x41: // IBM/MS
6396 case 0x42: // IBM/MS
6397 case 0x43: // IBM/MS
6398 case 0x44: // IBM/MS
6399 case 0x45: // IBM/MS lock/unlock drive
6400 case 0x46: // IBM/MS eject media
6401 case 0x47: // IBM/MS extended seek
6402 case 0x49: // IBM/MS extended media change
6403 case 0x50: // IBM/MS send packet command
6405 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6407 SET_AH(1); // code=invalid function in AH or invalid parameter
6408 SET_DISK_RET_STATUS(1);
6409 SET_CF(); /* unsuccessful */
6415 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6416 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6419 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6421 Bit16u *hd_cylinders;
6431 if (drive == 0x80) {
6432 hd_type = inb_cmos(0x12) & 0xf0;
6433 if (hd_type != 0xf0)
6434 BX_INFO(panic_msg_reg12h,0);
6435 hd_type = inb_cmos(0x19); // HD0: extended type
6437 BX_INFO(panic_msg_reg19h,0,0x19);
6440 hd_type = inb_cmos(0x12) & 0x0f;
6441 if (hd_type != 0x0f)
6442 BX_INFO(panic_msg_reg12h,1);
6443 hd_type = inb_cmos(0x1a); // HD0: extended type
6445 BX_INFO(panic_msg_reg19h,0,0x1a);
6450 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6451 write_word(ss, hd_cylinders, cylinders);
6454 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6456 // sectors per track
6457 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6460 #endif //else BX_USE_ATADRV
6463 //////////////////////
6464 // FLOPPY functions //
6465 //////////////////////
6468 floppy_media_known(drive)
6472 Bit16u media_state_offset;
6474 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6481 media_state_offset = 0x0090;
6483 media_state_offset += 1;
6485 val8 = read_byte(0x0040, media_state_offset);
6486 val8 = (val8 >> 4) & 0x01;
6490 // check pass, return KNOWN
6495 floppy_media_sense(drive)
6499 Bit16u media_state_offset;
6500 Bit8u drive_type, config_data, media_state;
6502 if (floppy_drive_recal(drive) == 0) {
6506 // for now cheat and get drive type from CMOS,
6507 // assume media is same as drive type
6509 // ** config_data **
6510 // Bitfields for diskette media control:
6511 // Bit(s) Description (Table M0028)
6512 // 7-6 last data rate set by controller
6513 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6514 // 5-4 last diskette drive step rate selected
6515 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6516 // 3-2 {data rate at start of operation}
6519 // ** media_state **
6520 // Bitfields for diskette drive media state:
6521 // Bit(s) Description (Table M0030)
6523 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6524 // 5 double stepping required (e.g. 360kB in 1.2MB)
6525 // 4 media type established
6526 // 3 drive capable of supporting 4MB media
6527 // 2-0 on exit from BIOS, contains
6528 // 000 trying 360kB in 360kB
6529 // 001 trying 360kB in 1.2MB
6530 // 010 trying 1.2MB in 1.2MB
6531 // 011 360kB in 360kB established
6532 // 100 360kB in 1.2MB established
6533 // 101 1.2MB in 1.2MB established
6535 // 111 all other formats/drives
6537 drive_type = inb_cmos(0x10);
6542 if ( drive_type == 1 ) {
6544 config_data = 0x00; // 0000 0000
6545 media_state = 0x25; // 0010 0101
6548 else if ( drive_type == 2 ) {
6549 // 1.2 MB 5.25" drive
6550 config_data = 0x00; // 0000 0000
6551 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6554 else if ( drive_type == 3 ) {
6556 config_data = 0x00; // 0000 0000 ???
6557 media_state = 0x17; // 0001 0111
6560 else if ( drive_type == 4 ) {
6561 // 1.44 MB 3.5" drive
6562 config_data = 0x00; // 0000 0000
6563 media_state = 0x17; // 0001 0111
6566 else if ( drive_type == 5 ) {
6567 // 2.88 MB 3.5" drive
6568 config_data = 0xCC; // 1100 1100
6569 media_state = 0xD7; // 1101 0111
6573 // Extended floppy size uses special cmos setting
6574 else if ( drive_type == 6 ) {
6576 config_data = 0x00; // 0000 0000
6577 media_state = 0x27; // 0010 0111
6580 else if ( drive_type == 7 ) {
6582 config_data = 0x00; // 0000 0000
6583 media_state = 0x27; // 0010 0111
6586 else if ( drive_type == 8 ) {
6588 config_data = 0x00; // 0000 0000
6589 media_state = 0x27; // 0010 0111
6595 config_data = 0x00; // 0000 0000
6596 media_state = 0x00; // 0000 0000
6601 media_state_offset = 0x90;
6603 media_state_offset = 0x91;
6604 write_byte(0x0040, 0x008B, config_data);
6605 write_byte(0x0040, media_state_offset, media_state);
6611 floppy_drive_recal(drive)
6615 Bit16u curr_cyl_offset;
6617 // set 40:3e bit 7 to 0
6618 val8 = read_byte(0x0000, 0x043e);
6620 write_byte(0x0000, 0x043e, val8);
6622 // turn on motor of selected drive, DMA & int enabled, normal operation
6631 // reset the disk motor timeout value of INT 08
6632 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6634 // check port 3f4 for drive readiness
6636 if ( (val8 & 0xf0) != 0x80 )
6637 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6639 // send Recalibrate command (2 bytes) to controller
6640 outb(0x03f5, 0x07); // 07: Recalibrate
6641 outb(0x03f5, drive); // 0=drive0, 1=drive1
6643 // turn on interrupts
6648 // wait on 40:3e bit 7 to become 1
6649 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6650 while ( val8 == 0 ) {
6651 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6654 val8 = 0; // separate asm from while() loop
6655 // turn off interrupts
6660 // set 40:3e bit 7 to 0, and calibrated bit
6661 val8 = read_byte(0x0000, 0x043e);
6664 val8 |= 0x02; // Drive 1 calibrated
6665 curr_cyl_offset = 0x0095;
6668 val8 |= 0x01; // Drive 0 calibrated
6669 curr_cyl_offset = 0x0094;
6671 write_byte(0x0040, 0x003e, val8);
6672 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6680 floppy_drive_exists(drive)
6685 // check CMOS to see if drive exists
6686 drive_type = inb_cmos(0x10);
6691 if ( drive_type == 0 )
6697 #if BX_SUPPORT_FLOPPY
6699 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6700 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6702 Bit8u drive, num_sectors, track, sector, head, status;
6703 Bit16u base_address, base_count, base_es;
6704 Bit8u page, mode_register, val8, dor;
6705 Bit8u return_status[7];
6706 Bit8u drive_type, num_floppies, ah;
6707 Bit16u es, last_addr;
6709 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6710 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6715 case 0x00: // diskette controller reset
6716 BX_DEBUG_INT13_FL("floppy f00\n");
6719 SET_AH(1); // invalid param
6720 set_diskette_ret_status(1);
6724 drive_type = inb_cmos(0x10);
6730 if (drive_type == 0) {
6731 SET_AH(0x80); // drive not responding
6732 set_diskette_ret_status(0x80);
6737 set_diskette_ret_status(0);
6738 CLEAR_CF(); // successful
6739 set_diskette_current_cyl(drive, 0); // current cylinder
6742 case 0x01: // Read Diskette Status
6744 val8 = read_byte(0x0000, 0x0441);
6751 case 0x02: // Read Diskette Sectors
6752 case 0x03: // Write Diskette Sectors
6753 case 0x04: // Verify Diskette Sectors
6754 num_sectors = GET_AL();
6760 if ( (drive > 1) || (head > 1) ||
6761 (num_sectors == 0) || (num_sectors > 72) ) {
6762 BX_INFO("floppy: drive>1 || head>1 ...\n");
6764 set_diskette_ret_status(1);
6765 SET_AL(0); // no sectors read
6766 SET_CF(); // error occurred
6770 // see if drive exists
6771 if (floppy_drive_exists(drive) == 0) {
6772 SET_AH(0x80); // not responding
6773 set_diskette_ret_status(0x80);
6774 SET_AL(0); // no sectors read
6775 SET_CF(); // error occurred
6779 // see if media in drive, and type is known
6780 if (floppy_media_known(drive) == 0) {
6781 if (floppy_media_sense(drive) == 0) {
6782 SET_AH(0x0C); // Media type not found
6783 set_diskette_ret_status(0x0C);
6784 SET_AL(0); // no sectors read
6785 SET_CF(); // error occurred
6791 // Read Diskette Sectors
6793 //-----------------------------------
6794 // set up DMA controller for transfer
6795 //-----------------------------------
6797 // es:bx = pointer to where to place information from diskette
6798 // port 04: DMA-1 base and current address, channel 2
6799 // port 05: DMA-1 base and current count, channel 2
6800 page = (ES >> 12); // upper 4 bits
6801 base_es = (ES << 4); // lower 16bits contributed by ES
6802 base_address = base_es + BX; // lower 16 bits of address
6803 // contributed by ES:BX
6804 if ( base_address < base_es ) {
6805 // in case of carry, adjust page by 1
6808 base_count = (num_sectors * 512) - 1;
6810 // check for 64K boundary overrun
6811 last_addr = base_address + base_count;
6812 if (last_addr < base_address) {
6814 set_diskette_ret_status(0x09);
6815 SET_AL(0); // no sectors read
6816 SET_CF(); // error occurred
6820 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6823 BX_DEBUG_INT13_FL("clear flip-flop\n");
6824 outb(0x000c, 0x00); // clear flip-flop
6825 outb(0x0004, base_address);
6826 outb(0x0004, base_address>>8);
6827 BX_DEBUG_INT13_FL("clear flip-flop\n");
6828 outb(0x000c, 0x00); // clear flip-flop
6829 outb(0x0005, base_count);
6830 outb(0x0005, base_count>>8);
6832 // port 0b: DMA-1 Mode Register
6833 mode_register = 0x46; // single mode, increment, autoinit disable,
6834 // transfer type=write, channel 2
6835 BX_DEBUG_INT13_FL("setting mode register\n");
6836 outb(0x000b, mode_register);
6838 BX_DEBUG_INT13_FL("setting page register\n");
6839 // port 81: DMA-1 Page Register, channel 2
6842 BX_DEBUG_INT13_FL("unmask chan 2\n");
6843 outb(0x000a, 0x02); // unmask channel 2
6845 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6848 //--------------------------------------
6849 // set up floppy controller for transfer
6850 //--------------------------------------
6852 // set 40:3e bit 7 to 0
6853 val8 = read_byte(0x0000, 0x043e);
6855 write_byte(0x0000, 0x043e, val8);
6857 // turn on motor of selected drive, DMA & int enabled, normal operation
6866 // reset the disk motor timeout value of INT 08
6867 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6869 // check port 3f4 for drive readiness
6871 if ( (val8 & 0xf0) != 0x80 )
6872 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6874 // send read-normal-data command (9 bytes) to controller
6875 outb(0x03f5, 0xe6); // e6: read normal data
6876 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6877 outb(0x03f5, track);
6879 outb(0x03f5, sector);
6880 outb(0x03f5, 2); // 512 byte sector size
6881 outb(0x03f5, 0); // last sector number possible on track
6882 outb(0x03f5, 0); // Gap length
6883 outb(0x03f5, 0xff); // Gap length
6885 // turn on interrupts
6890 // wait on 40:3e bit 7 to become 1
6891 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6892 while ( val8 == 0 ) {
6893 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6896 val8 = 0; // separate asm from while() loop
6897 // turn off interrupts
6902 // set 40:3e bit 7 to 0
6903 val8 = read_byte(0x0000, 0x043e);
6905 write_byte(0x0000, 0x043e, val8);
6907 // check port 3f4 for accessibility to status bytes
6909 if ( (val8 & 0xc0) != 0xc0 )
6910 BX_PANIC("int13_diskette: ctrl not ready\n");
6912 // read 7 return status bytes from controller
6913 // using loop index broken, have to unroll...
6914 return_status[0] = inb(0x3f5);
6915 return_status[1] = inb(0x3f5);
6916 return_status[2] = inb(0x3f5);
6917 return_status[3] = inb(0x3f5);
6918 return_status[4] = inb(0x3f5);
6919 return_status[5] = inb(0x3f5);
6920 return_status[6] = inb(0x3f5);
6921 // record in BIOS Data Area
6922 write_byte(0x0040, 0x0042, return_status[0]);
6923 write_byte(0x0040, 0x0043, return_status[1]);
6924 write_byte(0x0040, 0x0044, return_status[2]);
6925 write_byte(0x0040, 0x0045, return_status[3]);
6926 write_byte(0x0040, 0x0046, return_status[4]);
6927 write_byte(0x0040, 0x0047, return_status[5]);
6928 write_byte(0x0040, 0x0048, return_status[6]);
6930 if ( (return_status[0] & 0xc0) != 0 ) {
6932 set_diskette_ret_status(0x20);
6933 SET_AL(0); // no sectors read
6934 SET_CF(); // error occurred
6938 // ??? should track be new val from return_status[3] ?
6939 set_diskette_current_cyl(drive, track);
6940 // AL = number of sectors read (same value as passed)
6941 SET_AH(0x00); // success
6942 CLEAR_CF(); // success
6945 else if (ah == 0x03) {
6946 // Write Diskette Sectors
6948 //-----------------------------------
6949 // set up DMA controller for transfer
6950 //-----------------------------------
6952 // es:bx = pointer to where to place information from diskette
6953 // port 04: DMA-1 base and current address, channel 2
6954 // port 05: DMA-1 base and current count, channel 2
6955 page = (ES >> 12); // upper 4 bits
6956 base_es = (ES << 4); // lower 16bits contributed by ES
6957 base_address = base_es + BX; // lower 16 bits of address
6958 // contributed by ES:BX
6959 if ( base_address < base_es ) {
6960 // in case of carry, adjust page by 1
6963 base_count = (num_sectors * 512) - 1;
6965 // check for 64K boundary overrun
6966 last_addr = base_address + base_count;
6967 if (last_addr < base_address) {
6969 set_diskette_ret_status(0x09);
6970 SET_AL(0); // no sectors read
6971 SET_CF(); // error occurred
6975 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6978 outb(0x000c, 0x00); // clear flip-flop
6979 outb(0x0004, base_address);
6980 outb(0x0004, base_address>>8);
6981 outb(0x000c, 0x00); // clear flip-flop
6982 outb(0x0005, base_count);
6983 outb(0x0005, base_count>>8);
6985 // port 0b: DMA-1 Mode Register
6986 mode_register = 0x4a; // single mode, increment, autoinit disable,
6987 // transfer type=read, channel 2
6988 outb(0x000b, mode_register);
6990 // port 81: DMA-1 Page Register, channel 2
6993 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6996 //--------------------------------------
6997 // set up floppy controller for transfer
6998 //--------------------------------------
7000 // set 40:3e bit 7 to 0
7001 val8 = read_byte(0x0000, 0x043e);
7003 write_byte(0x0000, 0x043e, val8);
7005 // turn on motor of selected drive, DMA & int enabled, normal operation
7014 // reset the disk motor timeout value of INT 08
7015 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7017 // check port 3f4 for drive readiness
7019 if ( (val8 & 0xf0) != 0x80 )
7020 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7022 // send read-normal-data command (9 bytes) to controller
7023 outb(0x03f5, 0xc5); // c5: write normal data
7024 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7025 outb(0x03f5, track);
7027 outb(0x03f5, sector);
7028 outb(0x03f5, 2); // 512 byte sector size
7029 outb(0x03f5, 0); // last sector number possible on track
7030 outb(0x03f5, 0); // Gap length
7031 outb(0x03f5, 0xff); // Gap length
7033 // turn on interrupts
7038 // wait on 40:3e bit 7 to become 1
7039 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7040 while ( val8 == 0 ) {
7041 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7044 val8 = 0; // separate asm from while() loop
7045 // turn off interrupts
7050 // set 40:3e bit 7 to 0
7051 val8 = read_byte(0x0000, 0x043e);
7053 write_byte(0x0000, 0x043e, val8);
7055 // check port 3f4 for accessibility to status bytes
7057 if ( (val8 & 0xc0) != 0xc0 )
7058 BX_PANIC("int13_diskette: ctrl not ready\n");
7060 // read 7 return status bytes from controller
7061 // using loop index broken, have to unroll...
7062 return_status[0] = inb(0x3f5);
7063 return_status[1] = inb(0x3f5);
7064 return_status[2] = inb(0x3f5);
7065 return_status[3] = inb(0x3f5);
7066 return_status[4] = inb(0x3f5);
7067 return_status[5] = inb(0x3f5);
7068 return_status[6] = inb(0x3f5);
7069 // record in BIOS Data Area
7070 write_byte(0x0040, 0x0042, return_status[0]);
7071 write_byte(0x0040, 0x0043, return_status[1]);
7072 write_byte(0x0040, 0x0044, return_status[2]);
7073 write_byte(0x0040, 0x0045, return_status[3]);
7074 write_byte(0x0040, 0x0046, return_status[4]);
7075 write_byte(0x0040, 0x0047, return_status[5]);
7076 write_byte(0x0040, 0x0048, return_status[6]);
7078 if ( (return_status[0] & 0xc0) != 0 ) {
7079 if ( (return_status[1] & 0x02) != 0 ) {
7080 // diskette not writable.
7081 // AH=status code=0x03 (tried to write on write-protected disk)
7082 // AL=number of sectors written=0
7087 BX_PANIC("int13_diskette_function: read error\n");
7091 // ??? should track be new val from return_status[3] ?
7092 set_diskette_current_cyl(drive, track);
7093 // AL = number of sectors read (same value as passed)
7094 SET_AH(0x00); // success
7095 CLEAR_CF(); // success
7098 else { // if (ah == 0x04)
7099 // Verify Diskette Sectors
7101 // ??? should track be new val from return_status[3] ?
7102 set_diskette_current_cyl(drive, track);
7103 // AL = number of sectors verified (same value as passed)
7104 CLEAR_CF(); // success
7105 SET_AH(0x00); // success
7110 case 0x05: // format diskette track
7111 BX_DEBUG_INT13_FL("floppy f05\n");
7113 num_sectors = GET_AL();
7118 if ((drive > 1) || (head > 1) || (track > 79) ||
7119 (num_sectors == 0) || (num_sectors > 18)) {
7121 set_diskette_ret_status(1);
7122 SET_CF(); // error occurred
7125 // see if drive exists
7126 if (floppy_drive_exists(drive) == 0) {
7127 SET_AH(0x80); // drive not responding
7128 set_diskette_ret_status(0x80);
7129 SET_CF(); // error occurred
7133 // see if media in drive, and type is known
7134 if (floppy_media_known(drive) == 0) {
7135 if (floppy_media_sense(drive) == 0) {
7136 SET_AH(0x0C); // Media type not found
7137 set_diskette_ret_status(0x0C);
7138 SET_AL(0); // no sectors read
7139 SET_CF(); // error occurred
7144 // set up DMA controller for transfer
7145 page = (ES >> 12); // upper 4 bits
7146 base_es = (ES << 4); // lower 16bits contributed by ES
7147 base_address = base_es + BX; // lower 16 bits of address
7148 // contributed by ES:BX
7149 if ( base_address < base_es ) {
7150 // in case of carry, adjust page by 1
7153 base_count = (num_sectors * 4) - 1;
7155 // check for 64K boundary overrun
7156 last_addr = base_address + base_count;
7157 if (last_addr < base_address) {
7159 set_diskette_ret_status(0x09);
7160 SET_AL(0); // no sectors read
7161 SET_CF(); // error occurred
7166 outb(0x000c, 0x00); // clear flip-flop
7167 outb(0x0004, base_address);
7168 outb(0x0004, base_address>>8);
7169 outb(0x000c, 0x00); // clear flip-flop
7170 outb(0x0005, base_count);
7171 outb(0x0005, base_count>>8);
7172 mode_register = 0x4a; // single mode, increment, autoinit disable,
7173 // transfer type=read, channel 2
7174 outb(0x000b, mode_register);
7175 // port 81: DMA-1 Page Register, channel 2
7179 // set up floppy controller for transfer
7180 val8 = read_byte(0x0000, 0x043e);
7182 write_byte(0x0000, 0x043e, val8);
7183 // turn on motor of selected drive, DMA & int enabled, normal operation
7192 // reset the disk motor timeout value of INT 08
7193 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7195 // check port 3f4 for drive readiness
7197 if ( (val8 & 0xf0) != 0x80 )
7198 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7200 // send read-normal-data command (6 bytes) to controller
7201 outb(0x03f5, 0x4d); // 4d: format track
7202 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7203 outb(0x03f5, 2); // 512 byte sector size
7204 outb(0x03f5, num_sectors); // number of sectors per track
7205 outb(0x03f5, 0); // Gap length
7206 outb(0x03f5, 0xf6); // Fill byte
7207 // turn on interrupts
7211 // wait on 40:3e bit 7 to become 1
7212 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7213 while ( val8 == 0 ) {
7214 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7216 val8 = 0; // separate asm from while() loop
7217 // turn off interrupts
7221 // set 40:3e bit 7 to 0
7222 val8 = read_byte(0x0000, 0x043e);
7224 write_byte(0x0000, 0x043e, val8);
7225 // check port 3f4 for accessibility to status bytes
7227 if ( (val8 & 0xc0) != 0xc0 )
7228 BX_PANIC("int13_diskette: ctrl not ready\n");
7230 // read 7 return status bytes from controller
7231 // using loop index broken, have to unroll...
7232 return_status[0] = inb(0x3f5);
7233 return_status[1] = inb(0x3f5);
7234 return_status[2] = inb(0x3f5);
7235 return_status[3] = inb(0x3f5);
7236 return_status[4] = inb(0x3f5);
7237 return_status[5] = inb(0x3f5);
7238 return_status[6] = inb(0x3f5);
7239 // record in BIOS Data Area
7240 write_byte(0x0040, 0x0042, return_status[0]);
7241 write_byte(0x0040, 0x0043, return_status[1]);
7242 write_byte(0x0040, 0x0044, return_status[2]);
7243 write_byte(0x0040, 0x0045, return_status[3]);
7244 write_byte(0x0040, 0x0046, return_status[4]);
7245 write_byte(0x0040, 0x0047, return_status[5]);
7246 write_byte(0x0040, 0x0048, return_status[6]);
7248 if ( (return_status[0] & 0xc0) != 0 ) {
7249 if ( (return_status[1] & 0x02) != 0 ) {
7250 // diskette not writable.
7251 // AH=status code=0x03 (tried to write on write-protected disk)
7252 // AL=number of sectors written=0
7257 BX_PANIC("int13_diskette_function: write error\n");
7262 set_diskette_ret_status(0);
7263 set_diskette_current_cyl(drive, 0);
7264 CLEAR_CF(); // successful
7268 case 0x08: // read diskette drive parameters
7269 BX_DEBUG_INT13_FL("floppy f08\n");
7279 SET_DL(num_floppies);
7284 drive_type = inb_cmos(0x10);
7286 if (drive_type & 0xf0)
7288 if (drive_type & 0x0f)
7300 SET_DL(num_floppies);
7302 switch (drive_type) {
7305 SET_DH(0); // max head #
7308 case 1: // 360KB, 5.25"
7309 CX = 0x2709; // 40 tracks, 9 sectors
7310 SET_DH(1); // max head #
7313 case 2: // 1.2MB, 5.25"
7314 CX = 0x4f0f; // 80 tracks, 15 sectors
7315 SET_DH(1); // max head #
7318 case 3: // 720KB, 3.5"
7319 CX = 0x4f09; // 80 tracks, 9 sectors
7320 SET_DH(1); // max head #
7323 case 4: // 1.44MB, 3.5"
7324 CX = 0x4f12; // 80 tracks, 18 sectors
7325 SET_DH(1); // max head #
7328 case 5: // 2.88MB, 3.5"
7329 CX = 0x4f24; // 80 tracks, 36 sectors
7330 SET_DH(1); // max head #
7333 case 6: // 160k, 5.25"
7334 CX = 0x2708; // 40 tracks, 8 sectors
7335 SET_DH(0); // max head #
7338 case 7: // 180k, 5.25"
7339 CX = 0x2709; // 40 tracks, 9 sectors
7340 SET_DH(0); // max head #
7343 case 8: // 320k, 5.25"
7344 CX = 0x2708; // 40 tracks, 8 sectors
7345 SET_DH(1); // max head #
7349 BX_PANIC("floppy: int13: bad floppy type\n");
7352 /* set es & di to point to 11 byte diskette param table in ROM */
7356 mov ax, #diskette_param_table2
7357 mov _int13_diskette_function.DI+2[bp], ax
7358 mov _int13_diskette_function.ES+2[bp], cs
7361 CLEAR_CF(); // success
7362 /* disk status not changed upon success */
7366 case 0x15: // read diskette drive type
7367 BX_DEBUG_INT13_FL("floppy f15\n");
7370 SET_AH(0); // only 2 drives supported
7371 // set_diskette_ret_status here ???
7375 drive_type = inb_cmos(0x10);
7381 CLEAR_CF(); // successful, not present
7382 if (drive_type==0) {
7383 SET_AH(0); // drive not present
7386 SET_AH(1); // drive present, does not support change line
7391 case 0x16: // get diskette change line status
7392 BX_DEBUG_INT13_FL("floppy f16\n");
7395 SET_AH(0x01); // invalid drive
7396 set_diskette_ret_status(0x01);
7401 SET_AH(0x06); // change line not supported
7402 set_diskette_ret_status(0x06);
7406 case 0x17: // set diskette type for format(old)
7407 BX_DEBUG_INT13_FL("floppy f17\n");
7408 /* not used for 1.44M floppies */
7409 SET_AH(0x01); // not supported
7410 set_diskette_ret_status(1); /* not supported */
7414 case 0x18: // set diskette type for format(new)
7415 BX_DEBUG_INT13_FL("floppy f18\n");
7416 SET_AH(0x01); // do later
7417 set_diskette_ret_status(1);
7422 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7424 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7425 SET_AH(0x01); // ???
7426 set_diskette_ret_status(1);
7432 #else // #if BX_SUPPORT_FLOPPY
7434 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7435 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7439 switch ( GET_AH() ) {
7441 case 0x01: // Read Diskette Status
7443 val8 = read_byte(0x0000, 0x0441);
7452 write_byte(0x0000, 0x0441, 0x01);
7456 #endif // #if BX_SUPPORT_FLOPPY
7459 set_diskette_ret_status(value)
7462 write_byte(0x0040, 0x0041, value);
7466 set_diskette_current_cyl(drive, cyl)
7471 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7472 write_byte(0x0040, 0x0094+drive, cyl);
7476 determine_floppy_media(drive)
7480 Bit8u val8, DOR, ctrl_info;
7482 ctrl_info = read_byte(0x0040, 0x008F);
7490 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7493 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7497 if ( (ctrl_info & 0x04) != 0x04 ) {
7498 // Drive not determined means no drive exists, done.
7503 // check Main Status Register for readiness
7504 val8 = inb(0x03f4) & 0x80; // Main Status Register
7506 BX_PANIC("d_f_m: MRQ bit not set\n");
7510 // existing BDA values
7512 // turn on drive motor
7513 outb(0x03f2, DOR); // Digital Output Register
7516 BX_PANIC("d_f_m: OK so far\n");
7521 int17_function(regs, ds, iret_addr)
7522 pusha_regs_t regs; // regs pushed from PUSHA instruction
7523 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7524 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7526 Bit16u addr,timeout;
7533 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7534 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7535 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7536 if (regs.u.r8.ah == 0) {
7537 outb(addr, regs.u.r8.al);
7539 outb(addr+2, val8 | 0x01); // send strobe
7543 outb(addr+2, val8 & ~0x01);
7544 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7548 if (regs.u.r8.ah == 1) {
7550 outb(addr+2, val8 & ~0x04); // send init
7554 outb(addr+2, val8 | 0x04);
7557 regs.u.r8.ah = (val8 ^ 0x48);
7558 if (!timeout) regs.u.r8.ah |= 0x01;
7559 ClearCF(iret_addr.flags);
7561 SetCF(iret_addr.flags); // Unsupported
7565 // returns bootsegment in ax, drive in bl
7567 int19_function(bseqnr)
7570 Bit16u ebda_seg=read_word(0x0040,0x000E);
7579 // if BX_ELTORITO_BOOT is not defined, old behavior
7580 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7581 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7582 // 0: system boot sequence, first drive C: then A:
7583 // 1: system boot sequence, first drive A: then C:
7584 // else BX_ELTORITO_BOOT is defined
7585 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7586 // CMOS reg 0x3D & 0x0f : 1st boot device
7587 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7588 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7589 // boot device codes:
7590 // 0x00 : not defined
7591 // 0x01 : first floppy
7592 // 0x02 : first harddrive
7593 // 0x03 : first cdrom
7594 // else : boot failure
7596 // Get the boot sequence
7597 #if BX_ELTORITO_BOOT
7598 bootseq=inb_cmos(0x3d);
7599 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7601 if (bseqnr==2) bootseq >>= 4;
7602 if (bseqnr==3) bootseq >>= 8;
7603 if (bootseq<0x10) lastdrive = 1;
7604 bootdrv=0x00; bootcd=0;
7605 switch(bootseq & 0x0f) {
7606 case 0x01: bootdrv=0x00; bootcd=0; break;
7607 case 0x02: bootdrv=0x80; bootcd=0; break;
7608 case 0x03: bootdrv=0x00; bootcd=1; break;
7609 default: return 0x00000000;
7612 bootseq=inb_cmos(0x2d);
7618 bootdrv=0x00; bootcd=0;
7619 if((bootseq&0x20)==0) bootdrv=0x80;
7620 #endif // BX_ELTORITO_BOOT
7622 #if BX_ELTORITO_BOOT
7623 // We have to boot from cd
7625 status = cdrom_boot();
7628 if ( (status & 0x00ff) !=0 ) {
7629 print_cdromboot_failure(status);
7630 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7634 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7635 bootdrv = (Bit8u)(status>>8);
7638 #endif // BX_ELTORITO_BOOT
7640 // We have to boot from harddisk or floppy
7649 mov _int19_function.status + 2[bp], ax
7650 mov dl, _int19_function.bootdrv + 2[bp]
7651 mov ax, _int19_function.bootseg + 2[bp]
7652 mov es, ax ;; segment
7653 mov bx, #0x0000 ;; offset
7654 mov ah, #0x02 ;; function 2, read diskette sector
7655 mov al, #0x01 ;; read 1 sector
7656 mov ch, #0x00 ;; track 0
7657 mov cl, #0x01 ;; sector 1
7658 mov dh, #0x00 ;; head 0
7659 int #0x13 ;; read sector
7662 mov _int19_function.status + 2[bp], ax
7669 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7674 // check signature if instructed by cmos reg 0x38, only for floppy
7675 // bootchk = 1 : signature check disabled
7676 // bootchk = 0 : signature check enabled
7677 if (bootdrv != 0) bootchk = 0;
7678 else bootchk = inb_cmos(0x38) & 0x01;
7680 #if BX_ELTORITO_BOOT
7681 // if boot from cd, no signature check
7684 #endif // BX_ELTORITO_BOOT
7687 if (read_word(bootseg,0x1fe) != 0xaa55) {
7688 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7693 #if BX_ELTORITO_BOOT
7694 // Print out the boot string
7695 print_boot_device(bootcd, bootdrv);
7696 #else // BX_ELTORITO_BOOT
7697 print_boot_device(0, bootdrv);
7698 #endif // BX_ELTORITO_BOOT
7700 // return the boot segment
7701 return (((Bit32u)bootdrv) << 16) + bootseg;
7705 int1a_function(regs, ds, iret_addr)
7706 pusha_regs_t regs; // regs pushed from PUSHA instruction
7707 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7708 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7712 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);
7718 switch (regs.u.r8.ah) {
7719 case 0: // get current clock count
7723 regs.u.r16.cx = BiosData->ticks_high;
7724 regs.u.r16.dx = BiosData->ticks_low;
7725 regs.u.r8.al = BiosData->midnight_flag;
7726 BiosData->midnight_flag = 0; // reset flag
7731 ClearCF(iret_addr.flags); // OK
7734 case 1: // Set Current Clock Count
7738 BiosData->ticks_high = regs.u.r16.cx;
7739 BiosData->ticks_low = regs.u.r16.dx;
7740 BiosData->midnight_flag = 0; // reset flag
7745 ClearCF(iret_addr.flags); // OK
7749 case 2: // Read CMOS Time
7750 if (rtc_updating()) {
7751 SetCF(iret_addr.flags);
7755 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7756 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7757 regs.u.r8.ch = inb_cmos(0x04); // Hours
7758 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7760 regs.u.r8.al = regs.u.r8.ch;
7761 ClearCF(iret_addr.flags); // OK
7764 case 3: // Set CMOS Time
7765 // Using a debugger, I notice the following masking/setting
7766 // of bits in Status Register B, by setting Reg B to
7767 // a few values and getting its value after INT 1A was called.
7769 // try#1 try#2 try#3
7770 // before 1111 1101 0111 1101 0000 0000
7771 // after 0110 0010 0110 0010 0000 0010
7773 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7774 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7775 if (rtc_updating()) {
7777 // fall through as if an update were not in progress
7779 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7780 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7781 outb_cmos(0x04, regs.u.r8.ch); // Hours
7782 // Set Daylight Savings time enabled bit to requested value
7783 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7784 // (reg B already selected)
7785 outb_cmos(0x0b, val8);
7787 regs.u.r8.al = val8; // val last written to Reg B
7788 ClearCF(iret_addr.flags); // OK
7791 case 4: // Read CMOS Date
7793 if (rtc_updating()) {
7794 SetCF(iret_addr.flags);
7797 regs.u.r8.cl = inb_cmos(0x09); // Year
7798 regs.u.r8.dh = inb_cmos(0x08); // Month
7799 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7800 regs.u.r8.ch = inb_cmos(0x32); // Century
7801 regs.u.r8.al = regs.u.r8.ch;
7802 ClearCF(iret_addr.flags); // OK
7805 case 5: // Set CMOS Date
7806 // Using a debugger, I notice the following masking/setting
7807 // of bits in Status Register B, by setting Reg B to
7808 // a few values and getting its value after INT 1A was called.
7810 // try#1 try#2 try#3 try#4
7811 // before 1111 1101 0111 1101 0000 0010 0000 0000
7812 // after 0110 1101 0111 1101 0000 0010 0000 0000
7814 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7815 // My assumption: RegB = (RegB & 01111111b)
7816 if (rtc_updating()) {
7818 SetCF(iret_addr.flags);
7821 outb_cmos(0x09, regs.u.r8.cl); // Year
7822 outb_cmos(0x08, regs.u.r8.dh); // Month
7823 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7824 outb_cmos(0x32, regs.u.r8.ch); // Century
7825 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7826 outb_cmos(0x0b, val8);
7828 regs.u.r8.al = val8; // AL = val last written to Reg B
7829 ClearCF(iret_addr.flags); // OK
7832 case 6: // Set Alarm Time in CMOS
7833 // Using a debugger, I notice the following masking/setting
7834 // of bits in Status Register B, by setting Reg B to
7835 // a few values and getting its value after INT 1A was called.
7837 // try#1 try#2 try#3
7838 // before 1101 1111 0101 1111 0000 0000
7839 // after 0110 1111 0111 1111 0010 0000
7841 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7842 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7843 val8 = inb_cmos(0x0b); // Get Status Reg B
7846 // Alarm interrupt enabled already
7847 SetCF(iret_addr.flags); // Error: alarm in use
7850 if (rtc_updating()) {
7852 // fall through as if an update were not in progress
7854 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7855 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7856 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7857 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7858 // enable Status Reg B alarm bit, clear halt clock bit
7859 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7860 ClearCF(iret_addr.flags); // OK
7863 case 7: // Turn off Alarm
7864 // Using a debugger, I notice the following masking/setting
7865 // of bits in Status Register B, by setting Reg B to
7866 // a few values and getting its value after INT 1A was called.
7868 // try#1 try#2 try#3 try#4
7869 // before 1111 1101 0111 1101 0010 0000 0010 0010
7870 // after 0100 0101 0101 0101 0000 0000 0000 0010
7872 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7873 // My assumption: RegB = (RegB & 01010111b)
7874 val8 = inb_cmos(0x0b); // Get Status Reg B
7875 // clear clock-halt bit, disable alarm bit
7876 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7878 regs.u.r8.al = val8; // val last written to Reg B
7879 ClearCF(iret_addr.flags); // OK
7883 // real mode PCI BIOS functions now handled in assembler code
7884 // this C code handles the error code for information only
7885 if (regs.u.r8.bl == 0xff) {
7886 BX_INFO("PCI BIOS: PCI not present\n");
7887 } else if (regs.u.r8.bl == 0x81) {
7888 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7889 } else if (regs.u.r8.bl == 0x83) {
7890 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7891 } else if (regs.u.r8.bl == 0x86) {
7892 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7894 regs.u.r8.ah = regs.u.r8.bl;
7895 SetCF(iret_addr.flags);
7900 SetCF(iret_addr.flags); // Unsupported
7905 int70_function(regs, ds, iret_addr)
7906 pusha_regs_t regs; // regs pushed from PUSHA instruction
7907 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7908 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7910 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7911 Bit8u registerB = 0, registerC = 0;
7913 // Check which modes are enabled and have occurred.
7914 registerB = inb_cmos( 0xB );
7915 registerC = inb_cmos( 0xC );
7917 if( ( registerB & 0x60 ) != 0 ) {
7918 if( ( registerC & 0x20 ) != 0 ) {
7919 // Handle Alarm Interrupt.
7926 if( ( registerC & 0x40 ) != 0 ) {
7927 // Handle Periodic Interrupt.
7929 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7930 // Wait Interval (Int 15, AH=83) active.
7931 Bit32u time, toggle;
7933 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
7934 if( time < 0x3D1 ) {
7936 Bit16u segment, offset;
7938 offset = read_word( 0x40, 0x98 );
7939 segment = read_word( 0x40, 0x9A );
7940 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7941 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
7942 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
7944 // Continue waiting.
7946 write_dword( 0x40, 0x9C, time );
7959 ;------------------------------------------
7960 ;- INT74h : PS/2 mouse hardware interrupt -
7961 ;------------------------------------------
7966 push #0x00 ;; placeholder for status
7967 push #0x00 ;; placeholder for X
7968 push #0x00 ;; placeholder for Y
7969 push #0x00 ;; placeholder for Z
7970 push #0x00 ;; placeholder for make_far_call boolean
7971 call _int74_function
7972 pop cx ;; remove make_far_call from stack
7975 ;; make far call to EBDA:0022
7978 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
7980 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7985 add sp, #8 ;; pop status, x, y, z
7987 pop ds ;; restore DS
7992 ;; This will perform an IRET, but will retain value of current CF
7993 ;; by altering flags on stack. Better than RETF #02.
7998 and BYTE [bp + 0x06], #0xfe
8004 or BYTE [bp + 0x06], #0x01
8009 ;----------------------
8010 ;- INT13h (relocated) -
8011 ;----------------------
8013 ; int13_relocated is a little bit messed up since I played with it
8014 ; I have to rewrite it:
8015 ; - call a function that detect which function to call
8016 ; - make all called C function get the same parameters list
8020 #if BX_ELTORITO_BOOT
8021 ;; check for an eltorito function
8023 jb int13_not_eltorito
8025 ja int13_not_eltorito
8034 jmp _int13_eltorito ;; ELDX not used
8042 ;; check if emulation active
8043 call _cdemu_isactive
8045 je int13_cdemu_inactive
8047 ;; check if access to the emulated drive
8048 call _cdemu_emulated_drive
8051 cmp al,dl ;; int13 on emulated drive
8066 jmp _int13_cdemu ;; ELDX not used
8069 and dl,#0xE0 ;; mask to get device class, including cdroms
8070 cmp al,dl ;; al is 0x00 or 0x80
8071 jne int13_cdemu_inactive ;; inactive for device class
8083 dec dl ;; real drive is dl - 1
8086 int13_cdemu_inactive:
8092 #endif // BX_ELTORITO_BOOT
8103 push dx ;; push eltorito value of dx instead of sp
8114 ;; now the 16-bit registers can be restored with:
8115 ;; pop ds; pop es; popa; iret
8116 ;; arguments passed to functions should be
8117 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8123 jmp _int13_diskette_function
8132 // ebx is modified: BSD 5.2.1 boot loader problem
8133 // someone should figure out which 32 bit register that actually are used
8150 call _int13_harddisk
8162 int18_handler: ;; Boot Failure routing
8163 call _int18_panic_msg
8170 int19_relocated: ;; Boot function, relocated
8172 ;; int19 was beginning to be really complex, so now it
8173 ;; just calls an C function, that does the work
8174 ;; it returns in BL the boot drive, and in AX the boot segment
8175 ;; the boot segment will be 0x0000 if something has failed
8187 call _int19_function
8190 ;; bl contains the boot drive
8191 ;; ax contains the boot segment or 0 if failure
8193 test ax, ax ;; if ax is 0 try next boot device
8199 call _int19_function
8202 test ax, ax ;; if ax is 0 try next boot device
8208 call _int19_function
8211 test ax, ax ;; if ax is 0 call int18
8215 mov dl, bl ;; set drive so guest os find it
8216 shl eax, #0x04 ;; convert seg to ip
8217 mov 2[bp], ax ;; set ip
8219 shr eax, #0x04 ;; get cs back
8220 and ax, #0xF000 ;; remove what went in ip
8221 mov 4[bp], ax ;; set cs
8223 mov es, ax ;; set es to zero fixes [ 549815 ]
8224 mov [bp], ax ;; set bp to zero
8225 mov ax, #0xaa55 ;; set ok flag
8228 iret ;; Beam me up Scotty
8233 int1c_handler: ;; User Timer Tick
8237 ;----------------------
8238 ;- POST: Floppy Drive -
8239 ;----------------------
8245 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8247 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8249 mov 0x0440, al ;; diskette motor timeout counter: not active
8250 mov 0x0441, al ;; diskette controller status return code
8252 mov 0x0442, al ;; disk & diskette controller status register 0
8253 mov 0x0443, al ;; diskette controller status register 1
8254 mov 0x0444, al ;; diskette controller status register 2
8255 mov 0x0445, al ;; diskette controller cylinder number
8256 mov 0x0446, al ;; diskette controller head number
8257 mov 0x0447, al ;; diskette controller sector number
8258 mov 0x0448, al ;; diskette controller bytes written
8260 mov 0x048b, al ;; diskette configuration data
8262 ;; -----------------------------------------------------------------
8263 ;; (048F) diskette controller information
8265 mov al, #0x10 ;; get CMOS diskette drive type
8268 mov ah, al ;; save byte to AH
8271 shr al, #4 ;; look at top 4 bits for drive 0
8272 jz f0_missing ;; jump if no drive0
8273 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8276 mov bl, #0x00 ;; no drive0
8279 mov al, ah ;; restore from AH
8280 and al, #0x0f ;; look at bottom 4 bits for drive 1
8281 jz f1_missing ;; jump if no drive1
8282 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8284 ;; leave high bits in BL zerod
8285 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8286 ;; -----------------------------------------------------------------
8289 mov 0x0490, al ;; diskette 0 media state
8290 mov 0x0491, al ;; diskette 1 media state
8292 ;; diskette 0,1 operational starting state
8293 ;; drive type has not been determined,
8294 ;; has no changed detection line
8298 mov 0x0494, al ;; diskette 0 current cylinder
8299 mov 0x0495, al ;; diskette 1 current cylinder
8302 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8304 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8305 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8306 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8311 ;--------------------
8312 ;- POST: HARD DRIVE -
8313 ;--------------------
8314 ; relocated here because the primary POST area isnt big enough.
8317 // INT 76h calls INT 15h function ax=9100
8319 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8325 mov 0x0474, al /* hard disk status of last operation */
8326 mov 0x0477, al /* hard disk port offset (XT only ???) */
8327 mov 0x048c, al /* hard disk status register */
8328 mov 0x048d, al /* hard disk error register */
8329 mov 0x048e, al /* hard disk task complete flag */
8331 mov 0x0475, al /* hard disk number attached */
8333 mov 0x0476, al /* hard disk control byte */
8334 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8335 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8336 ;; INT 41h: hard disk 0 configuration pointer
8337 ;; INT 46h: hard disk 1 configuration pointer
8338 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8339 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8341 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8353 cmp al, #47 ;; decimal 47 - user definable
8357 ;; CMOS purpose param table offset
8358 ;; 1b cylinders low 0
8359 ;; 1c cylinders high 1
8361 ;; 1e write pre-comp low 5
8362 ;; 1f write pre-comp high 6
8363 ;; 20 retries/bad map/heads>8 8
8364 ;; 21 landing zone low C
8365 ;; 22 landing zone high D
8366 ;; 23 sectors/track E
8371 ;;; Filling EBDA table for hard disk 0.
8379 mov (0x003d + 0x05), ax ;; write precomp word
8384 mov (0x003d + 0x08), al ;; drive control byte
8393 mov (0x003d + 0x0C), ax ;; landing zone word
8395 mov al, #0x1c ;; get cylinders word in AX
8397 in al, #0x71 ;; high byte
8401 in al, #0x71 ;; low byte
8402 mov bx, ax ;; BX = cylinders
8407 mov cl, al ;; CL = heads
8412 mov dl, al ;; DL = sectors
8415 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8417 hd0_post_physical_chs:
8418 ;; no logical CHS mapping used, just physical CHS
8419 ;; use Standard Fixed Disk Parameter Table (FDPT)
8420 mov (0x003d + 0x00), bx ;; number of physical cylinders
8421 mov (0x003d + 0x02), cl ;; number of physical heads
8422 mov (0x003d + 0x0E), dl ;; number of physical sectors
8425 hd0_post_logical_chs:
8426 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8427 mov (0x003d + 0x09), bx ;; number of physical cylinders
8428 mov (0x003d + 0x0b), cl ;; number of physical heads
8429 mov (0x003d + 0x04), dl ;; number of physical sectors
8430 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8432 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8435 jnbe hd0_post_above_2048
8436 ;; 1024 < c <= 2048 cylinders
8439 jmp hd0_post_store_logical
8441 hd0_post_above_2048:
8443 jnbe hd0_post_above_4096
8444 ;; 2048 < c <= 4096 cylinders
8447 jmp hd0_post_store_logical
8449 hd0_post_above_4096:
8451 jnbe hd0_post_above_8192
8452 ;; 4096 < c <= 8192 cylinders
8455 jmp hd0_post_store_logical
8457 hd0_post_above_8192:
8458 ;; 8192 < c <= 16384 cylinders
8462 hd0_post_store_logical:
8463 mov (0x003d + 0x00), bx ;; number of physical cylinders
8464 mov (0x003d + 0x02), cl ;; number of physical heads
8466 mov cl, #0x0f ;; repeat count
8467 mov si, #0x003d ;; offset to disk0 FDPT
8468 mov al, #0x00 ;; sum
8469 hd0_post_checksum_loop:
8473 jnz hd0_post_checksum_loop
8474 not al ;; now take 2s complement
8477 ;;; Done filling EBDA table for hard disk 0.
8481 ;; is there really a second hard disk? if not, return now
8489 ;; check that the hd type is really 0x0f.
8494 ;; check that the extended type is 47 - user definable
8498 cmp al, #47 ;; decimal 47 - user definable
8503 ;; CMOS purpose param table offset
8504 ;; 0x24 cylinders low 0
8505 ;; 0x25 cylinders high 1
8507 ;; 0x27 write pre-comp low 5
8508 ;; 0x28 write pre-comp high 6
8510 ;; 0x2a landing zone low C
8511 ;; 0x2b landing zone high D
8512 ;; 0x2c sectors/track E
8513 ;;; Fill EBDA table for hard disk 1.
8523 mov (0x004d + 0x05), ax ;; write precomp word
8528 mov (0x004d + 0x08), al ;; drive control byte
8537 mov (0x004d + 0x0C), ax ;; landing zone word
8539 mov al, #0x25 ;; get cylinders word in AX
8541 in al, #0x71 ;; high byte
8545 in al, #0x71 ;; low byte
8546 mov bx, ax ;; BX = cylinders
8551 mov cl, al ;; CL = heads
8556 mov dl, al ;; DL = sectors
8559 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8561 hd1_post_physical_chs:
8562 ;; no logical CHS mapping used, just physical CHS
8563 ;; use Standard Fixed Disk Parameter Table (FDPT)
8564 mov (0x004d + 0x00), bx ;; number of physical cylinders
8565 mov (0x004d + 0x02), cl ;; number of physical heads
8566 mov (0x004d + 0x0E), dl ;; number of physical sectors
8569 hd1_post_logical_chs:
8570 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8571 mov (0x004d + 0x09), bx ;; number of physical cylinders
8572 mov (0x004d + 0x0b), cl ;; number of physical heads
8573 mov (0x004d + 0x04), dl ;; number of physical sectors
8574 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8576 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8579 jnbe hd1_post_above_2048
8580 ;; 1024 < c <= 2048 cylinders
8583 jmp hd1_post_store_logical
8585 hd1_post_above_2048:
8587 jnbe hd1_post_above_4096
8588 ;; 2048 < c <= 4096 cylinders
8591 jmp hd1_post_store_logical
8593 hd1_post_above_4096:
8595 jnbe hd1_post_above_8192
8596 ;; 4096 < c <= 8192 cylinders
8599 jmp hd1_post_store_logical
8601 hd1_post_above_8192:
8602 ;; 8192 < c <= 16384 cylinders
8606 hd1_post_store_logical:
8607 mov (0x004d + 0x00), bx ;; number of physical cylinders
8608 mov (0x004d + 0x02), cl ;; number of physical heads
8610 mov cl, #0x0f ;; repeat count
8611 mov si, #0x004d ;; offset to disk0 FDPT
8612 mov al, #0x00 ;; sum
8613 hd1_post_checksum_loop:
8617 jnz hd1_post_checksum_loop
8618 not al ;; now take 2s complement
8621 ;;; Done filling EBDA table for hard disk 1.
8625 ;--------------------
8626 ;- POST: EBDA segment
8627 ;--------------------
8628 ; relocated here because the primary POST area isnt big enough.
8633 mov byte ptr [0x0], #EBDA_SIZE
8635 xor ax, ax ; mov EBDA seg into 40E
8637 mov word ptr [0x40E], #EBDA_SEG
8640 ;--------------------
8641 ;- POST: EOI + jmp via [0x40:67)
8642 ;--------------------
8643 ; relocated here because the primary POST area isnt big enough.
8653 ;--------------------
8656 out #0xA0, al ;; slave PIC EOI
8659 out #0x20, al ;; master PIC EOI
8662 ;--------------------
8664 ;; in: AL in BCD format
8665 ;; out: AL in binary format, AH will always be 0
8668 and bl, #0x0f ;; bl has low digit
8669 shr al, #4 ;; al has high digit
8671 mul al, bh ;; multiply high digit by 10 (result in AX)
8672 add al, bl ;; then add low digit
8675 ;--------------------
8677 ;; Setup the Timer Ticks Count (0x46C:dword) and
8678 ;; Timer Ticks Roller Flag (0x470:byte)
8679 ;; The Timer Ticks Count needs to be set according to
8680 ;; the current CMOS time, as if ticks have been occurring
8681 ;; at 18.2hz since midnight up to this point. Calculating
8682 ;; this is a little complicated. Here are the factors I gather
8683 ;; regarding this. 14,318,180 hz was the original clock speed,
8684 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8685 ;; at the time, or 4 to drive the CGA video adapter. The div3
8686 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8687 ;; the timer. With a maximum 16bit timer count, this is again
8688 ;; divided down by 65536 to 18.2hz.
8690 ;; 14,318,180 Hz clock
8691 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8692 ;; /4 = 1,193,181 Hz fed to timer
8693 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8694 ;; 1 second = 18.20650736 ticks
8695 ;; 1 minute = 1092.390442 ticks
8696 ;; 1 hour = 65543.42651 ticks
8698 ;; Given the values in the CMOS clock, one could calculate
8699 ;; the number of ticks by the following:
8700 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8701 ;; (BcdToBin(minutes) * 1092.3904)
8702 ;; (BcdToBin(hours) * 65543.427)
8703 ;; To get a little more accuracy, since Im using integer
8704 ;; arithmatic, I use:
8705 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8706 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8707 ;; (BcdToBin(hours) * 65543427) / 1000
8712 xor eax, eax ;; clear EAX
8715 in al, #0x71 ;; AL has CMOS seconds in BCD
8716 call BcdToBin ;; EAX now has seconds in binary
8722 mov ecx, eax ;; ECX will accumulate total ticks
8725 xor eax, eax ;; clear EAX
8728 in al, #0x71 ;; AL has CMOS minutes in BCD
8729 call BcdToBin ;; EAX now has minutes in binary
8735 add ecx, eax ;; add to total ticks
8738 xor eax, eax ;; clear EAX
8741 in al, #0x71 ;; AL has CMOS hours in BCD
8742 call BcdToBin ;; EAX now has hours in binary
8748 add ecx, eax ;; add to total ticks
8750 mov 0x46C, ecx ;; Timer Ticks Count
8752 mov 0x470, al ;; Timer Ticks Rollover Flag
8755 ;--------------------
8757 ;; record completion in BIOS task complete flag
8769 ;--------------------
8774 #include "apmbios.S"
8778 #include "apmbios.S"
8781 #include "apmbios.S"
8785 ;--------------------
8790 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8791 dw bios32_entry_point, 0xf ;; 32 bit physical address
8792 db 0 ;; revision level
8793 ;; length in paragraphs and checksum stored in a word to prevent errors
8794 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8795 & 0xff) << 8) + 0x01
8796 db 0,0,0,0,0 ;; reserved
8801 cmp eax, #0x49435024
8803 mov eax, #0x80000000
8808 cmp eax, #0x12378086
8810 mov ebx, #0x000f0000
8812 mov edx, #pcibios_protected
8827 cmp al, #0x01 ;; installation check
8831 mov edx, #0x20494350
8834 pci_pro_f02: ;; find pci device
8842 call pci_pro_select_reg
8856 pci_pro_f08: ;; read configuration byte
8859 call pci_pro_select_reg
8868 pci_pro_f09: ;; read configuration word
8871 call pci_pro_select_reg
8880 pci_pro_f0a: ;; read configuration dword
8883 call pci_pro_select_reg
8890 pci_pro_f0b: ;; write configuration byte
8893 call pci_pro_select_reg
8902 pci_pro_f0c: ;; write configuration word
8905 call pci_pro_select_reg
8914 pci_pro_f0d: ;; write configuration dword
8917 call pci_pro_select_reg
8960 mov eax, #0x80000000
8965 cmp eax, #0x12378086
8975 cmp al, #0x01 ;; installation check
8980 mov edx, #0x20494350
8982 mov di, #pcibios_protected
8985 pci_real_f02: ;; find pci device
8995 call pci_real_select_reg
8999 jne pci_real_nextdev
9006 jne pci_real_devloop
9011 pci_real_f08: ;; read configuration byte
9014 call pci_real_select_reg
9023 pci_real_f09: ;; read configuration word
9026 call pci_real_select_reg
9035 pci_real_f0a: ;; read configuration dword
9038 call pci_real_select_reg
9045 pci_real_f0b: ;; write configuration byte
9048 call pci_real_select_reg
9057 pci_real_f0c: ;; write configuration word
9060 call pci_real_select_reg
9069 pci_real_f0d: ;; write configuration dword
9071 jne pci_real_unknown
9072 call pci_real_select_reg
9093 pci_real_select_reg:
9107 pci_routing_table_structure:
9108 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9110 dw 32 + (6 * 16) ;; table size
9111 db 0 ;; PCI interrupt router bus
9112 db 0x08 ;; PCI interrupt router DevFunc
9113 dw 0x0000 ;; PCI exclusive IRQs
9114 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9115 dw 0x7000 ;; compatible PCI interrupt router device ID
9116 dw 0,0 ;; Miniport data
9117 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9119 ;; first slot entry PCI-to-ISA (embedded)
9120 db 0 ;; pci bus number
9121 db 0x08 ;; pci device number (bit 7-3)
9122 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9123 dw 0xdef8 ;; IRQ bitmap INTA#
9124 db 0x61 ;; link value INTB#
9125 dw 0xdef8 ;; IRQ bitmap INTB#
9126 db 0x62 ;; link value INTC#
9127 dw 0xdef8 ;; IRQ bitmap INTC#
9128 db 0x63 ;; link value INTD#
9129 dw 0xdef8 ;; IRQ bitmap INTD#
9130 db 0 ;; physical slot (0 = embedded)
9132 ;; second slot entry: 1st PCI slot
9133 db 0 ;; pci bus number
9134 db 0x10 ;; pci device number (bit 7-3)
9135 db 0x61 ;; link value INTA#
9136 dw 0xdef8 ;; IRQ bitmap INTA#
9137 db 0x62 ;; link value INTB#
9138 dw 0xdef8 ;; IRQ bitmap INTB#
9139 db 0x63 ;; link value INTC#
9140 dw 0xdef8 ;; IRQ bitmap INTC#
9141 db 0x60 ;; link value INTD#
9142 dw 0xdef8 ;; IRQ bitmap INTD#
9143 db 1 ;; physical slot (0 = embedded)
9145 ;; third slot entry: 2nd PCI slot
9146 db 0 ;; pci bus number
9147 db 0x18 ;; pci device number (bit 7-3)
9148 db 0x62 ;; link value INTA#
9149 dw 0xdef8 ;; IRQ bitmap INTA#
9150 db 0x63 ;; link value INTB#
9151 dw 0xdef8 ;; IRQ bitmap INTB#
9152 db 0x60 ;; link value INTC#
9153 dw 0xdef8 ;; IRQ bitmap INTC#
9154 db 0x61 ;; link value INTD#
9155 dw 0xdef8 ;; IRQ bitmap INTD#
9156 db 2 ;; physical slot (0 = embedded)
9158 ;; 4th slot entry: 3rd PCI slot
9159 db 0 ;; pci bus number
9160 db 0x20 ;; pci device number (bit 7-3)
9161 db 0x63 ;; link value INTA#
9162 dw 0xdef8 ;; IRQ bitmap INTA#
9163 db 0x60 ;; link value INTB#
9164 dw 0xdef8 ;; IRQ bitmap INTB#
9165 db 0x61 ;; link value INTC#
9166 dw 0xdef8 ;; IRQ bitmap INTC#
9167 db 0x62 ;; link value INTD#
9168 dw 0xdef8 ;; IRQ bitmap INTD#
9169 db 3 ;; physical slot (0 = embedded)
9171 ;; 5th slot entry: 4rd PCI slot
9172 db 0 ;; pci bus number
9173 db 0x28 ;; pci device number (bit 7-3)
9174 db 0x60 ;; link value INTA#
9175 dw 0xdef8 ;; IRQ bitmap INTA#
9176 db 0x61 ;; link value INTB#
9177 dw 0xdef8 ;; IRQ bitmap INTB#
9178 db 0x62 ;; link value INTC#
9179 dw 0xdef8 ;; IRQ bitmap INTC#
9180 db 0x63 ;; link value INTD#
9181 dw 0xdef8 ;; IRQ bitmap INTD#
9182 db 4 ;; physical slot (0 = embedded)
9184 ;; 6th slot entry: 5rd PCI slot
9185 db 0 ;; pci bus number
9186 db 0x30 ;; pci device number (bit 7-3)
9187 db 0x61 ;; link value INTA#
9188 dw 0xdef8 ;; IRQ bitmap INTA#
9189 db 0x62 ;; link value INTB#
9190 dw 0xdef8 ;; IRQ bitmap INTB#
9191 db 0x63 ;; link value INTC#
9192 dw 0xdef8 ;; IRQ bitmap INTC#
9193 db 0x60 ;; link value INTD#
9194 dw 0xdef8 ;; IRQ bitmap INTD#
9195 db 5 ;; physical slot (0 = embedded)
9201 pcibios_init_sel_reg:
9213 pcibios_init_set_elcr:
9237 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9242 mov si, #pci_routing_table_structure
9246 call pcibios_init_sel_reg
9249 cmp eax, [si+12] ;; check irq router
9252 call pcibios_init_sel_reg
9253 push bx ;; save irq router bus + devfunc
9256 out dx, ax ;; reset PIRQ route control
9264 add si, #0x20 ;; set pointer to 1st entry
9266 mov ax, #pci_irq_list
9275 call pcibios_init_sel_reg
9279 jnz pci_test_int_pin
9285 call pcibios_init_sel_reg
9290 dec al ;; determine pirq reg
9299 call pcibios_init_sel_reg
9306 mov bx, [bp-2] ;; pci irq list pointer
9311 call pcibios_init_set_elcr
9315 add bl, [bp-3] ;; pci function number
9317 call pcibios_init_sel_reg
9327 mov byte ptr[bp-3], #0x00
9335 #endif // BX_PCIBIOS
9337 ; parallel port detection: base address in DX, index in BX, timeout in CL
9342 and al, #0xdf ; clear input mode
9352 mov [bx+0x408], dx ; Parallel I/O address
9354 mov [bx+0x478], cl ; Parallel printer timeout
9359 ; serial port detection: base address in DX, index in BX, timeout in CL
9361 ; no serial port in the VM -PAD
9381 mov [bx+0x400], dx ; Serial I/O address
9383 mov [bx+0x47c], cl ; Serial timeout
9410 ;; Scan for existence of valid expansion ROMS.
9411 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9412 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9413 ;; System ROM: only 0xE0000
9419 ;; 2 ROM length in 512-byte blocks
9420 ;; 3 ROM initialization entry point (FAR CALL)
9425 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9426 cmp [0], #0xAA55 ;; look for signature
9427 jne rom_scan_increment
9429 jnz rom_scan_increment
9430 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9432 ;; We want our increment in 512-byte quantities, rounded to
9433 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9435 jz block_count_rounded
9436 and al, #0xfc ;; needs rounding up
9438 block_count_rounded:
9440 xor bx, bx ;; Restore DS back to 0000:
9443 ;; Push addr of ROM entry point
9445 push #0x0003 ;; Push offset
9446 mov bp, sp ;; Call ROM init routine using seg:off on stack
9447 db 0xff ;; call_far ss:[bp+0]
9450 cli ;; In case expansion ROM BIOS turns IF on
9451 add sp, #2 ;; Pop offset value
9452 pop cx ;; Pop seg value (restore CX)
9453 pop ax ;; Restore AX
9455 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9456 ;; because the segment selector is shifted left 4 bits.
9461 xor ax, ax ;; Restore DS back to 0000:
9467 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9468 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9469 ; but the tables themeselves can be elsewhere.
9478 mov cx, #0x001f ; 0x1f bytes to copy
9480 mov es, ax ; destination segment is 0xf0000
9481 mov di, #smbios_entry_point ; destination offset
9483 mov ds, ax ; source segment is 0x9f000
9484 mov si, #0x0000 ; source offset is 0
9502 ;; for 'C' strings and other data, insert them here with
9503 ;; a the following hack:
9504 ;; DATA_SEG_DEFS_HERE
9510 .org 0xe05b ; POST Entry Point
9515 ;; first reset the DMA controllers
9519 ;; then initialize the DMA controllers
9521 out 0xD6, al ; cascade mode of channel 4 enabled
9523 out 0xD4, al ; unmask channel 4
9525 ;; Examine CMOS shutdown status.
9533 ;; Reset CMOS shutdown status.
9535 out 0x70, AL ; select CMOS register Fh
9537 out 0x71, AL ; set shutdown action to normal
9539 ;; Examine CMOS shutdown status.
9542 ;; 0x00, 0x09, 0x0D+ = normal startup
9550 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9554 ;; Examine CMOS shutdown status.
9555 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9557 call _shutdown_status_panic
9563 ; 0xb0, 0x20, /* mov al, #0x20 */
9564 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9574 ; case 0: normal startup
9583 ;; zero out BIOS data area (40:00..40:ff)
9585 mov cx, #0x0080 ;; 128 words
9591 call _log_bios_start
9593 ;; set all interrupts to default handler
9594 mov bx, #0x0000 ;; offset index
9595 mov cx, #0x0100 ;; counter (256 interrupts)
9596 mov ax, #dummy_iret_handler
9606 loop post_default_ints
9608 ;; set vector 0x79 to zero
9609 ;; this is used by 'gardian angel' protection system
9610 SET_INT_VECTOR(0x79, #0, #0)
9612 ;; base memory in K 40:13 (word)
9613 mov ax, #BASE_MEM_IN_K
9617 ;; Manufacturing Test 40:12
9620 ;; Warm Boot Flag 0040:0072
9621 ;; value of 1234h = skip memory checks
9625 ;; Printer Services vector
9626 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9628 ;; Bootstrap failure vector
9629 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9631 ;; Bootstrap Loader vector
9632 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9634 ;; User Timer Tick vector
9635 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9637 ;; Memory Size Check vector
9638 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9640 ;; Equipment Configuration Check vector
9641 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9644 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9650 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9651 ;; int 1C already points at dummy_iret_handler (above)
9652 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9655 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9660 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9666 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9667 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9671 mov 0x0417, al /* keyboard shift flags, set 1 */
9672 mov 0x0418, al /* keyboard shift flags, set 2 */
9673 mov 0x0419, al /* keyboard alt-numpad work area */
9674 mov 0x0471, al /* keyboard ctrl-break flag */
9675 mov 0x0497, al /* keyboard status flags 4 */
9677 mov 0x0496, al /* keyboard status flags 3 */
9680 /* keyboard head of buffer pointer */
9684 /* keyboard end of buffer pointer */
9687 /* keyboard pointer to start of buffer */
9691 /* keyboard pointer to end of buffer */
9695 /* init the keyboard */
9698 ;; mov CMOS Equipment Byte to BDA Equipment Word
9707 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9711 mov cl, #0x14 ; timeout value
9712 mov dx, #0x378 ; Parallel I/O address, port 1
9714 mov dx, #0x278 ; Parallel I/O address, port 2
9717 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9719 or ax, bx ; set number of parallel ports
9723 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9724 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9726 mov cl, #0x0a ; timeout value
9727 mov dx, #0x03f8 ; Serial I/O address, port 1
9729 mov dx, #0x02f8 ; Serial I/O address, port 2
9731 mov dx, #0x03e8 ; Serial I/O address, port 3
9733 mov dx, #0x02e8 ; Serial I/O address, port 4
9736 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9738 or ax, bx ; set number of serial port
9742 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9743 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9744 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9745 ;; BIOS DATA AREA 0x4CE ???
9746 call timer_tick_post
9749 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9751 ;; IRQ13 (FPU exception) setup
9752 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9755 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9760 mov al, #0x11 ; send initialisation commands
9775 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9776 #if BX_USE_PS2_MOUSE
9781 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9784 call _copy_e820_table
9803 call _print_bios_banner
9808 call floppy_drive_post
9815 call hard_drive_post
9818 ;; ATA/ATAPI driver setup
9823 #else // BX_USE_ATADRV
9828 call hard_drive_post
9830 #endif // BX_USE_ATADRV
9832 #if BX_ELTORITO_BOOT
9834 ;; eltorito floppy/harddisk emulation from cd
9838 #endif // BX_ELTORITO_BOOT
9841 //JMP_EP(0x0064) ; INT 19h location
9844 .org 0xe2c3 ; NMI Handler Entry Point
9846 ;; FIXME the NMI handler should not panic
9847 ;; but iret when called from int75 (fpu exception)
9848 call _nmi_handler_msg
9852 out 0xf0, al // clear irq13
9853 call eoi_both_pics // clear interrupt
9854 int 2 // legacy nmi call
9857 ;-------------------------------------------
9858 ;- INT 13h Fixed Disk Services Entry Point -
9859 ;-------------------------------------------
9860 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9862 //JMPL(int13_relocated)
9865 .org 0xe401 ; Fixed Disk Parameter Table
9870 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9874 ;-------------------------------------------
9875 ;- System BIOS Configuration Data Table
9876 ;-------------------------------------------
9877 .org BIOS_CONFIG_TABLE
9878 db 0x08 ; Table size (bytes) -Lo
9879 db 0x00 ; Table size (bytes) -Hi
9884 ; b7: 1=DMA channel 3 used by hard disk
9885 ; b6: 1=2 interrupt controllers present
9887 ; b4: 1=BIOS calls int 15h/4Fh every key
9888 ; b3: 1=wait for extern event supported (Int 15h/41h)
9889 ; b2: 1=extended BIOS data area used
9890 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9891 ; b0: 1=Dual bus (MicroChannel + ISA)
9895 (BX_CALL_INT15_4F << 4) | \
9897 (BX_USE_EBDA << 2) | \
9901 ; b7: 1=32-bit DMA supported
9902 ; b6: 1=int16h, function 9 supported
9903 ; b5: 1=int15h/C6h (get POS data) supported
9904 ; b4: 1=int15h/C7h (get mem map info) supported
9905 ; b3: 1=int15h/C8h (en/dis CPU) supported
9906 ; b2: 1=non-8042 kb controller
9907 ; b1: 1=data streaming supported
9921 ; b4: POST supports ROM-to-RAM enable/disable
9922 ; b3: SCSI on system board
9923 ; b2: info panel installed
9924 ; b1: Initial Machine Load (IML) system - BIOS on disk
9925 ; b0: SCSI supported in IML
9929 ; b6: EEPROM present
9930 ; b5-3: ABIOS presence (011 = not supported)
9932 ; b1: memory split above 16Mb supported
9933 ; b0: POSTEXT directly supported by POST
9935 ; Feature byte 5 (IBM)
9936 ; b1: enhanced mouse
9942 .org 0xe729 ; Baud Rate Generator Table
9947 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
9953 call _int14_function
9959 ;----------------------------------------
9960 ;- INT 16h Keyboard Service Entry Point -
9961 ;----------------------------------------
9977 call _int16_function
9987 and BYTE [bp + 0x06], #0xbf
9995 or BYTE [bp + 0x06], #0x40
10003 int16_wait_for_key:
10007 jne int16_key_found
10011 /* no key yet, call int 15h, function AX=9002 */
10012 0x50, /* push AX */
10013 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10014 0xcd, 0x15, /* int 15h */
10016 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10018 jmp int16_wait_for_key
10023 call _int16_function
10028 /* notify int16 complete w/ int 15h, function AX=9102 */
10029 0x50, /* push AX */
10030 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10031 0xcd, 0x15, /* int 15h */
10038 ;-------------------------------------------------
10039 ;- INT09h : Keyboard Hardware Service Entry Point -
10040 ;-------------------------------------------------
10046 mov al, #0xAD ;;disable keyboard
10055 in al, #0x60 ;;read key from keyboard controller
10056 //test al, #0x80 ;;look for key release
10057 //jnz int09_process_key ;; dont pass releases to intercept?
10059 ;; check for extended key
10061 jne int09_call_int15_4f
10066 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10068 mov BYTE [0x496], al
10071 in al, #0x60 ;;read another key from keyboard controller
10075 int09_call_int15_4f:
10078 #ifdef BX_CALL_INT15_4F
10079 mov ah, #0x4f ;; allow for keyboard intercept
10086 //int09_process_key:
10089 call _int09_function
10095 call eoi_master_pic
10098 mov al, #0xAE ;;enable keyboard
10106 ;----------------------------------------
10107 ;- INT 13h Diskette Service Entry Point -
10108 ;----------------------------------------
10111 jmp int13_noeltorito
10113 ;---------------------------------------------
10114 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10115 ;---------------------------------------------
10116 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10126 mov al, #0x08 ; sense interrupt status
10144 mov ax, #0x0000 ;; segment 0000
10146 call eoi_master_pic
10148 or al, #0x80 ;; diskette interrupt has occurred
10156 .org 0xefc7 ; Diskette Controller Parameter Table
10157 diskette_param_table:
10158 ;; Since no provisions are made for multiple drive types, most
10159 ;; values in this table are ignored. I set parameters for 1.44M
10162 db 0x02 ;; head load time 0000001, DMA used
10174 ;----------------------------------------
10175 ;- INT17h : Printer Service Entry Point -
10176 ;----------------------------------------
10183 call _int17_function
10188 diskette_param_table2:
10189 ;; New diskette parameter table adding 3 parameters from IBM
10190 ;; Since no provisions are made for multiple drive types, most
10191 ;; values in this table are ignored. I set parameters for 1.44M
10194 db 0x02 ;; head load time 0000001, DMA used
10204 db 79 ;; maximum track
10205 db 0 ;; data transfer rate
10206 db 4 ;; drive type in cmos
10208 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10215 .org 0xf065 ; INT 10h Video Support Service Entry Point
10217 ;; dont do anything, since the VGA BIOS handles int10h requests
10220 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10225 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10226 ; ??? different for Pentium (machine check)?
10238 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10250 .org 0xf859 ; INT 15h System Services Entry Point
10264 #if BX_USE_PS2_MOUSE
10266 je int15_handler_mouse
10268 call _int15_function
10269 int15_handler_mouse_ret:
10271 int15_handler32_ret:
10281 #if BX_USE_PS2_MOUSE
10282 int15_handler_mouse:
10283 call _int15_function_mouse
10284 jmp int15_handler_mouse_ret
10289 call _int15_function32
10291 jmp int15_handler32_ret
10293 ;; Protected mode IDT descriptor
10295 ;; I just make the limit 0, so the machine will shutdown
10296 ;; if an exception occurs during protected mode memory
10299 ;; Set base to f0000 to correspond to beginning of BIOS,
10300 ;; in case I actually define an IDT later
10304 dw 0x0000 ;; limit 15:00
10305 dw 0x0000 ;; base 15:00
10306 db 0x0f ;; base 23:16
10308 ;; Real mode IDT descriptor
10310 ;; Set to typical real-mode values.
10315 dw 0x03ff ;; limit 15:00
10316 dw 0x0000 ;; base 15:00
10317 db 0x00 ;; base 23:16
10323 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10336 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10337 mov ds, ax ; on 16bit protected mode.
10338 jmp int1a_callfunction
10345 int1a_callfunction:
10346 call _int1a_function
10352 ;; int70h: IRQ8 - CMOS RTC
10359 call _int70_function
10367 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10375 ;; time to turn off drive(s)?
10378 jz int08_floppy_off
10381 jnz int08_floppy_off
10382 ;; turn motor(s) off
10391 mov eax, 0x046c ;; get ticks dword
10394 ;; compare eax to one days worth of timer ticks at 18.2 hz
10395 cmp eax, #0x001800B0
10396 jb int08_store_ticks
10397 ;; there has been a midnight rollover at this point
10398 xor eax, eax ;; zero out counter
10399 inc BYTE 0x0470 ;; increment rollover flag
10402 mov 0x046c, eax ;; store new ticks dword
10403 ;; chain to user timer tick INT #0x1c
10405 //;; call_ep [ds:loc]
10406 //CALL_EP( 0x1c << 2 )
10409 call eoi_master_pic
10414 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10418 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10420 ;------------------------------------------------
10421 ;- IRET Instruction for Dummy Interrupt Handler -
10422 ;------------------------------------------------
10423 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10424 dummy_iret_handler:
10427 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10436 .org 0xfff0 ; Power-up Entry Point
10443 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10444 .ascii BIOS_BUILD_DATE
10446 .org 0xfffe ; System Model ID
10450 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10453 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10454 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10455 * This font is public domain
10457 static Bit8u vgafont8[128*8]=
10459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10460 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10461 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10462 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10463 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10464 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10465 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10466 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10467 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10468 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10469 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10470 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10471 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10472 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10473 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10474 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10475 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10476 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10477 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10478 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10479 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10480 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10481 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10482 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10483 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10484 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10485 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10486 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10487 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10488 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10489 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10490 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10492 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10493 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10494 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10495 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10496 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10497 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10498 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10499 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10500 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10501 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10502 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10503 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10504 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10505 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10506 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10507 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10508 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10509 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10510 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10511 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10512 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10513 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10514 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10515 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10516 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10517 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10518 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10519 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10520 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10521 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10522 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10523 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10524 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10525 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10526 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10527 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10528 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10529 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10530 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10531 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10532 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10533 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10534 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10535 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10536 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10537 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10538 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10539 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10540 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10541 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10542 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10543 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10544 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10545 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10546 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10547 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10548 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10549 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10550 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10551 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10552 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10553 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10555 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10556 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10557 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10558 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10559 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10560 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10561 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10562 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10563 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10564 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10565 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10566 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10567 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10568 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10569 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10570 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10571 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10572 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10573 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10574 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10575 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10576 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10577 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10578 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10579 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10580 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10581 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10582 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10583 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10584 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10585 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10586 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10592 // just carve out some blank space for HVMLOADER to write the MP tables to
10594 // NOTE: There should be enough space for a 32 processor entry MP table
10598 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10599 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
10600 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
10601 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
10602 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
10603 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
10604 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
10605 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
10606 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
10607 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
10608 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
10609 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
10610 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
10611 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
10612 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
10615 smbios_entry_point:
10616 db 0,0,0,0,0,0,0,0 ; 8 bytes
10617 db 0,0,0,0,0,0,0,0 ; 16 bytes
10618 db 0,0,0,0,0,0,0,0 ; 24 bytes
10619 db 0,0,0,0,0,0,0 ; 31 bytes
10622 #else // !HVMASSIST
10626 // bcc-generated data will be placed here
10628 // For documentation of this config structure, look on developer.intel.com and
10629 // search for multiprocessor specification. Note that when you change anything
10630 // you must update the checksum (a pain!). It would be better to construct this
10631 // with C structures, or at least fill in the checksum automatically.
10633 // Maybe this structs could be moved elsewhere than d000
10635 #if (BX_SMP_PROCESSORS==1)
10636 // no structure necessary.
10637 #elif (BX_SMP_PROCESSORS==2)
10638 // define the Intel MP Configuration Structure for 2 processors at
10639 // APIC ID 0,1. I/O APIC at ID=2.
10642 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10643 dw (mp_config_end-mp_config_table) ;; table length
10645 db 0x65 ;; checksum
10646 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10647 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10648 db 0x20, 0x20, 0x20, 0x20
10649 db 0x20, 0x20, 0x20, 0x20
10650 dw 0,0 ;; oem table ptr
10651 dw 0 ;; oem table size
10652 dw 20 ;; entry count
10653 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10654 dw 0 ;; extended table length
10655 db 0 ;; extended table checksum
10658 db 0 ;; entry type=processor
10659 db 0 ;; local APIC id
10660 db 0x11 ;; local APIC version number
10661 db 3 ;; cpu flags: enabled, bootstrap processor
10662 db 0,6,0,0 ;; cpu signature
10663 dw 0x201,0 ;; feature flags
10667 db 0 ;; entry type=processor
10668 db 1 ;; local APIC id
10669 db 0x11 ;; local APIC version number
10670 db 1 ;; cpu flags: enabled
10671 db 0,6,0,0 ;; cpu signature
10672 dw 0x201,0 ;; feature flags
10676 db 1 ;; entry type=bus
10678 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10680 db 2 ;; entry type=I/O APIC
10681 db 2 ;; apic id=2. linux will set.
10682 db 0x11 ;; I/O APIC version number
10683 db 1 ;; flags=1=enabled
10684 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10686 db 3 ;; entry type=I/O interrupt
10687 db 0 ;; interrupt type=vectored interrupt
10688 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10689 db 0 ;; source bus ID is ISA
10690 db 0 ;; source bus IRQ
10691 db 2 ;; destination I/O APIC ID
10692 db 0 ;; destination I/O APIC interrrupt in
10693 ;; repeat pattern for interrupts 0-15
10703 db 3,0,0,0,0,10,2,10
10704 db 3,0,0,0,0,11,2,11
10705 db 3,0,0,0,0,12,2,12
10706 db 3,0,0,0,0,13,2,13
10707 db 3,0,0,0,0,14,2,14
10708 db 3,0,0,0,0,15,2,15
10709 #elif (BX_SMP_PROCESSORS==4)
10710 // define the Intel MP Configuration Structure for 4 processors at
10711 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10714 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10715 dw (mp_config_end-mp_config_table) ;; table length
10717 db 0xdd ;; checksum
10718 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10719 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10720 db 0x20, 0x20, 0x20, 0x20
10721 db 0x20, 0x20, 0x20, 0x20
10722 dw 0,0 ;; oem table ptr
10723 dw 0 ;; oem table size
10724 dw 22 ;; entry count
10725 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10726 dw 0 ;; extended table length
10727 db 0 ;; extended table checksum
10730 db 0 ;; entry type=processor
10731 db 0 ;; local APIC id
10732 db 0x11 ;; local APIC version number
10733 db 3 ;; cpu flags: enabled, bootstrap processor
10734 db 0,6,0,0 ;; cpu signature
10735 dw 0x201,0 ;; feature flags
10739 db 0 ;; entry type=processor
10740 db 1 ;; local APIC id
10741 db 0x11 ;; local APIC version number
10742 db 1 ;; cpu flags: enabled
10743 db 0,6,0,0 ;; cpu signature
10744 dw 0x201,0 ;; feature flags
10748 db 0 ;; entry type=processor
10749 db 2 ;; local APIC id
10750 db 0x11 ;; local APIC version number
10751 db 1 ;; cpu flags: enabled
10752 db 0,6,0,0 ;; cpu signature
10753 dw 0x201,0 ;; feature flags
10757 db 0 ;; entry type=processor
10758 db 3 ;; local APIC id
10759 db 0x11 ;; local APIC version number
10760 db 1 ;; cpu flags: enabled
10761 db 0,6,0,0 ;; cpu signature
10762 dw 0x201,0 ;; feature flags
10766 db 1 ;; entry type=bus
10768 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10770 db 2 ;; entry type=I/O APIC
10771 db 4 ;; apic id=4. linux will set.
10772 db 0x11 ;; I/O APIC version number
10773 db 1 ;; flags=1=enabled
10774 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10776 db 3 ;; entry type=I/O interrupt
10777 db 0 ;; interrupt type=vectored interrupt
10778 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10779 db 0 ;; source bus ID is ISA
10780 db 0 ;; source bus IRQ
10781 db 4 ;; destination I/O APIC ID
10782 db 0 ;; destination I/O APIC interrrupt in
10783 ;; repeat pattern for interrupts 0-15
10793 db 3,0,0,0,0,10,4,10
10794 db 3,0,0,0,0,11,4,11
10795 db 3,0,0,0,0,12,4,12
10796 db 3,0,0,0,0,13,4,13
10797 db 3,0,0,0,0,14,4,14
10798 db 3,0,0,0,0,15,4,15
10799 #elif (BX_SMP_PROCESSORS==8)
10800 // define the Intel MP Configuration Structure for 8 processors at
10801 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10804 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10805 dw (mp_config_end-mp_config_table) ;; table length
10807 db 0xc3 ;; checksum
10808 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10809 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10810 db 0x20, 0x20, 0x20, 0x20
10811 db 0x20, 0x20, 0x20, 0x20
10812 dw 0,0 ;; oem table ptr
10813 dw 0 ;; oem table size
10814 dw 26 ;; entry count
10815 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10816 dw 0 ;; extended table length
10817 db 0 ;; extended table checksum
10820 db 0 ;; entry type=processor
10821 db 0 ;; local APIC id
10822 db 0x11 ;; local APIC version number
10823 db 3 ;; cpu flags: enabled, bootstrap processor
10824 db 0,6,0,0 ;; cpu signature
10825 dw 0x201,0 ;; feature flags
10829 db 0 ;; entry type=processor
10830 db 1 ;; local APIC id
10831 db 0x11 ;; local APIC version number
10832 db 1 ;; cpu flags: enabled
10833 db 0,6,0,0 ;; cpu signature
10834 dw 0x201,0 ;; feature flags
10838 db 0 ;; entry type=processor
10839 db 2 ;; local APIC id
10840 db 0x11 ;; local APIC version number
10841 db 1 ;; cpu flags: enabled
10842 db 0,6,0,0 ;; cpu signature
10843 dw 0x201,0 ;; feature flags
10847 db 0 ;; entry type=processor
10848 db 3 ;; local APIC id
10849 db 0x11 ;; local APIC version number
10850 db 1 ;; cpu flags: enabled
10851 db 0,6,0,0 ;; cpu signature
10852 dw 0x201,0 ;; feature flags
10856 db 0 ;; entry type=processor
10857 db 4 ;; local APIC id
10858 db 0x11 ;; local APIC version number
10859 db 1 ;; cpu flags: enabled
10860 db 0,6,0,0 ;; cpu signature
10861 dw 0x201,0 ;; feature flags
10865 db 0 ;; entry type=processor
10866 db 5 ;; local APIC id
10867 db 0x11 ;; local APIC version number
10868 db 1 ;; cpu flags: enabled
10869 db 0,6,0,0 ;; cpu signature
10870 dw 0x201,0 ;; feature flags
10874 db 0 ;; entry type=processor
10875 db 6 ;; local APIC id
10876 db 0x11 ;; local APIC version number
10877 db 1 ;; cpu flags: enabled
10878 db 0,6,0,0 ;; cpu signature
10879 dw 0x201,0 ;; feature flags
10883 db 0 ;; entry type=processor
10884 db 7 ;; local APIC id
10885 db 0x11 ;; local APIC version number
10886 db 1 ;; cpu flags: enabled
10887 db 0,6,0,0 ;; cpu signature
10888 dw 0x201,0 ;; feature flags
10892 db 1 ;; entry type=bus
10894 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10896 db 2 ;; entry type=I/O APIC
10898 db 0x11 ;; I/O APIC version number
10899 db 1 ;; flags=1=enabled
10900 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10902 db 3 ;; entry type=I/O interrupt
10903 db 0 ;; interrupt type=vectored interrupt
10904 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10905 db 0 ;; source bus ID is ISA
10906 db 0 ;; source bus IRQ
10907 db 8 ;; destination I/O APIC ID
10908 db 0 ;; destination I/O APIC interrrupt in
10909 ;; repeat pattern for interrupts 0-15
10919 db 3,0,0,0,0,10,8,10
10920 db 3,0,0,0,0,11,8,11
10921 db 3,0,0,0,0,12,8,12
10922 db 3,0,0,0,0,13,8,13
10923 db 3,0,0,0,0,14,8,14
10924 db 3,0,0,0,0,15,8,15
10926 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
10927 #endif // if (BX_SMP_PROCESSORS==...)
10929 mp_config_end: // this label used to find length of mp structure
10932 #if (BX_SMP_PROCESSORS>1)
10934 mp_floating_pointer_structure:
10935 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
10936 dw mp_config_table, 0xf ;; pointer to MP configuration table
10937 db 1 ;; length of this struct in 16-bit byte chunks
10938 db 4 ;; MP spec revision
10939 db 0xc1 ;; checksum
10940 db 0 ;; MP feature byte 1. value 0 means look at the config table
10941 db 0,0,0,0 ;; MP feature bytes 2-5.
10946 #endif // HVMASSIST