1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.1 2007/11/29 20:26:38 pdinda Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 // ROM BIOS for use with Bochs/Plex x86 emulation environment
32 // Xen full virtualization does not handle unaligned IO with page crossing.
33 // Disable 32-bit PIO as a workaround.
37 // ROM BIOS compatability entry points:
38 // ===================================
39 // $e05b ; POST Entry Point
40 // $e2c3 ; NMI Handler Entry Point
41 // $e3fe ; INT 13h Fixed Disk Services Entry Point
42 // $e401 ; Fixed Disk Parameter Table
43 // $e6f2 ; INT 19h Boot Load Service Entry Point
44 // $e6f5 ; Configuration Data Table
45 // $e729 ; Baud Rate Generator Table
46 // $e739 ; INT 14h Serial Communications Service Entry Point
47 // $e82e ; INT 16h Keyboard Service Entry Point
48 // $e987 ; INT 09h Keyboard Service Entry Point
49 // $ec59 ; INT 13h Diskette Service Entry Point
50 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
51 // $efc7 ; Diskette Controller Parameter Table
52 // $efd2 ; INT 17h Printer Service Entry Point
53 // $f045 ; INT 10 Functions 0-Fh Entry Point
54 // $f065 ; INT 10h Video Support Service Entry Point
55 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
56 // $f841 ; INT 12h Memory Size Service Entry Point
57 // $f84d ; INT 11h Equipment List Service Entry Point
58 // $f859 ; INT 15h System Services Entry Point
59 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
60 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
61 // $fea5 ; INT 08h System Timer ISR Entry Point
62 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
63 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
64 // $ff54 ; INT 05h Print Screen Service Entry Point
65 // $fff0 ; Power-up Entry Point
66 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
67 // $fffe ; System Model ID
69 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
71 // - supports up to 4 ATA interfaces
72 // - device/geometry detection
73 // - 16bits/32bits device access
75 // - datain/dataout/packet command support
77 // NOTES for El-Torito Boot (cbbochs@free.fr)
78 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
79 // - Current code is only able to boot mono-session cds
80 // - Current code can not boot and emulate a hard-disk
81 // the bios will panic otherwise
82 // - Current code also use memory in EBDA segement.
83 // - I used cmos byte 0x3D to store extended information on boot-device
84 // - Code has to be modified modified to handle multiple cdrom drives
85 // - Here are the cdrom boot failure codes:
86 // 1 : no atapi device found
87 // 2 : no atapi cdrom found
88 // 3 : can not read cd - BRVD
89 // 4 : cd is not eltorito (BRVD)
90 // 5 : cd is not eltorito (ISO TAG)
91 // 6 : cd is not eltorito (ELTORITO TAG)
92 // 7 : can not read cd - boot catalog
93 // 8 : boot catalog : bad header
94 // 9 : boot catalog : bad platform
95 // 10 : boot catalog : bad signature
96 // 11 : boot catalog : bootable flag not set
97 // 12 : can not read cd - boot image
101 // I used memory starting at 0x121 in the segment
102 // - the translation policy is defined in cmos regs 0x39 & 0x3a
107 // - needs to be reworked. Uses direct [bp] offsets. (?)
110 // - f04 (verify sectors) isn't complete (?)
111 // - f02/03/04 should set current cyl,etc in BDA (?)
112 // - rewrite int13_relocated & clean up int13 entry code
115 // - NMI access (bit7 of addr written to 70h)
118 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
119 // - could send the multiple-sector read/write commands
122 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
123 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
124 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
125 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
126 // This is ok. But DL should be reincremented afterwards.
127 // - Fix all "FIXME ElTorito Various"
128 // - should be able to boot any cdrom instead of the first one
130 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
132 #define DEBUG_ROMBIOS 0
135 #define DEBUG_INT13_HD 0
136 #define DEBUG_INT13_CD 0
137 #define DEBUG_INT13_ET 0
138 #define DEBUG_INT13_FL 0
139 #define DEBUG_INT15 0
140 #define DEBUG_INT16 0
141 #define DEBUG_INT1A 0
142 #define DEBUG_INT74 0
146 #define BX_USE_PS2_MOUSE 1
147 #define BX_CALL_INT15_4F 1
148 #define BX_USE_EBDA 1
149 #define BX_SUPPORT_FLOPPY 1
150 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
154 #define BX_USE_ATADRV 1
155 #define BX_ELTORITO_BOOT 1
157 #define BX_MAX_ATA_INTERFACES 4
158 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
160 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
161 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
163 /* model byte 0xFC = AT */
164 #define SYS_MODEL_ID 0xFC
165 #define SYS_SUBMODEL_ID 0x00
166 #define BIOS_REVISION 1
167 #define BIOS_CONFIG_TABLE 0xe6f5
169 #ifndef BIOS_BUILD_DATE
170 # define BIOS_BUILD_DATE "06/23/99"
173 // 1K of base memory used for Extended Bios Data Area (EBDA)
174 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
175 #define EBDA_SEG 0x9FC0
176 #define EBDA_SIZE 1 // In KiB
177 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
179 // Define the application NAME
181 # define BX_APPNAME "HVMAssist"
183 # define BX_APPNAME "Plex86"
185 # define BX_APPNAME "Bochs"
189 #if BX_USE_ATADRV && BX_CPU<3
190 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
192 #if BX_USE_ATADRV && !BX_USE_EBDA
193 # error ATA/ATAPI Driver can only be used if EBDA is available
195 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
196 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
198 #if BX_PCIBIOS && BX_CPU<3
199 # error PCI BIOS can only be used with 386+ cpu
201 #if BX_APM && BX_CPU<3
202 # error APM BIOS can only be used with 386+ cpu
205 #ifndef BX_SMP_PROCESSORS
206 #define BX_SMP_PROCESSORS 1
207 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
210 #define PANIC_PORT 0x400
211 #define PANIC_PORT2 0x401
212 #define INFO_PORT 0x402
213 #define DEBUG_PORT 0x403
216 // #$20 is hex 20 = 32
217 // #0x20 is hex 20 = 32
224 // all hex literals should be prefixed with '0x'
225 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
226 // no mov SEG-REG, #value, must mov register into seg-reg
227 // grep -i "mov[ ]*.s" rombios.c
229 // This is for compiling with gcc2 and gcc3
230 #define ASM_START #asm
231 #define ASM_END #endasm
245 ;; the HALT macro is called with the line number of the HALT call.
246 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
247 ;; to print a BX_PANIC message. This will normally halt the simulation
248 ;; with a message such as "BIOS panic at rombios.c, line 4091".
249 ;; However, users can choose to make panics non-fatal and continue.
276 typedef unsigned char Bit8u;
277 typedef unsigned short Bit16u;
278 typedef unsigned short bx_bool;
279 typedef unsigned long Bit32u;
283 void memsetb(seg,offset,value,count);
284 void memcpyb(dseg,doffset,sseg,soffset,count);
285 void memcpyd(dseg,doffset,sseg,soffset,count);
287 // memset of count bytes
289 memsetb(seg,offset,value,count)
304 mov cx, 10[bp] ; count
307 mov ax, 4[bp] ; segment
309 mov ax, 6[bp] ; offset
311 mov al, 8[bp] ; value
326 // memcpy of count bytes
328 memcpyb(dseg,doffset,sseg,soffset,count)
346 mov cx, 12[bp] ; count
349 mov ax, 4[bp] ; dsegment
351 mov ax, 6[bp] ; doffset
353 mov ax, 8[bp] ; ssegment
355 mov ax, 10[bp] ; soffset
374 // memcpy of count dword
376 memcpyd(dseg,doffset,sseg,soffset,count)
394 mov cx, 12[bp] ; count
397 mov ax, 4[bp] ; dsegment
399 mov ax, 6[bp] ; doffset
401 mov ax, 8[bp] ; ssegment
403 mov ax, 10[bp] ; soffset
421 #endif //BX_USE_ATADRV
423 // read_dword and write_dword functions
424 static Bit32u read_dword();
425 static void write_dword();
428 read_dword(seg, offset)
438 mov ax, 4[bp] ; segment
440 mov bx, 6[bp] ; offset
445 ;; ax = return value (word)
446 ;; dx = return value (word)
455 write_dword(seg, offset, data)
467 mov ax, 4[bp] ; segment
469 mov bx, 6[bp] ; offset
470 mov ax, 8[bp] ; data word
471 mov [bx], ax ; write data word
474 mov ax, 10[bp] ; data word
475 mov [bx], ax ; write data word
484 // Bit32u (unsigned long) and long helper functions
513 cmp eax, dword ptr [di]
532 mul eax, dword ptr [di]
628 // for access to RAM area which is used by interrupt vectors
629 // and BIOS Data Area
632 unsigned char filler1[0x400];
633 unsigned char filler2[0x6c];
639 #define BiosData ((bios_data_t *) 0)
643 Bit16u heads; // # heads
644 Bit16u cylinders; // # cylinders
645 Bit16u spt; // # sectors / track
665 Bit8u iface; // ISA or PCI
666 Bit16u iobase1; // IO Base 1
667 Bit16u iobase2; // IO Base 2
672 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
673 Bit8u device; // Detected type of attached devices (hd/cd/none)
674 Bit8u removable; // Removable device flag
675 Bit8u lock; // Locks for removable devices
676 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
677 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
678 Bit16u blksize; // block size
680 Bit8u translation; // type of translation
681 chs_t lchs; // Logical CHS
682 chs_t pchs; // Physical CHS
684 Bit32u sectors; // Total sectors count
689 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
692 ata_device_t devices[BX_MAX_ATA_DEVICES];
694 // map between (bios hd id - 0x80) and ata channels
695 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
697 // map between (bios cd id - 0xE0) and ata channels
698 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
700 // Buffer for DPTE table
703 // Count of transferred sectors and bytes
710 // ElTorito Device Emulation data
714 Bit8u emulated_drive;
715 Bit8u controller_index;
718 Bit16u buffer_segment;
725 #endif // BX_ELTORITO_BOOT
727 // for access to EBDA area
728 // The EBDA structure should conform to
729 // http://www.cybertrails.com/~fys/rombios.htm document
730 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
732 unsigned char filler1[0x3D];
734 // FDPT - Can be splitted in data members if needed
735 unsigned char fdpt0[0x10];
736 unsigned char fdpt1[0x10];
738 unsigned char filler2[0xC4];
744 // El Torito Emulation data
746 #endif // BX_ELTORITO_BOOT
750 #define EbdaData ((ebda_data_t *) 0)
752 // for access to the int13ext structure
763 #define Int13Ext ((int13ext_t *) 0)
765 // Disk Physical Table definition
772 Bit32u sector_count1;
773 Bit32u sector_count2;
784 Bit8u device_path[8];
789 #define Int13DPT ((dpt_t *) 0)
791 #endif // BX_USE_ATADRV
796 Bit16u di, si, bp, sp;
797 Bit16u bx, dx, cx, ax;
801 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
809 Bit32u edi, esi, ebp, esp;
810 Bit32u ebx, edx, ecx, eax;
813 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
814 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
842 #define SetCF(x) x.u.r8.flagsl |= 0x01
843 #define SetZF(x) x.u.r8.flagsl |= 0x40
844 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
845 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
846 #define GetCF(x) (x.u.r8.flagsl & 0x01)
857 static Bit8u inb_cmos();
859 static void outb_cmos();
862 static void init_rtc();
863 static bx_bool rtc_updating();
865 static Bit8u read_byte();
866 static Bit16u read_word();
867 static void write_byte();
868 static void write_word();
869 static void bios_printf();
870 static void copy_e820_table();
872 static Bit8u inhibit_mouse_int_and_events();
873 static void enable_mouse_int_and_events();
874 static Bit8u send_to_mouse_ctrl();
875 static Bit8u get_mouse_data();
876 static void set_kbd_command_byte();
878 static void int09_function();
879 static void int13_harddisk();
880 static void int13_cdrom();
881 static void int13_cdemu();
882 static void int13_eltorito();
883 static void int13_diskette_function();
884 static void int14_function();
885 static void int15_function();
886 static void int16_function();
887 static void int17_function();
888 static Bit32u int19_function();
889 static void int1a_function();
890 static void int70_function();
891 static void int74_function();
892 static Bit16u get_CS();
893 //static Bit16u get_DS();
894 //static void set_DS();
895 static Bit16u get_SS();
896 static unsigned int enqueue_key();
897 static unsigned int dequeue_key();
898 static void get_hd_geometry();
899 static void set_diskette_ret_status();
900 static void set_diskette_current_cyl();
901 static void determine_floppy_media();
902 static bx_bool floppy_drive_exists();
903 static bx_bool floppy_drive_recal();
904 static bx_bool floppy_media_known();
905 static bx_bool floppy_media_sense();
906 static bx_bool set_enable_a20();
907 static void debugger_on();
908 static void debugger_off();
909 static void keyboard_init();
910 static void keyboard_panic();
911 static void shutdown_status_panic();
912 static void nmi_handler_msg();
914 static void print_bios_banner();
915 static void print_boot_device();
916 static void print_boot_failure();
917 static void print_cdromboot_failure();
921 // ATA / ATAPI driver
926 Bit16u ata_cmd_non_data();
927 Bit16u ata_cmd_data_in();
928 Bit16u ata_cmd_data_out();
929 Bit16u ata_cmd_packet();
931 Bit16u atapi_get_sense();
932 Bit16u atapi_is_ready();
933 Bit16u atapi_is_cdrom();
935 #endif // BX_USE_ATADRV
940 Bit8u cdemu_isactive();
941 Bit8u cdemu_emulated_drive();
945 #endif // BX_ELTORITO_BOOT
947 static char bios_cvs_version_string[] = "$Revision: 1.1 $";
948 static char bios_date_string[] = "$Date: 2007/11/29 20:26:38 $";
950 static char CVSID[] = "$Id: rombios.c,v 1.1 2007/11/29 20:26:38 pdinda Exp $";
952 /* Offset to skip the CVS $Id: prefix */
953 #define bios_version_string (CVSID + 4)
955 #define BIOS_PRINTF_HALT 1
956 #define BIOS_PRINTF_SCREEN 2
957 #define BIOS_PRINTF_INFO 4
958 #define BIOS_PRINTF_DEBUG 8
959 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
960 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
962 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
964 // Defines the output macros.
965 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
966 // per-device basis. Debug info are sent only in debug mode
968 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
970 # define BX_DEBUG(format, p...)
972 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
973 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
976 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
978 # define BX_DEBUG_ATA(a...)
981 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
983 # define BX_DEBUG_INT13_HD(a...)
986 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
988 # define BX_DEBUG_INT13_CD(a...)
991 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
993 # define BX_DEBUG_INT13_ET(a...)
996 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
998 # define BX_DEBUG_INT13_FL(a...)
1001 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1003 # define BX_DEBUG_INT15(a...)
1006 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1008 # define BX_DEBUG_INT16(a...)
1011 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1013 # define BX_DEBUG_INT1A(a...)
1016 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1018 # define BX_DEBUG_INT74(a...)
1021 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1022 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1023 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1024 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1025 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1026 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1027 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1028 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1030 #define GET_AL() ( AX & 0x00ff )
1031 #define GET_BL() ( BX & 0x00ff )
1032 #define GET_CL() ( CX & 0x00ff )
1033 #define GET_DL() ( DX & 0x00ff )
1034 #define GET_AH() ( AX >> 8 )
1035 #define GET_BH() ( BX >> 8 )
1036 #define GET_CH() ( CX >> 8 )
1037 #define GET_DH() ( DX >> 8 )
1039 #define GET_ELDL() ( ELDX & 0x00ff )
1040 #define GET_ELDH() ( ELDX >> 8 )
1042 #define SET_CF() FLAGS |= 0x0001
1043 #define CLEAR_CF() FLAGS &= 0xfffe
1044 #define GET_CF() (FLAGS & 0x0001)
1046 #define SET_ZF() FLAGS |= 0x0040
1047 #define CLEAR_ZF() FLAGS &= 0xffbf
1048 #define GET_ZF() (FLAGS & 0x0040)
1050 #define UNSUPPORTED_FUNCTION 0x86
1053 #define MAX_SCAN_CODE 0x53
1061 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1062 { none, none, none, none, none },
1063 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1064 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1065 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1066 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1067 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1068 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1069 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1070 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1071 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1072 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1073 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1074 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1075 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1076 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1077 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1078 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1079 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1080 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1081 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1082 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1083 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1084 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1085 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1086 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1087 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1088 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1089 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1090 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1091 { none, none, none, none, none }, /* L Ctrl */
1092 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1093 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1094 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1095 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1096 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1097 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1098 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1099 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1100 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1101 { 0x273b, 0x273a, none, none, none }, /* ;: */
1102 { 0x2827, 0x2822, none, none, none }, /* '" */
1103 { 0x2960, 0x297e, none, none, none }, /* `~ */
1104 { none, none, none, none, none }, /* L shift */
1105 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1106 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1107 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1108 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1109 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1110 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1111 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1112 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1113 { 0x332c, 0x333c, none, none, none }, /* ,< */
1114 { 0x342e, 0x343e, none, none, none }, /* .> */
1115 { 0x352f, 0x353f, none, none, none }, /* /? */
1116 { none, none, none, none, none }, /* R Shift */
1117 { 0x372a, 0x372a, none, none, none }, /* * */
1118 { none, none, none, none, none }, /* L Alt */
1119 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1120 { none, none, none, none, none }, /* caps lock */
1121 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1122 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1123 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1124 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1125 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1126 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1127 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1128 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1129 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1130 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1131 { none, none, none, none, none }, /* Num Lock */
1132 { none, none, none, none, none }, /* Scroll Lock */
1133 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1134 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1135 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1136 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1137 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1138 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1139 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1140 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1141 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1142 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1143 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1144 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1145 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1229 outb_cmos(cmos_reg, val)
1237 mov al, 4[bp] ;; cmos_reg
1239 mov al, 6[bp] ;; val
1254 mov al, 4[bp] ;; cmos_reg
1265 printf("rombios: init_rtc()\n");
1266 outb_cmos(0x0a, 0x26);
1267 outb_cmos(0x0b, 0x02);
1275 // This function checks to see if the update-in-progress bit
1276 // is set in CMOS Status Register A. If not, it returns 0.
1277 // If it is set, it tries to wait until there is a transition
1278 // to 0, and will return 0 if such a transition occurs. A 1
1279 // is returned only after timing out. The maximum period
1280 // that this bit should be set is constrained to 244useconds.
1281 // The count I use below guarantees coverage or more than
1282 // this time, with any reasonable IPS setting.
1287 while (--count != 0) {
1288 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1291 return(1); // update-in-progress never transitioned to 0
1296 read_byte(seg, offset)
1306 mov ax, 4[bp] ; segment
1308 mov bx, 6[bp] ; offset
1310 ;; al = return value (byte)
1319 read_word(seg, offset)
1329 mov ax, 4[bp] ; segment
1331 mov bx, 6[bp] ; offset
1333 ;; ax = return value (word)
1342 write_byte(seg, offset, data)
1354 mov ax, 4[bp] ; segment
1356 mov bx, 6[bp] ; offset
1357 mov al, 8[bp] ; data byte
1358 mov [bx], al ; write data byte
1368 write_word(seg, offset, data)
1380 mov ax, 4[bp] ; segment
1382 mov bx, 6[bp] ; offset
1383 mov ax, 8[bp] ; data word
1384 mov [bx], ax ; write data word
1410 //set_DS(ds_selector)
1411 // Bit16u ds_selector;
1418 // mov ax, 4[bp] ; ds_selector
1438 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1439 if (nr_entries > 32)
1441 write_word(0xe000, 0x8, nr_entries);
1442 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1444 #endif /* HVMASSIST */
1447 /* serial debug port*/
1448 #define BX_DEBUG_PORT 0x03f8
1451 #define UART_RBR 0x00
1452 #define UART_THR 0x00
1455 #define UART_IER 0x01
1456 #define UART_IIR 0x02
1457 #define UART_FCR 0x02
1458 #define UART_LCR 0x03
1459 #define UART_MCR 0x04
1460 #define UART_DLL 0x00
1461 #define UART_DLM 0x01
1464 #define UART_LSR 0x05
1465 #define UART_MSR 0x06
1466 #define UART_SCR 0x07
1468 int uart_can_tx_byte(base_port)
1471 return inb(base_port + UART_LSR) & 0x20;
1474 void uart_wait_to_tx_byte(base_port)
1477 while (!uart_can_tx_byte(base_port));
1480 void uart_wait_until_sent(base_port)
1483 while (!(inb(base_port + UART_LSR) & 0x40));
1486 void uart_tx_byte(base_port, data)
1490 uart_wait_to_tx_byte(base_port);
1491 outb(base_port + UART_THR, data);
1492 uart_wait_until_sent(base_port);
1521 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1522 uart_tx_byte(BX_DEBUG_PORT, c);
1527 #if BX_VIRTUAL_PORTS
1528 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1529 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1531 if (action & BIOS_PRINTF_SCREEN) {
1532 if (c == '\n') wrch('\r');
1538 put_int(action, val, width, neg)
1543 short nval = val / 10;
1545 put_int(action, nval, width - 1, neg);
1547 while (--width > 0) send(action, ' ');
1548 if (neg) send(action, '-');
1550 send(action, val - (nval * 10) + '0');
1554 put_uint(action, val, width, neg)
1560 unsigned short nval = val / 10;
1562 put_uint(action, nval, width - 1, neg);
1564 while (--width > 0) send(action, ' ');
1565 if (neg) send(action, '-');
1567 send(action, val - (nval * 10) + '0');
1570 //--------------------------------------------------------------------------
1572 // A compact variable argument printf function which prints its output via
1573 // an I/O port so that it can be logged by Bochs/Plex.
1574 // Currently, only %x is supported (or %02x, %04x, etc).
1576 // Supports %[format_width][format]
1577 // where format can be d,x,c,s
1578 //--------------------------------------------------------------------------
1580 bios_printf(action, s)
1584 Bit8u c, format_char;
1588 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1596 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1597 #if BX_VIRTUAL_PORTS
1598 outb(PANIC_PORT2, 0x00);
1600 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1603 while (c = read_byte(get_CS(), s)) {
1608 else if (in_format) {
1609 if ( (c>='0') && (c<='9') ) {
1610 format_width = (format_width * 10) + (c - '0');
1613 arg_ptr++; // increment to next arg
1614 arg = read_word(arg_seg, arg_ptr);
1616 if (format_width == 0)
1618 for (i=format_width-1; i>=0; i--) {
1619 nibble = (arg >> (4 * i)) & 0x000f;
1620 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1623 else if (c == 'u') {
1624 put_uint(action, arg, format_width, 0);
1626 else if (c == 'd') {
1628 put_int(action, -arg, format_width - 1, 1);
1630 put_int(action, arg, format_width, 0);
1632 else if (c == 's') {
1633 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1635 else if (c == 'c') {
1639 BX_PANIC("bios_printf: unknown format\n");
1649 if (action & BIOS_PRINTF_HALT) {
1650 // freeze in a busy loop.
1660 //--------------------------------------------------------------------------
1662 //--------------------------------------------------------------------------
1663 // this file is based on LinuxBIOS implementation of keyboard.c
1664 // could convert to #asm to gain space
1671 printf("rombios: keyboard_init\n");
1673 /* printf("Assuming keyboard already inited and returning\n");
1676 /* ------------------- Flush buffers ------------------------*/
1677 /* Wait until buffer is empty */
1679 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1681 /* flush incoming keys */
1685 if (inb(0x64) & 0x01) {
1691 // Due to timer issues, and if the IPS setting is > 15000000,
1692 // the incoming keys might not be flushed here. That will
1693 // cause a panic a few lines below. See sourceforge bug report :
1694 // [ 642031 ] FATAL: Keyboard RESET error:993
1696 /* ------------------- controller side ----------------------*/
1697 /* send cmd = 0xAA, self test 8042 */
1700 /* Wait until buffer is empty */
1702 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1703 if (max==0x0) keyboard_panic(00);
1707 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1708 if (max==0x0) keyboard_panic(01);
1710 /* read self-test result, 0x55 should be returned from 0x60 */
1711 if ((inb(0x60) != 0x55)){
1712 keyboard_panic(991);
1715 /* send cmd = 0xAB, keyboard interface test */
1718 /* Wait until buffer is empty */
1720 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1721 if (max==0x0) keyboard_panic(10);
1725 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1726 if (max==0x0) keyboard_panic(11);
1728 /* read keyboard interface test result, */
1729 /* 0x00 should be returned form 0x60 */
1730 if ((inb(0x60) != 0x00)) {
1731 keyboard_panic(992);
1734 /* Enable Keyboard clock */
1738 /* ------------------- keyboard side ------------------------*/
1739 /* reset kerboard and self test (keyboard side) */
1742 /* Wait until buffer is empty */
1744 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1745 if (max==0x0) keyboard_panic(20);
1749 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1750 if (max==0x0) keyboard_panic(21);
1752 /* keyboard should return ACK */
1753 if ((inb(0x60) != 0xfa)) {
1754 keyboard_panic(993);
1759 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1760 if (max==0x0) keyboard_panic(31);
1762 if ((inb(0x60) != 0xaa)) {
1763 keyboard_panic(994);
1766 /* Disable keyboard */
1769 /* Wait until buffer is empty */
1771 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1772 if (max==0x0) keyboard_panic(40);
1776 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1777 if (max==0x0) keyboard_panic(41);
1779 /* keyboard should return ACK */
1782 printf("rc=0x%x\n",rc);
1783 keyboard_panic(995);
1786 /* Write Keyboard Mode */
1789 /* Wait until buffer is empty */
1791 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1792 if (max==0x0) keyboard_panic(50);
1794 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1797 /* Wait until buffer is empty */
1799 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1800 if (max==0x0) keyboard_panic(60);
1802 /* Enable keyboard */
1805 /* Wait until buffer is empty */
1807 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1808 if (max==0x0) keyboard_panic(70);
1812 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1813 if (max==0x0) keyboard_panic(70);
1815 /* keyboard should return ACK */
1816 if ((inb(0x60) != 0xfa)) {
1817 keyboard_panic(996);
1821 printf("keyboard init done.\n");
1824 //--------------------------------------------------------------------------
1826 //--------------------------------------------------------------------------
1828 keyboard_panic(status)
1831 // If you're getting a 993 keyboard panic here,
1832 // please see the comment in keyboard_init
1833 printf("Keyboard error:%u CONTINUING\n",status); return;
1834 BX_PANIC("Keyboard error:%u\n",status);
1837 //--------------------------------------------------------------------------
1838 // shutdown_status_panic
1839 // called when the shutdown statsu is not implemented, displays the status
1840 //--------------------------------------------------------------------------
1842 shutdown_status_panic(status)
1845 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1848 //--------------------------------------------------------------------------
1849 // print_bios_banner
1850 // displays a the bios version
1851 //--------------------------------------------------------------------------
1855 printf("Hi from peter's modified bios\n");
1856 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1857 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1861 //--------------------------------------------------------------------------
1862 // print_boot_device
1863 // displays the boot device
1864 //--------------------------------------------------------------------------
1866 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1869 print_boot_device(cdboot, drive)
1870 Bit8u cdboot; Bit16u drive;
1874 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1875 // drive contains real/emulated boot drive
1877 if(cdboot)i=2; // CD-Rom
1878 else if((drive&0x0080)==0x00)i=0; // Floppy
1879 else if((drive&0x0080)==0x80)i=1; // Hard drive
1882 printf("Booting from %s...\n",drivetypes[i]);
1885 //--------------------------------------------------------------------------
1886 // print_boot_failure
1887 // displays the reason why boot failed
1888 //--------------------------------------------------------------------------
1890 print_boot_failure(cdboot, drive, reason, lastdrive)
1891 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1893 Bit16u drivenum = drive&0x7f;
1895 // cdboot: 1 if boot from cd, 0 otherwise
1896 // drive : drive number
1897 // reason: 0 signature check failed, 1 read error
1898 // lastdrive: 1 boot drive is the last one in boot sequence
1901 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1902 else if (drive & 0x80)
1903 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1905 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1909 BX_PANIC("Not a bootable disk\n");
1911 BX_PANIC("Could not read the boot disk\n");
1915 //--------------------------------------------------------------------------
1916 // print_cdromboot_failure
1917 // displays the reason why boot failed
1918 //--------------------------------------------------------------------------
1920 print_cdromboot_failure( code )
1923 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1931 BX_PANIC("NMI Handler called\n");
1937 BX_PANIC("INT18: BOOT FAILURE\n");
1944 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1946 BX_INFO("%s\n", bios_version_string);
1955 // Use PS2 System Control port A to set A20 enable
1957 // get current setting first
1960 // change A20 status
1962 outb(0x92, oldval | 0x02);
1964 outb(0x92, oldval & 0xfd);
1966 return((oldval & 0x02) != 0);
1983 // ---------------------------------------------------------------------------
1984 // Start of ATA/ATAPI Driver
1985 // ---------------------------------------------------------------------------
1987 // Global defines -- ATA register and register bits.
1988 // command block & control block regs
1989 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1990 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1991 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1992 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1993 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1994 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1995 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1996 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1997 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1998 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1999 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2000 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2001 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2003 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2004 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2005 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2006 #define ATA_CB_ER_MC 0x20 // ATA media change
2007 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2008 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2009 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2010 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2011 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2013 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2014 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2015 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2016 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2017 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2019 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2020 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2021 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2022 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2023 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2025 // bits 7-4 of the device/head (CB_DH) reg
2026 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2027 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2029 // status reg (CB_STAT and CB_ASTAT) bits
2030 #define ATA_CB_STAT_BSY 0x80 // busy
2031 #define ATA_CB_STAT_RDY 0x40 // ready
2032 #define ATA_CB_STAT_DF 0x20 // device fault
2033 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2034 #define ATA_CB_STAT_SKC 0x10 // seek complete
2035 #define ATA_CB_STAT_SERV 0x10 // service
2036 #define ATA_CB_STAT_DRQ 0x08 // data request
2037 #define ATA_CB_STAT_CORR 0x04 // corrected
2038 #define ATA_CB_STAT_IDX 0x02 // index
2039 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2040 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2042 // device control reg (CB_DC) bits
2043 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2044 #define ATA_CB_DC_SRST 0x04 // soft reset
2045 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2047 // Most mandtory and optional ATA commands (from ATA-3),
2048 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2049 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2050 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2051 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2052 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2053 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2054 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2055 #define ATA_CMD_DEVICE_RESET 0x08
2056 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2057 #define ATA_CMD_FLUSH_CACHE 0xE7
2058 #define ATA_CMD_FORMAT_TRACK 0x50
2059 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2060 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2061 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2062 #define ATA_CMD_IDLE1 0xE3
2063 #define ATA_CMD_IDLE2 0x97
2064 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2065 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2066 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2067 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2068 #define ATA_CMD_NOP 0x00
2069 #define ATA_CMD_PACKET 0xA0
2070 #define ATA_CMD_READ_BUFFER 0xE4
2071 #define ATA_CMD_READ_DMA 0xC8
2072 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2073 #define ATA_CMD_READ_MULTIPLE 0xC4
2074 #define ATA_CMD_READ_SECTORS 0x20
2075 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2076 #define ATA_CMD_RECALIBRATE 0x10
2077 #define ATA_CMD_SEEK 0x70
2078 #define ATA_CMD_SET_FEATURES 0xEF
2079 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2080 #define ATA_CMD_SLEEP1 0xE6
2081 #define ATA_CMD_SLEEP2 0x99
2082 #define ATA_CMD_STANDBY1 0xE2
2083 #define ATA_CMD_STANDBY2 0x96
2084 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2085 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2086 #define ATA_CMD_WRITE_BUFFER 0xE8
2087 #define ATA_CMD_WRITE_DMA 0xCA
2088 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2089 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2090 #define ATA_CMD_WRITE_SECTORS 0x30
2091 #define ATA_CMD_WRITE_VERIFY 0x3C
2093 #define ATA_IFACE_NONE 0x00
2094 #define ATA_IFACE_ISA 0x00
2095 #define ATA_IFACE_PCI 0x01
2097 #define ATA_TYPE_NONE 0x00
2098 #define ATA_TYPE_UNKNOWN 0x01
2099 #define ATA_TYPE_ATA 0x02
2100 #define ATA_TYPE_ATAPI 0x03
2102 #define ATA_DEVICE_NONE 0x00
2103 #define ATA_DEVICE_HD 0xFF
2104 #define ATA_DEVICE_CDROM 0x05
2106 #define ATA_MODE_NONE 0x00
2107 #define ATA_MODE_PIO16 0x00
2108 #define ATA_MODE_PIO32 0x01
2109 #define ATA_MODE_ISADMA 0x02
2110 #define ATA_MODE_PCIDMA 0x03
2111 #define ATA_MODE_USEIRQ 0x10
2113 #define ATA_TRANSLATION_NONE 0
2114 #define ATA_TRANSLATION_LBA 1
2115 #define ATA_TRANSLATION_LARGE 2
2116 #define ATA_TRANSLATION_RECHS 3
2118 #define ATA_DATA_NO 0x00
2119 #define ATA_DATA_IN 0x01
2120 #define ATA_DATA_OUT 0x02
2122 // ---------------------------------------------------------------------------
2123 // ATA/ATAPI driver : initialization
2124 // ---------------------------------------------------------------------------
2127 Bit16u ebda_seg=read_word(0x0040,0x000E);
2128 Bit8u channel, device;
2130 printf("rom_bios: ata_init\n");
2132 // Channels info init.
2133 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2134 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2135 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2136 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2137 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2140 // Devices info init.
2141 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2142 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2143 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2144 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2145 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2146 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2147 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2148 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2149 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2150 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2151 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2152 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2153 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2154 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2156 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2159 // hdidmap and cdidmap init.
2160 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2161 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2162 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2165 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2166 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2169 // ---------------------------------------------------------------------------
2170 // ATA/ATAPI driver : device detection
2171 // ---------------------------------------------------------------------------
2175 Bit16u ebda_seg=read_word(0x0040,0x000E);
2176 Bit8u hdcount, cdcount, device, type;
2177 Bit8u buffer[0x0200];
2179 #if BX_MAX_ATA_INTERFACES > 0
2180 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2181 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2182 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2183 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2185 #if BX_MAX_ATA_INTERFACES > 1
2186 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2187 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2188 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2189 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2191 #if BX_MAX_ATA_INTERFACES > 2
2192 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2193 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2194 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2195 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2197 #if BX_MAX_ATA_INTERFACES > 3
2198 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2199 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2200 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2201 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2203 #if BX_MAX_ATA_INTERFACES > 4
2204 #error Please fill the ATA interface informations
2210 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2211 Bit16u iobase1, iobase2;
2212 Bit8u channel, slave, shift;
2213 Bit8u sc, sn, cl, ch, st;
2215 channel = device / 2;
2218 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2219 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2221 // Disable interrupts
2222 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2225 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2226 outb(iobase1+ATA_CB_SC, 0x55);
2227 outb(iobase1+ATA_CB_SN, 0xaa);
2228 outb(iobase1+ATA_CB_SC, 0xaa);
2229 outb(iobase1+ATA_CB_SN, 0x55);
2230 outb(iobase1+ATA_CB_SC, 0x55);
2231 outb(iobase1+ATA_CB_SN, 0xaa);
2233 // If we found something
2234 sc = inb(iobase1+ATA_CB_SC);
2235 sn = inb(iobase1+ATA_CB_SN);
2237 if ( (sc == 0x55) && (sn == 0xaa) ) {
2238 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2240 // reset the channel
2243 // check for ATA or ATAPI
2244 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2245 sc = inb(iobase1+ATA_CB_SC);
2246 sn = inb(iobase1+ATA_CB_SN);
2247 if ( (sc==0x01) && (sn==0x01) ) {
2248 cl = inb(iobase1+ATA_CB_CL);
2249 ch = inb(iobase1+ATA_CB_CH);
2250 st = inb(iobase1+ATA_CB_STAT);
2252 if ( (cl==0x14) && (ch==0xeb) ) {
2253 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2255 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2256 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2261 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2263 // Now we send a IDENTIFY command to ATA device
2264 if(type == ATA_TYPE_ATA) {
2266 Bit16u cylinders, heads, spt, blksize;
2267 Bit8u translation, removable, mode;
2269 // default mode to PIO16
2270 mode = ATA_MODE_PIO16;
2272 //Temporary values to do the transfer
2273 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2274 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2276 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2277 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2279 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2281 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2284 blksize = read_word(get_SS(),buffer+10);
2286 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2287 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2288 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2290 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2292 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2293 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2294 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2295 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2296 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2297 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2298 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2299 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2300 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2302 translation = inb_cmos(0x39 + channel/2);
2303 for (shift=device%4; shift>0; shift--) translation >>= 2;
2304 translation &= 0x03;
2306 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2308 switch (translation) {
2309 case ATA_TRANSLATION_NONE:
2312 case ATA_TRANSLATION_LBA:
2315 case ATA_TRANSLATION_LARGE:
2318 case ATA_TRANSLATION_RECHS:
2322 switch (translation) {
2323 case ATA_TRANSLATION_NONE:
2325 case ATA_TRANSLATION_LBA:
2328 heads = sectors / 1024;
2329 if (heads>128) heads = 255;
2330 else if (heads>64) heads = 128;
2331 else if (heads>32) heads = 64;
2332 else if (heads>16) heads = 32;
2334 cylinders = sectors / heads;
2336 case ATA_TRANSLATION_RECHS:
2337 // Take care not to overflow
2339 if(cylinders>61439) cylinders=61439;
2341 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2343 // then go through the large bitshift process
2344 case ATA_TRANSLATION_LARGE:
2345 while(cylinders > 1024) {
2349 // If we max out the head count
2350 if (heads > 127) break;
2354 // clip to 1024 cylinders in lchs
2355 if (cylinders > 1024) cylinders=1024;
2356 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2358 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2359 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2360 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2363 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2367 // Now we send a IDENTIFY command to ATAPI device
2368 if(type == ATA_TYPE_ATAPI) {
2370 Bit8u type, removable, mode;
2373 // default mode to PIO16
2374 mode = ATA_MODE_PIO16;
2376 //Temporary values to do the transfer
2377 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2378 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2380 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2381 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2383 type = read_byte(get_SS(),buffer+1) & 0x1f;
2384 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2386 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2390 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2391 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2392 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2393 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2396 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2403 Bit8u c, i, version, model[41];
2407 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2409 case ATA_TYPE_ATAPI:
2410 // Read ATA/ATAPI version
2411 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2412 for(version=15;version>0;version--) {
2413 if((ataversion&(1<<version))!=0)
2419 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2420 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2424 write_byte(get_SS(),model+40,0x00);
2426 if(read_byte(get_SS(),model+i)==0x20)
2427 write_byte(get_SS(),model+i,0x00);
2435 printf("ata%d %s: ",channel,slave?" slave":"master");
2436 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2437 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2439 case ATA_TYPE_ATAPI:
2440 printf("ata%d %s: ",channel,slave?" slave":"master");
2441 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2442 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2443 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2445 printf(" ATAPI-%d Device\n",version);
2447 case ATA_TYPE_UNKNOWN:
2448 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2454 // Store the devices counts
2455 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2456 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2457 write_byte(0x40,0x75, hdcount);
2461 // FIXME : should use bios=cmos|auto|disable bits
2462 // FIXME : should know about translation bits
2463 // FIXME : move hard_drive_post here
2467 // ---------------------------------------------------------------------------
2468 // ATA/ATAPI driver : software reset
2469 // ---------------------------------------------------------------------------
2471 // 8.2.1 Software reset - Device 0
2473 void ata_reset(device)
2476 Bit16u ebda_seg=read_word(0x0040,0x000E);
2477 Bit16u iobase1, iobase2;
2478 Bit8u channel, slave, sn, sc;
2481 channel = device / 2;
2484 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2485 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2489 // 8.2.1 (a) -- set SRST in DC
2490 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2492 // 8.2.1 (b) -- wait for BSY
2495 Bit8u status = inb(iobase1+ATA_CB_STAT);
2496 if ((status & ATA_CB_STAT_BSY) != 0) break;
2499 // 8.2.1 (f) -- clear SRST
2500 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2502 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2504 // 8.2.1 (g) -- check for sc==sn==0x01
2506 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2507 sc = inb(iobase1+ATA_CB_SC);
2508 sn = inb(iobase1+ATA_CB_SN);
2510 if ( (sc==0x01) && (sn==0x01) ) {
2512 // 8.2.1 (h) -- wait for not BSY
2515 Bit8u status = inb(iobase1+ATA_CB_STAT);
2516 if ((status & ATA_CB_STAT_BSY) == 0) break;
2521 // 8.2.1 (i) -- wait for DRDY
2524 Bit8u status = inb(iobase1+ATA_CB_STAT);
2525 if ((status & ATA_CB_STAT_RDY) != 0) break;
2528 // Enable interrupts
2529 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2532 // ---------------------------------------------------------------------------
2533 // ATA/ATAPI driver : execute a non data command
2534 // ---------------------------------------------------------------------------
2536 Bit16u ata_cmd_non_data()
2539 // ---------------------------------------------------------------------------
2540 // ATA/ATAPI driver : execute a data-in command
2541 // ---------------------------------------------------------------------------
2546 // 3 : expected DRQ=1
2547 // 4 : no sectors left to read/verify
2548 // 5 : more sectors to read/verify
2549 // 6 : no sectors left to write
2550 // 7 : more sectors to write
2551 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2552 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2555 Bit16u ebda_seg=read_word(0x0040,0x000E);
2556 Bit16u iobase1, iobase2, blksize;
2557 Bit8u channel, slave;
2558 Bit8u status, current, mode;
2560 channel = device / 2;
2563 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2564 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2565 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2566 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2567 if (mode == ATA_MODE_PIO32) blksize>>=2;
2570 // sector will be 0 only on lba access. Convert to lba-chs
2572 sector = (Bit16u) (lba & 0x000000ffL);
2574 cylinder = (Bit16u) (lba & 0x0000ffffL);
2576 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2579 // Reset count of transferred data
2580 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2581 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2584 status = inb(iobase1 + ATA_CB_STAT);
2585 if (status & ATA_CB_STAT_BSY) return 1;
2587 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2588 outb(iobase1 + ATA_CB_FR, 0x00);
2589 outb(iobase1 + ATA_CB_SC, count);
2590 outb(iobase1 + ATA_CB_SN, sector);
2591 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2592 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2593 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2594 outb(iobase1 + ATA_CB_CMD, command);
2597 status = inb(iobase1 + ATA_CB_STAT);
2598 if ( !(status & ATA_CB_STAT_BSY) ) break;
2601 if (status & ATA_CB_STAT_ERR) {
2602 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2604 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2605 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2609 // FIXME : move seg/off translation here
2612 sti ;; enable higher priority interrupts
2620 mov di, _ata_cmd_data_in.offset + 2[bp]
2621 mov ax, _ata_cmd_data_in.segment + 2[bp]
2622 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2624 ;; adjust if there will be an overrun. 2K max sector size
2626 jbe ata_in_no_adjust
2629 sub di, #0x0800 ;; sub 2 kbytes from offset
2630 add ax, #0x0080 ;; add 2 Kbytes to segment
2633 mov es, ax ;; segment in es
2635 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2637 mov ah, _ata_cmd_data_in.mode + 2[bp]
2638 cmp ah, #ATA_MODE_PIO32
2643 insw ;; CX words transfered from port(DX) to ES:[DI]
2648 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2651 mov _ata_cmd_data_in.offset + 2[bp], di
2652 mov _ata_cmd_data_in.segment + 2[bp], es
2657 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2659 status = inb(iobase1 + ATA_CB_STAT);
2661 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2662 != ATA_CB_STAT_RDY ) {
2663 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2669 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2670 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2671 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2677 // Enable interrupts
2678 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2682 // ---------------------------------------------------------------------------
2683 // ATA/ATAPI driver : execute a data-out command
2684 // ---------------------------------------------------------------------------
2689 // 3 : expected DRQ=1
2690 // 4 : no sectors left to read/verify
2691 // 5 : more sectors to read/verify
2692 // 6 : no sectors left to write
2693 // 7 : more sectors to write
2694 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2695 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2698 Bit16u ebda_seg=read_word(0x0040,0x000E);
2699 Bit16u iobase1, iobase2, blksize;
2700 Bit8u channel, slave;
2701 Bit8u status, current, mode;
2703 channel = device / 2;
2706 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2707 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2708 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2709 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2710 if (mode == ATA_MODE_PIO32) blksize>>=2;
2713 // sector will be 0 only on lba access. Convert to lba-chs
2715 sector = (Bit16u) (lba & 0x000000ffL);
2717 cylinder = (Bit16u) (lba & 0x0000ffffL);
2719 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2722 // Reset count of transferred data
2723 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2724 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2727 status = inb(iobase1 + ATA_CB_STAT);
2728 if (status & ATA_CB_STAT_BSY) return 1;
2730 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2731 outb(iobase1 + ATA_CB_FR, 0x00);
2732 outb(iobase1 + ATA_CB_SC, count);
2733 outb(iobase1 + ATA_CB_SN, sector);
2734 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2735 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2736 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2737 outb(iobase1 + ATA_CB_CMD, command);
2740 status = inb(iobase1 + ATA_CB_STAT);
2741 if ( !(status & ATA_CB_STAT_BSY) ) break;
2744 if (status & ATA_CB_STAT_ERR) {
2745 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2747 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2748 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2752 // FIXME : move seg/off translation here
2755 sti ;; enable higher priority interrupts
2763 mov si, _ata_cmd_data_out.offset + 2[bp]
2764 mov ax, _ata_cmd_data_out.segment + 2[bp]
2765 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2767 ;; adjust if there will be an overrun. 2K max sector size
2769 jbe ata_out_no_adjust
2772 sub si, #0x0800 ;; sub 2 kbytes from offset
2773 add ax, #0x0080 ;; add 2 Kbytes to segment
2776 mov es, ax ;; segment in es
2778 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2780 mov ah, _ata_cmd_data_out.mode + 2[bp]
2781 cmp ah, #ATA_MODE_PIO32
2787 outsw ;; CX words transfered from port(DX) to ES:[SI]
2793 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2796 mov _ata_cmd_data_out.offset + 2[bp], si
2797 mov _ata_cmd_data_out.segment + 2[bp], es
2802 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2804 status = inb(iobase1 + ATA_CB_STAT);
2806 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2807 != ATA_CB_STAT_RDY ) {
2808 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2814 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2815 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2816 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2822 // Enable interrupts
2823 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2827 // ---------------------------------------------------------------------------
2828 // ATA/ATAPI driver : execute a packet command
2829 // ---------------------------------------------------------------------------
2832 // 1 : error in parameters
2836 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2838 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2842 Bit16u ebda_seg=read_word(0x0040,0x000E);
2843 Bit16u iobase1, iobase2;
2844 Bit16u lcount, lbefore, lafter, count;
2845 Bit8u channel, slave;
2846 Bit8u status, mode, lmode;
2847 Bit32u total, transfer;
2849 channel = device / 2;
2852 // Data out is not supported yet
2853 if (inout == ATA_DATA_OUT) {
2854 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2858 // The header length must be even
2860 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2864 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2865 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2866 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2869 if (cmdlen < 12) cmdlen=12;
2870 if (cmdlen > 12) cmdlen=16;
2873 // Reset count of transferred data
2874 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2875 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2877 status = inb(iobase1 + ATA_CB_STAT);
2878 if (status & ATA_CB_STAT_BSY) return 2;
2880 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2881 // outb(iobase1 + ATA_CB_FR, 0x00);
2882 // outb(iobase1 + ATA_CB_SC, 0x00);
2883 // outb(iobase1 + ATA_CB_SN, 0x00);
2884 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2885 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2886 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2887 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2889 // Device should ok to receive command
2891 status = inb(iobase1 + ATA_CB_STAT);
2892 if ( !(status & ATA_CB_STAT_BSY) ) break;
2895 if (status & ATA_CB_STAT_ERR) {
2896 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2898 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2899 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2903 // Normalize address
2904 cmdseg += (cmdoff / 16);
2907 // Send command to device
2909 sti ;; enable higher priority interrupts
2914 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2915 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2916 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2917 mov es, ax ;; segment in es
2919 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2923 outsw ;; CX words transfered from port(DX) to ES:[SI]
2928 if (inout == ATA_DATA_NO) {
2929 status = inb(iobase1 + ATA_CB_STAT);
2934 status = inb(iobase1 + ATA_CB_STAT);
2936 // Check if command completed
2937 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2939 if (status & ATA_CB_STAT_ERR) {
2940 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2944 // Device must be ready to send data
2945 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2946 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2947 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
2951 // Normalize address
2952 bufseg += (bufoff / 16);
2955 // Get the byte count
2956 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
2958 // adjust to read what we want
2971 lafter=lcount-length;
2983 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
2984 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
2986 // If counts not dividable by 4, use 16bits mode
2988 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
2989 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
2990 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
2992 // adds an extra byte if count are odd. before is always even
2993 if (lcount & 0x01) {
2995 if ((lafter > 0) && (lafter & 0x01)) {
3000 if (lmode == ATA_MODE_PIO32) {
3001 lcount>>=2; lbefore>>=2; lafter>>=2;
3004 lcount>>=1; lbefore>>=1; lafter>>=1;
3013 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3015 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3016 jcxz ata_packet_no_before
3018 mov ah, _ata_cmd_packet.lmode + 2[bp]
3019 cmp ah, #ATA_MODE_PIO32
3020 je ata_packet_in_before_32
3022 ata_packet_in_before_16:
3024 loop ata_packet_in_before_16
3025 jmp ata_packet_no_before
3027 ata_packet_in_before_32:
3029 ata_packet_in_before_32_loop:
3031 loop ata_packet_in_before_32_loop
3034 ata_packet_no_before:
3035 mov cx, _ata_cmd_packet.lcount + 2[bp]
3036 jcxz ata_packet_after
3038 mov di, _ata_cmd_packet.bufoff + 2[bp]
3039 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3042 mov ah, _ata_cmd_packet.lmode + 2[bp]
3043 cmp ah, #ATA_MODE_PIO32
3048 insw ;; CX words transfered tp port(DX) to ES:[DI]
3049 jmp ata_packet_after
3053 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3056 mov cx, _ata_cmd_packet.lafter + 2[bp]
3057 jcxz ata_packet_done
3059 mov ah, _ata_cmd_packet.lmode + 2[bp]
3060 cmp ah, #ATA_MODE_PIO32
3061 je ata_packet_in_after_32
3063 ata_packet_in_after_16:
3065 loop ata_packet_in_after_16
3068 ata_packet_in_after_32:
3070 ata_packet_in_after_32_loop:
3072 loop ata_packet_in_after_32_loop
3079 // Compute new buffer address
3082 // Save transferred bytes count
3084 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3088 // Final check, device must be ready
3089 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3090 != ATA_CB_STAT_RDY ) {
3091 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3095 // Enable interrupts
3096 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3100 // ---------------------------------------------------------------------------
3101 // End of ATA/ATAPI Driver
3102 // ---------------------------------------------------------------------------
3104 // ---------------------------------------------------------------------------
3105 // Start of ATA/ATAPI generic functions
3106 // ---------------------------------------------------------------------------
3109 atapi_get_sense(device)
3116 memsetb(get_SS(),atacmd,0,12);
3121 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3124 if ((buffer[0] & 0x7e) == 0x70) {
3125 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3132 atapi_is_ready(device)
3138 memsetb(get_SS(),atacmd,0,12);
3141 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3144 if (atapi_get_sense(device) !=0 ) {
3145 memsetb(get_SS(),atacmd,0,12);
3147 // try to send Test Unit Ready again
3148 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3151 return atapi_get_sense(device);
3157 atapi_is_cdrom(device)
3160 Bit16u ebda_seg=read_word(0x0040,0x000E);
3162 if (device >= BX_MAX_ATA_DEVICES)
3165 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3168 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3174 // ---------------------------------------------------------------------------
3175 // End of ATA/ATAPI generic functions
3176 // ---------------------------------------------------------------------------
3178 #endif // BX_USE_ATADRV
3180 #if BX_ELTORITO_BOOT
3182 // ---------------------------------------------------------------------------
3183 // Start of El-Torito boot functions
3184 // ---------------------------------------------------------------------------
3189 Bit16u ebda_seg=read_word(0x0040,0x000E);
3191 printf("rombios: cdemu_init\n");
3193 // the only important data is this one for now
3194 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3200 Bit16u ebda_seg=read_word(0x0040,0x000E);
3202 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3206 cdemu_emulated_drive()
3208 Bit16u ebda_seg=read_word(0x0040,0x000E);
3210 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3213 static char isotag[6]="CD001";
3214 static char eltorito[24]="EL TORITO SPECIFICATION";
3216 // Returns ah: emulated drive, al: error code
3221 Bit16u ebda_seg=read_word(0x0040,0x000E);
3222 Bit8u atacmd[12], buffer[2048];
3224 Bit16u boot_segment, nbsectors, i, error;
3227 // Find out the first cdrom
3228 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3229 if (atapi_is_cdrom(device)) break;
3233 if(device >= BX_MAX_ATA_DEVICES) return 2;
3235 // Read the Boot Record Volume Descriptor
3236 memsetb(get_SS(),atacmd,0,12);
3237 atacmd[0]=0x28; // READ command
3238 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3239 atacmd[8]=(0x01 & 0x00ff); // Sectors
3240 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3241 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3242 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3243 atacmd[5]=(0x11 & 0x000000ff);
3244 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3248 if(buffer[0]!=0)return 4;
3250 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3253 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3255 // ok, now we calculate the Boot catalog address
3256 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3258 // And we read the Boot Catalog
3259 memsetb(get_SS(),atacmd,0,12);
3260 atacmd[0]=0x28; // READ command
3261 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3262 atacmd[8]=(0x01 & 0x00ff); // Sectors
3263 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3264 atacmd[3]=(lba & 0x00ff0000) >> 16;
3265 atacmd[4]=(lba & 0x0000ff00) >> 8;
3266 atacmd[5]=(lba & 0x000000ff);
3267 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3271 if(buffer[0x00]!=0x01)return 8; // Header
3272 if(buffer[0x01]!=0x00)return 9; // Platform
3273 if(buffer[0x1E]!=0x55)return 10; // key 1
3274 if(buffer[0x1F]!=0xAA)return 10; // key 2
3276 // Initial/Default Entry
3277 if(buffer[0x20]!=0x88)return 11; // Bootable
3279 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3280 if(buffer[0x21]==0){
3281 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3282 // Win2000 cd boot needs to know it booted from cd
3283 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3285 else if(buffer[0x21]<4)
3286 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3288 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3290 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3291 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3293 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3294 if(boot_segment==0x0000)boot_segment=0x07C0;
3296 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3297 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3299 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3300 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3302 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3303 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3305 // And we read the image in memory
3306 memsetb(get_SS(),atacmd,0,12);
3307 atacmd[0]=0x28; // READ command
3308 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3309 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3310 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3311 atacmd[3]=(lba & 0x00ff0000) >> 16;
3312 atacmd[4]=(lba & 0x0000ff00) >> 8;
3313 atacmd[5]=(lba & 0x000000ff);
3314 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3317 // Remember the media type
3318 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3319 case 0x01: // 1.2M floppy
3320 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3321 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3322 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3324 case 0x02: // 1.44M floppy
3325 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3326 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3327 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3329 case 0x03: // 2.88M floppy
3330 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3331 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3332 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3334 case 0x04: // Harddrive
3335 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3336 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3337 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3338 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3342 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3343 // Increase bios installed hardware number of devices
3344 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3345 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3347 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3351 // everything is ok, so from now on, the emulation is active
3352 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3353 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3355 // return the boot drive + no error
3356 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3359 // ---------------------------------------------------------------------------
3360 // End of El-Torito boot functions
3361 // ---------------------------------------------------------------------------
3362 #endif // BX_ELTORITO_BOOT
3365 int14_function(regs, ds, iret_addr)
3366 pusha_regs_t regs; // regs pushed from PUSHA instruction
3367 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3368 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3370 Bit16u addr,timer,val16;
3377 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3378 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3379 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3380 switch (regs.u.r8.ah) {
3382 outb(addr+3, inb(addr+3) | 0x80);
3383 if (regs.u.r8.al & 0xE0 == 0) {
3387 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3388 outb(addr, val16 & 0xFF);
3389 outb(addr+1, val16 >> 8);
3391 outb(addr+3, regs.u.r8.al & 0x1F);
3392 regs.u.r8.ah = inb(addr+5);
3393 regs.u.r8.al = inb(addr+6);
3394 ClearCF(iret_addr.flags);
3397 timer = read_word(0x0040, 0x006C);
3398 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3399 val16 = read_word(0x0040, 0x006C);
3400 if (val16 != timer) {
3405 if (timeout) outb(addr, regs.u.r8.al);
3406 regs.u.r8.ah = inb(addr+5);
3407 if (!timeout) regs.u.r8.ah |= 0x80;
3408 ClearCF(iret_addr.flags);
3411 timer = read_word(0x0040, 0x006C);
3412 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3413 val16 = read_word(0x0040, 0x006C);
3414 if (val16 != timer) {
3421 regs.u.r8.al = inb(addr);
3423 regs.u.r8.ah = inb(addr+5);
3425 ClearCF(iret_addr.flags);
3428 regs.u.r8.ah = inb(addr+5);
3429 regs.u.r8.al = inb(addr+6);
3430 ClearCF(iret_addr.flags);
3433 SetCF(iret_addr.flags); // Unsupported
3436 SetCF(iret_addr.flags); // Unsupported
3441 int15_function(regs, ES, DS, FLAGS)
3442 pusha_regs_t regs; // REGS pushed via pusha
3443 Bit16u ES, DS, FLAGS;
3445 Bit16u ebda_seg=read_word(0x0040,0x000E);
3446 bx_bool prev_a20_enable;
3455 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3457 switch (regs.u.r8.ah) {
3458 case 0x24: /* A20 Control */
3459 switch (regs.u.r8.al) {
3471 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3481 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3483 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3489 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3493 /* keyboard intercept */
3495 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3502 case 0x52: // removable media eject
3504 regs.u.r8.ah = 0; // "ok ejection may proceed"
3508 if( regs.u.r8.al == 0 ) {
3509 // Set Interval requested.
3510 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3511 // Interval not already set.
3512 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3513 write_word( 0x40, 0x98, ES ); // Byte location, segment
3514 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3515 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3516 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3518 irqDisable = inb( 0xA1 );
3519 outb( 0xA1, irqDisable & 0xFE );
3520 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3521 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3523 // Interval already set.
3524 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3526 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3528 } else if( regs.u.r8.al == 1 ) {
3529 // Clear Interval requested
3530 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3532 bRegister = inb_cmos( 0xB );
3533 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3535 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3537 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3546 # error "Int15 function 87h not supported on < 80386"
3548 // +++ should probably have descriptor checks
3549 // +++ should have exception handlers
3551 // turn off interrupts
3556 prev_a20_enable = set_enable_a20(1); // enable A20 line
3558 // 128K max of transfer on 386+ ???
3559 // source == destination ???
3561 // ES:SI points to descriptor table
3562 // offset use initially comments
3563 // ==============================================
3564 // 00..07 Unused zeros Null descriptor
3565 // 08..0f GDT zeros filled in by BIOS
3566 // 10..17 source ssssssss source of data
3567 // 18..1f dest dddddddd destination of data
3568 // 20..27 CS zeros filled in by BIOS
3569 // 28..2f SS zeros filled in by BIOS
3576 // check for access rights of source & dest here
3578 // Initialize GDT descriptor
3579 base15_00 = (ES << 4) + regs.u.r16.si;
3580 base23_16 = ES >> 12;
3581 if (base15_00 < (ES<<4))
3583 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3584 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3585 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3586 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3587 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3589 // Initialize CS descriptor
3590 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3591 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3592 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3593 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3594 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3596 // Initialize SS descriptor
3598 base15_00 = ss << 4;
3599 base23_16 = ss >> 12;
3600 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3601 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3602 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3603 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3604 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3608 // Compile generates locals offset info relative to SP.
3609 // Get CX (word count) from stack.
3612 mov cx, _int15_function.CX [bx]
3614 // since we need to set SS:SP, save them to the BDA
3615 // for future restore
3625 lidt [pmode_IDT_info]
3626 ;; perhaps do something with IDT here
3628 ;; set PE bit in CR0
3632 ;; far jump to flush CPU queue after transition to protected mode
3633 JMP_AP(0x0020, protected_mode)
3636 ;; GDT points to valid descriptor table, now load SS, DS, ES
3637 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3639 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3641 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3647 movsw ;; move CX words from DS:SI to ES:DI
3649 ;; make sure DS and ES limits are 64KB
3654 ;; reset PG bit in CR0 ???
3659 ;; far jump to flush CPU queue after transition to real mode
3660 JMP_AP(0xf000, real_mode)
3663 ;; restore IDT to normal real-mode defaults
3665 lidt [rmode_IDT_info]
3667 // restore SS:SP from the BDA
3675 set_enable_a20(prev_a20_enable);
3677 // turn back on interrupts
3688 // Get the amount of extended memory (above 1M)
3690 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3693 regs.u.r8.al = inb_cmos(0x30);
3694 regs.u.r8.ah = inb_cmos(0x31);
3697 if(regs.u.r16.ax > 0x3c00)
3698 regs.u.r16.ax = 0x3c00;
3705 /* Device busy interrupt. Called by Int 16h when no key available */
3709 /* Interrupt complete. Called by Int 16h when key becomes available */
3713 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3715 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3721 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3726 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3736 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3738 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3742 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3743 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3745 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3750 #if BX_USE_PS2_MOUSE
3752 int15_function_mouse(regs, ES, DS, FLAGS)
3753 pusha_regs_t regs; // REGS pushed via pusha
3754 Bit16u ES, DS, FLAGS;
3756 Bit16u ebda_seg=read_word(0x0040,0x000E);
3757 Bit8u mouse_flags_1, mouse_flags_2;
3758 Bit16u mouse_driver_seg;
3759 Bit16u mouse_driver_offset;
3760 Bit8u comm_byte, prev_command_byte;
3761 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3763 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3765 switch (regs.u.r8.ah) {
3767 // Return Codes status in AH
3768 // =========================
3770 // 01: invalid subfunction (AL > 7)
3771 // 02: invalid input value (out of allowable range)
3772 // 03: interface error
3773 // 04: resend command received from mouse controller,
3774 // device driver should attempt command again
3775 // 05: cannot enable mouse, since no far call has been installed
3776 // 80/86: mouse service not implemented
3778 switch (regs.u.r8.al) {
3779 case 0: // Disable/Enable Mouse
3780 BX_DEBUG_INT15("case 0:\n");
3781 switch (regs.u.r8.bh) {
3782 case 0: // Disable Mouse
3783 BX_DEBUG_INT15("case 0: disable mouse\n");
3784 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3785 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3787 ret = get_mouse_data(&mouse_data1);
3788 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3801 case 1: // Enable Mouse
3802 BX_DEBUG_INT15("case 1: enable mouse\n");
3803 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3804 if ( (mouse_flags_2 & 0x80) == 0 ) {
3805 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3807 regs.u.r8.ah = 5; // no far call installed
3810 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3811 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3813 ret = get_mouse_data(&mouse_data1);
3814 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3815 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3825 default: // invalid subfunction
3826 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3828 regs.u.r8.ah = 1; // invalid subfunction
3833 case 1: // Reset Mouse
3834 case 5: // Initialize Mouse
3835 BX_DEBUG_INT15("case 1 or 5:\n");
3836 if (regs.u.r8.al == 5) {
3837 if (regs.u.r8.bh != 3) {
3839 regs.u.r8.ah = 0x02; // invalid input
3842 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3843 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3844 mouse_flags_1 = 0x00;
3845 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3846 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3849 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3850 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3852 ret = get_mouse_data(&mouse_data3);
3853 // if no mouse attached, it will return RESEND
3854 if (mouse_data3 == 0xfe) {
3858 if (mouse_data3 != 0xfa)
3859 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3861 ret = get_mouse_data(&mouse_data1);
3863 ret = get_mouse_data(&mouse_data2);
3865 // turn IRQ12 and packet generation on
3866 enable_mouse_int_and_events();
3869 regs.u.r8.bl = mouse_data1;
3870 regs.u.r8.bh = mouse_data2;
3882 case 2: // Set Sample Rate
3883 BX_DEBUG_INT15("case 2:\n");
3884 switch (regs.u.r8.bh) {
3885 case 0: mouse_data1 = 10; break; // 10 reports/sec
3886 case 1: mouse_data1 = 20; break; // 20 reports/sec
3887 case 2: mouse_data1 = 40; break; // 40 reports/sec
3888 case 3: mouse_data1 = 60; break; // 60 reports/sec
3889 case 4: mouse_data1 = 80; break; // 80 reports/sec
3890 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3891 case 6: mouse_data1 = 200; break; // 200 reports/sec
3892 default: mouse_data1 = 0;
3894 if (mouse_data1 > 0) {
3895 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3897 ret = get_mouse_data(&mouse_data2);
3898 ret = send_to_mouse_ctrl(mouse_data1);
3899 ret = get_mouse_data(&mouse_data2);
3905 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3910 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3914 case 3: // Set Resolution
3915 BX_DEBUG_INT15("case 3:\n");
3917 // 0 = 25 dpi, 1 count per millimeter
3918 // 1 = 50 dpi, 2 counts per millimeter
3919 // 2 = 100 dpi, 4 counts per millimeter
3920 // 3 = 200 dpi, 8 counts per millimeter
3925 case 4: // Get Device ID
3926 BX_DEBUG_INT15("case 4:\n");
3927 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3928 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3930 ret = get_mouse_data(&mouse_data1);
3931 ret = get_mouse_data(&mouse_data2);
3934 regs.u.r8.bh = mouse_data2;
3938 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3942 case 6: // Return Status & Set Scaling Factor...
3943 BX_DEBUG_INT15("case 6:\n");
3944 switch (regs.u.r8.bh) {
3945 case 0: // Return Status
3946 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3947 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
3949 ret = get_mouse_data(&mouse_data1);
3950 if (mouse_data1 != 0xfa)
3951 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
3953 ret = get_mouse_data(&mouse_data1);
3955 ret = get_mouse_data(&mouse_data2);
3957 ret = get_mouse_data(&mouse_data3);
3961 regs.u.r8.bl = mouse_data1;
3962 regs.u.r8.cl = mouse_data2;
3963 regs.u.r8.dl = mouse_data3;
3964 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3975 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3978 case 1: // Set Scaling Factor to 1:1
3979 case 2: // Set Scaling Factor to 2:1
3980 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3981 if (regs.u.r8.bh == 1) {
3982 ret = send_to_mouse_ctrl(0xE6);
3984 ret = send_to_mouse_ctrl(0xE7);
3987 get_mouse_data(&mouse_data1);
3988 ret = (mouse_data1 != 0xFA);
3996 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3998 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4002 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4006 case 7: // Set Mouse Handler Address
4007 BX_DEBUG_INT15("case 7:\n");
4008 mouse_driver_seg = ES;
4009 mouse_driver_offset = regs.u.r16.bx;
4010 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4011 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4012 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4013 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4014 /* remove handler */
4015 if ( (mouse_flags_2 & 0x80) != 0 ) {
4016 mouse_flags_2 &= ~0x80;
4017 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4021 /* install handler */
4022 mouse_flags_2 |= 0x80;
4024 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4030 BX_DEBUG_INT15("case default:\n");
4031 regs.u.r8.ah = 1; // invalid function
4037 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4038 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4040 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4047 int15_function32(regs, ES, DS, FLAGS)
4048 pushad_regs_t regs; // REGS pushed via pushad
4049 Bit16u ES, DS, FLAGS;
4051 Bit32u extended_memory_size=0; // 64bits long
4054 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4056 switch (regs.u.r8.ah) {
4058 // Wait for CX:DX microseconds. currently using the
4059 // refresh request port 0x61 bit4, toggling every 15usec
4067 ;; Get the count in eax
4070 mov ax, _int15_function.CX [bx]
4073 mov ax, _int15_function.DX [bx]
4075 ;; convert to numbers of 15usec ticks
4081 ;; wait for ecx number of refresh requests
4102 switch(regs.u.r8.al)
4104 case 0x20: // coded by osmaker aka K.J.
4105 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4108 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4109 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4111 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4112 memcpyb(ES, regs.u.r16.di,
4113 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4115 regs.u.r32.ebx += 0x14;
4116 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4118 regs.u.r32.eax = 0x534D4150;
4119 regs.u.r32.ecx = 0x14;
4122 } else if (regs.u.r16.bx == 1) {
4123 extended_memory_size = inb_cmos(0x35);
4124 extended_memory_size <<= 8;
4125 extended_memory_size |= inb_cmos(0x34);
4126 extended_memory_size *= 64;
4127 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4129 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4131 extended_memory_size *= 1024;
4132 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4134 if (extended_memory_size <= 15728640)
4136 extended_memory_size = inb_cmos(0x31);
4137 extended_memory_size <<= 8;
4138 extended_memory_size |= inb_cmos(0x30);
4139 extended_memory_size *= 1024;
4142 write_word(ES, regs.u.r16.di, 0x0000);
4143 write_word(ES, regs.u.r16.di+2, 0x0010);
4144 write_word(ES, regs.u.r16.di+4, 0x0000);
4145 write_word(ES, regs.u.r16.di+6, 0x0000);
4147 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4148 extended_memory_size >>= 16;
4149 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4150 extended_memory_size >>= 16;
4151 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4152 extended_memory_size >>= 16;
4153 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4155 write_word(ES, regs.u.r16.di+16, 0x1);
4156 write_word(ES, regs.u.r16.di+18, 0x0);
4159 regs.u.r32.eax = 0x534D4150;
4160 regs.u.r32.ecx = 0x14;
4163 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4164 goto int15_unimplemented;
4167 switch(regs.u.r16.bx)
4170 write_word(ES, regs.u.r16.di, 0x00);
4171 write_word(ES, regs.u.r16.di+2, 0x00);
4172 write_word(ES, regs.u.r16.di+4, 0x00);
4173 write_word(ES, regs.u.r16.di+6, 0x00);
4175 write_word(ES, regs.u.r16.di+8, 0xFC00);
4176 write_word(ES, regs.u.r16.di+10, 0x0009);
4177 write_word(ES, regs.u.r16.di+12, 0x0000);
4178 write_word(ES, regs.u.r16.di+14, 0x0000);
4180 write_word(ES, regs.u.r16.di+16, 0x1);
4181 write_word(ES, regs.u.r16.di+18, 0x0);
4185 regs.u.r32.eax = 0x534D4150;
4186 regs.u.r32.ecx = 0x14;
4191 extended_memory_size = inb_cmos(0x35);
4192 extended_memory_size <<= 8;
4193 extended_memory_size |= inb_cmos(0x34);
4194 extended_memory_size *= 64;
4195 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4197 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4199 extended_memory_size *= 1024;
4200 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4202 if(extended_memory_size <= 15728640)
4204 extended_memory_size = inb_cmos(0x31);
4205 extended_memory_size <<= 8;
4206 extended_memory_size |= inb_cmos(0x30);
4207 extended_memory_size *= 1024;
4210 write_word(ES, regs.u.r16.di, 0x0000);
4211 write_word(ES, regs.u.r16.di+2, 0x0010);
4212 write_word(ES, regs.u.r16.di+4, 0x0000);
4213 write_word(ES, regs.u.r16.di+6, 0x0000);
4215 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4216 extended_memory_size >>= 16;
4217 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4218 extended_memory_size >>= 16;
4219 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4220 extended_memory_size >>= 16;
4221 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4223 write_word(ES, regs.u.r16.di+16, 0x1);
4224 write_word(ES, regs.u.r16.di+18, 0x0);
4227 regs.u.r32.eax = 0x534D4150;
4228 regs.u.r32.ecx = 0x14;
4232 default: /* AX=E820, DX=534D4150, BX unrecognized */
4233 goto int15_unimplemented;
4238 // if DX != 0x534D4150)
4239 goto int15_unimplemented;
4244 // do we have any reason to fail here ?
4247 // my real system sets ax and bx to 0
4248 // this is confirmed by Ralph Brown list
4249 // but syslinux v1.48 is known to behave
4250 // strangely if ax is set to 0
4251 // regs.u.r16.ax = 0;
4252 // regs.u.r16.bx = 0;
4254 // Get the amount of extended memory (above 1M)
4255 regs.u.r8.cl = inb_cmos(0x30);
4256 regs.u.r8.ch = inb_cmos(0x31);
4259 if(regs.u.r16.cx > 0x3c00)
4261 regs.u.r16.cx = 0x3c00;
4264 // Get the amount of extended memory above 16M in 64k blocs
4265 regs.u.r8.dl = inb_cmos(0x34);
4266 regs.u.r8.dh = inb_cmos(0x35);
4268 // Set configured memory equal to extended memory
4269 regs.u.r16.ax = regs.u.r16.cx;
4270 regs.u.r16.bx = regs.u.r16.dx;
4272 default: /* AH=0xE8?? but not implemented */
4273 goto int15_unimplemented;
4276 int15_unimplemented:
4277 // fall into the default
4279 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4280 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4282 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4288 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4289 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4291 Bit8u scan_code, ascii_code, shift_flags, count;
4292 Bit16u kbd_code, max;
4294 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4297 case 0x00: /* read keyboard input */
4299 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4300 BX_PANIC("KBD: int16h: out of keyboard input\n");
4302 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4303 else if (ascii_code == 0xE0) ascii_code = 0;
4304 AX = (scan_code << 8) | ascii_code;
4307 case 0x01: /* check keyboard status */
4308 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4312 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4313 else if (ascii_code == 0xE0) ascii_code = 0;
4314 AX = (scan_code << 8) | ascii_code;
4318 case 0x02: /* get shift flag status */
4319 shift_flags = read_byte(0x0040, 0x17);
4320 SET_AL(shift_flags);
4323 case 0x05: /* store key-stroke into buffer */
4324 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4332 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4333 // bit Bochs Description
4335 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4336 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4337 // 4 1 INT 16/AH=0Ah supported
4338 // 3 0 INT 16/AX=0306h supported
4339 // 2 0 INT 16/AX=0305h supported
4340 // 1 0 INT 16/AX=0304h supported
4341 // 0 0 INT 16/AX=0300h supported
4346 case 0x0A: /* GET KEYBOARD ID */
4352 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4354 if ((inb(0x60) == 0xfa)) {
4357 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4360 kbd_code |= (inb(0x60) << 8);
4362 } while (--count>0);
4368 case 0x10: /* read MF-II keyboard input */
4370 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4371 BX_PANIC("KBD: int16h: out of keyboard input\n");
4373 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4374 AX = (scan_code << 8) | ascii_code;
4377 case 0x11: /* check MF-II keyboard status */
4378 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4382 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4383 AX = (scan_code << 8) | ascii_code;
4387 case 0x12: /* get extended keyboard status */
4388 shift_flags = read_byte(0x0040, 0x17);
4389 SET_AL(shift_flags);
4390 shift_flags = read_byte(0x0040, 0x18);
4391 SET_AH(shift_flags);
4392 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4395 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4396 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4399 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4400 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4404 if (GET_AL() == 0x08)
4405 SET_AH(0x02); // unsupported, aka normal keyboard
4408 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4413 dequeue_key(scan_code, ascii_code, incr)
4418 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4423 buffer_start = 0x001E;
4424 buffer_end = 0x003E;
4426 buffer_start = read_word(0x0040, 0x0080);
4427 buffer_end = read_word(0x0040, 0x0082);
4430 buffer_head = read_word(0x0040, 0x001a);
4431 buffer_tail = read_word(0x0040, 0x001c);
4433 if (buffer_head != buffer_tail) {
4435 acode = read_byte(0x0040, buffer_head);
4436 scode = read_byte(0x0040, buffer_head+1);
4437 write_byte(ss, ascii_code, acode);
4438 write_byte(ss, scan_code, scode);
4442 if (buffer_head >= buffer_end)
4443 buffer_head = buffer_start;
4444 write_word(0x0040, 0x001a, buffer_head);
4453 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4456 inhibit_mouse_int_and_events()
4458 Bit8u command_byte, prev_command_byte;
4460 // Turn off IRQ generation and aux data line
4461 if ( inb(0x64) & 0x02 )
4462 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4463 outb(0x64, 0x20); // get command byte
4464 while ( (inb(0x64) & 0x01) != 0x01 );
4465 prev_command_byte = inb(0x60);
4466 command_byte = prev_command_byte;
4467 //while ( (inb(0x64) & 0x02) );
4468 if ( inb(0x64) & 0x02 )
4469 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4470 command_byte &= 0xfd; // turn off IRQ 12 generation
4471 command_byte |= 0x20; // disable mouse serial clock line
4472 outb(0x64, 0x60); // write command byte
4473 outb(0x60, command_byte);
4474 return(prev_command_byte);
4478 enable_mouse_int_and_events()
4482 // Turn on IRQ generation and aux data line
4483 if ( inb(0x64) & 0x02 )
4484 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4485 outb(0x64, 0x20); // get command byte
4486 while ( (inb(0x64) & 0x01) != 0x01 );
4487 command_byte = inb(0x60);
4488 //while ( (inb(0x64) & 0x02) );
4489 if ( inb(0x64) & 0x02 )
4490 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4491 command_byte |= 0x02; // turn on IRQ 12 generation
4492 command_byte &= 0xdf; // enable mouse serial clock line
4493 outb(0x64, 0x60); // write command byte
4494 outb(0x60, command_byte);
4498 send_to_mouse_ctrl(sendbyte)
4503 // wait for chance to write to ctrl
4504 if ( inb(0x64) & 0x02 )
4505 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4507 outb(0x60, sendbyte);
4513 get_mouse_data(data)
4519 while ( (inb(0x64) & 0x21) != 0x21 ) {
4522 response = inb(0x60);
4525 write_byte(ss, data, response);
4530 set_kbd_command_byte(command_byte)
4533 if ( inb(0x64) & 0x02 )
4534 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4537 outb(0x64, 0x60); // write command byte
4538 outb(0x60, command_byte);
4542 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4543 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4545 Bit8u scancode, asciicode, shift_flags;
4546 Bit8u mf2_flags, mf2_state, led_flags;
4549 // DS has been set to F000 before call
4553 scancode = GET_AL();
4555 if (scancode == 0) {
4556 BX_INFO("KBD: int09 handler: AL=0\n");
4561 shift_flags = read_byte(0x0040, 0x17);
4562 mf2_flags = read_byte(0x0040, 0x18);
4563 mf2_state = read_byte(0x0040, 0x96);
4564 led_flags = read_byte(0x0040, 0x97);
4568 case 0x3a: /* Caps Lock press */
4569 shift_flags ^= 0x40;
4570 write_byte(0x0040, 0x17, shift_flags);
4572 write_byte(0x0040, 0x18, mf2_flags);
4574 write_byte(0x0040, 0x97, led_flags);
4576 case 0xba: /* Caps Lock release */
4578 write_byte(0x0040, 0x18, mf2_flags);
4581 case 0x2a: /* L Shift press */
4582 /*shift_flags &= ~0x40;*/
4583 shift_flags |= 0x02;
4584 write_byte(0x0040, 0x17, shift_flags);
4586 write_byte(0x0040, 0x97, led_flags);
4588 case 0xaa: /* L Shift release */
4589 shift_flags &= ~0x02;
4590 write_byte(0x0040, 0x17, shift_flags);
4593 case 0x36: /* R Shift press */
4594 /*shift_flags &= ~0x40;*/
4595 shift_flags |= 0x01;
4596 write_byte(0x0040, 0x17, shift_flags);
4598 write_byte(0x0040, 0x97, led_flags);
4600 case 0xb6: /* R Shift release */
4601 shift_flags &= ~0x01;
4602 write_byte(0x0040, 0x17, shift_flags);
4605 case 0x1d: /* Ctrl press */
4606 shift_flags |= 0x04;
4607 write_byte(0x0040, 0x17, shift_flags);
4608 if (mf2_state & 0x01) {
4613 write_byte(0x0040, 0x18, mf2_flags);
4615 case 0x9d: /* Ctrl release */
4616 shift_flags &= ~0x04;
4617 write_byte(0x0040, 0x17, shift_flags);
4618 if (mf2_state & 0x01) {
4623 write_byte(0x0040, 0x18, mf2_flags);
4626 case 0x38: /* Alt press */
4627 shift_flags |= 0x08;
4628 write_byte(0x0040, 0x17, shift_flags);
4629 if (mf2_state & 0x01) {
4634 write_byte(0x0040, 0x18, mf2_flags);
4636 case 0xb8: /* Alt release */
4637 shift_flags &= ~0x08;
4638 write_byte(0x0040, 0x17, shift_flags);
4639 if (mf2_state & 0x01) {
4644 write_byte(0x0040, 0x18, mf2_flags);
4647 case 0x45: /* Num Lock press */
4648 if ((mf2_state & 0x01) == 0) {
4650 write_byte(0x0040, 0x18, mf2_flags);
4651 shift_flags ^= 0x20;
4653 write_byte(0x0040, 0x17, shift_flags);
4654 write_byte(0x0040, 0x97, led_flags);
4657 case 0xc5: /* Num Lock release */
4658 if ((mf2_state & 0x01) == 0) {
4660 write_byte(0x0040, 0x18, mf2_flags);
4664 case 0x46: /* Scroll Lock press */
4666 write_byte(0x0040, 0x18, mf2_flags);
4667 shift_flags ^= 0x10;
4669 write_byte(0x0040, 0x17, shift_flags);
4670 write_byte(0x0040, 0x97, led_flags);
4673 case 0xc6: /* Scroll Lock release */
4675 write_byte(0x0040, 0x18, mf2_flags);
4679 if (scancode & 0x80) return; /* toss key releases ... */
4680 if (scancode > MAX_SCAN_CODE) {
4681 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4684 if (shift_flags & 0x08) { /* ALT */
4685 asciicode = scan_to_scanascii[scancode].alt;
4686 scancode = scan_to_scanascii[scancode].alt >> 8;
4688 else if (shift_flags & 0x04) { /* CONTROL */
4689 asciicode = scan_to_scanascii[scancode].control;
4690 scancode = scan_to_scanascii[scancode].control >> 8;
4692 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4693 /* check if lock state should be ignored
4694 * because a SHIFT key are pressed */
4696 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4697 asciicode = scan_to_scanascii[scancode].normal;
4698 scancode = scan_to_scanascii[scancode].normal >> 8;
4701 asciicode = scan_to_scanascii[scancode].shift;
4702 scancode = scan_to_scanascii[scancode].shift >> 8;
4706 /* check if lock is on */
4707 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4708 asciicode = scan_to_scanascii[scancode].shift;
4709 scancode = scan_to_scanascii[scancode].shift >> 8;
4712 asciicode = scan_to_scanascii[scancode].normal;
4713 scancode = scan_to_scanascii[scancode].normal >> 8;
4716 if (scancode==0 && asciicode==0) {
4717 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4719 enqueue_key(scancode, asciicode);
4726 enqueue_key(scan_code, ascii_code)
4727 Bit8u scan_code, ascii_code;
4729 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4731 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4732 // scan_code, ascii_code);
4735 buffer_start = 0x001E;
4736 buffer_end = 0x003E;
4738 buffer_start = read_word(0x0040, 0x0080);
4739 buffer_end = read_word(0x0040, 0x0082);
4742 buffer_head = read_word(0x0040, 0x001A);
4743 buffer_tail = read_word(0x0040, 0x001C);
4745 temp_tail = buffer_tail;
4747 if (buffer_tail >= buffer_end)
4748 buffer_tail = buffer_start;
4750 if (buffer_tail == buffer_head) {
4754 write_byte(0x0040, temp_tail, ascii_code);
4755 write_byte(0x0040, temp_tail+1, scan_code);
4756 write_word(0x0040, 0x001C, buffer_tail);
4762 int74_function(make_farcall, Z, Y, X, status)
4763 Bit16u make_farcall, Z, Y, X, status;
4765 Bit16u ebda_seg=read_word(0x0040,0x000E);
4766 Bit8u in_byte, index, package_count;
4767 Bit8u mouse_flags_1, mouse_flags_2;
4769 BX_DEBUG_INT74("entering int74_function\n");
4772 in_byte = inb(0x64);
4773 if ( (in_byte & 0x21) != 0x21 ) {
4776 in_byte = inb(0x60);
4777 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4779 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4780 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4782 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4783 // BX_PANIC("int74_function:\n");
4787 package_count = mouse_flags_2 & 0x07;
4788 index = mouse_flags_1 & 0x07;
4789 write_byte(ebda_seg, 0x28 + index, in_byte);
4791 if ( (index+1) >= package_count ) {
4792 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4793 status = read_byte(ebda_seg, 0x0028 + 0);
4794 X = read_byte(ebda_seg, 0x0028 + 1);
4795 Y = read_byte(ebda_seg, 0x0028 + 2);
4798 // check if far call handler installed
4799 if (mouse_flags_2 & 0x80)
4805 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4808 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4813 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4814 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4817 Bit16u ebda_seg=read_word(0x0040,0x000E);
4818 Bit16u cylinder, head, sector;
4819 Bit16u segment, offset;
4820 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4822 Bit8u device, status;
4824 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4826 write_byte(0x0040, 0x008e, 0); // clear completion flag
4828 // basic check : device has to be defined
4829 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4830 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4834 // Get the ata channel
4835 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4837 // basic check : device has to be valid
4838 if (device >= BX_MAX_ATA_DEVICES) {
4839 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4845 case 0x00: /* disk controller reset */
4850 case 0x01: /* read disk status */
4851 status = read_byte(0x0040, 0x0074);
4853 SET_DISK_RET_STATUS(0);
4854 /* set CF if error status read */
4855 if (status) goto int13_fail_nostatus;
4856 else goto int13_success_noah;
4859 case 0x02: // read disk sectors
4860 case 0x03: // write disk sectors
4861 case 0x04: // verify disk sectors
4864 cylinder = GET_CH();
4865 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4866 sector = (GET_CL() & 0x3f);
4872 if ( (count > 128) || (count == 0) ) {
4873 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4877 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4878 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4879 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4881 // sanity check on cyl heads, sec
4882 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4883 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4888 if ( GET_AH() == 0x04 ) goto int13_success;
4890 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4891 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4893 // if needed, translate lchs to lba, and execute command
4894 if ( (nph != nlh) || (npspt != nlspt)) {
4895 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4896 sector = 0; // this forces the command to be lba
4899 if ( GET_AH() == 0x02 )
4900 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4902 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4904 // Set nb of sector transferred
4905 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4908 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4910 goto int13_fail_noah;
4916 case 0x05: /* format disk track */
4917 BX_INFO("format disk track called\n");
4922 case 0x08: /* read disk drive parameters */
4924 // Get logical geometry from table
4925 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4926 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4927 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4928 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4930 nlc = nlc - 2; /* 0 based , last sector not used */
4933 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4935 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4937 // FIXME should set ES & DI
4942 case 0x10: /* check drive ready */
4943 // should look at 40:8E also???
4945 // Read the status from controller
4946 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
4947 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
4952 goto int13_fail_noah;
4956 case 0x15: /* read disk drive size */
4958 // Get physical geometry from table
4959 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4960 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4961 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4963 // Compute sector count seen by int13
4964 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
4968 SET_AH(3); // hard disk accessible
4969 goto int13_success_noah;
4972 case 0x41: // IBM/MS installation check
4973 BX=0xaa55; // install check
4974 SET_AH(0x30); // EDD 3.0
4975 CX=0x0007; // ext disk access and edd, removable supported
4976 goto int13_success_noah;
4979 case 0x42: // IBM/MS extended read
4980 case 0x43: // IBM/MS extended write
4981 case 0x44: // IBM/MS verify
4982 case 0x47: // IBM/MS extended seek
4984 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
4985 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
4986 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
4988 // Can't use 64 bits lba
4989 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
4991 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4995 // Get 32 bits lba and check
4996 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
4997 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
4998 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5002 // If verify or seek
5003 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5006 // Execute the command
5007 if ( GET_AH() == 0x42 )
5008 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5010 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5012 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5013 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5016 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5018 goto int13_fail_noah;
5024 case 0x45: // IBM/MS lock/unlock drive
5025 case 0x49: // IBM/MS extended media change
5026 goto int13_success; // Always success for HD
5029 case 0x46: // IBM/MS eject media
5030 SET_AH(0xb2); // Volume Not Removable
5031 goto int13_fail_noah; // Always fail for HD
5034 case 0x48: // IBM/MS get drive parameters
5035 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5037 // Buffer is too small
5045 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5046 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5047 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5048 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5049 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5051 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5052 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5053 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5054 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5055 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5056 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5057 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5058 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5063 Bit8u channel, dev, irq, mode, checksum, i, translation;
5064 Bit16u iobase1, iobase2, options;
5066 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5068 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5069 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5072 channel = device / 2;
5073 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5074 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5075 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5076 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5077 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5079 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5080 options |= (1<<4); // lba translation
5081 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5082 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5083 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5085 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5086 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5087 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5088 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5089 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5090 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5091 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5092 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5093 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5094 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5095 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5098 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5099 checksum = ~checksum;
5100 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5105 Bit8u channel, iface, checksum, i;
5108 channel = device / 2;
5109 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5110 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5112 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5113 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5114 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5115 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5116 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5118 if (iface==ATA_IFACE_ISA) {
5119 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5120 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5121 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5122 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5127 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5128 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5129 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5130 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5132 if (iface==ATA_IFACE_ISA) {
5133 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5134 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5135 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5140 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5141 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5142 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5143 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5146 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5147 checksum = ~checksum;
5148 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5154 case 0x4e: // // IBM/MS set hardware configuration
5155 // DMA, prefetch, PIO maximum not supported
5168 case 0x09: /* initialize drive parameters */
5169 case 0x0c: /* seek to specified cylinder */
5170 case 0x0d: /* alternate disk reset */
5171 case 0x11: /* recalibrate */
5172 case 0x14: /* controller internal diagnostic */
5173 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5177 case 0x0a: /* read disk sectors with ECC */
5178 case 0x0b: /* write disk sectors with ECC */
5179 case 0x18: // set media type for format
5180 case 0x50: // IBM/MS send packet command
5182 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5188 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5190 SET_DISK_RET_STATUS(GET_AH());
5191 int13_fail_nostatus:
5192 SET_CF(); // error occurred
5196 SET_AH(0x00); // no error
5198 SET_DISK_RET_STATUS(0x00);
5199 CLEAR_CF(); // no error
5203 // ---------------------------------------------------------------------------
5204 // Start of int13 for cdrom
5205 // ---------------------------------------------------------------------------
5208 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5209 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5211 Bit16u ebda_seg=read_word(0x0040,0x000E);
5212 Bit8u device, status, locks;
5215 Bit16u count, segment, offset, i, size;
5217 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5218 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5220 SET_DISK_RET_STATUS(0x00);
5222 /* basic check : device should be 0xE0+ */
5223 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5224 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5228 // Get the ata channel
5229 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5231 /* basic check : device has to be valid */
5232 if (device >= BX_MAX_ATA_DEVICES) {
5233 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5239 // all those functions return SUCCESS
5240 case 0x00: /* disk controller reset */
5241 case 0x09: /* initialize drive parameters */
5242 case 0x0c: /* seek to specified cylinder */
5243 case 0x0d: /* alternate disk reset */
5244 case 0x10: /* check drive ready */
5245 case 0x11: /* recalibrate */
5246 case 0x14: /* controller internal diagnostic */
5247 case 0x16: /* detect disk change */
5251 // all those functions return disk write-protected
5252 case 0x03: /* write disk sectors */
5253 case 0x05: /* format disk track */
5254 case 0x43: // IBM/MS extended write
5256 goto int13_fail_noah;
5259 case 0x01: /* read disk status */
5260 status = read_byte(0x0040, 0x0074);
5262 SET_DISK_RET_STATUS(0);
5264 /* set CF if error status read */
5265 if (status) goto int13_fail_nostatus;
5266 else goto int13_success_noah;
5269 case 0x15: /* read disk drive size */
5271 goto int13_fail_noah;
5274 case 0x41: // IBM/MS installation check
5275 BX=0xaa55; // install check
5276 SET_AH(0x30); // EDD 2.1
5277 CX=0x0007; // ext disk access, removable and edd
5278 goto int13_success_noah;
5281 case 0x42: // IBM/MS extended read
5282 case 0x44: // IBM/MS verify sectors
5283 case 0x47: // IBM/MS extended seek
5285 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5286 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5287 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5289 // Can't use 64 bits lba
5290 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5292 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5297 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5299 // If verify or seek
5300 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5303 memsetb(get_SS(),atacmd,0,12);
5304 atacmd[0]=0x28; // READ command
5305 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5306 atacmd[8]=(count & 0x00ff); // Sectors
5307 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5308 atacmd[3]=(lba & 0x00ff0000) >> 16;
5309 atacmd[4]=(lba & 0x0000ff00) >> 8;
5310 atacmd[5]=(lba & 0x000000ff);
5311 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5313 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5314 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5317 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5319 goto int13_fail_noah;
5325 case 0x45: // IBM/MS lock/unlock drive
5326 if (GET_AL() > 2) goto int13_fail;
5328 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5332 if (locks == 0xff) {
5335 goto int13_fail_noah;
5337 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5341 if (locks == 0x00) {
5344 goto int13_fail_noah;
5346 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5347 SET_AL(locks==0?0:1);
5350 SET_AL(locks==0?0:1);
5356 case 0x46: // IBM/MS eject media
5357 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5360 SET_AH(0xb1); // media locked
5361 goto int13_fail_noah;
5363 // FIXME should handle 0x31 no media in device
5364 // FIXME should handle 0xb5 valid request failed
5366 // Call removable media eject
5373 mov _int13_cdrom.status + 2[bp], ah
5374 jnc int13_cdrom_rme_end
5375 mov _int13_cdrom.status, #1
5376 int13_cdrom_rme_end:
5381 SET_AH(0xb1); // media locked
5382 goto int13_fail_noah;
5388 case 0x48: // IBM/MS get drive parameters
5389 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5391 // Buffer is too small
5397 Bit16u cylinders, heads, spt, blksize;
5399 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5401 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5402 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5403 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5404 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5405 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5406 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5407 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5408 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5413 Bit8u channel, dev, irq, mode, checksum, i;
5414 Bit16u iobase1, iobase2, options;
5416 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5418 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5419 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5422 channel = device / 2;
5423 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5424 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5425 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5426 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5428 // FIXME atapi device
5429 options = (1<<4); // lba translation
5430 options |= (1<<5); // removable device
5431 options |= (1<<6); // atapi device
5432 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5434 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5435 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5436 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5437 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5438 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5439 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5440 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5441 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5442 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5443 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5444 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5447 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5448 checksum = ~checksum;
5449 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5454 Bit8u channel, iface, checksum, i;
5457 channel = device / 2;
5458 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5459 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5461 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5462 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5463 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5464 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5465 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5467 if (iface==ATA_IFACE_ISA) {
5468 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5469 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5470 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5471 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5476 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5477 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5478 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5479 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5481 if (iface==ATA_IFACE_ISA) {
5482 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5483 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5484 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5489 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5490 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5491 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5492 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5495 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5496 checksum = ~checksum;
5497 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5503 case 0x49: // IBM/MS extended media change
5504 // always send changed ??
5506 goto int13_fail_nostatus;
5509 case 0x4e: // // IBM/MS set hardware configuration
5510 // DMA, prefetch, PIO maximum not supported
5523 // all those functions return unimplemented
5524 case 0x02: /* read sectors */
5525 case 0x04: /* verify sectors */
5526 case 0x08: /* read disk drive parameters */
5527 case 0x0a: /* read disk sectors with ECC */
5528 case 0x0b: /* write disk sectors with ECC */
5529 case 0x18: /* set media type for format */
5530 case 0x50: // ? - send packet command
5532 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5538 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5540 SET_DISK_RET_STATUS(GET_AH());
5541 int13_fail_nostatus:
5542 SET_CF(); // error occurred
5546 SET_AH(0x00); // no error
5548 SET_DISK_RET_STATUS(0x00);
5549 CLEAR_CF(); // no error
5553 // ---------------------------------------------------------------------------
5554 // End of int13 for cdrom
5555 // ---------------------------------------------------------------------------
5557 #if BX_ELTORITO_BOOT
5558 // ---------------------------------------------------------------------------
5559 // Start of int13 for eltorito functions
5560 // ---------------------------------------------------------------------------
5563 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5564 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5566 Bit16u ebda_seg=read_word(0x0040,0x000E);
5568 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5569 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5573 // FIXME ElTorito Various. Should be implemented
5574 case 0x4a: // ElTorito - Initiate disk emu
5575 case 0x4c: // ElTorito - Initiate disk emu and boot
5576 case 0x4d: // ElTorito - Return Boot catalog
5577 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5581 case 0x4b: // ElTorito - Terminate disk emu
5582 // FIXME ElTorito Hardcoded
5583 write_byte(DS,SI+0x00,0x13);
5584 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5585 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5586 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5587 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5588 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5589 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5590 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5591 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5592 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5593 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5594 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5596 // If we have to terminate emulation
5597 if(GET_AL() == 0x00) {
5598 // FIXME ElTorito Various. Should be handled accordingly to spec
5599 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5606 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5612 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5613 SET_DISK_RET_STATUS(GET_AH());
5614 SET_CF(); // error occurred
5618 SET_AH(0x00); // no error
5619 SET_DISK_RET_STATUS(0x00);
5620 CLEAR_CF(); // no error
5624 // ---------------------------------------------------------------------------
5625 // End of int13 for eltorito functions
5626 // ---------------------------------------------------------------------------
5628 // ---------------------------------------------------------------------------
5629 // Start of int13 when emulating a device from the cd
5630 // ---------------------------------------------------------------------------
5633 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5634 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5636 Bit16u ebda_seg=read_word(0x0040,0x000E);
5637 Bit8u device, status;
5638 Bit16u vheads, vspt, vcylinders;
5639 Bit16u head, sector, cylinder, nbsectors;
5640 Bit32u vlba, ilba, slba, elba;
5641 Bit16u before, segment, offset;
5644 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5645 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5647 /* at this point, we are emulating a floppy/harddisk */
5649 // Recompute the device number
5650 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5651 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5653 SET_DISK_RET_STATUS(0x00);
5655 /* basic checks : emulation should be active, dl should equal the emulated drive */
5656 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5657 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5658 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5664 // all those functions return SUCCESS
5665 case 0x00: /* disk controller reset */
5666 case 0x09: /* initialize drive parameters */
5667 case 0x0c: /* seek to specified cylinder */
5668 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5669 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5670 case 0x11: /* recalibrate */
5671 case 0x14: /* controller internal diagnostic */
5672 case 0x16: /* detect disk change */
5676 // all those functions return disk write-protected
5677 case 0x03: /* write disk sectors */
5678 case 0x05: /* format disk track */
5680 goto int13_fail_noah;
5683 case 0x01: /* read disk status */
5684 status=read_byte(0x0040, 0x0074);
5686 SET_DISK_RET_STATUS(0);
5688 /* set CF if error status read */
5689 if (status) goto int13_fail_nostatus;
5690 else goto int13_success_noah;
5693 case 0x02: // read disk sectors
5694 case 0x04: // verify disk sectors
5695 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5696 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5697 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5699 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5701 sector = GET_CL() & 0x003f;
5702 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5704 nbsectors = GET_AL();
5708 // no sector to read ?
5709 if(nbsectors==0) goto int13_success;
5711 // sanity checks sco openserver needs this!
5713 || (cylinder >= vcylinders)
5714 || (head >= vheads)) {
5718 // After controls, verify do nothing
5719 if (GET_AH() == 0x04) goto int13_success;
5721 segment = ES+(BX / 16);
5724 // calculate the virtual lba inside the image
5725 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5727 // In advance so we don't loose the count
5731 slba = (Bit32u)vlba/4;
5732 before= (Bit16u)vlba%4;
5735 elba = (Bit32u)(vlba+nbsectors-1)/4;
5737 memsetb(get_SS(),atacmd,0,12);
5738 atacmd[0]=0x28; // READ command
5739 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5740 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5741 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5742 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5743 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5744 atacmd[5]=(ilba+slba & 0x000000ff);
5745 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5746 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5749 goto int13_fail_noah;
5755 case 0x08: /* read disk drive parameters */
5756 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5757 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5758 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5762 SET_CH( vcylinders & 0xff );
5763 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5765 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5766 // FIXME ElTorito Harddisk. should send the HD count
5768 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5769 case 0x01: SET_BL( 0x02 ); break;
5770 case 0x02: SET_BL( 0x04 ); break;
5771 case 0x03: SET_BL( 0x06 ); break;
5777 mov ax, #diskette_param_table2
5778 mov _int13_cdemu.DI+2[bp], ax
5779 mov _int13_cdemu.ES+2[bp], cs
5785 case 0x15: /* read disk drive size */
5786 // FIXME ElTorito Harddisk. What geometry to send ?
5788 goto int13_success_noah;
5791 // all those functions return unimplemented
5792 case 0x0a: /* read disk sectors with ECC */
5793 case 0x0b: /* write disk sectors with ECC */
5794 case 0x18: /* set media type for format */
5795 case 0x41: // IBM/MS installation check
5796 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5797 case 0x42: // IBM/MS extended read
5798 case 0x43: // IBM/MS extended write
5799 case 0x44: // IBM/MS verify sectors
5800 case 0x45: // IBM/MS lock/unlock drive
5801 case 0x46: // IBM/MS eject media
5802 case 0x47: // IBM/MS extended seek
5803 case 0x48: // IBM/MS get drive parameters
5804 case 0x49: // IBM/MS extended media change
5805 case 0x4e: // ? - set hardware configuration
5806 case 0x50: // ? - send packet command
5808 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5814 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5816 SET_DISK_RET_STATUS(GET_AH());
5817 int13_fail_nostatus:
5818 SET_CF(); // error occurred
5822 SET_AH(0x00); // no error
5824 SET_DISK_RET_STATUS(0x00);
5825 CLEAR_CF(); // no error
5829 // ---------------------------------------------------------------------------
5830 // End of int13 when emulating a device from the cd
5831 // ---------------------------------------------------------------------------
5833 #endif // BX_ELTORITO_BOOT
5835 #else //BX_USE_ATADRV
5838 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5853 mov ax,4[bp] // cylinder
5855 mov bl,6[bp] // hd_heads
5858 mov bl,8[bp] // head
5860 mov bl,10[bp] // hd_sectors
5862 mov bl,12[bp] // sector
5891 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5892 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5894 Bit8u drive, num_sectors, sector, head, status, mod;
5898 Bit16u max_cylinder, cylinder, total_sectors;
5899 Bit16u hd_cylinders;
5900 Bit8u hd_heads, hd_sectors;
5907 Bit16u count, segment, offset;
5911 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5913 write_byte(0x0040, 0x008e, 0); // clear completion flag
5915 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5917 /* check how many disks first (cmos reg 0x12), return an error if
5918 drive not present */
5919 drive_map = inb_cmos(0x12);
5920 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5921 (((drive_map & 0x0f)==0) ? 0 : 2);
5922 n_drives = (drive_map==0) ? 0 :
5923 ((drive_map==3) ? 2 : 1);
5925 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5927 SET_DISK_RET_STATUS(0x01);
5928 SET_CF(); /* error occurred */
5934 case 0x00: /* disk controller reset */
5935 BX_DEBUG_INT13_HD("int13_f00\n");
5938 SET_DISK_RET_STATUS(0);
5939 set_diskette_ret_status(0);
5940 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5941 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5942 CLEAR_CF(); /* successful */
5946 case 0x01: /* read disk status */
5947 BX_DEBUG_INT13_HD("int13_f01\n");
5948 status = read_byte(0x0040, 0x0074);
5950 SET_DISK_RET_STATUS(0);
5951 /* set CF if error status read */
5952 if (status) SET_CF();
5957 case 0x04: // verify disk sectors
5958 case 0x02: // read disk sectors
5960 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5962 num_sectors = GET_AL();
5963 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5964 sector = (GET_CL() & 0x3f);
5968 if (hd_cylinders > 1024) {
5969 if (hd_cylinders <= 2048) {
5972 else if (hd_cylinders <= 4096) {
5975 else if (hd_cylinders <= 8192) {
5978 else { // hd_cylinders <= 16384
5982 ax = head / hd_heads;
5983 cyl_mod = ax & 0xff;
5985 cylinder |= cyl_mod;
5988 if ( (cylinder >= hd_cylinders) ||
5989 (sector > hd_sectors) ||
5990 (head >= hd_heads) ) {
5992 SET_DISK_RET_STATUS(1);
5993 SET_CF(); /* error occurred */
5997 if ( (num_sectors > 128) || (num_sectors == 0) )
5998 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6001 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6003 if ( GET_AH() == 0x04 ) {
6005 SET_DISK_RET_STATUS(0);
6010 status = inb(0x1f7);
6011 if (status & 0x80) {
6012 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6014 outb(0x01f2, num_sectors);
6015 /* activate LBA? (tomv) */
6016 if (hd_heads > 16) {
6017 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6018 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6021 outb(0x01f3, sector);
6022 outb(0x01f4, cylinder & 0x00ff);
6023 outb(0x01f5, cylinder >> 8);
6024 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6029 status = inb(0x1f7);
6030 if ( !(status & 0x80) ) break;
6033 if (status & 0x01) {
6034 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6035 } else if ( !(status & 0x08) ) {
6036 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6037 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6044 sti ;; enable higher priority interrupts
6049 ;; store temp bx in real DI register
6052 mov di, _int13_harddisk.tempbx + 2 [bp]
6055 ;; adjust if there will be an overrun
6057 jbe i13_f02_no_adjust
6059 sub di, #0x0200 ; sub 512 bytes from offset
6061 add ax, #0x0020 ; add 512 to segment
6065 mov cx, #0x0100 ;; counter (256 words = 512b)
6066 mov dx, #0x01f0 ;; AT data read port
6069 insw ;; CX words transfered from port(DX) to ES:[DI]
6072 ;; store real DI register back to temp bx
6075 mov _int13_harddisk.tempbx + 2 [bp], di
6081 if (num_sectors == 0) {
6082 status = inb(0x1f7);
6083 if ( (status & 0xc9) != 0x40 )
6084 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6088 status = inb(0x1f7);
6089 if ( (status & 0xc9) != 0x48 )
6090 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6096 SET_DISK_RET_STATUS(0);
6097 SET_AL(sector_count);
6098 CLEAR_CF(); /* successful */
6103 case 0x03: /* write disk sectors */
6104 BX_DEBUG_INT13_HD("int13_f03\n");
6105 drive = GET_ELDL ();
6106 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6108 num_sectors = GET_AL();
6109 cylinder = GET_CH();
6110 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6111 sector = (GET_CL() & 0x3f);
6114 if (hd_cylinders > 1024) {
6115 if (hd_cylinders <= 2048) {
6118 else if (hd_cylinders <= 4096) {
6121 else if (hd_cylinders <= 8192) {
6124 else { // hd_cylinders <= 16384
6128 ax = head / hd_heads;
6129 cyl_mod = ax & 0xff;
6131 cylinder |= cyl_mod;
6134 if ( (cylinder >= hd_cylinders) ||
6135 (sector > hd_sectors) ||
6136 (head >= hd_heads) ) {
6138 SET_DISK_RET_STATUS(1);
6139 SET_CF(); /* error occurred */
6143 if ( (num_sectors > 128) || (num_sectors == 0) )
6144 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6147 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6149 status = inb(0x1f7);
6150 if (status & 0x80) {
6151 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6153 // should check for Drive Ready Bit also in status reg
6154 outb(0x01f2, num_sectors);
6156 /* activate LBA? (tomv) */
6157 if (hd_heads > 16) {
6158 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6159 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6162 outb(0x01f3, sector);
6163 outb(0x01f4, cylinder & 0x00ff);
6164 outb(0x01f5, cylinder >> 8);
6165 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6169 // wait for busy bit to turn off after seeking
6171 status = inb(0x1f7);
6172 if ( !(status & 0x80) ) break;
6175 if ( !(status & 0x08) ) {
6176 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6177 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6184 sti ;; enable higher priority interrupts
6189 ;; store temp bx in real SI register
6192 mov si, _int13_harddisk.tempbx + 2 [bp]
6195 ;; adjust if there will be an overrun
6197 jbe i13_f03_no_adjust
6199 sub si, #0x0200 ; sub 512 bytes from offset
6201 add ax, #0x0020 ; add 512 to segment
6205 mov cx, #0x0100 ;; counter (256 words = 512b)
6206 mov dx, #0x01f0 ;; AT data read port
6210 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6212 ;; store real SI register back to temp bx
6215 mov _int13_harddisk.tempbx + 2 [bp], si
6221 if (num_sectors == 0) {
6222 status = inb(0x1f7);
6223 if ( (status & 0xe9) != 0x40 )
6224 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6228 status = inb(0x1f7);
6229 if ( (status & 0xc9) != 0x48 )
6230 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6236 SET_DISK_RET_STATUS(0);
6237 SET_AL(sector_count);
6238 CLEAR_CF(); /* successful */
6242 case 0x05: /* format disk track */
6243 BX_DEBUG_INT13_HD("int13_f05\n");
6244 BX_PANIC("format disk track called\n");
6247 SET_DISK_RET_STATUS(0);
6248 CLEAR_CF(); /* successful */
6252 case 0x08: /* read disk drive parameters */
6253 BX_DEBUG_INT13_HD("int13_f08\n");
6255 drive = GET_ELDL ();
6256 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6260 if (hd_cylinders <= 1024) {
6261 // hd_cylinders >>= 0;
6264 else if (hd_cylinders <= 2048) {
6268 else if (hd_cylinders <= 4096) {
6272 else if (hd_cylinders <= 8192) {
6276 else { // hd_cylinders <= 16384
6281 max_cylinder = hd_cylinders - 2; /* 0 based */
6283 SET_CH(max_cylinder & 0xff);
6284 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6285 SET_DH(hd_heads - 1);
6286 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6288 SET_DISK_RET_STATUS(0);
6289 CLEAR_CF(); /* successful */
6294 case 0x09: /* initialize drive parameters */
6295 BX_DEBUG_INT13_HD("int13_f09\n");
6297 SET_DISK_RET_STATUS(0);
6298 CLEAR_CF(); /* successful */
6302 case 0x0a: /* read disk sectors with ECC */
6303 BX_DEBUG_INT13_HD("int13_f0a\n");
6304 case 0x0b: /* write disk sectors with ECC */
6305 BX_DEBUG_INT13_HD("int13_f0b\n");
6306 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6310 case 0x0c: /* seek to specified cylinder */
6311 BX_DEBUG_INT13_HD("int13_f0c\n");
6312 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6314 SET_DISK_RET_STATUS(0);
6315 CLEAR_CF(); /* successful */
6319 case 0x0d: /* alternate disk reset */
6320 BX_DEBUG_INT13_HD("int13_f0d\n");
6322 SET_DISK_RET_STATUS(0);
6323 CLEAR_CF(); /* successful */
6327 case 0x10: /* check drive ready */
6328 BX_DEBUG_INT13_HD("int13_f10\n");
6330 //SET_DISK_RET_STATUS(0);
6331 //CLEAR_CF(); /* successful */
6335 // should look at 40:8E also???
6336 status = inb(0x01f7);
6337 if ( (status & 0xc0) == 0x40 ) {
6339 SET_DISK_RET_STATUS(0);
6340 CLEAR_CF(); // drive ready
6345 SET_DISK_RET_STATUS(0xAA);
6346 SET_CF(); // not ready
6351 case 0x11: /* recalibrate */
6352 BX_DEBUG_INT13_HD("int13_f11\n");
6354 SET_DISK_RET_STATUS(0);
6355 CLEAR_CF(); /* successful */
6359 case 0x14: /* controller internal diagnostic */
6360 BX_DEBUG_INT13_HD("int13_f14\n");
6362 SET_DISK_RET_STATUS(0);
6363 CLEAR_CF(); /* successful */
6368 case 0x15: /* read disk drive size */
6370 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6374 mov al, _int13_harddisk.hd_heads + 2 [bp]
6375 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6376 mul al, ah ;; ax = heads * sectors
6377 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6378 dec bx ;; use (cylinders - 1) ???
6379 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6380 ;; now we need to move the 32bit result dx:ax to what the
6381 ;; BIOS wants which is cx:dx.
6382 ;; and then into CX:DX on the stack
6383 mov _int13_harddisk.CX + 2 [bp], dx
6384 mov _int13_harddisk.DX + 2 [bp], ax
6387 SET_AH(3); // hard disk accessible
6388 SET_DISK_RET_STATUS(0); // ??? should this be 0
6389 CLEAR_CF(); // successful
6393 case 0x18: // set media type for format
6394 case 0x41: // IBM/MS
6395 case 0x42: // IBM/MS
6396 case 0x43: // IBM/MS
6397 case 0x44: // IBM/MS
6398 case 0x45: // IBM/MS lock/unlock drive
6399 case 0x46: // IBM/MS eject media
6400 case 0x47: // IBM/MS extended seek
6401 case 0x49: // IBM/MS extended media change
6402 case 0x50: // IBM/MS send packet command
6404 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6406 SET_AH(1); // code=invalid function in AH or invalid parameter
6407 SET_DISK_RET_STATUS(1);
6408 SET_CF(); /* unsuccessful */
6414 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6415 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6418 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6420 Bit16u *hd_cylinders;
6430 if (drive == 0x80) {
6431 hd_type = inb_cmos(0x12) & 0xf0;
6432 if (hd_type != 0xf0)
6433 BX_INFO(panic_msg_reg12h,0);
6434 hd_type = inb_cmos(0x19); // HD0: extended type
6436 BX_INFO(panic_msg_reg19h,0,0x19);
6439 hd_type = inb_cmos(0x12) & 0x0f;
6440 if (hd_type != 0x0f)
6441 BX_INFO(panic_msg_reg12h,1);
6442 hd_type = inb_cmos(0x1a); // HD0: extended type
6444 BX_INFO(panic_msg_reg19h,0,0x1a);
6449 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6450 write_word(ss, hd_cylinders, cylinders);
6453 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6455 // sectors per track
6456 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6459 #endif //else BX_USE_ATADRV
6462 //////////////////////
6463 // FLOPPY functions //
6464 //////////////////////
6467 floppy_media_known(drive)
6471 Bit16u media_state_offset;
6473 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6480 media_state_offset = 0x0090;
6482 media_state_offset += 1;
6484 val8 = read_byte(0x0040, media_state_offset);
6485 val8 = (val8 >> 4) & 0x01;
6489 // check pass, return KNOWN
6494 floppy_media_sense(drive)
6498 Bit16u media_state_offset;
6499 Bit8u drive_type, config_data, media_state;
6501 if (floppy_drive_recal(drive) == 0) {
6505 // for now cheat and get drive type from CMOS,
6506 // assume media is same as drive type
6508 // ** config_data **
6509 // Bitfields for diskette media control:
6510 // Bit(s) Description (Table M0028)
6511 // 7-6 last data rate set by controller
6512 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6513 // 5-4 last diskette drive step rate selected
6514 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6515 // 3-2 {data rate at start of operation}
6518 // ** media_state **
6519 // Bitfields for diskette drive media state:
6520 // Bit(s) Description (Table M0030)
6522 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6523 // 5 double stepping required (e.g. 360kB in 1.2MB)
6524 // 4 media type established
6525 // 3 drive capable of supporting 4MB media
6526 // 2-0 on exit from BIOS, contains
6527 // 000 trying 360kB in 360kB
6528 // 001 trying 360kB in 1.2MB
6529 // 010 trying 1.2MB in 1.2MB
6530 // 011 360kB in 360kB established
6531 // 100 360kB in 1.2MB established
6532 // 101 1.2MB in 1.2MB established
6534 // 111 all other formats/drives
6536 drive_type = inb_cmos(0x10);
6541 if ( drive_type == 1 ) {
6543 config_data = 0x00; // 0000 0000
6544 media_state = 0x25; // 0010 0101
6547 else if ( drive_type == 2 ) {
6548 // 1.2 MB 5.25" drive
6549 config_data = 0x00; // 0000 0000
6550 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6553 else if ( drive_type == 3 ) {
6555 config_data = 0x00; // 0000 0000 ???
6556 media_state = 0x17; // 0001 0111
6559 else if ( drive_type == 4 ) {
6560 // 1.44 MB 3.5" drive
6561 config_data = 0x00; // 0000 0000
6562 media_state = 0x17; // 0001 0111
6565 else if ( drive_type == 5 ) {
6566 // 2.88 MB 3.5" drive
6567 config_data = 0xCC; // 1100 1100
6568 media_state = 0xD7; // 1101 0111
6572 // Extended floppy size uses special cmos setting
6573 else if ( drive_type == 6 ) {
6575 config_data = 0x00; // 0000 0000
6576 media_state = 0x27; // 0010 0111
6579 else if ( drive_type == 7 ) {
6581 config_data = 0x00; // 0000 0000
6582 media_state = 0x27; // 0010 0111
6585 else if ( drive_type == 8 ) {
6587 config_data = 0x00; // 0000 0000
6588 media_state = 0x27; // 0010 0111
6594 config_data = 0x00; // 0000 0000
6595 media_state = 0x00; // 0000 0000
6600 media_state_offset = 0x90;
6602 media_state_offset = 0x91;
6603 write_byte(0x0040, 0x008B, config_data);
6604 write_byte(0x0040, media_state_offset, media_state);
6610 floppy_drive_recal(drive)
6614 Bit16u curr_cyl_offset;
6616 // set 40:3e bit 7 to 0
6617 val8 = read_byte(0x0000, 0x043e);
6619 write_byte(0x0000, 0x043e, val8);
6621 // turn on motor of selected drive, DMA & int enabled, normal operation
6630 // reset the disk motor timeout value of INT 08
6631 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6633 // check port 3f4 for drive readiness
6635 if ( (val8 & 0xf0) != 0x80 )
6636 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6638 // send Recalibrate command (2 bytes) to controller
6639 outb(0x03f5, 0x07); // 07: Recalibrate
6640 outb(0x03f5, drive); // 0=drive0, 1=drive1
6642 // turn on interrupts
6647 // wait on 40:3e bit 7 to become 1
6648 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6649 while ( val8 == 0 ) {
6650 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6653 val8 = 0; // separate asm from while() loop
6654 // turn off interrupts
6659 // set 40:3e bit 7 to 0, and calibrated bit
6660 val8 = read_byte(0x0000, 0x043e);
6663 val8 |= 0x02; // Drive 1 calibrated
6664 curr_cyl_offset = 0x0095;
6667 val8 |= 0x01; // Drive 0 calibrated
6668 curr_cyl_offset = 0x0094;
6670 write_byte(0x0040, 0x003e, val8);
6671 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6679 floppy_drive_exists(drive)
6684 // check CMOS to see if drive exists
6685 drive_type = inb_cmos(0x10);
6690 if ( drive_type == 0 )
6696 #if BX_SUPPORT_FLOPPY
6698 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6699 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6701 Bit8u drive, num_sectors, track, sector, head, status;
6702 Bit16u base_address, base_count, base_es;
6703 Bit8u page, mode_register, val8, dor;
6704 Bit8u return_status[7];
6705 Bit8u drive_type, num_floppies, ah;
6706 Bit16u es, last_addr;
6708 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6709 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6714 case 0x00: // diskette controller reset
6715 BX_DEBUG_INT13_FL("floppy f00\n");
6718 SET_AH(1); // invalid param
6719 set_diskette_ret_status(1);
6723 drive_type = inb_cmos(0x10);
6729 if (drive_type == 0) {
6730 SET_AH(0x80); // drive not responding
6731 set_diskette_ret_status(0x80);
6736 set_diskette_ret_status(0);
6737 CLEAR_CF(); // successful
6738 set_diskette_current_cyl(drive, 0); // current cylinder
6741 case 0x01: // Read Diskette Status
6743 val8 = read_byte(0x0000, 0x0441);
6750 case 0x02: // Read Diskette Sectors
6751 case 0x03: // Write Diskette Sectors
6752 case 0x04: // Verify Diskette Sectors
6753 num_sectors = GET_AL();
6759 if ( (drive > 1) || (head > 1) ||
6760 (num_sectors == 0) || (num_sectors > 72) ) {
6761 BX_INFO("floppy: drive>1 || head>1 ...\n");
6763 set_diskette_ret_status(1);
6764 SET_AL(0); // no sectors read
6765 SET_CF(); // error occurred
6769 // see if drive exists
6770 if (floppy_drive_exists(drive) == 0) {
6771 SET_AH(0x80); // not responding
6772 set_diskette_ret_status(0x80);
6773 SET_AL(0); // no sectors read
6774 SET_CF(); // error occurred
6778 // see if media in drive, and type is known
6779 if (floppy_media_known(drive) == 0) {
6780 if (floppy_media_sense(drive) == 0) {
6781 SET_AH(0x0C); // Media type not found
6782 set_diskette_ret_status(0x0C);
6783 SET_AL(0); // no sectors read
6784 SET_CF(); // error occurred
6790 // Read Diskette Sectors
6792 //-----------------------------------
6793 // set up DMA controller for transfer
6794 //-----------------------------------
6796 // es:bx = pointer to where to place information from diskette
6797 // port 04: DMA-1 base and current address, channel 2
6798 // port 05: DMA-1 base and current count, channel 2
6799 page = (ES >> 12); // upper 4 bits
6800 base_es = (ES << 4); // lower 16bits contributed by ES
6801 base_address = base_es + BX; // lower 16 bits of address
6802 // contributed by ES:BX
6803 if ( base_address < base_es ) {
6804 // in case of carry, adjust page by 1
6807 base_count = (num_sectors * 512) - 1;
6809 // check for 64K boundary overrun
6810 last_addr = base_address + base_count;
6811 if (last_addr < base_address) {
6813 set_diskette_ret_status(0x09);
6814 SET_AL(0); // no sectors read
6815 SET_CF(); // error occurred
6819 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6822 BX_DEBUG_INT13_FL("clear flip-flop\n");
6823 outb(0x000c, 0x00); // clear flip-flop
6824 outb(0x0004, base_address);
6825 outb(0x0004, base_address>>8);
6826 BX_DEBUG_INT13_FL("clear flip-flop\n");
6827 outb(0x000c, 0x00); // clear flip-flop
6828 outb(0x0005, base_count);
6829 outb(0x0005, base_count>>8);
6831 // port 0b: DMA-1 Mode Register
6832 mode_register = 0x46; // single mode, increment, autoinit disable,
6833 // transfer type=write, channel 2
6834 BX_DEBUG_INT13_FL("setting mode register\n");
6835 outb(0x000b, mode_register);
6837 BX_DEBUG_INT13_FL("setting page register\n");
6838 // port 81: DMA-1 Page Register, channel 2
6841 BX_DEBUG_INT13_FL("unmask chan 2\n");
6842 outb(0x000a, 0x02); // unmask channel 2
6844 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6847 //--------------------------------------
6848 // set up floppy controller for transfer
6849 //--------------------------------------
6851 // set 40:3e bit 7 to 0
6852 val8 = read_byte(0x0000, 0x043e);
6854 write_byte(0x0000, 0x043e, val8);
6856 // turn on motor of selected drive, DMA & int enabled, normal operation
6865 // reset the disk motor timeout value of INT 08
6866 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6868 // check port 3f4 for drive readiness
6870 if ( (val8 & 0xf0) != 0x80 )
6871 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6873 // send read-normal-data command (9 bytes) to controller
6874 outb(0x03f5, 0xe6); // e6: read normal data
6875 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6876 outb(0x03f5, track);
6878 outb(0x03f5, sector);
6879 outb(0x03f5, 2); // 512 byte sector size
6880 outb(0x03f5, 0); // last sector number possible on track
6881 outb(0x03f5, 0); // Gap length
6882 outb(0x03f5, 0xff); // Gap length
6884 // turn on interrupts
6889 // wait on 40:3e bit 7 to become 1
6890 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6891 while ( val8 == 0 ) {
6892 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6895 val8 = 0; // separate asm from while() loop
6896 // turn off interrupts
6901 // set 40:3e bit 7 to 0
6902 val8 = read_byte(0x0000, 0x043e);
6904 write_byte(0x0000, 0x043e, val8);
6906 // check port 3f4 for accessibility to status bytes
6908 if ( (val8 & 0xc0) != 0xc0 )
6909 BX_PANIC("int13_diskette: ctrl not ready\n");
6911 // read 7 return status bytes from controller
6912 // using loop index broken, have to unroll...
6913 return_status[0] = inb(0x3f5);
6914 return_status[1] = inb(0x3f5);
6915 return_status[2] = inb(0x3f5);
6916 return_status[3] = inb(0x3f5);
6917 return_status[4] = inb(0x3f5);
6918 return_status[5] = inb(0x3f5);
6919 return_status[6] = inb(0x3f5);
6920 // record in BIOS Data Area
6921 write_byte(0x0040, 0x0042, return_status[0]);
6922 write_byte(0x0040, 0x0043, return_status[1]);
6923 write_byte(0x0040, 0x0044, return_status[2]);
6924 write_byte(0x0040, 0x0045, return_status[3]);
6925 write_byte(0x0040, 0x0046, return_status[4]);
6926 write_byte(0x0040, 0x0047, return_status[5]);
6927 write_byte(0x0040, 0x0048, return_status[6]);
6929 if ( (return_status[0] & 0xc0) != 0 ) {
6931 set_diskette_ret_status(0x20);
6932 SET_AL(0); // no sectors read
6933 SET_CF(); // error occurred
6937 // ??? should track be new val from return_status[3] ?
6938 set_diskette_current_cyl(drive, track);
6939 // AL = number of sectors read (same value as passed)
6940 SET_AH(0x00); // success
6941 CLEAR_CF(); // success
6944 else if (ah == 0x03) {
6945 // Write Diskette Sectors
6947 //-----------------------------------
6948 // set up DMA controller for transfer
6949 //-----------------------------------
6951 // es:bx = pointer to where to place information from diskette
6952 // port 04: DMA-1 base and current address, channel 2
6953 // port 05: DMA-1 base and current count, channel 2
6954 page = (ES >> 12); // upper 4 bits
6955 base_es = (ES << 4); // lower 16bits contributed by ES
6956 base_address = base_es + BX; // lower 16 bits of address
6957 // contributed by ES:BX
6958 if ( base_address < base_es ) {
6959 // in case of carry, adjust page by 1
6962 base_count = (num_sectors * 512) - 1;
6964 // check for 64K boundary overrun
6965 last_addr = base_address + base_count;
6966 if (last_addr < base_address) {
6968 set_diskette_ret_status(0x09);
6969 SET_AL(0); // no sectors read
6970 SET_CF(); // error occurred
6974 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6977 outb(0x000c, 0x00); // clear flip-flop
6978 outb(0x0004, base_address);
6979 outb(0x0004, base_address>>8);
6980 outb(0x000c, 0x00); // clear flip-flop
6981 outb(0x0005, base_count);
6982 outb(0x0005, base_count>>8);
6984 // port 0b: DMA-1 Mode Register
6985 mode_register = 0x4a; // single mode, increment, autoinit disable,
6986 // transfer type=read, channel 2
6987 outb(0x000b, mode_register);
6989 // port 81: DMA-1 Page Register, channel 2
6992 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6995 //--------------------------------------
6996 // set up floppy controller for transfer
6997 //--------------------------------------
6999 // set 40:3e bit 7 to 0
7000 val8 = read_byte(0x0000, 0x043e);
7002 write_byte(0x0000, 0x043e, val8);
7004 // turn on motor of selected drive, DMA & int enabled, normal operation
7013 // reset the disk motor timeout value of INT 08
7014 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7016 // check port 3f4 for drive readiness
7018 if ( (val8 & 0xf0) != 0x80 )
7019 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7021 // send read-normal-data command (9 bytes) to controller
7022 outb(0x03f5, 0xc5); // c5: write normal data
7023 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7024 outb(0x03f5, track);
7026 outb(0x03f5, sector);
7027 outb(0x03f5, 2); // 512 byte sector size
7028 outb(0x03f5, 0); // last sector number possible on track
7029 outb(0x03f5, 0); // Gap length
7030 outb(0x03f5, 0xff); // Gap length
7032 // turn on interrupts
7037 // wait on 40:3e bit 7 to become 1
7038 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7039 while ( val8 == 0 ) {
7040 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7043 val8 = 0; // separate asm from while() loop
7044 // turn off interrupts
7049 // set 40:3e bit 7 to 0
7050 val8 = read_byte(0x0000, 0x043e);
7052 write_byte(0x0000, 0x043e, val8);
7054 // check port 3f4 for accessibility to status bytes
7056 if ( (val8 & 0xc0) != 0xc0 )
7057 BX_PANIC("int13_diskette: ctrl not ready\n");
7059 // read 7 return status bytes from controller
7060 // using loop index broken, have to unroll...
7061 return_status[0] = inb(0x3f5);
7062 return_status[1] = inb(0x3f5);
7063 return_status[2] = inb(0x3f5);
7064 return_status[3] = inb(0x3f5);
7065 return_status[4] = inb(0x3f5);
7066 return_status[5] = inb(0x3f5);
7067 return_status[6] = inb(0x3f5);
7068 // record in BIOS Data Area
7069 write_byte(0x0040, 0x0042, return_status[0]);
7070 write_byte(0x0040, 0x0043, return_status[1]);
7071 write_byte(0x0040, 0x0044, return_status[2]);
7072 write_byte(0x0040, 0x0045, return_status[3]);
7073 write_byte(0x0040, 0x0046, return_status[4]);
7074 write_byte(0x0040, 0x0047, return_status[5]);
7075 write_byte(0x0040, 0x0048, return_status[6]);
7077 if ( (return_status[0] & 0xc0) != 0 ) {
7078 if ( (return_status[1] & 0x02) != 0 ) {
7079 // diskette not writable.
7080 // AH=status code=0x03 (tried to write on write-protected disk)
7081 // AL=number of sectors written=0
7086 BX_PANIC("int13_diskette_function: read error\n");
7090 // ??? should track be new val from return_status[3] ?
7091 set_diskette_current_cyl(drive, track);
7092 // AL = number of sectors read (same value as passed)
7093 SET_AH(0x00); // success
7094 CLEAR_CF(); // success
7097 else { // if (ah == 0x04)
7098 // Verify Diskette Sectors
7100 // ??? should track be new val from return_status[3] ?
7101 set_diskette_current_cyl(drive, track);
7102 // AL = number of sectors verified (same value as passed)
7103 CLEAR_CF(); // success
7104 SET_AH(0x00); // success
7109 case 0x05: // format diskette track
7110 BX_DEBUG_INT13_FL("floppy f05\n");
7112 num_sectors = GET_AL();
7117 if ((drive > 1) || (head > 1) || (track > 79) ||
7118 (num_sectors == 0) || (num_sectors > 18)) {
7120 set_diskette_ret_status(1);
7121 SET_CF(); // error occurred
7124 // see if drive exists
7125 if (floppy_drive_exists(drive) == 0) {
7126 SET_AH(0x80); // drive not responding
7127 set_diskette_ret_status(0x80);
7128 SET_CF(); // error occurred
7132 // see if media in drive, and type is known
7133 if (floppy_media_known(drive) == 0) {
7134 if (floppy_media_sense(drive) == 0) {
7135 SET_AH(0x0C); // Media type not found
7136 set_diskette_ret_status(0x0C);
7137 SET_AL(0); // no sectors read
7138 SET_CF(); // error occurred
7143 // set up DMA controller for transfer
7144 page = (ES >> 12); // upper 4 bits
7145 base_es = (ES << 4); // lower 16bits contributed by ES
7146 base_address = base_es + BX; // lower 16 bits of address
7147 // contributed by ES:BX
7148 if ( base_address < base_es ) {
7149 // in case of carry, adjust page by 1
7152 base_count = (num_sectors * 4) - 1;
7154 // check for 64K boundary overrun
7155 last_addr = base_address + base_count;
7156 if (last_addr < base_address) {
7158 set_diskette_ret_status(0x09);
7159 SET_AL(0); // no sectors read
7160 SET_CF(); // error occurred
7165 outb(0x000c, 0x00); // clear flip-flop
7166 outb(0x0004, base_address);
7167 outb(0x0004, base_address>>8);
7168 outb(0x000c, 0x00); // clear flip-flop
7169 outb(0x0005, base_count);
7170 outb(0x0005, base_count>>8);
7171 mode_register = 0x4a; // single mode, increment, autoinit disable,
7172 // transfer type=read, channel 2
7173 outb(0x000b, mode_register);
7174 // port 81: DMA-1 Page Register, channel 2
7178 // set up floppy controller for transfer
7179 val8 = read_byte(0x0000, 0x043e);
7181 write_byte(0x0000, 0x043e, val8);
7182 // turn on motor of selected drive, DMA & int enabled, normal operation
7191 // reset the disk motor timeout value of INT 08
7192 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7194 // check port 3f4 for drive readiness
7196 if ( (val8 & 0xf0) != 0x80 )
7197 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7199 // send read-normal-data command (6 bytes) to controller
7200 outb(0x03f5, 0x4d); // 4d: format track
7201 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7202 outb(0x03f5, 2); // 512 byte sector size
7203 outb(0x03f5, num_sectors); // number of sectors per track
7204 outb(0x03f5, 0); // Gap length
7205 outb(0x03f5, 0xf6); // Fill byte
7206 // turn on interrupts
7210 // wait on 40:3e bit 7 to become 1
7211 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7212 while ( val8 == 0 ) {
7213 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7215 val8 = 0; // separate asm from while() loop
7216 // turn off interrupts
7220 // set 40:3e bit 7 to 0
7221 val8 = read_byte(0x0000, 0x043e);
7223 write_byte(0x0000, 0x043e, val8);
7224 // check port 3f4 for accessibility to status bytes
7226 if ( (val8 & 0xc0) != 0xc0 )
7227 BX_PANIC("int13_diskette: ctrl not ready\n");
7229 // read 7 return status bytes from controller
7230 // using loop index broken, have to unroll...
7231 return_status[0] = inb(0x3f5);
7232 return_status[1] = inb(0x3f5);
7233 return_status[2] = inb(0x3f5);
7234 return_status[3] = inb(0x3f5);
7235 return_status[4] = inb(0x3f5);
7236 return_status[5] = inb(0x3f5);
7237 return_status[6] = inb(0x3f5);
7238 // record in BIOS Data Area
7239 write_byte(0x0040, 0x0042, return_status[0]);
7240 write_byte(0x0040, 0x0043, return_status[1]);
7241 write_byte(0x0040, 0x0044, return_status[2]);
7242 write_byte(0x0040, 0x0045, return_status[3]);
7243 write_byte(0x0040, 0x0046, return_status[4]);
7244 write_byte(0x0040, 0x0047, return_status[5]);
7245 write_byte(0x0040, 0x0048, return_status[6]);
7247 if ( (return_status[0] & 0xc0) != 0 ) {
7248 if ( (return_status[1] & 0x02) != 0 ) {
7249 // diskette not writable.
7250 // AH=status code=0x03 (tried to write on write-protected disk)
7251 // AL=number of sectors written=0
7256 BX_PANIC("int13_diskette_function: write error\n");
7261 set_diskette_ret_status(0);
7262 set_diskette_current_cyl(drive, 0);
7263 CLEAR_CF(); // successful
7267 case 0x08: // read diskette drive parameters
7268 BX_DEBUG_INT13_FL("floppy f08\n");
7278 SET_DL(num_floppies);
7283 drive_type = inb_cmos(0x10);
7285 if (drive_type & 0xf0)
7287 if (drive_type & 0x0f)
7299 SET_DL(num_floppies);
7301 switch (drive_type) {
7304 SET_DH(0); // max head #
7307 case 1: // 360KB, 5.25"
7308 CX = 0x2709; // 40 tracks, 9 sectors
7309 SET_DH(1); // max head #
7312 case 2: // 1.2MB, 5.25"
7313 CX = 0x4f0f; // 80 tracks, 15 sectors
7314 SET_DH(1); // max head #
7317 case 3: // 720KB, 3.5"
7318 CX = 0x4f09; // 80 tracks, 9 sectors
7319 SET_DH(1); // max head #
7322 case 4: // 1.44MB, 3.5"
7323 CX = 0x4f12; // 80 tracks, 18 sectors
7324 SET_DH(1); // max head #
7327 case 5: // 2.88MB, 3.5"
7328 CX = 0x4f24; // 80 tracks, 36 sectors
7329 SET_DH(1); // max head #
7332 case 6: // 160k, 5.25"
7333 CX = 0x2708; // 40 tracks, 8 sectors
7334 SET_DH(0); // max head #
7337 case 7: // 180k, 5.25"
7338 CX = 0x2709; // 40 tracks, 9 sectors
7339 SET_DH(0); // max head #
7342 case 8: // 320k, 5.25"
7343 CX = 0x2708; // 40 tracks, 8 sectors
7344 SET_DH(1); // max head #
7348 BX_PANIC("floppy: int13: bad floppy type\n");
7351 /* set es & di to point to 11 byte diskette param table in ROM */
7355 mov ax, #diskette_param_table2
7356 mov _int13_diskette_function.DI+2[bp], ax
7357 mov _int13_diskette_function.ES+2[bp], cs
7360 CLEAR_CF(); // success
7361 /* disk status not changed upon success */
7365 case 0x15: // read diskette drive type
7366 BX_DEBUG_INT13_FL("floppy f15\n");
7369 SET_AH(0); // only 2 drives supported
7370 // set_diskette_ret_status here ???
7374 drive_type = inb_cmos(0x10);
7380 CLEAR_CF(); // successful, not present
7381 if (drive_type==0) {
7382 SET_AH(0); // drive not present
7385 SET_AH(1); // drive present, does not support change line
7390 case 0x16: // get diskette change line status
7391 BX_DEBUG_INT13_FL("floppy f16\n");
7394 SET_AH(0x01); // invalid drive
7395 set_diskette_ret_status(0x01);
7400 SET_AH(0x06); // change line not supported
7401 set_diskette_ret_status(0x06);
7405 case 0x17: // set diskette type for format(old)
7406 BX_DEBUG_INT13_FL("floppy f17\n");
7407 /* not used for 1.44M floppies */
7408 SET_AH(0x01); // not supported
7409 set_diskette_ret_status(1); /* not supported */
7413 case 0x18: // set diskette type for format(new)
7414 BX_DEBUG_INT13_FL("floppy f18\n");
7415 SET_AH(0x01); // do later
7416 set_diskette_ret_status(1);
7421 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7423 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7424 SET_AH(0x01); // ???
7425 set_diskette_ret_status(1);
7431 #else // #if BX_SUPPORT_FLOPPY
7433 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7434 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7438 switch ( GET_AH() ) {
7440 case 0x01: // Read Diskette Status
7442 val8 = read_byte(0x0000, 0x0441);
7451 write_byte(0x0000, 0x0441, 0x01);
7455 #endif // #if BX_SUPPORT_FLOPPY
7458 set_diskette_ret_status(value)
7461 write_byte(0x0040, 0x0041, value);
7465 set_diskette_current_cyl(drive, cyl)
7470 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7471 write_byte(0x0040, 0x0094+drive, cyl);
7475 determine_floppy_media(drive)
7479 Bit8u val8, DOR, ctrl_info;
7481 ctrl_info = read_byte(0x0040, 0x008F);
7489 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7492 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7496 if ( (ctrl_info & 0x04) != 0x04 ) {
7497 // Drive not determined means no drive exists, done.
7502 // check Main Status Register for readiness
7503 val8 = inb(0x03f4) & 0x80; // Main Status Register
7505 BX_PANIC("d_f_m: MRQ bit not set\n");
7509 // existing BDA values
7511 // turn on drive motor
7512 outb(0x03f2, DOR); // Digital Output Register
7515 BX_PANIC("d_f_m: OK so far\n");
7520 int17_function(regs, ds, iret_addr)
7521 pusha_regs_t regs; // regs pushed from PUSHA instruction
7522 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7523 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7525 Bit16u addr,timeout;
7532 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7533 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7534 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7535 if (regs.u.r8.ah == 0) {
7536 outb(addr, regs.u.r8.al);
7538 outb(addr+2, val8 | 0x01); // send strobe
7542 outb(addr+2, val8 & ~0x01);
7543 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7547 if (regs.u.r8.ah == 1) {
7549 outb(addr+2, val8 & ~0x04); // send init
7553 outb(addr+2, val8 | 0x04);
7556 regs.u.r8.ah = (val8 ^ 0x48);
7557 if (!timeout) regs.u.r8.ah |= 0x01;
7558 ClearCF(iret_addr.flags);
7560 SetCF(iret_addr.flags); // Unsupported
7564 // returns bootsegment in ax, drive in bl
7566 int19_function(bseqnr)
7569 Bit16u ebda_seg=read_word(0x0040,0x000E);
7578 // if BX_ELTORITO_BOOT is not defined, old behavior
7579 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7580 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7581 // 0: system boot sequence, first drive C: then A:
7582 // 1: system boot sequence, first drive A: then C:
7583 // else BX_ELTORITO_BOOT is defined
7584 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7585 // CMOS reg 0x3D & 0x0f : 1st boot device
7586 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7587 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7588 // boot device codes:
7589 // 0x00 : not defined
7590 // 0x01 : first floppy
7591 // 0x02 : first harddrive
7592 // 0x03 : first cdrom
7593 // else : boot failure
7595 // Get the boot sequence
7596 #if BX_ELTORITO_BOOT
7597 bootseq=inb_cmos(0x3d);
7598 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7600 if (bseqnr==2) bootseq >>= 4;
7601 if (bseqnr==3) bootseq >>= 8;
7602 if (bootseq<0x10) lastdrive = 1;
7603 bootdrv=0x00; bootcd=0;
7604 switch(bootseq & 0x0f) {
7605 case 0x01: bootdrv=0x00; bootcd=0; break;
7606 case 0x02: bootdrv=0x80; bootcd=0; break;
7607 case 0x03: bootdrv=0x00; bootcd=1; break;
7608 default: return 0x00000000;
7611 bootseq=inb_cmos(0x2d);
7617 bootdrv=0x00; bootcd=0;
7618 if((bootseq&0x20)==0) bootdrv=0x80;
7619 #endif // BX_ELTORITO_BOOT
7621 #if BX_ELTORITO_BOOT
7622 // We have to boot from cd
7624 status = cdrom_boot();
7627 if ( (status & 0x00ff) !=0 ) {
7628 print_cdromboot_failure(status);
7629 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7633 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7634 bootdrv = (Bit8u)(status>>8);
7637 #endif // BX_ELTORITO_BOOT
7639 // We have to boot from harddisk or floppy
7648 mov _int19_function.status + 2[bp], ax
7649 mov dl, _int19_function.bootdrv + 2[bp]
7650 mov ax, _int19_function.bootseg + 2[bp]
7651 mov es, ax ;; segment
7652 mov bx, #0x0000 ;; offset
7653 mov ah, #0x02 ;; function 2, read diskette sector
7654 mov al, #0x01 ;; read 1 sector
7655 mov ch, #0x00 ;; track 0
7656 mov cl, #0x01 ;; sector 1
7657 mov dh, #0x00 ;; head 0
7658 int #0x13 ;; read sector
7661 mov _int19_function.status + 2[bp], ax
7668 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7673 // check signature if instructed by cmos reg 0x38, only for floppy
7674 // bootchk = 1 : signature check disabled
7675 // bootchk = 0 : signature check enabled
7676 if (bootdrv != 0) bootchk = 0;
7677 else bootchk = inb_cmos(0x38) & 0x01;
7679 #if BX_ELTORITO_BOOT
7680 // if boot from cd, no signature check
7683 #endif // BX_ELTORITO_BOOT
7686 if (read_word(bootseg,0x1fe) != 0xaa55) {
7687 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7692 #if BX_ELTORITO_BOOT
7693 // Print out the boot string
7694 print_boot_device(bootcd, bootdrv);
7695 #else // BX_ELTORITO_BOOT
7696 print_boot_device(0, bootdrv);
7697 #endif // BX_ELTORITO_BOOT
7699 // return the boot segment
7700 return (((Bit32u)bootdrv) << 16) + bootseg;
7704 int1a_function(regs, ds, iret_addr)
7705 pusha_regs_t regs; // regs pushed from PUSHA instruction
7706 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7707 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7711 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);
7717 switch (regs.u.r8.ah) {
7718 case 0: // get current clock count
7722 regs.u.r16.cx = BiosData->ticks_high;
7723 regs.u.r16.dx = BiosData->ticks_low;
7724 regs.u.r8.al = BiosData->midnight_flag;
7725 BiosData->midnight_flag = 0; // reset flag
7730 ClearCF(iret_addr.flags); // OK
7733 case 1: // Set Current Clock Count
7737 BiosData->ticks_high = regs.u.r16.cx;
7738 BiosData->ticks_low = regs.u.r16.dx;
7739 BiosData->midnight_flag = 0; // reset flag
7744 ClearCF(iret_addr.flags); // OK
7748 case 2: // Read CMOS Time
7749 if (rtc_updating()) {
7750 SetCF(iret_addr.flags);
7754 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7755 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7756 regs.u.r8.ch = inb_cmos(0x04); // Hours
7757 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7759 regs.u.r8.al = regs.u.r8.ch;
7760 ClearCF(iret_addr.flags); // OK
7763 case 3: // Set CMOS Time
7764 // Using a debugger, I notice the following masking/setting
7765 // of bits in Status Register B, by setting Reg B to
7766 // a few values and getting its value after INT 1A was called.
7768 // try#1 try#2 try#3
7769 // before 1111 1101 0111 1101 0000 0000
7770 // after 0110 0010 0110 0010 0000 0010
7772 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7773 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7774 if (rtc_updating()) {
7776 // fall through as if an update were not in progress
7778 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7779 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7780 outb_cmos(0x04, regs.u.r8.ch); // Hours
7781 // Set Daylight Savings time enabled bit to requested value
7782 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7783 // (reg B already selected)
7784 outb_cmos(0x0b, val8);
7786 regs.u.r8.al = val8; // val last written to Reg B
7787 ClearCF(iret_addr.flags); // OK
7790 case 4: // Read CMOS Date
7792 if (rtc_updating()) {
7793 SetCF(iret_addr.flags);
7796 regs.u.r8.cl = inb_cmos(0x09); // Year
7797 regs.u.r8.dh = inb_cmos(0x08); // Month
7798 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7799 regs.u.r8.ch = inb_cmos(0x32); // Century
7800 regs.u.r8.al = regs.u.r8.ch;
7801 ClearCF(iret_addr.flags); // OK
7804 case 5: // Set CMOS Date
7805 // Using a debugger, I notice the following masking/setting
7806 // of bits in Status Register B, by setting Reg B to
7807 // a few values and getting its value after INT 1A was called.
7809 // try#1 try#2 try#3 try#4
7810 // before 1111 1101 0111 1101 0000 0010 0000 0000
7811 // after 0110 1101 0111 1101 0000 0010 0000 0000
7813 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7814 // My assumption: RegB = (RegB & 01111111b)
7815 if (rtc_updating()) {
7817 SetCF(iret_addr.flags);
7820 outb_cmos(0x09, regs.u.r8.cl); // Year
7821 outb_cmos(0x08, regs.u.r8.dh); // Month
7822 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7823 outb_cmos(0x32, regs.u.r8.ch); // Century
7824 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7825 outb_cmos(0x0b, val8);
7827 regs.u.r8.al = val8; // AL = val last written to Reg B
7828 ClearCF(iret_addr.flags); // OK
7831 case 6: // Set Alarm Time in CMOS
7832 // Using a debugger, I notice the following masking/setting
7833 // of bits in Status Register B, by setting Reg B to
7834 // a few values and getting its value after INT 1A was called.
7836 // try#1 try#2 try#3
7837 // before 1101 1111 0101 1111 0000 0000
7838 // after 0110 1111 0111 1111 0010 0000
7840 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7841 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7842 val8 = inb_cmos(0x0b); // Get Status Reg B
7845 // Alarm interrupt enabled already
7846 SetCF(iret_addr.flags); // Error: alarm in use
7849 if (rtc_updating()) {
7851 // fall through as if an update were not in progress
7853 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7854 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7855 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7856 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7857 // enable Status Reg B alarm bit, clear halt clock bit
7858 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7859 ClearCF(iret_addr.flags); // OK
7862 case 7: // Turn off Alarm
7863 // Using a debugger, I notice the following masking/setting
7864 // of bits in Status Register B, by setting Reg B to
7865 // a few values and getting its value after INT 1A was called.
7867 // try#1 try#2 try#3 try#4
7868 // before 1111 1101 0111 1101 0010 0000 0010 0010
7869 // after 0100 0101 0101 0101 0000 0000 0000 0010
7871 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7872 // My assumption: RegB = (RegB & 01010111b)
7873 val8 = inb_cmos(0x0b); // Get Status Reg B
7874 // clear clock-halt bit, disable alarm bit
7875 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7877 regs.u.r8.al = val8; // val last written to Reg B
7878 ClearCF(iret_addr.flags); // OK
7882 // real mode PCI BIOS functions now handled in assembler code
7883 // this C code handles the error code for information only
7884 if (regs.u.r8.bl == 0xff) {
7885 BX_INFO("PCI BIOS: PCI not present\n");
7886 } else if (regs.u.r8.bl == 0x81) {
7887 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7888 } else if (regs.u.r8.bl == 0x83) {
7889 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7890 } else if (regs.u.r8.bl == 0x86) {
7891 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7893 regs.u.r8.ah = regs.u.r8.bl;
7894 SetCF(iret_addr.flags);
7899 SetCF(iret_addr.flags); // Unsupported
7904 int70_function(regs, ds, iret_addr)
7905 pusha_regs_t regs; // regs pushed from PUSHA instruction
7906 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7907 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7909 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7910 Bit8u registerB = 0, registerC = 0;
7912 // Check which modes are enabled and have occurred.
7913 registerB = inb_cmos( 0xB );
7914 registerC = inb_cmos( 0xC );
7916 if( ( registerB & 0x60 ) != 0 ) {
7917 if( ( registerC & 0x20 ) != 0 ) {
7918 // Handle Alarm Interrupt.
7925 if( ( registerC & 0x40 ) != 0 ) {
7926 // Handle Periodic Interrupt.
7928 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7929 // Wait Interval (Int 15, AH=83) active.
7930 Bit32u time, toggle;
7932 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
7933 if( time < 0x3D1 ) {
7935 Bit16u segment, offset;
7937 offset = read_word( 0x40, 0x98 );
7938 segment = read_word( 0x40, 0x9A );
7939 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7940 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
7941 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
7943 // Continue waiting.
7945 write_dword( 0x40, 0x9C, time );
7958 ;------------------------------------------
7959 ;- INT74h : PS/2 mouse hardware interrupt -
7960 ;------------------------------------------
7965 push #0x00 ;; placeholder for status
7966 push #0x00 ;; placeholder for X
7967 push #0x00 ;; placeholder for Y
7968 push #0x00 ;; placeholder for Z
7969 push #0x00 ;; placeholder for make_far_call boolean
7970 call _int74_function
7971 pop cx ;; remove make_far_call from stack
7974 ;; make far call to EBDA:0022
7977 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
7979 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7984 add sp, #8 ;; pop status, x, y, z
7986 pop ds ;; restore DS
7991 ;; This will perform an IRET, but will retain value of current CF
7992 ;; by altering flags on stack. Better than RETF #02.
7997 and BYTE [bp + 0x06], #0xfe
8003 or BYTE [bp + 0x06], #0x01
8008 ;----------------------
8009 ;- INT13h (relocated) -
8010 ;----------------------
8012 ; int13_relocated is a little bit messed up since I played with it
8013 ; I have to rewrite it:
8014 ; - call a function that detect which function to call
8015 ; - make all called C function get the same parameters list
8019 #if BX_ELTORITO_BOOT
8020 ;; check for an eltorito function
8022 jb int13_not_eltorito
8024 ja int13_not_eltorito
8033 jmp _int13_eltorito ;; ELDX not used
8041 ;; check if emulation active
8042 call _cdemu_isactive
8044 je int13_cdemu_inactive
8046 ;; check if access to the emulated drive
8047 call _cdemu_emulated_drive
8050 cmp al,dl ;; int13 on emulated drive
8065 jmp _int13_cdemu ;; ELDX not used
8068 and dl,#0xE0 ;; mask to get device class, including cdroms
8069 cmp al,dl ;; al is 0x00 or 0x80
8070 jne int13_cdemu_inactive ;; inactive for device class
8082 dec dl ;; real drive is dl - 1
8085 int13_cdemu_inactive:
8091 #endif // BX_ELTORITO_BOOT
8102 push dx ;; push eltorito value of dx instead of sp
8113 ;; now the 16-bit registers can be restored with:
8114 ;; pop ds; pop es; popa; iret
8115 ;; arguments passed to functions should be
8116 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8122 jmp _int13_diskette_function
8131 // ebx is modified: BSD 5.2.1 boot loader problem
8132 // someone should figure out which 32 bit register that actually are used
8149 call _int13_harddisk
8161 int18_handler: ;; Boot Failure routing
8162 call _int18_panic_msg
8169 int19_relocated: ;; Boot function, relocated
8171 ;; int19 was beginning to be really complex, so now it
8172 ;; just calls an C function, that does the work
8173 ;; it returns in BL the boot drive, and in AX the boot segment
8174 ;; the boot segment will be 0x0000 if something has failed
8186 call _int19_function
8189 ;; bl contains the boot drive
8190 ;; ax contains the boot segment or 0 if failure
8192 test ax, ax ;; if ax is 0 try next boot device
8198 call _int19_function
8201 test ax, ax ;; if ax is 0 try next boot device
8207 call _int19_function
8210 test ax, ax ;; if ax is 0 call int18
8214 mov dl, bl ;; set drive so guest os find it
8215 shl eax, #0x04 ;; convert seg to ip
8216 mov 2[bp], ax ;; set ip
8218 shr eax, #0x04 ;; get cs back
8219 and ax, #0xF000 ;; remove what went in ip
8220 mov 4[bp], ax ;; set cs
8222 mov es, ax ;; set es to zero fixes [ 549815 ]
8223 mov [bp], ax ;; set bp to zero
8224 mov ax, #0xaa55 ;; set ok flag
8227 iret ;; Beam me up Scotty
8232 int1c_handler: ;; User Timer Tick
8236 ;----------------------
8237 ;- POST: Floppy Drive -
8238 ;----------------------
8244 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8246 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8248 mov 0x0440, al ;; diskette motor timeout counter: not active
8249 mov 0x0441, al ;; diskette controller status return code
8251 mov 0x0442, al ;; disk & diskette controller status register 0
8252 mov 0x0443, al ;; diskette controller status register 1
8253 mov 0x0444, al ;; diskette controller status register 2
8254 mov 0x0445, al ;; diskette controller cylinder number
8255 mov 0x0446, al ;; diskette controller head number
8256 mov 0x0447, al ;; diskette controller sector number
8257 mov 0x0448, al ;; diskette controller bytes written
8259 mov 0x048b, al ;; diskette configuration data
8261 ;; -----------------------------------------------------------------
8262 ;; (048F) diskette controller information
8264 mov al, #0x10 ;; get CMOS diskette drive type
8267 mov ah, al ;; save byte to AH
8270 shr al, #4 ;; look at top 4 bits for drive 0
8271 jz f0_missing ;; jump if no drive0
8272 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8275 mov bl, #0x00 ;; no drive0
8278 mov al, ah ;; restore from AH
8279 and al, #0x0f ;; look at bottom 4 bits for drive 1
8280 jz f1_missing ;; jump if no drive1
8281 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8283 ;; leave high bits in BL zerod
8284 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8285 ;; -----------------------------------------------------------------
8288 mov 0x0490, al ;; diskette 0 media state
8289 mov 0x0491, al ;; diskette 1 media state
8291 ;; diskette 0,1 operational starting state
8292 ;; drive type has not been determined,
8293 ;; has no changed detection line
8297 mov 0x0494, al ;; diskette 0 current cylinder
8298 mov 0x0495, al ;; diskette 1 current cylinder
8301 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8303 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8304 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8305 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8310 ;--------------------
8311 ;- POST: HARD DRIVE -
8312 ;--------------------
8313 ; relocated here because the primary POST area isnt big enough.
8316 // INT 76h calls INT 15h function ax=9100
8318 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8324 mov 0x0474, al /* hard disk status of last operation */
8325 mov 0x0477, al /* hard disk port offset (XT only ???) */
8326 mov 0x048c, al /* hard disk status register */
8327 mov 0x048d, al /* hard disk error register */
8328 mov 0x048e, al /* hard disk task complete flag */
8330 mov 0x0475, al /* hard disk number attached */
8332 mov 0x0476, al /* hard disk control byte */
8333 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8334 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8335 ;; INT 41h: hard disk 0 configuration pointer
8336 ;; INT 46h: hard disk 1 configuration pointer
8337 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8338 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8340 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8352 cmp al, #47 ;; decimal 47 - user definable
8356 ;; CMOS purpose param table offset
8357 ;; 1b cylinders low 0
8358 ;; 1c cylinders high 1
8360 ;; 1e write pre-comp low 5
8361 ;; 1f write pre-comp high 6
8362 ;; 20 retries/bad map/heads>8 8
8363 ;; 21 landing zone low C
8364 ;; 22 landing zone high D
8365 ;; 23 sectors/track E
8370 ;;; Filling EBDA table for hard disk 0.
8378 mov (0x003d + 0x05), ax ;; write precomp word
8383 mov (0x003d + 0x08), al ;; drive control byte
8392 mov (0x003d + 0x0C), ax ;; landing zone word
8394 mov al, #0x1c ;; get cylinders word in AX
8396 in al, #0x71 ;; high byte
8400 in al, #0x71 ;; low byte
8401 mov bx, ax ;; BX = cylinders
8406 mov cl, al ;; CL = heads
8411 mov dl, al ;; DL = sectors
8414 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8416 hd0_post_physical_chs:
8417 ;; no logical CHS mapping used, just physical CHS
8418 ;; use Standard Fixed Disk Parameter Table (FDPT)
8419 mov (0x003d + 0x00), bx ;; number of physical cylinders
8420 mov (0x003d + 0x02), cl ;; number of physical heads
8421 mov (0x003d + 0x0E), dl ;; number of physical sectors
8424 hd0_post_logical_chs:
8425 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8426 mov (0x003d + 0x09), bx ;; number of physical cylinders
8427 mov (0x003d + 0x0b), cl ;; number of physical heads
8428 mov (0x003d + 0x04), dl ;; number of physical sectors
8429 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8431 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8434 jnbe hd0_post_above_2048
8435 ;; 1024 < c <= 2048 cylinders
8438 jmp hd0_post_store_logical
8440 hd0_post_above_2048:
8442 jnbe hd0_post_above_4096
8443 ;; 2048 < c <= 4096 cylinders
8446 jmp hd0_post_store_logical
8448 hd0_post_above_4096:
8450 jnbe hd0_post_above_8192
8451 ;; 4096 < c <= 8192 cylinders
8454 jmp hd0_post_store_logical
8456 hd0_post_above_8192:
8457 ;; 8192 < c <= 16384 cylinders
8461 hd0_post_store_logical:
8462 mov (0x003d + 0x00), bx ;; number of physical cylinders
8463 mov (0x003d + 0x02), cl ;; number of physical heads
8465 mov cl, #0x0f ;; repeat count
8466 mov si, #0x003d ;; offset to disk0 FDPT
8467 mov al, #0x00 ;; sum
8468 hd0_post_checksum_loop:
8472 jnz hd0_post_checksum_loop
8473 not al ;; now take 2s complement
8476 ;;; Done filling EBDA table for hard disk 0.
8480 ;; is there really a second hard disk? if not, return now
8488 ;; check that the hd type is really 0x0f.
8493 ;; check that the extended type is 47 - user definable
8497 cmp al, #47 ;; decimal 47 - user definable
8502 ;; CMOS purpose param table offset
8503 ;; 0x24 cylinders low 0
8504 ;; 0x25 cylinders high 1
8506 ;; 0x27 write pre-comp low 5
8507 ;; 0x28 write pre-comp high 6
8509 ;; 0x2a landing zone low C
8510 ;; 0x2b landing zone high D
8511 ;; 0x2c sectors/track E
8512 ;;; Fill EBDA table for hard disk 1.
8522 mov (0x004d + 0x05), ax ;; write precomp word
8527 mov (0x004d + 0x08), al ;; drive control byte
8536 mov (0x004d + 0x0C), ax ;; landing zone word
8538 mov al, #0x25 ;; get cylinders word in AX
8540 in al, #0x71 ;; high byte
8544 in al, #0x71 ;; low byte
8545 mov bx, ax ;; BX = cylinders
8550 mov cl, al ;; CL = heads
8555 mov dl, al ;; DL = sectors
8558 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8560 hd1_post_physical_chs:
8561 ;; no logical CHS mapping used, just physical CHS
8562 ;; use Standard Fixed Disk Parameter Table (FDPT)
8563 mov (0x004d + 0x00), bx ;; number of physical cylinders
8564 mov (0x004d + 0x02), cl ;; number of physical heads
8565 mov (0x004d + 0x0E), dl ;; number of physical sectors
8568 hd1_post_logical_chs:
8569 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8570 mov (0x004d + 0x09), bx ;; number of physical cylinders
8571 mov (0x004d + 0x0b), cl ;; number of physical heads
8572 mov (0x004d + 0x04), dl ;; number of physical sectors
8573 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8575 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8578 jnbe hd1_post_above_2048
8579 ;; 1024 < c <= 2048 cylinders
8582 jmp hd1_post_store_logical
8584 hd1_post_above_2048:
8586 jnbe hd1_post_above_4096
8587 ;; 2048 < c <= 4096 cylinders
8590 jmp hd1_post_store_logical
8592 hd1_post_above_4096:
8594 jnbe hd1_post_above_8192
8595 ;; 4096 < c <= 8192 cylinders
8598 jmp hd1_post_store_logical
8600 hd1_post_above_8192:
8601 ;; 8192 < c <= 16384 cylinders
8605 hd1_post_store_logical:
8606 mov (0x004d + 0x00), bx ;; number of physical cylinders
8607 mov (0x004d + 0x02), cl ;; number of physical heads
8609 mov cl, #0x0f ;; repeat count
8610 mov si, #0x004d ;; offset to disk0 FDPT
8611 mov al, #0x00 ;; sum
8612 hd1_post_checksum_loop:
8616 jnz hd1_post_checksum_loop
8617 not al ;; now take 2s complement
8620 ;;; Done filling EBDA table for hard disk 1.
8624 ;--------------------
8625 ;- POST: EBDA segment
8626 ;--------------------
8627 ; relocated here because the primary POST area isnt big enough.
8632 mov byte ptr [0x0], #EBDA_SIZE
8634 xor ax, ax ; mov EBDA seg into 40E
8636 mov word ptr [0x40E], #EBDA_SEG
8639 ;--------------------
8640 ;- POST: EOI + jmp via [0x40:67)
8641 ;--------------------
8642 ; relocated here because the primary POST area isnt big enough.
8652 ;--------------------
8655 out #0xA0, al ;; slave PIC EOI
8658 out #0x20, al ;; master PIC EOI
8661 ;--------------------
8663 ;; in: AL in BCD format
8664 ;; out: AL in binary format, AH will always be 0
8667 and bl, #0x0f ;; bl has low digit
8668 shr al, #4 ;; al has high digit
8670 mul al, bh ;; multiply high digit by 10 (result in AX)
8671 add al, bl ;; then add low digit
8674 ;--------------------
8676 ;; Setup the Timer Ticks Count (0x46C:dword) and
8677 ;; Timer Ticks Roller Flag (0x470:byte)
8678 ;; The Timer Ticks Count needs to be set according to
8679 ;; the current CMOS time, as if ticks have been occurring
8680 ;; at 18.2hz since midnight up to this point. Calculating
8681 ;; this is a little complicated. Here are the factors I gather
8682 ;; regarding this. 14,318,180 hz was the original clock speed,
8683 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8684 ;; at the time, or 4 to drive the CGA video adapter. The div3
8685 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8686 ;; the timer. With a maximum 16bit timer count, this is again
8687 ;; divided down by 65536 to 18.2hz.
8689 ;; 14,318,180 Hz clock
8690 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8691 ;; /4 = 1,193,181 Hz fed to timer
8692 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8693 ;; 1 second = 18.20650736 ticks
8694 ;; 1 minute = 1092.390442 ticks
8695 ;; 1 hour = 65543.42651 ticks
8697 ;; Given the values in the CMOS clock, one could calculate
8698 ;; the number of ticks by the following:
8699 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8700 ;; (BcdToBin(minutes) * 1092.3904)
8701 ;; (BcdToBin(hours) * 65543.427)
8702 ;; To get a little more accuracy, since Im using integer
8703 ;; arithmatic, I use:
8704 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8705 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8706 ;; (BcdToBin(hours) * 65543427) / 1000
8711 xor eax, eax ;; clear EAX
8714 in al, #0x71 ;; AL has CMOS seconds in BCD
8715 call BcdToBin ;; EAX now has seconds in binary
8721 mov ecx, eax ;; ECX will accumulate total ticks
8724 xor eax, eax ;; clear EAX
8727 in al, #0x71 ;; AL has CMOS minutes in BCD
8728 call BcdToBin ;; EAX now has minutes in binary
8734 add ecx, eax ;; add to total ticks
8737 xor eax, eax ;; clear EAX
8740 in al, #0x71 ;; AL has CMOS hours in BCD
8741 call BcdToBin ;; EAX now has hours in binary
8747 add ecx, eax ;; add to total ticks
8749 mov 0x46C, ecx ;; Timer Ticks Count
8751 mov 0x470, al ;; Timer Ticks Rollover Flag
8754 ;--------------------
8756 ;; record completion in BIOS task complete flag
8768 ;--------------------
8773 #include "apmbios.S"
8777 #include "apmbios.S"
8780 #include "apmbios.S"
8784 ;--------------------
8789 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8790 dw bios32_entry_point, 0xf ;; 32 bit physical address
8791 db 0 ;; revision level
8792 ;; length in paragraphs and checksum stored in a word to prevent errors
8793 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8794 & 0xff) << 8) + 0x01
8795 db 0,0,0,0,0 ;; reserved
8800 cmp eax, #0x49435024
8802 mov eax, #0x80000000
8807 cmp eax, #0x12378086
8809 mov ebx, #0x000f0000
8811 mov edx, #pcibios_protected
8826 cmp al, #0x01 ;; installation check
8830 mov edx, #0x20494350
8833 pci_pro_f02: ;; find pci device
8841 call pci_pro_select_reg
8855 pci_pro_f08: ;; read configuration byte
8858 call pci_pro_select_reg
8867 pci_pro_f09: ;; read configuration word
8870 call pci_pro_select_reg
8879 pci_pro_f0a: ;; read configuration dword
8882 call pci_pro_select_reg
8889 pci_pro_f0b: ;; write configuration byte
8892 call pci_pro_select_reg
8901 pci_pro_f0c: ;; write configuration word
8904 call pci_pro_select_reg
8913 pci_pro_f0d: ;; write configuration dword
8916 call pci_pro_select_reg
8959 mov eax, #0x80000000
8964 cmp eax, #0x12378086
8974 cmp al, #0x01 ;; installation check
8979 mov edx, #0x20494350
8981 mov di, #pcibios_protected
8984 pci_real_f02: ;; find pci device
8994 call pci_real_select_reg
8998 jne pci_real_nextdev
9005 jne pci_real_devloop
9010 pci_real_f08: ;; read configuration byte
9013 call pci_real_select_reg
9022 pci_real_f09: ;; read configuration word
9025 call pci_real_select_reg
9034 pci_real_f0a: ;; read configuration dword
9037 call pci_real_select_reg
9044 pci_real_f0b: ;; write configuration byte
9047 call pci_real_select_reg
9056 pci_real_f0c: ;; write configuration word
9059 call pci_real_select_reg
9068 pci_real_f0d: ;; write configuration dword
9070 jne pci_real_unknown
9071 call pci_real_select_reg
9092 pci_real_select_reg:
9106 pci_routing_table_structure:
9107 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9109 dw 32 + (6 * 16) ;; table size
9110 db 0 ;; PCI interrupt router bus
9111 db 0x08 ;; PCI interrupt router DevFunc
9112 dw 0x0000 ;; PCI exclusive IRQs
9113 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9114 dw 0x7000 ;; compatible PCI interrupt router device ID
9115 dw 0,0 ;; Miniport data
9116 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9118 ;; first slot entry PCI-to-ISA (embedded)
9119 db 0 ;; pci bus number
9120 db 0x08 ;; pci device number (bit 7-3)
9121 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9122 dw 0xdef8 ;; IRQ bitmap INTA#
9123 db 0x61 ;; link value INTB#
9124 dw 0xdef8 ;; IRQ bitmap INTB#
9125 db 0x62 ;; link value INTC#
9126 dw 0xdef8 ;; IRQ bitmap INTC#
9127 db 0x63 ;; link value INTD#
9128 dw 0xdef8 ;; IRQ bitmap INTD#
9129 db 0 ;; physical slot (0 = embedded)
9131 ;; second slot entry: 1st PCI slot
9132 db 0 ;; pci bus number
9133 db 0x10 ;; pci device number (bit 7-3)
9134 db 0x61 ;; link value INTA#
9135 dw 0xdef8 ;; IRQ bitmap INTA#
9136 db 0x62 ;; link value INTB#
9137 dw 0xdef8 ;; IRQ bitmap INTB#
9138 db 0x63 ;; link value INTC#
9139 dw 0xdef8 ;; IRQ bitmap INTC#
9140 db 0x60 ;; link value INTD#
9141 dw 0xdef8 ;; IRQ bitmap INTD#
9142 db 1 ;; physical slot (0 = embedded)
9144 ;; third slot entry: 2nd PCI slot
9145 db 0 ;; pci bus number
9146 db 0x18 ;; pci device number (bit 7-3)
9147 db 0x62 ;; link value INTA#
9148 dw 0xdef8 ;; IRQ bitmap INTA#
9149 db 0x63 ;; link value INTB#
9150 dw 0xdef8 ;; IRQ bitmap INTB#
9151 db 0x60 ;; link value INTC#
9152 dw 0xdef8 ;; IRQ bitmap INTC#
9153 db 0x61 ;; link value INTD#
9154 dw 0xdef8 ;; IRQ bitmap INTD#
9155 db 2 ;; physical slot (0 = embedded)
9157 ;; 4th slot entry: 3rd PCI slot
9158 db 0 ;; pci bus number
9159 db 0x20 ;; pci device number (bit 7-3)
9160 db 0x63 ;; link value INTA#
9161 dw 0xdef8 ;; IRQ bitmap INTA#
9162 db 0x60 ;; link value INTB#
9163 dw 0xdef8 ;; IRQ bitmap INTB#
9164 db 0x61 ;; link value INTC#
9165 dw 0xdef8 ;; IRQ bitmap INTC#
9166 db 0x62 ;; link value INTD#
9167 dw 0xdef8 ;; IRQ bitmap INTD#
9168 db 3 ;; physical slot (0 = embedded)
9170 ;; 5th slot entry: 4rd PCI slot
9171 db 0 ;; pci bus number
9172 db 0x28 ;; pci device number (bit 7-3)
9173 db 0x60 ;; link value INTA#
9174 dw 0xdef8 ;; IRQ bitmap INTA#
9175 db 0x61 ;; link value INTB#
9176 dw 0xdef8 ;; IRQ bitmap INTB#
9177 db 0x62 ;; link value INTC#
9178 dw 0xdef8 ;; IRQ bitmap INTC#
9179 db 0x63 ;; link value INTD#
9180 dw 0xdef8 ;; IRQ bitmap INTD#
9181 db 4 ;; physical slot (0 = embedded)
9183 ;; 6th slot entry: 5rd PCI slot
9184 db 0 ;; pci bus number
9185 db 0x30 ;; pci device number (bit 7-3)
9186 db 0x61 ;; link value INTA#
9187 dw 0xdef8 ;; IRQ bitmap INTA#
9188 db 0x62 ;; link value INTB#
9189 dw 0xdef8 ;; IRQ bitmap INTB#
9190 db 0x63 ;; link value INTC#
9191 dw 0xdef8 ;; IRQ bitmap INTC#
9192 db 0x60 ;; link value INTD#
9193 dw 0xdef8 ;; IRQ bitmap INTD#
9194 db 5 ;; physical slot (0 = embedded)
9200 pcibios_init_sel_reg:
9212 pcibios_init_set_elcr:
9236 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9241 mov si, #pci_routing_table_structure
9245 call pcibios_init_sel_reg
9248 cmp eax, [si+12] ;; check irq router
9251 call pcibios_init_sel_reg
9252 push bx ;; save irq router bus + devfunc
9255 out dx, ax ;; reset PIRQ route control
9263 add si, #0x20 ;; set pointer to 1st entry
9265 mov ax, #pci_irq_list
9274 call pcibios_init_sel_reg
9278 jnz pci_test_int_pin
9284 call pcibios_init_sel_reg
9289 dec al ;; determine pirq reg
9298 call pcibios_init_sel_reg
9305 mov bx, [bp-2] ;; pci irq list pointer
9310 call pcibios_init_set_elcr
9314 add bl, [bp-3] ;; pci function number
9316 call pcibios_init_sel_reg
9326 mov byte ptr[bp-3], #0x00
9334 #endif // BX_PCIBIOS
9336 ; parallel port detection: base address in DX, index in BX, timeout in CL
9341 and al, #0xdf ; clear input mode
9351 mov [bx+0x408], dx ; Parallel I/O address
9353 mov [bx+0x478], cl ; Parallel printer timeout
9358 ; serial port detection: base address in DX, index in BX, timeout in CL
9360 ; no serial port in the VM -PAD
9380 mov [bx+0x400], dx ; Serial I/O address
9382 mov [bx+0x47c], cl ; Serial timeout
9409 ;; Scan for existence of valid expansion ROMS.
9410 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9411 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9412 ;; System ROM: only 0xE0000
9418 ;; 2 ROM length in 512-byte blocks
9419 ;; 3 ROM initialization entry point (FAR CALL)
9424 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9425 cmp [0], #0xAA55 ;; look for signature
9426 jne rom_scan_increment
9428 jnz rom_scan_increment
9429 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9431 ;; We want our increment in 512-byte quantities, rounded to
9432 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9434 jz block_count_rounded
9435 and al, #0xfc ;; needs rounding up
9437 block_count_rounded:
9439 xor bx, bx ;; Restore DS back to 0000:
9442 ;; Push addr of ROM entry point
9444 push #0x0003 ;; Push offset
9445 mov bp, sp ;; Call ROM init routine using seg:off on stack
9446 db 0xff ;; call_far ss:[bp+0]
9449 cli ;; In case expansion ROM BIOS turns IF on
9450 add sp, #2 ;; Pop offset value
9451 pop cx ;; Pop seg value (restore CX)
9452 pop ax ;; Restore AX
9454 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9455 ;; because the segment selector is shifted left 4 bits.
9460 xor ax, ax ;; Restore DS back to 0000:
9466 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9467 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9468 ; but the tables themeselves can be elsewhere.
9477 mov cx, #0x001f ; 0x1f bytes to copy
9479 mov es, ax ; destination segment is 0xf0000
9480 mov di, #smbios_entry_point ; destination offset
9482 mov ds, ax ; source segment is 0x9f000
9483 mov si, #0x0000 ; source offset is 0
9501 ;; for 'C' strings and other data, insert them here with
9502 ;; a the following hack:
9503 ;; DATA_SEG_DEFS_HERE
9509 .org 0xe05b ; POST Entry Point
9514 ;; first reset the DMA controllers
9518 ;; then initialize the DMA controllers
9520 out 0xD6, al ; cascade mode of channel 4 enabled
9522 out 0xD4, al ; unmask channel 4
9524 ;; Examine CMOS shutdown status.
9532 ;; Reset CMOS shutdown status.
9534 out 0x70, AL ; select CMOS register Fh
9536 out 0x71, AL ; set shutdown action to normal
9538 ;; Examine CMOS shutdown status.
9541 ;; 0x00, 0x09, 0x0D+ = normal startup
9549 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9553 ;; Examine CMOS shutdown status.
9554 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9556 call _shutdown_status_panic
9562 ; 0xb0, 0x20, /* mov al, #0x20 */
9563 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9573 ; case 0: normal startup
9582 ;; zero out BIOS data area (40:00..40:ff)
9584 mov cx, #0x0080 ;; 128 words
9590 call _log_bios_start
9592 ;; set all interrupts to default handler
9593 mov bx, #0x0000 ;; offset index
9594 mov cx, #0x0100 ;; counter (256 interrupts)
9595 mov ax, #dummy_iret_handler
9605 loop post_default_ints
9607 ;; set vector 0x79 to zero
9608 ;; this is used by 'gardian angel' protection system
9609 SET_INT_VECTOR(0x79, #0, #0)
9611 ;; base memory in K 40:13 (word)
9612 mov ax, #BASE_MEM_IN_K
9616 ;; Manufacturing Test 40:12
9619 ;; Warm Boot Flag 0040:0072
9620 ;; value of 1234h = skip memory checks
9624 ;; Printer Services vector
9625 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9627 ;; Bootstrap failure vector
9628 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9630 ;; Bootstrap Loader vector
9631 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9633 ;; User Timer Tick vector
9634 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9636 ;; Memory Size Check vector
9637 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9639 ;; Equipment Configuration Check vector
9640 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9643 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9649 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9650 ;; int 1C already points at dummy_iret_handler (above)
9651 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9654 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9659 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9665 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9666 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9670 mov 0x0417, al /* keyboard shift flags, set 1 */
9671 mov 0x0418, al /* keyboard shift flags, set 2 */
9672 mov 0x0419, al /* keyboard alt-numpad work area */
9673 mov 0x0471, al /* keyboard ctrl-break flag */
9674 mov 0x0497, al /* keyboard status flags 4 */
9676 mov 0x0496, al /* keyboard status flags 3 */
9679 /* keyboard head of buffer pointer */
9683 /* keyboard end of buffer pointer */
9686 /* keyboard pointer to start of buffer */
9690 /* keyboard pointer to end of buffer */
9694 /* init the keyboard */
9697 ;; mov CMOS Equipment Byte to BDA Equipment Word
9706 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9710 mov cl, #0x14 ; timeout value
9711 mov dx, #0x378 ; Parallel I/O address, port 1
9713 mov dx, #0x278 ; Parallel I/O address, port 2
9716 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9718 or ax, bx ; set number of parallel ports
9722 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9723 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9725 mov cl, #0x0a ; timeout value
9726 mov dx, #0x03f8 ; Serial I/O address, port 1
9728 mov dx, #0x02f8 ; Serial I/O address, port 2
9730 mov dx, #0x03e8 ; Serial I/O address, port 3
9732 mov dx, #0x02e8 ; Serial I/O address, port 4
9735 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9737 or ax, bx ; set number of serial port
9741 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9742 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9743 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9744 ;; BIOS DATA AREA 0x4CE ???
9745 call timer_tick_post
9748 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9750 ;; IRQ13 (FPU exception) setup
9751 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9754 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9757 mov al, #0x11 ; send initialisation commands
9772 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9773 #if BX_USE_PS2_MOUSE
9778 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9781 call _copy_e820_table
9787 call _print_bios_banner
9792 call floppy_drive_post
9799 call hard_drive_post
9802 ;; ATA/ATAPI driver setup
9807 #else // BX_USE_ATADRV
9812 call hard_drive_post
9814 #endif // BX_USE_ATADRV
9816 #if BX_ELTORITO_BOOT
9818 ;; eltorito floppy/harddisk emulation from cd
9822 #endif // BX_ELTORITO_BOOT
9825 //JMP_EP(0x0064) ; INT 19h location
9828 .org 0xe2c3 ; NMI Handler Entry Point
9830 ;; FIXME the NMI handler should not panic
9831 ;; but iret when called from int75 (fpu exception)
9832 call _nmi_handler_msg
9836 out 0xf0, al // clear irq13
9837 call eoi_both_pics // clear interrupt
9838 int 2 // legacy nmi call
9841 ;-------------------------------------------
9842 ;- INT 13h Fixed Disk Services Entry Point -
9843 ;-------------------------------------------
9844 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9846 //JMPL(int13_relocated)
9849 .org 0xe401 ; Fixed Disk Parameter Table
9854 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9858 ;-------------------------------------------
9859 ;- System BIOS Configuration Data Table
9860 ;-------------------------------------------
9861 .org BIOS_CONFIG_TABLE
9862 db 0x08 ; Table size (bytes) -Lo
9863 db 0x00 ; Table size (bytes) -Hi
9868 ; b7: 1=DMA channel 3 used by hard disk
9869 ; b6: 1=2 interrupt controllers present
9871 ; b4: 1=BIOS calls int 15h/4Fh every key
9872 ; b3: 1=wait for extern event supported (Int 15h/41h)
9873 ; b2: 1=extended BIOS data area used
9874 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9875 ; b0: 1=Dual bus (MicroChannel + ISA)
9879 (BX_CALL_INT15_4F << 4) | \
9881 (BX_USE_EBDA << 2) | \
9885 ; b7: 1=32-bit DMA supported
9886 ; b6: 1=int16h, function 9 supported
9887 ; b5: 1=int15h/C6h (get POS data) supported
9888 ; b4: 1=int15h/C7h (get mem map info) supported
9889 ; b3: 1=int15h/C8h (en/dis CPU) supported
9890 ; b2: 1=non-8042 kb controller
9891 ; b1: 1=data streaming supported
9905 ; b4: POST supports ROM-to-RAM enable/disable
9906 ; b3: SCSI on system board
9907 ; b2: info panel installed
9908 ; b1: Initial Machine Load (IML) system - BIOS on disk
9909 ; b0: SCSI supported in IML
9913 ; b6: EEPROM present
9914 ; b5-3: ABIOS presence (011 = not supported)
9916 ; b1: memory split above 16Mb supported
9917 ; b0: POSTEXT directly supported by POST
9919 ; Feature byte 5 (IBM)
9920 ; b1: enhanced mouse
9926 .org 0xe729 ; Baud Rate Generator Table
9931 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
9937 call _int14_function
9943 ;----------------------------------------
9944 ;- INT 16h Keyboard Service Entry Point -
9945 ;----------------------------------------
9961 call _int16_function
9971 and BYTE [bp + 0x06], #0xbf
9979 or BYTE [bp + 0x06], #0x40
9995 /* no key yet, call int 15h, function AX=9002 */
9997 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9998 0xcd, 0x15, /* int 15h */
10000 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10002 jmp int16_wait_for_key
10007 call _int16_function
10012 /* notify int16 complete w/ int 15h, function AX=9102 */
10013 0x50, /* push AX */
10014 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10015 0xcd, 0x15, /* int 15h */
10022 ;-------------------------------------------------
10023 ;- INT09h : Keyboard Hardware Service Entry Point -
10024 ;-------------------------------------------------
10030 mov al, #0xAD ;;disable keyboard
10039 in al, #0x60 ;;read key from keyboard controller
10040 //test al, #0x80 ;;look for key release
10041 //jnz int09_process_key ;; dont pass releases to intercept?
10043 ;; check for extended key
10045 jne int09_call_int15_4f
10050 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10052 mov BYTE [0x496], al
10055 in al, #0x60 ;;read another key from keyboard controller
10059 int09_call_int15_4f:
10062 #ifdef BX_CALL_INT15_4F
10063 mov ah, #0x4f ;; allow for keyboard intercept
10070 //int09_process_key:
10073 call _int09_function
10079 call eoi_master_pic
10082 mov al, #0xAE ;;enable keyboard
10090 ;----------------------------------------
10091 ;- INT 13h Diskette Service Entry Point -
10092 ;----------------------------------------
10095 jmp int13_noeltorito
10097 ;---------------------------------------------
10098 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10099 ;---------------------------------------------
10100 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10110 mov al, #0x08 ; sense interrupt status
10128 mov ax, #0x0000 ;; segment 0000
10130 call eoi_master_pic
10132 or al, #0x80 ;; diskette interrupt has occurred
10140 .org 0xefc7 ; Diskette Controller Parameter Table
10141 diskette_param_table:
10142 ;; Since no provisions are made for multiple drive types, most
10143 ;; values in this table are ignored. I set parameters for 1.44M
10146 db 0x02 ;; head load time 0000001, DMA used
10158 ;----------------------------------------
10159 ;- INT17h : Printer Service Entry Point -
10160 ;----------------------------------------
10167 call _int17_function
10172 diskette_param_table2:
10173 ;; New diskette parameter table adding 3 parameters from IBM
10174 ;; Since no provisions are made for multiple drive types, most
10175 ;; values in this table are ignored. I set parameters for 1.44M
10178 db 0x02 ;; head load time 0000001, DMA used
10188 db 79 ;; maximum track
10189 db 0 ;; data transfer rate
10190 db 4 ;; drive type in cmos
10192 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10199 .org 0xf065 ; INT 10h Video Support Service Entry Point
10201 ;; dont do anything, since the VGA BIOS handles int10h requests
10204 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10209 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10210 ; ??? different for Pentium (machine check)?
10222 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10234 .org 0xf859 ; INT 15h System Services Entry Point
10248 #if BX_USE_PS2_MOUSE
10250 je int15_handler_mouse
10252 call _int15_function
10253 int15_handler_mouse_ret:
10255 int15_handler32_ret:
10265 #if BX_USE_PS2_MOUSE
10266 int15_handler_mouse:
10267 call _int15_function_mouse
10268 jmp int15_handler_mouse_ret
10273 call _int15_function32
10275 jmp int15_handler32_ret
10277 ;; Protected mode IDT descriptor
10279 ;; I just make the limit 0, so the machine will shutdown
10280 ;; if an exception occurs during protected mode memory
10283 ;; Set base to f0000 to correspond to beginning of BIOS,
10284 ;; in case I actually define an IDT later
10288 dw 0x0000 ;; limit 15:00
10289 dw 0x0000 ;; base 15:00
10290 db 0x0f ;; base 23:16
10292 ;; Real mode IDT descriptor
10294 ;; Set to typical real-mode values.
10299 dw 0x03ff ;; limit 15:00
10300 dw 0x0000 ;; base 15:00
10301 db 0x00 ;; base 23:16
10307 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10320 mov ax, ss ; set readable descriptor to ds, for calling pcibios
10321 mov ds, ax ; on 16bit protected mode.
10322 jmp int1a_callfunction
10329 int1a_callfunction:
10330 call _int1a_function
10336 ;; int70h: IRQ8 - CMOS RTC
10343 call _int70_function
10351 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10359 ;; time to turn off drive(s)?
10362 jz int08_floppy_off
10365 jnz int08_floppy_off
10366 ;; turn motor(s) off
10375 mov eax, 0x046c ;; get ticks dword
10378 ;; compare eax to one days worth of timer ticks at 18.2 hz
10379 cmp eax, #0x001800B0
10380 jb int08_store_ticks
10381 ;; there has been a midnight rollover at this point
10382 xor eax, eax ;; zero out counter
10383 inc BYTE 0x0470 ;; increment rollover flag
10386 mov 0x046c, eax ;; store new ticks dword
10387 ;; chain to user timer tick INT #0x1c
10389 //;; call_ep [ds:loc]
10390 //CALL_EP( 0x1c << 2 )
10393 call eoi_master_pic
10398 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10402 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10404 ;------------------------------------------------
10405 ;- IRET Instruction for Dummy Interrupt Handler -
10406 ;------------------------------------------------
10407 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10408 dummy_iret_handler:
10411 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10420 .org 0xfff0 ; Power-up Entry Point
10427 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10428 .ascii BIOS_BUILD_DATE
10430 .org 0xfffe ; System Model ID
10434 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10437 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10438 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10439 * This font is public domain
10441 static Bit8u vgafont8[128*8]=
10443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10444 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10445 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10446 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10447 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10448 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10449 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10450 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10451 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10452 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10453 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10454 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10455 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10456 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10457 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10458 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10459 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10460 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10461 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10462 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10463 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10464 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10465 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10466 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10467 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10468 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10469 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10470 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10471 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10472 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10473 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10474 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10476 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10477 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10478 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10479 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10480 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10481 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10482 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10483 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10484 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10485 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10486 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10487 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10488 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10489 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10490 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10491 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10492 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10493 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10494 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10495 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10496 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10497 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10498 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10499 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10500 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10501 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10502 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10503 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10504 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10505 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10506 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10507 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10508 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10509 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10510 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10511 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10512 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10513 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10514 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10515 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10516 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10517 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10518 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10519 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10520 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10521 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10522 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10523 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10524 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10525 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10526 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10527 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10528 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10529 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10530 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10531 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10532 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10533 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10534 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10535 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10536 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10537 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10539 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10540 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10541 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10542 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10543 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10544 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10545 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10546 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10547 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10548 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10549 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10550 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10551 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10552 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10553 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10554 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10555 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10556 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10557 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10558 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10559 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10560 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10561 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10562 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10563 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10564 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10565 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10566 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10567 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10568 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10569 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10570 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10576 // just carve out some blank space for HVMLOADER to write the MP tables to
10578 // NOTE: There should be enough space for a 32 processor entry MP table
10582 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10583 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
10584 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
10585 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
10586 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
10587 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
10588 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
10589 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
10590 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
10591 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
10592 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
10593 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
10594 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
10595 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
10596 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
10599 smbios_entry_point:
10600 db 0,0,0,0,0,0,0,0 ; 8 bytes
10601 db 0,0,0,0,0,0,0,0 ; 16 bytes
10602 db 0,0,0,0,0,0,0,0 ; 24 bytes
10603 db 0,0,0,0,0,0,0 ; 31 bytes
10606 #else // !HVMASSIST
10610 // bcc-generated data will be placed here
10612 // For documentation of this config structure, look on developer.intel.com and
10613 // search for multiprocessor specification. Note that when you change anything
10614 // you must update the checksum (a pain!). It would be better to construct this
10615 // with C structures, or at least fill in the checksum automatically.
10617 // Maybe this structs could be moved elsewhere than d000
10619 #if (BX_SMP_PROCESSORS==1)
10620 // no structure necessary.
10621 #elif (BX_SMP_PROCESSORS==2)
10622 // define the Intel MP Configuration Structure for 2 processors at
10623 // APIC ID 0,1. I/O APIC at ID=2.
10626 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10627 dw (mp_config_end-mp_config_table) ;; table length
10629 db 0x65 ;; checksum
10630 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10631 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10632 db 0x20, 0x20, 0x20, 0x20
10633 db 0x20, 0x20, 0x20, 0x20
10634 dw 0,0 ;; oem table ptr
10635 dw 0 ;; oem table size
10636 dw 20 ;; entry count
10637 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10638 dw 0 ;; extended table length
10639 db 0 ;; extended table checksum
10642 db 0 ;; entry type=processor
10643 db 0 ;; local APIC id
10644 db 0x11 ;; local APIC version number
10645 db 3 ;; cpu flags: enabled, bootstrap processor
10646 db 0,6,0,0 ;; cpu signature
10647 dw 0x201,0 ;; feature flags
10651 db 0 ;; entry type=processor
10652 db 1 ;; local APIC id
10653 db 0x11 ;; local APIC version number
10654 db 1 ;; cpu flags: enabled
10655 db 0,6,0,0 ;; cpu signature
10656 dw 0x201,0 ;; feature flags
10660 db 1 ;; entry type=bus
10662 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10664 db 2 ;; entry type=I/O APIC
10665 db 2 ;; apic id=2. linux will set.
10666 db 0x11 ;; I/O APIC version number
10667 db 1 ;; flags=1=enabled
10668 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10670 db 3 ;; entry type=I/O interrupt
10671 db 0 ;; interrupt type=vectored interrupt
10672 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10673 db 0 ;; source bus ID is ISA
10674 db 0 ;; source bus IRQ
10675 db 2 ;; destination I/O APIC ID
10676 db 0 ;; destination I/O APIC interrrupt in
10677 ;; repeat pattern for interrupts 0-15
10687 db 3,0,0,0,0,10,2,10
10688 db 3,0,0,0,0,11,2,11
10689 db 3,0,0,0,0,12,2,12
10690 db 3,0,0,0,0,13,2,13
10691 db 3,0,0,0,0,14,2,14
10692 db 3,0,0,0,0,15,2,15
10693 #elif (BX_SMP_PROCESSORS==4)
10694 // define the Intel MP Configuration Structure for 4 processors at
10695 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10698 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10699 dw (mp_config_end-mp_config_table) ;; table length
10701 db 0xdd ;; checksum
10702 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10703 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10704 db 0x20, 0x20, 0x20, 0x20
10705 db 0x20, 0x20, 0x20, 0x20
10706 dw 0,0 ;; oem table ptr
10707 dw 0 ;; oem table size
10708 dw 22 ;; entry count
10709 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10710 dw 0 ;; extended table length
10711 db 0 ;; extended table checksum
10714 db 0 ;; entry type=processor
10715 db 0 ;; local APIC id
10716 db 0x11 ;; local APIC version number
10717 db 3 ;; cpu flags: enabled, bootstrap processor
10718 db 0,6,0,0 ;; cpu signature
10719 dw 0x201,0 ;; feature flags
10723 db 0 ;; entry type=processor
10724 db 1 ;; local APIC id
10725 db 0x11 ;; local APIC version number
10726 db 1 ;; cpu flags: enabled
10727 db 0,6,0,0 ;; cpu signature
10728 dw 0x201,0 ;; feature flags
10732 db 0 ;; entry type=processor
10733 db 2 ;; local APIC id
10734 db 0x11 ;; local APIC version number
10735 db 1 ;; cpu flags: enabled
10736 db 0,6,0,0 ;; cpu signature
10737 dw 0x201,0 ;; feature flags
10741 db 0 ;; entry type=processor
10742 db 3 ;; local APIC id
10743 db 0x11 ;; local APIC version number
10744 db 1 ;; cpu flags: enabled
10745 db 0,6,0,0 ;; cpu signature
10746 dw 0x201,0 ;; feature flags
10750 db 1 ;; entry type=bus
10752 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10754 db 2 ;; entry type=I/O APIC
10755 db 4 ;; apic id=4. linux will set.
10756 db 0x11 ;; I/O APIC version number
10757 db 1 ;; flags=1=enabled
10758 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10760 db 3 ;; entry type=I/O interrupt
10761 db 0 ;; interrupt type=vectored interrupt
10762 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10763 db 0 ;; source bus ID is ISA
10764 db 0 ;; source bus IRQ
10765 db 4 ;; destination I/O APIC ID
10766 db 0 ;; destination I/O APIC interrrupt in
10767 ;; repeat pattern for interrupts 0-15
10777 db 3,0,0,0,0,10,4,10
10778 db 3,0,0,0,0,11,4,11
10779 db 3,0,0,0,0,12,4,12
10780 db 3,0,0,0,0,13,4,13
10781 db 3,0,0,0,0,14,4,14
10782 db 3,0,0,0,0,15,4,15
10783 #elif (BX_SMP_PROCESSORS==8)
10784 // define the Intel MP Configuration Structure for 8 processors at
10785 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10788 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10789 dw (mp_config_end-mp_config_table) ;; table length
10791 db 0xc3 ;; checksum
10792 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10793 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10794 db 0x20, 0x20, 0x20, 0x20
10795 db 0x20, 0x20, 0x20, 0x20
10796 dw 0,0 ;; oem table ptr
10797 dw 0 ;; oem table size
10798 dw 26 ;; entry count
10799 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10800 dw 0 ;; extended table length
10801 db 0 ;; extended table checksum
10804 db 0 ;; entry type=processor
10805 db 0 ;; local APIC id
10806 db 0x11 ;; local APIC version number
10807 db 3 ;; cpu flags: enabled, bootstrap processor
10808 db 0,6,0,0 ;; cpu signature
10809 dw 0x201,0 ;; feature flags
10813 db 0 ;; entry type=processor
10814 db 1 ;; local APIC id
10815 db 0x11 ;; local APIC version number
10816 db 1 ;; cpu flags: enabled
10817 db 0,6,0,0 ;; cpu signature
10818 dw 0x201,0 ;; feature flags
10822 db 0 ;; entry type=processor
10823 db 2 ;; local APIC id
10824 db 0x11 ;; local APIC version number
10825 db 1 ;; cpu flags: enabled
10826 db 0,6,0,0 ;; cpu signature
10827 dw 0x201,0 ;; feature flags
10831 db 0 ;; entry type=processor
10832 db 3 ;; local APIC id
10833 db 0x11 ;; local APIC version number
10834 db 1 ;; cpu flags: enabled
10835 db 0,6,0,0 ;; cpu signature
10836 dw 0x201,0 ;; feature flags
10840 db 0 ;; entry type=processor
10841 db 4 ;; local APIC id
10842 db 0x11 ;; local APIC version number
10843 db 1 ;; cpu flags: enabled
10844 db 0,6,0,0 ;; cpu signature
10845 dw 0x201,0 ;; feature flags
10849 db 0 ;; entry type=processor
10850 db 5 ;; local APIC id
10851 db 0x11 ;; local APIC version number
10852 db 1 ;; cpu flags: enabled
10853 db 0,6,0,0 ;; cpu signature
10854 dw 0x201,0 ;; feature flags
10858 db 0 ;; entry type=processor
10859 db 6 ;; local APIC id
10860 db 0x11 ;; local APIC version number
10861 db 1 ;; cpu flags: enabled
10862 db 0,6,0,0 ;; cpu signature
10863 dw 0x201,0 ;; feature flags
10867 db 0 ;; entry type=processor
10868 db 7 ;; local APIC id
10869 db 0x11 ;; local APIC version number
10870 db 1 ;; cpu flags: enabled
10871 db 0,6,0,0 ;; cpu signature
10872 dw 0x201,0 ;; feature flags
10876 db 1 ;; entry type=bus
10878 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10880 db 2 ;; entry type=I/O APIC
10882 db 0x11 ;; I/O APIC version number
10883 db 1 ;; flags=1=enabled
10884 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10886 db 3 ;; entry type=I/O interrupt
10887 db 0 ;; interrupt type=vectored interrupt
10888 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10889 db 0 ;; source bus ID is ISA
10890 db 0 ;; source bus IRQ
10891 db 8 ;; destination I/O APIC ID
10892 db 0 ;; destination I/O APIC interrrupt in
10893 ;; repeat pattern for interrupts 0-15
10903 db 3,0,0,0,0,10,8,10
10904 db 3,0,0,0,0,11,8,11
10905 db 3,0,0,0,0,12,8,12
10906 db 3,0,0,0,0,13,8,13
10907 db 3,0,0,0,0,14,8,14
10908 db 3,0,0,0,0,15,8,15
10910 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
10911 #endif // if (BX_SMP_PROCESSORS==...)
10913 mp_config_end: // this label used to find length of mp structure
10916 #if (BX_SMP_PROCESSORS>1)
10918 mp_floating_pointer_structure:
10919 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
10920 dw mp_config_table, 0xf ;; pointer to MP configuration table
10921 db 1 ;; length of this struct in 16-bit byte chunks
10922 db 4 ;; MP spec revision
10923 db 0xc1 ;; checksum
10924 db 0 ;; MP feature byte 1. value 0 means look at the config table
10925 db 0,0,0,0 ;; MP feature bytes 2-5.
10930 #endif // HVMASSIST