1 /////////////////////////////////////////////////////////////////////////
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
128 #define DEBUG_INT13_HD 0
129 #define DEBUG_INT13_CD 0
130 #define DEBUG_INT13_ET 0
131 #define DEBUG_INT13_FL 0
132 #define DEBUG_INT15 0
133 #define DEBUG_INT16 0
134 #define DEBUG_INT1A 0
135 #define DEBUG_INT74 0
139 #define BX_USE_PS2_MOUSE 1
140 #define BX_CALL_INT15_4F 1
141 #define BX_USE_EBDA 1
142 #define BX_SUPPORT_FLOPPY 1
143 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
147 #define BX_USE_ATADRV 1
148 #define BX_ELTORITO_BOOT 1
150 #define BX_MAX_ATA_INTERFACES 4
151 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
153 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
154 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
156 /* model byte 0xFC = AT */
157 #define SYS_MODEL_ID 0xFC
158 #define SYS_SUBMODEL_ID 0x00
159 #define BIOS_REVISION 1
160 #define BIOS_CONFIG_TABLE 0xe6f5
162 #ifndef BIOS_BUILD_DATE
163 # define BIOS_BUILD_DATE "06/23/99"
166 // 1K of base memory used for Extended Bios Data Area (EBDA)
167 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
168 #define EBDA_SEG 0x9FC0
169 #define EBDA_SIZE 1 // In KiB
170 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
172 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
173 #define IPL_SEG 0x9ff0
174 #define IPL_TABLE_OFFSET 0x0000
175 #define IPL_TABLE_ENTRIES 8
176 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
177 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
178 #define IPL_SIZE 0xff
179 #define IPL_TYPE_FLOPPY 0x01
180 #define IPL_TYPE_HARDDISK 0x02
181 #define IPL_TYPE_CDROM 0x03
182 #define IPL_TYPE_BEV 0x80
184 // Define the application NAME
186 # define BX_APPNAME "QEMU"
187 #elif defined(PLEX86)
188 # define BX_APPNAME "Plex86"
190 # define BX_APPNAME "Bochs"
194 #if BX_USE_ATADRV && BX_CPU<3
195 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
197 #if BX_USE_ATADRV && !BX_USE_EBDA
198 # error ATA/ATAPI Driver can only be used if EBDA is available
200 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
201 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
203 #if BX_PCIBIOS && BX_CPU<3
204 # error PCI BIOS can only be used with 386+ cpu
206 #if BX_APM && BX_CPU<3
207 # error APM BIOS can only be used with 386+ cpu
210 // define this if you want to make PCIBIOS working on a specific bridge only
211 // undef enables PCIBIOS when at least one PCI device is found
212 // i440FX is emulated by Bochs and QEMU
213 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
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
;
282 void memsetb(seg
,offset
,value
,count
);
283 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
284 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
286 // memset of count bytes
288 memsetb(seg
,offset
,value
,count
)
303 mov cx
, 10[bp
] ; count
306 mov ax
, 4[bp
] ; segment
308 mov ax
, 6[bp
] ; offset
310 mov al
, 8[bp
] ; value
325 // memcpy of count bytes
327 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
345 mov cx
, 12[bp
] ; count
348 mov ax
, 4[bp
] ; dsegment
350 mov ax
, 6[bp
] ; doffset
352 mov ax
, 8[bp
] ; ssegment
354 mov ax
, 10[bp
] ; soffset
372 // memcpy of count dword
374 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
392 mov cx
, 12[bp
] ; count
395 mov ax
, 4[bp
] ; dsegment
397 mov ax
, 6[bp
] ; doffset
399 mov ax
, 8[bp
] ; ssegment
401 mov ax
, 10[bp
] ; soffset
419 // read_dword and write_dword functions
420 static Bit32u
read_dword();
421 static void write_dword();
424 read_dword(seg
, offset
)
434 mov ax
, 4[bp
] ; segment
436 mov bx
, 6[bp
] ; offset
440 ;; ax
= return value (word
)
441 ;; dx
= return value (word
)
450 write_dword(seg
, offset
, data
)
462 mov ax
, 4[bp
] ; segment
464 mov bx
, 6[bp
] ; offset
465 mov ax
, 8[bp
] ; data word
466 mov
[bx
], ax
; write data word
468 mov ax
, 10[bp
] ; data word
469 mov
[bx
], ax
; write data word
478 // Bit32u (unsigned long) and long helper functions
507 cmp eax
, dword ptr
[di
]
526 mul eax
, dword ptr
[di
]
622 // for access to RAM area which is used by interrupt vectors
623 // and BIOS Data Area
626 unsigned char filler1
[0x400];
627 unsigned char filler2
[0x6c];
633 #define BiosData ((bios_data_t *) 0)
637 Bit16u heads
; // # heads
638 Bit16u cylinders
; // # cylinders
639 Bit16u spt
; // # sectors / track
659 Bit8u iface
; // ISA or PCI
660 Bit16u iobase1
; // IO Base 1
661 Bit16u iobase2
; // IO Base 2
666 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
667 Bit8u device
; // Detected type of attached devices (hd/cd/none)
668 Bit8u removable
; // Removable device flag
669 Bit8u lock
; // Locks for removable devices
670 Bit8u mode
; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
671 Bit16u blksize
; // block size
673 Bit8u translation
; // type of translation
674 chs_t lchs
; // Logical CHS
675 chs_t pchs
; // Physical CHS
677 Bit32u sectors
; // Total sectors count
682 ata_channel_t channels
[BX_MAX_ATA_INTERFACES
];
685 ata_device_t devices
[BX_MAX_ATA_DEVICES
];
687 // map between (bios hd id - 0x80) and ata channels
688 Bit8u hdcount
, hdidmap
[BX_MAX_ATA_DEVICES
];
690 // map between (bios cd id - 0xE0) and ata channels
691 Bit8u cdcount
, cdidmap
[BX_MAX_ATA_DEVICES
];
693 // Buffer for DPTE table
696 // Count of transferred sectors and bytes
703 // ElTorito Device Emulation data
707 Bit8u emulated_drive
;
708 Bit8u controller_index
;
711 Bit16u buffer_segment
;
718 #endif // BX_ELTORITO_BOOT
720 // for access to EBDA area
721 // The EBDA structure should conform to
722 // http://www.frontiernet.net/~fys/rombios.htm document
723 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
724 // EBDA must be at most 768 bytes; it lives at 0x9fc00, and the boot
725 // device tables are at 0x9ff00 -- 0x9ffff
727 unsigned char filler1
[0x3D];
729 // FDPT - Can be splitted in data members if needed
730 unsigned char fdpt0
[0x10];
731 unsigned char fdpt1
[0x10];
733 unsigned char filler2
[0xC4];
739 // El Torito Emulation data
741 #endif // BX_ELTORITO_BOOT
745 #define EbdaData ((ebda_data_t *) 0)
747 // for access to the int13ext structure
758 #define Int13Ext ((int13ext_t *) 0)
760 // Disk Physical Table definition
767 Bit32u sector_count1
;
768 Bit32u sector_count2
;
779 Bit8u device_path
[8];
784 #define Int13DPT ((dpt_t *) 0)
786 #endif // BX_USE_ATADRV
791 Bit16u di
, si
, bp
, sp
;
792 Bit16u bx
, dx
, cx
, ax
;
796 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
804 Bit32u edi
, esi
, ebp
, esp
;
805 Bit32u ebx
, edx
, ecx
, eax
;
808 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
809 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
837 #define SetCF(x) x.u.r8.flagsl |= 0x01
838 #define SetZF(x) x.u.r8.flagsl |= 0x40
839 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
840 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
841 #define GetCF(x) (x.u.r8.flagsl & 0x01)
860 static Bit8u
inb_cmos();
862 static void outb_cmos();
865 static void init_rtc();
866 static bx_bool
rtc_updating();
868 static Bit8u
read_byte();
869 static Bit16u
read_word();
870 static void write_byte();
871 static void write_word();
872 static void bios_printf();
874 static Bit8u
inhibit_mouse_int_and_events();
875 static void enable_mouse_int_and_events();
876 static Bit8u
send_to_mouse_ctrl();
877 static Bit8u
get_mouse_data();
878 static void set_kbd_command_byte();
880 static void int09_function();
881 static void int13_harddisk();
882 static void int13_cdrom();
883 static void int13_cdemu();
884 static void int13_eltorito();
885 static void int13_diskette_function();
886 static void int14_function();
887 static void int15_function();
888 static void int16_function();
889 static void int17_function();
890 static void int19_function();
891 static void int1a_function();
892 static void int70_function();
893 static void int74_function();
894 static Bit16u
get_CS();
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$ $Date$";
949 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
952 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
954 # define BX_DEBUG_ATA(a...)
957 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
959 # define BX_DEBUG_INT13_HD(a...)
962 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
964 # define BX_DEBUG_INT13_CD(a...)
967 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
969 # define BX_DEBUG_INT13_ET(a...)
972 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
974 # define BX_DEBUG_INT13_FL(a...)
977 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
979 # define BX_DEBUG_INT15(a...)
982 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
984 # define BX_DEBUG_INT16(a...)
987 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
989 # define BX_DEBUG_INT1A(a...)
992 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
994 # define BX_DEBUG_INT74(a...)
997 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
998 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
999 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1000 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1001 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1002 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1003 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1004 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1006 #define GET_AL() ( AX & 0x00ff )
1007 #define GET_BL() ( BX & 0x00ff )
1008 #define GET_CL() ( CX & 0x00ff )
1009 #define GET_DL() ( DX & 0x00ff )
1010 #define GET_AH() ( AX >> 8 )
1011 #define GET_BH() ( BX >> 8 )
1012 #define GET_CH() ( CX >> 8 )
1013 #define GET_DH() ( DX >> 8 )
1015 #define GET_ELDL() ( ELDX & 0x00ff )
1016 #define GET_ELDH() ( ELDX >> 8 )
1018 #define SET_CF() FLAGS |= 0x0001
1019 #define CLEAR_CF() FLAGS &= 0xfffe
1020 #define GET_CF() (FLAGS & 0x0001)
1022 #define SET_ZF() FLAGS |= 0x0040
1023 #define CLEAR_ZF() FLAGS &= 0xffbf
1024 #define GET_ZF() (FLAGS & 0x0040)
1026 #define UNSUPPORTED_FUNCTION 0x86
1029 #define MAX_SCAN_CODE 0x58
1037 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1038 { none
, none
, none
, none
, none
},
1039 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1040 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1041 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1042 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1043 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1044 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1045 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1046 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1047 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1048 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1049 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1050 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1051 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1052 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1053 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1054 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1055 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1056 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1057 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1058 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1059 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1060 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1061 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1062 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1063 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1064 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1065 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1066 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1067 { none
, none
, none
, none
, none
}, /* L Ctrl */
1068 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1069 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1070 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1071 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1072 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1073 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1074 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1075 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1076 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1077 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1078 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1079 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1080 { none
, none
, none
, none
, none
}, /* L shift */
1081 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1082 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1083 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1084 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1085 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1086 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1087 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1088 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1089 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1090 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1091 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1092 { none
, none
, none
, none
, none
}, /* R Shift */
1093 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1094 { none
, none
, none
, none
, none
}, /* L Alt */
1095 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1096 { none
, none
, none
, none
, none
}, /* caps lock */
1097 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1098 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1099 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1100 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1101 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1102 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1103 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1104 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1105 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1106 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1107 { none
, none
, none
, none
, none
}, /* Num Lock */
1108 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1109 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1110 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1111 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1112 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1113 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1114 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1115 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1116 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1117 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1118 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1119 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1120 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1121 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1122 { none
, none
, none
, none
, none
},
1123 { none
, none
, none
, none
, none
},
1124 { 0x565c, 0x567c, none
, none
, none
}, /* \| */
1125 { 0x5700, 0x5700, none
, none
, none
}, /* F11 */
1126 { 0x5800, 0x5800, none
, none
, none
} /* F12 */
1210 outb_cmos(cmos_reg
, val
)
1218 mov al
, 4[bp
] ;; cmos_reg
1220 mov al
, 6[bp
] ;; val
1235 mov al
, 4[bp
] ;; cmos_reg
1246 outb_cmos(0x0a, 0x26);
1247 outb_cmos(0x0b, 0x02);
1255 // This function checks to see if the update-in-progress bit
1256 // is set in CMOS Status Register A. If not, it returns 0.
1257 // If it is set, it tries to wait until there is a transition
1258 // to 0, and will return 0 if such a transition occurs. A 1
1259 // is returned only after timing out. The maximum period
1260 // that this bit should be set is constrained to 244useconds.
1261 // The count I use below guarantees coverage or more than
1262 // this time, with any reasonable IPS setting.
1267 while (--count
!= 0) {
1268 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1271 return(1); // update-in-progress never transitioned to 0
1276 read_byte(seg
, offset
)
1286 mov ax
, 4[bp
] ; segment
1288 mov bx
, 6[bp
] ; offset
1290 ;; al
= return value (byte
)
1299 read_word(seg
, offset
)
1309 mov ax
, 4[bp
] ; segment
1311 mov bx
, 6[bp
] ; offset
1313 ;; ax
= return value (word
)
1322 write_byte(seg
, offset
, data
)
1334 mov ax
, 4[bp
] ; segment
1336 mov bx
, 6[bp
] ; offset
1337 mov al
, 8[bp
] ; data byte
1338 mov
[bx
], al
; write data byte
1348 write_word(seg
, offset
, data
)
1360 mov ax
, 4[bp
] ; segment
1362 mov bx
, 6[bp
] ; offset
1363 mov ax
, 8[bp
] ; data word
1364 mov
[bx
], ax
; write data word
1390 /* serial debug port*/
1391 #define BX_DEBUG_PORT 0x03f8
1394 #define UART_RBR 0x00
1395 #define UART_THR 0x00
1398 #define UART_IER 0x01
1399 #define UART_IIR 0x02
1400 #define UART_FCR 0x02
1401 #define UART_LCR 0x03
1402 #define UART_MCR 0x04
1403 #define UART_DLL 0x00
1404 #define UART_DLM 0x01
1407 #define UART_LSR 0x05
1408 #define UART_MSR 0x06
1409 #define UART_SCR 0x07
1411 int uart_can_tx_byte(base_port
)
1414 return inb(base_port
+ UART_LSR
) & 0x20;
1417 void uart_wait_to_tx_byte(base_port
)
1420 while (!uart_can_tx_byte(base_port
));
1423 void uart_wait_until_sent(base_port
)
1426 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1429 void uart_tx_byte(base_port
, data
)
1433 uart_wait_to_tx_byte(base_port
);
1434 outb(base_port
+ UART_THR
, data
);
1435 uart_wait_until_sent(base_port
);
1464 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1465 uart_tx_byte(BX_DEBUG_PORT
, c
);
1467 #if BX_VIRTUAL_PORTS
1468 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1469 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1471 if (action
& BIOS_PRINTF_SCREEN
) {
1472 if (c
== '\n') wrch('\r');
1478 put_int(action
, val
, width
, neg
)
1483 short nval
= val
/ 10;
1485 put_int(action
, nval
, width
- 1, neg
);
1487 while (--width
> 0) send(action
, ' ');
1488 if (neg
) send(action
, '-');
1490 send(action
, val
- (nval
* 10) + '0');
1494 put_uint(action
, val
, width
, neg
)
1500 unsigned short nval
= val
/ 10;
1502 put_uint(action
, nval
, width
- 1, neg
);
1504 while (--width
> 0) send(action
, ' ');
1505 if (neg
) send(action
, '-');
1507 send(action
, val
- (nval
* 10) + '0');
1511 put_luint(action
, val
, width
, neg
)
1517 unsigned long nval
= val
/ 10;
1519 put_luint(action
, nval
, width
- 1, neg
);
1521 while (--width
> 0) send(action
, ' ');
1522 if (neg
) send(action
, '-');
1524 send(action
, val
- (nval
* 10) + '0');
1527 void put_str(action
, s
)
1535 while (c
= read_byte(get_CS(), s
)) {
1541 //--------------------------------------------------------------------------
1543 // A compact variable argument printf function.
1545 // Supports %[format_width][length]format
1546 // where format can be x,X,u,d,s,c
1547 // and the optional length modifier is l (ell)
1548 //--------------------------------------------------------------------------
1550 bios_printf(action
, s
)
1554 Bit8u c
, format_char
;
1558 Bit16u arg_seg
, arg
, nibble
, hibyte
, shift_count
, format_width
, hexadd
;
1566 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1567 #if BX_VIRTUAL_PORTS
1568 outb(PANIC_PORT2
, 0x00);
1570 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1573 while (c
= read_byte(get_CS(), s
)) {
1578 else if (in_format
) {
1579 if ( (c
>='0') && (c
<='9') ) {
1580 format_width
= (format_width
* 10) + (c
- '0');
1583 arg_ptr
++; // increment to next arg
1584 arg
= read_word(arg_seg
, arg_ptr
);
1585 if (c
== 'x' || c
== 'X') {
1586 if (format_width
== 0)
1592 for (i
=format_width
-1; i
>=0; i
--) {
1593 nibble
= (arg
>> (4 * i
)) & 0x000f;
1594 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1597 else if (c
== 'u') {
1598 put_uint(action
, arg
, format_width
, 0);
1600 else if (c
== 'l') {
1602 c
= read_byte(get_CS(), s
); /* is it ld,lx,lu? */
1603 arg_ptr
++; /* increment to next arg */
1604 hibyte
= read_word(arg_seg
, arg_ptr
);
1606 if (hibyte
& 0x8000)
1607 put_luint(action
, 0L-(((Bit32u
) hibyte
<< 16) | arg
), format_width
-1, 1);
1609 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1611 else if (c
== 'u') {
1612 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1614 else if (c
== 'x' || c
== 'X')
1616 if (format_width
== 0)
1622 for (i
=format_width
-1; i
>=0; i
--) {
1623 nibble
= ((((Bit32u
) hibyte
<<16) | arg
) >> (4 * i
)) & 0x000f;
1624 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1628 else if (c
== 'd') {
1630 put_int(action
, -arg
, format_width
- 1, 1);
1632 put_int(action
, arg
, format_width
, 0);
1634 else if (c
== 's') {
1635 put_str(action
, arg
);
1637 else if (c
== 'c') {
1641 BX_PANIC("bios_printf: unknown format\n");
1651 if (action
& BIOS_PRINTF_HALT
) {
1652 // freeze in a busy loop.
1662 //--------------------------------------------------------------------------
1664 //--------------------------------------------------------------------------
1665 // this file is based on LinuxBIOS implementation of keyboard.c
1666 // could convert to #asm to gain space
1672 /* ------------------- Flush buffers ------------------------*/
1673 /* Wait until buffer is empty */
1675 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1677 /* flush incoming keys */
1681 if (inb(0x64) & 0x01) {
1687 // Due to timer issues, and if the IPS setting is > 15000000,
1688 // the incoming keys might not be flushed here. That will
1689 // cause a panic a few lines below. See sourceforge bug report :
1690 // [ 642031 ] FATAL: Keyboard RESET error:993
1692 /* ------------------- controller side ----------------------*/
1693 /* send cmd = 0xAA, self test 8042 */
1696 /* Wait until buffer is empty */
1698 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1699 if (max
==0x0) keyboard_panic(00);
1703 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1704 if (max
==0x0) keyboard_panic(01);
1706 /* read self-test result, 0x55 should be returned from 0x60 */
1707 if ((inb(0x60) != 0x55)){
1708 keyboard_panic(991);
1711 /* send cmd = 0xAB, keyboard interface test */
1714 /* Wait until buffer is empty */
1716 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1717 if (max
==0x0) keyboard_panic(10);
1721 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1722 if (max
==0x0) keyboard_panic(11);
1724 /* read keyboard interface test result, */
1725 /* 0x00 should be returned form 0x60 */
1726 if ((inb(0x60) != 0x00)) {
1727 keyboard_panic(992);
1730 /* Enable Keyboard clock */
1734 /* ------------------- keyboard side ------------------------*/
1735 /* reset kerboard and self test (keyboard side) */
1738 /* Wait until buffer is empty */
1740 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1741 if (max
==0x0) keyboard_panic(20);
1745 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1746 if (max
==0x0) keyboard_panic(21);
1748 /* keyboard should return ACK */
1749 if ((inb(0x60) != 0xfa)) {
1750 keyboard_panic(993);
1755 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1756 if (max
==0x0) keyboard_panic(31);
1758 if ((inb(0x60) != 0xaa)) {
1759 keyboard_panic(994);
1762 /* Disable keyboard */
1765 /* Wait until buffer is empty */
1767 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1768 if (max
==0x0) keyboard_panic(40);
1772 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1773 if (max
==0x0) keyboard_panic(41);
1775 /* keyboard should return ACK */
1776 if ((inb(0x60) != 0xfa)) {
1777 keyboard_panic(995);
1780 /* Write Keyboard Mode */
1783 /* Wait until buffer is empty */
1785 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1786 if (max
==0x0) keyboard_panic(50);
1788 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1791 /* Wait until buffer is empty */
1793 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1794 if (max
==0x0) keyboard_panic(60);
1796 /* Enable keyboard */
1799 /* Wait until buffer is empty */
1801 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1802 if (max
==0x0) keyboard_panic(70);
1806 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1807 if (max
==0x0) keyboard_panic(70);
1809 /* keyboard should return ACK */
1810 if ((inb(0x60) != 0xfa)) {
1811 keyboard_panic(996);
1817 //--------------------------------------------------------------------------
1819 //--------------------------------------------------------------------------
1821 keyboard_panic(status
)
1824 // If you're getting a 993 keyboard panic here,
1825 // please see the comment in keyboard_init
1827 BX_PANIC("Keyboard error:%u\n",status
);
1830 //--------------------------------------------------------------------------
1831 // shutdown_status_panic
1832 // called when the shutdown statsu is not implemented, displays the status
1833 //--------------------------------------------------------------------------
1835 shutdown_status_panic(status
)
1838 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1841 //--------------------------------------------------------------------------
1842 // print_bios_banner
1843 // displays a the bios version
1844 //--------------------------------------------------------------------------
1848 printf(BX_APPNAME
" BIOS - build: %s\n%s\nOptions: ",
1849 BIOS_BUILD_DATE
, bios_cvs_version_string
);
1857 #if BX_ELTORITO_BOOT
1866 //--------------------------------------------------------------------------
1867 // BIOS Boot Specification 1.0.1 compatibility
1869 // Very basic support for the BIOS Boot Specification, which allows expansion
1870 // ROMs to register themselves as boot devices, instead of just stealing the
1871 // INT 19h boot vector.
1873 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1874 // one; we just lie to the option ROMs to make them behave correctly.
1875 // We also don't support letting option ROMs register as bootable disk
1876 // drives (BCVs), only as bootable devices (BEVs).
1878 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1879 //--------------------------------------------------------------------------
1887 Bit16u ss
= get_SS();
1889 /* Clear out the IPL table. */
1890 memsetb(IPL_SEG
, IPL_TABLE_OFFSET
, 0, IPL_SIZE
);
1893 e
.type
= IPL_TYPE_FLOPPY
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1894 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1898 e
.type
= IPL_TYPE_HARDDISK
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1899 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1902 #if BX_ELTORITO_BOOT
1904 e
.type
= IPL_TYPE_CDROM
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1905 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1909 /* Remember how many devices we have */
1910 write_word(IPL_SEG
, IPL_COUNT_OFFSET
, count
);
1911 /* Not tried booting anything yet */
1912 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xffff);
1916 get_boot_vector(i
, e
)
1917 Bit16u i
; ipl_entry_t
*e
;
1920 Bit16u ss
= get_SS();
1921 /* Get the count of boot devices, and refuse to overrun the array */
1922 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
1923 if (i
>= count
) return 0;
1924 /* OK to read this device */
1925 memcpyb(ss
, e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (*e
), sizeof (*e
));
1930 //--------------------------------------------------------------------------
1931 // print_boot_device
1932 // displays the boot device
1933 //--------------------------------------------------------------------------
1935 static char drivetypes
[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1938 print_boot_device(type
)
1941 /* NIC appears as type 0x80 */
1942 if (type
== IPL_TYPE_BEV
) type
= 0x4;
1943 if (type
== 0 || type
> 0x4) BX_PANIC("Bad drive type\n");
1944 printf("Booting from %s...\n", drivetypes
[type
]);
1947 //--------------------------------------------------------------------------
1948 // print_boot_failure
1949 // displays the reason why boot failed
1950 //--------------------------------------------------------------------------
1952 print_boot_failure(type
, reason
)
1953 Bit16u type
; Bit8u reason
;
1955 if (type
== 0 || type
> 0x3) BX_PANIC("Bad drive type\n");
1957 printf("Boot from %s failed", drivetypes
[type
]);
1959 /* Report the reason too */
1961 printf(": not a bootable disk");
1963 printf(": could not read the boot disk");
1968 //--------------------------------------------------------------------------
1969 // print_cdromboot_failure
1970 // displays the reason why boot failed
1971 //--------------------------------------------------------------------------
1973 print_cdromboot_failure( code
)
1976 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1984 BX_PANIC("NMI Handler called\n");
1990 BX_PANIC("INT18: BOOT FAILURE\n");
1997 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
1999 BX_INFO("%s\n", bios_cvs_version_string
);
2008 // Use PS2 System Control port A to set A20 enable
2010 // get current setting first
2013 // change A20 status
2015 outb(0x92, oldval
| 0x02);
2017 outb(0x92, oldval
& 0xfd);
2019 return((oldval
& 0x02) != 0);
2036 // ---------------------------------------------------------------------------
2037 // Start of ATA/ATAPI Driver
2038 // ---------------------------------------------------------------------------
2040 // Global defines -- ATA register and register bits.
2041 // command block & control block regs
2042 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2043 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2044 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2045 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2046 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2047 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2048 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2049 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2050 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2051 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2052 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2053 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2054 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2056 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2057 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2058 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2059 #define ATA_CB_ER_MC 0x20 // ATA media change
2060 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2061 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2062 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2063 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2064 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2066 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2067 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2068 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2069 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2070 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2072 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2073 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2074 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2075 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2076 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2078 // bits 7-4 of the device/head (CB_DH) reg
2079 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2080 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2081 #define ATA_CB_DH_LBA 0x40 // use LBA
2083 // status reg (CB_STAT and CB_ASTAT) bits
2084 #define ATA_CB_STAT_BSY 0x80 // busy
2085 #define ATA_CB_STAT_RDY 0x40 // ready
2086 #define ATA_CB_STAT_DF 0x20 // device fault
2087 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2088 #define ATA_CB_STAT_SKC 0x10 // seek complete
2089 #define ATA_CB_STAT_SERV 0x10 // service
2090 #define ATA_CB_STAT_DRQ 0x08 // data request
2091 #define ATA_CB_STAT_CORR 0x04 // corrected
2092 #define ATA_CB_STAT_IDX 0x02 // index
2093 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2094 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2096 // device control reg (CB_DC) bits
2097 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2098 #define ATA_CB_DC_SRST 0x04 // soft reset
2099 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2101 // Most mandtory and optional ATA commands (from ATA-3),
2102 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2103 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2104 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2105 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2106 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2107 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2108 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2109 #define ATA_CMD_DEVICE_RESET 0x08
2110 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2111 #define ATA_CMD_FLUSH_CACHE 0xE7
2112 #define ATA_CMD_FORMAT_TRACK 0x50
2113 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2114 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2115 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2116 #define ATA_CMD_IDLE1 0xE3
2117 #define ATA_CMD_IDLE2 0x97
2118 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2119 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2120 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2121 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2122 #define ATA_CMD_NOP 0x00
2123 #define ATA_CMD_PACKET 0xA0
2124 #define ATA_CMD_READ_BUFFER 0xE4
2125 #define ATA_CMD_READ_DMA 0xC8
2126 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2127 #define ATA_CMD_READ_MULTIPLE 0xC4
2128 #define ATA_CMD_READ_SECTORS 0x20
2129 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2130 #define ATA_CMD_RECALIBRATE 0x10
2131 #define ATA_CMD_REQUEST_SENSE 0x03
2132 #define ATA_CMD_SEEK 0x70
2133 #define ATA_CMD_SET_FEATURES 0xEF
2134 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2135 #define ATA_CMD_SLEEP1 0xE6
2136 #define ATA_CMD_SLEEP2 0x99
2137 #define ATA_CMD_STANDBY1 0xE2
2138 #define ATA_CMD_STANDBY2 0x96
2139 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2140 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2141 #define ATA_CMD_WRITE_BUFFER 0xE8
2142 #define ATA_CMD_WRITE_DMA 0xCA
2143 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2144 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2145 #define ATA_CMD_WRITE_SECTORS 0x30
2146 #define ATA_CMD_WRITE_VERIFY 0x3C
2148 #define ATA_IFACE_NONE 0x00
2149 #define ATA_IFACE_ISA 0x00
2150 #define ATA_IFACE_PCI 0x01
2152 #define ATA_TYPE_NONE 0x00
2153 #define ATA_TYPE_UNKNOWN 0x01
2154 #define ATA_TYPE_ATA 0x02
2155 #define ATA_TYPE_ATAPI 0x03
2157 #define ATA_DEVICE_NONE 0x00
2158 #define ATA_DEVICE_HD 0xFF
2159 #define ATA_DEVICE_CDROM 0x05
2161 #define ATA_MODE_NONE 0x00
2162 #define ATA_MODE_PIO16 0x00
2163 #define ATA_MODE_PIO32 0x01
2164 #define ATA_MODE_ISADMA 0x02
2165 #define ATA_MODE_PCIDMA 0x03
2166 #define ATA_MODE_USEIRQ 0x10
2168 #define ATA_TRANSLATION_NONE 0
2169 #define ATA_TRANSLATION_LBA 1
2170 #define ATA_TRANSLATION_LARGE 2
2171 #define ATA_TRANSLATION_RECHS 3
2173 #define ATA_DATA_NO 0x00
2174 #define ATA_DATA_IN 0x01
2175 #define ATA_DATA_OUT 0x02
2177 // ---------------------------------------------------------------------------
2178 // ATA/ATAPI driver : initialization
2179 // ---------------------------------------------------------------------------
2182 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2183 Bit8u channel
, device
;
2185 // Channels info init.
2186 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2187 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2188 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2189 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2190 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2193 // Devices info init.
2194 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2195 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2196 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2197 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2198 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2199 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2200 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2201 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2202 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2203 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2204 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2205 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2206 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2207 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2209 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2212 // hdidmap and cdidmap init.
2213 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2214 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2215 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2218 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2219 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2225 #define NOT_BSY_DRQ 3
2226 #define NOT_BSY_NOT_DRQ 4
2227 #define NOT_BSY_RDY 5
2229 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
2232 static int await_ide(when_done
,base
,timeout
)
2237 Bit32u time
=0,last
=0;
2240 status
= inb(base
+ ATA_CB_STAT
); // for the times you're supposed to throw one away
2242 status
= inb(base
+ATA_CB_STAT
);
2244 if (when_done
== BSY
)
2245 result
= status
& ATA_CB_STAT_BSY
;
2246 else if (when_done
== NOT_BSY
)
2247 result
= !(status
& ATA_CB_STAT_BSY
);
2248 else if (when_done
== NOT_BSY_DRQ
)
2249 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_DRQ
);
2250 else if (when_done
== NOT_BSY_NOT_DRQ
)
2251 result
= !(status
& ATA_CB_STAT_BSY
) && !(status
& ATA_CB_STAT_DRQ
);
2252 else if (when_done
== NOT_BSY_RDY
)
2253 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_RDY
);
2254 else if (when_done
== TIMEOUT
)
2257 if (result
) return 0;
2258 if (time
>>16 != last
) // mod 2048 each 16 ms
2261 BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done
,time
>>11, timeout
);
2263 if (status
& ATA_CB_STAT_ERR
)
2265 BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done
,time
>>11, timeout
);
2268 if ((timeout
== 0) || ((time
>>11) > timeout
)) break;
2270 BX_INFO("IDE time out\n");
2274 // ---------------------------------------------------------------------------
2275 // ATA/ATAPI driver : device detection
2276 // ---------------------------------------------------------------------------
2280 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2281 Bit8u hdcount
, cdcount
, device
, type
;
2282 Bit8u buffer
[0x0200];
2284 #if BX_MAX_ATA_INTERFACES > 0
2285 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2286 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2287 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2288 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2290 #if BX_MAX_ATA_INTERFACES > 1
2291 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2292 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2293 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2294 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2296 #if BX_MAX_ATA_INTERFACES > 2
2297 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2298 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2299 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2300 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2302 #if BX_MAX_ATA_INTERFACES > 3
2303 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2304 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2305 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2306 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2308 #if BX_MAX_ATA_INTERFACES > 4
2309 #error Please fill the ATA interface informations
2315 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2316 Bit16u iobase1
, iobase2
;
2317 Bit8u channel
, slave
, shift
;
2318 Bit8u sc
, sn
, cl
, ch
, st
;
2320 channel
= device
/ 2;
2323 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2324 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2326 // Disable interrupts
2327 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2330 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2331 outb(iobase1
+ATA_CB_SC
, 0x55);
2332 outb(iobase1
+ATA_CB_SN
, 0xaa);
2333 outb(iobase1
+ATA_CB_SC
, 0xaa);
2334 outb(iobase1
+ATA_CB_SN
, 0x55);
2335 outb(iobase1
+ATA_CB_SC
, 0x55);
2336 outb(iobase1
+ATA_CB_SN
, 0xaa);
2338 // If we found something
2339 sc
= inb(iobase1
+ATA_CB_SC
);
2340 sn
= inb(iobase1
+ATA_CB_SN
);
2342 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2343 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2345 // reset the channel
2348 // check for ATA or ATAPI
2349 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2350 sc
= inb(iobase1
+ATA_CB_SC
);
2351 sn
= inb(iobase1
+ATA_CB_SN
);
2352 if ((sc
==0x01) && (sn
==0x01)) {
2353 cl
= inb(iobase1
+ATA_CB_CL
);
2354 ch
= inb(iobase1
+ATA_CB_CH
);
2355 st
= inb(iobase1
+ATA_CB_STAT
);
2357 if ((cl
==0x14) && (ch
==0xeb)) {
2358 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2359 } else if ((cl
==0x00) && (ch
==0x00) && (st
!=0x00)) {
2360 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2361 } else if ((cl
==0xff) && (ch
==0xff)) {
2362 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2367 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2369 // Now we send a IDENTIFY command to ATA device
2370 if(type
== ATA_TYPE_ATA
) {
2372 Bit16u cylinders
, heads
, spt
, blksize
;
2373 Bit8u translation
, removable
, mode
;
2375 //Temporary values to do the transfer
2376 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2377 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2379 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2380 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2382 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2383 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2384 blksize
= read_word(get_SS(),buffer
+10);
2386 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2387 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2388 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2390 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2392 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2393 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2394 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2395 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2396 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2397 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2398 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2399 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2400 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2402 translation
= inb_cmos(0x39 + channel
/2);
2403 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2404 translation
&= 0x03;
2406 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2408 switch (translation
) {
2409 case ATA_TRANSLATION_NONE
:
2412 case ATA_TRANSLATION_LBA
:
2415 case ATA_TRANSLATION_LARGE
:
2418 case ATA_TRANSLATION_RECHS
:
2422 switch (translation
) {
2423 case ATA_TRANSLATION_NONE
:
2425 case ATA_TRANSLATION_LBA
:
2428 heads
= sectors
/ 1024;
2429 if (heads
>128) heads
= 255;
2430 else if (heads
>64) heads
= 128;
2431 else if (heads
>32) heads
= 64;
2432 else if (heads
>16) heads
= 32;
2434 cylinders
= sectors
/ heads
;
2436 case ATA_TRANSLATION_RECHS
:
2437 // Take care not to overflow
2439 if(cylinders
>61439) cylinders
=61439;
2441 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2443 // then go through the large bitshift process
2444 case ATA_TRANSLATION_LARGE
:
2445 while(cylinders
> 1024) {
2449 // If we max out the head count
2450 if (heads
> 127) break;
2454 // clip to 1024 cylinders in lchs
2455 if (cylinders
> 1024) cylinders
=1024;
2456 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2458 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2459 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2460 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2463 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2467 // Now we send a IDENTIFY command to ATAPI device
2468 if(type
== ATA_TYPE_ATAPI
) {
2470 Bit8u type
, removable
, mode
;
2473 //Temporary values to do the transfer
2474 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2475 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2477 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2478 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2480 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2481 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2482 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2485 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2486 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2487 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2488 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2491 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2498 Bit8u c
, i
, version
, model
[41];
2502 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2504 case ATA_TYPE_ATAPI
:
2505 // Read ATA/ATAPI version
2506 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2507 for(version
=15;version
>0;version
--) {
2508 if((ataversion
&(1<<version
))!=0)
2514 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2515 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2519 write_byte(get_SS(),model
+40,0x00);
2521 if(read_byte(get_SS(),model
+i
)==0x20)
2522 write_byte(get_SS(),model
+i
,0x00);
2530 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2531 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2532 if (sizeinmb
< (1UL<<16))
2533 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version
, (Bit16u
)sizeinmb
);
2535 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version
, (Bit16u
)(sizeinmb
>>10));
2537 case ATA_TYPE_ATAPI
:
2538 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2539 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2540 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2541 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2543 printf(" ATAPI-%d Device\n",version
);
2545 case ATA_TYPE_UNKNOWN
:
2546 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2552 // Store the devices counts
2553 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2554 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2555 write_byte(0x40,0x75, hdcount
);
2559 // FIXME : should use bios=cmos|auto|disable bits
2560 // FIXME : should know about translation bits
2561 // FIXME : move hard_drive_post here
2565 // ---------------------------------------------------------------------------
2566 // ATA/ATAPI driver : software reset
2567 // ---------------------------------------------------------------------------
2569 // 8.2.1 Software reset - Device 0
2571 void ata_reset(device
)
2574 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2575 Bit16u iobase1
, iobase2
;
2576 Bit8u channel
, slave
, sn
, sc
;
2580 channel
= device
/ 2;
2583 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2584 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2588 // 8.2.1 (a) -- set SRST in DC
2589 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2591 // 8.2.1 (b) -- wait for BSY
2592 await_ide(BSY
, iobase1
, 20);
2594 // 8.2.1 (f) -- clear SRST
2595 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2597 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2598 if (type
!= ATA_TYPE_NONE
) {
2600 // 8.2.1 (g) -- check for sc==sn==0x01
2602 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2603 sc
= inb(iobase1
+ATA_CB_SC
);
2604 sn
= inb(iobase1
+ATA_CB_SN
);
2606 if ( (sc
==0x01) && (sn
==0x01) ) {
2607 if (type
== ATA_TYPE_ATA
) //ATA
2608 await_ide(NOT_BSY_RDY
, iobase1
, IDE_TIMEOUT
);
2610 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2613 // 8.2.1 (h) -- wait for not BSY
2614 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2617 // Enable interrupts
2618 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2621 // ---------------------------------------------------------------------------
2622 // ATA/ATAPI driver : execute a non data command
2623 // ---------------------------------------------------------------------------
2625 Bit16u
ata_cmd_non_data()
2628 // ---------------------------------------------------------------------------
2629 // ATA/ATAPI driver : execute a data-in command
2630 // ---------------------------------------------------------------------------
2635 // 3 : expected DRQ=1
2636 // 4 : no sectors left to read/verify
2637 // 5 : more sectors to read/verify
2638 // 6 : no sectors left to write
2639 // 7 : more sectors to write
2640 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2641 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2644 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2645 Bit16u iobase1
, iobase2
, blksize
;
2646 Bit8u channel
, slave
;
2647 Bit8u status
, current
, mode
;
2649 channel
= device
/ 2;
2652 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2653 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2654 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2655 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2656 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2659 // Reset count of transferred data
2660 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2661 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2664 status
= inb(iobase1
+ ATA_CB_STAT
);
2665 if (status
& ATA_CB_STAT_BSY
) return 1;
2667 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2669 // sector will be 0 only on lba access. Convert to lba-chs
2671 if ((count
>= 1 << 8) || (lba
+ count
>= 1UL << 28)) {
2672 outb(iobase1
+ ATA_CB_FR
, 0x00);
2673 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2674 outb(iobase1
+ ATA_CB_SN
, lba
>> 24);
2675 outb(iobase1
+ ATA_CB_CL
, 0);
2676 outb(iobase1
+ ATA_CB_CH
, 0);
2678 count
&= (1UL << 8) - 1;
2679 lba
&= (1UL << 24) - 1;
2681 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2682 cylinder
= (Bit16u
) ((lba
>>8) & 0x0000ffffL
);
2683 head
= ((Bit16u
) ((lba
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2686 outb(iobase1
+ ATA_CB_FR
, 0x00);
2687 outb(iobase1
+ ATA_CB_SC
, count
);
2688 outb(iobase1
+ ATA_CB_SN
, sector
);
2689 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2690 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2691 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2692 outb(iobase1
+ ATA_CB_CMD
, command
);
2694 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2695 status
= inb(iobase1
+ ATA_CB_STAT
);
2697 if (status
& ATA_CB_STAT_ERR
) {
2698 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2700 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2701 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2705 // FIXME : move seg/off translation here
2708 sti
;; enable higher priority interrupts
2716 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2717 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2718 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2720 ;; adjust
if there will be an overrun
. 2K max sector size
2722 jbe ata_in_no_adjust
2725 sub di
, #0x0800 ;; sub 2 kbytes from offset
2726 add ax
, #0x0080 ;; add 2 Kbytes to segment
2729 mov es
, ax
;; segment in es
2731 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2733 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2734 cmp ah
, #ATA_MODE_PIO32
2739 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2744 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2747 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2748 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2753 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2755 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2756 status
= inb(iobase1
+ ATA_CB_STAT
);
2758 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2759 != ATA_CB_STAT_RDY
) {
2760 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2766 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2767 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2768 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2774 // Enable interrupts
2775 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2779 // ---------------------------------------------------------------------------
2780 // ATA/ATAPI driver : execute a data-out command
2781 // ---------------------------------------------------------------------------
2786 // 3 : expected DRQ=1
2787 // 4 : no sectors left to read/verify
2788 // 5 : more sectors to read/verify
2789 // 6 : no sectors left to write
2790 // 7 : more sectors to write
2791 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2792 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2795 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2796 Bit16u iobase1
, iobase2
, blksize
;
2797 Bit8u channel
, slave
;
2798 Bit8u status
, current
, mode
;
2800 channel
= device
/ 2;
2803 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2804 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2805 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2806 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2807 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2810 // Reset count of transferred data
2811 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2812 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2815 status
= inb(iobase1
+ ATA_CB_STAT
);
2816 if (status
& ATA_CB_STAT_BSY
) return 1;
2818 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2820 // sector will be 0 only on lba access. Convert to lba-chs
2822 if ((count
>= 1 << 8) || (lba
+ count
>= 1UL << 28)) {
2823 outb(iobase1
+ ATA_CB_FR
, 0x00);
2824 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2825 outb(iobase1
+ ATA_CB_SN
, lba
>> 24);
2826 outb(iobase1
+ ATA_CB_CL
, 0);
2827 outb(iobase1
+ ATA_CB_CH
, 0);
2829 count
&= (1UL << 8) - 1;
2830 lba
&= (1UL << 24) - 1;
2832 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2833 cylinder
= (Bit16u
) ((lba
>>8) & 0x0000ffffL
);
2834 head
= ((Bit16u
) ((lba
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2837 outb(iobase1
+ ATA_CB_FR
, 0x00);
2838 outb(iobase1
+ ATA_CB_SC
, count
);
2839 outb(iobase1
+ ATA_CB_SN
, sector
);
2840 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2841 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2842 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2843 outb(iobase1
+ ATA_CB_CMD
, command
);
2845 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2846 status
= inb(iobase1
+ ATA_CB_STAT
);
2848 if (status
& ATA_CB_STAT_ERR
) {
2849 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2851 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2852 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2856 // FIXME : move seg/off translation here
2859 sti
;; enable higher priority interrupts
2867 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2868 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2869 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2871 ;; adjust
if there will be an overrun
. 2K max sector size
2873 jbe ata_out_no_adjust
2876 sub si
, #0x0800 ;; sub 2 kbytes from offset
2877 add ax
, #0x0080 ;; add 2 Kbytes to segment
2880 mov es
, ax
;; segment in es
2882 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2884 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2885 cmp ah
, #ATA_MODE_PIO32
2891 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2897 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2900 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2901 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2906 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2908 status
= inb(iobase1
+ ATA_CB_STAT
);
2910 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2911 != ATA_CB_STAT_RDY
) {
2912 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2918 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2919 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2920 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2926 // Enable interrupts
2927 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2931 // ---------------------------------------------------------------------------
2932 // ATA/ATAPI driver : execute a packet command
2933 // ---------------------------------------------------------------------------
2936 // 1 : error in parameters
2940 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2942 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2946 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2947 Bit16u iobase1
, iobase2
;
2948 Bit16u lcount
, lbefore
, lafter
, count
;
2949 Bit8u channel
, slave
;
2950 Bit8u status
, mode
, lmode
;
2951 Bit32u total
, transfer
;
2953 channel
= device
/ 2;
2956 // Data out is not supported yet
2957 if (inout
== ATA_DATA_OUT
) {
2958 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2962 // The header length must be even
2964 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2968 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2969 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2970 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2973 if (cmdlen
< 12) cmdlen
=12;
2974 if (cmdlen
> 12) cmdlen
=16;
2977 // Reset count of transferred data
2978 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2979 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2981 status
= inb(iobase1
+ ATA_CB_STAT
);
2982 if (status
& ATA_CB_STAT_BSY
) return 2;
2984 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2985 outb(iobase1
+ ATA_CB_FR
, 0x00);
2986 outb(iobase1
+ ATA_CB_SC
, 0x00);
2987 outb(iobase1
+ ATA_CB_SN
, 0x00);
2988 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2989 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2990 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2991 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2993 // Device should ok to receive command
2994 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2995 status
= inb(iobase1
+ ATA_CB_STAT
);
2997 if (status
& ATA_CB_STAT_ERR
) {
2998 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
3000 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
3001 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
3005 // Normalize address
3006 cmdseg
+= (cmdoff
/ 16);
3009 // Send command to device
3011 sti
;; enable higher priority interrupts
3016 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
3017 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
3018 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
3019 mov es
, ax
;; segment in es
3021 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
3025 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
3030 if (inout
== ATA_DATA_NO
) {
3031 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3032 status
= inb(iobase1
+ ATA_CB_STAT
);
3039 if (loops
== 0) {//first time through
3040 status
= inb(iobase2
+ ATA_CB_ASTAT
);
3041 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3044 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3047 status
= inb(iobase1
+ ATA_CB_STAT
);
3048 sc
= inb(iobase1
+ ATA_CB_SC
);
3050 // Check if command completed
3051 if(((inb(iobase1
+ ATA_CB_SC
)&0x7)==0x3) &&
3052 ((status
& (ATA_CB_STAT_RDY
| ATA_CB_STAT_ERR
)) == ATA_CB_STAT_RDY
)) break;
3054 if (status
& ATA_CB_STAT_ERR
) {
3055 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
3059 // Normalize address
3060 bufseg
+= (bufoff
/ 16);
3063 // Get the byte count
3064 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
3066 // adjust to read what we want
3079 lafter
=lcount
-length
;
3091 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
3092 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
3094 // If counts not dividable by 4, use 16bits mode
3096 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
3097 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
3098 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
3100 // adds an extra byte if count are odd. before is always even
3101 if (lcount
& 0x01) {
3103 if ((lafter
> 0) && (lafter
& 0x01)) {
3108 if (lmode
== ATA_MODE_PIO32
) {
3109 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
3112 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
3121 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
3123 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
3124 jcxz ata_packet_no_before
3126 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3127 cmp ah
, #ATA_MODE_PIO32
3128 je ata_packet_in_before_32
3130 ata_packet_in_before_16
:
3132 loop ata_packet_in_before_16
3133 jmp ata_packet_no_before
3135 ata_packet_in_before_32
:
3137 ata_packet_in_before_32_loop
:
3139 loop ata_packet_in_before_32_loop
3142 ata_packet_no_before
:
3143 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3144 jcxz ata_packet_after
3146 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3147 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3150 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3151 cmp ah
, #ATA_MODE_PIO32
3156 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3157 jmp ata_packet_after
3161 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3164 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3165 jcxz ata_packet_done
3167 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3168 cmp ah
, #ATA_MODE_PIO32
3169 je ata_packet_in_after_32
3171 ata_packet_in_after_16
:
3173 loop ata_packet_in_after_16
3176 ata_packet_in_after_32
:
3178 ata_packet_in_after_32_loop
:
3180 loop ata_packet_in_after_32_loop
3187 // Compute new buffer address
3190 // Save transferred bytes count
3192 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3196 // Final check, device must be ready
3197 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3198 != ATA_CB_STAT_RDY
) {
3199 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3203 // Enable interrupts
3204 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3208 // ---------------------------------------------------------------------------
3209 // End of ATA/ATAPI Driver
3210 // ---------------------------------------------------------------------------
3212 // ---------------------------------------------------------------------------
3213 // Start of ATA/ATAPI generic functions
3214 // ---------------------------------------------------------------------------
3217 atapi_get_sense(device
, seg
, asc
, ascq
)
3224 memsetb(get_SS(),atacmd
,0,12);
3227 atacmd
[0]=ATA_CMD_REQUEST_SENSE
;
3228 atacmd
[4]=sizeof(buffer
);
3229 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 18L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3232 write_byte(seg
,asc
,buffer
[12]);
3233 write_byte(seg
,ascq
,buffer
[13]);
3239 atapi_is_ready(device
)
3246 Bit32u timeout
; //measured in ms
3250 Bit16u ebda_seg
= read_word(0x0040,0x000E);
3251 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
) {
3252 printf("not implemented for non-ATAPI device\n");
3256 BX_DEBUG_ATA("ata_detect_medium: begin\n");
3257 memsetb(get_SS(),packet
, 0, sizeof packet
);
3258 packet
[0] = 0x25; /* READ CAPACITY */
3260 /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
3261 * is reported by the device. If the device reports "IN PROGRESS",
3262 * 30 seconds is added. */
3266 while (time
< timeout
) {
3267 if (ata_cmd_packet(device
, sizeof(packet
), get_SS(), packet
, 0, 8L, ATA_DATA_IN
, get_SS(), buf
) == 0)
3270 if (atapi_get_sense(device
, get_SS(), &asc
, &ascq
) == 0) {
3271 if (asc
== 0x3a) { /* MEDIUM NOT PRESENT */
3272 BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
3276 if (asc
== 0x04 && ascq
== 0x01 && !in_progress
) {
3277 /* IN PROGRESS OF BECOMING READY */
3278 printf("Waiting for device to detect medium... ");
3279 /* Allow 30 seconds more */
3286 BX_DEBUG_ATA("read capacity failed\n");
3290 block_len
= (Bit32u
) buf
[4] << 24
3291 | (Bit32u
) buf
[5] << 16
3292 | (Bit32u
) buf
[6] << 8
3293 | (Bit32u
) buf
[7] << 0;
3294 BX_DEBUG_ATA("block_len=%u\n", block_len
);
3296 if (block_len
!= 2048 && block_len
!= 512)
3298 printf("Unsupported sector size %u\n", block_len
);
3301 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, block_len
);
3303 sectors
= (Bit32u
) buf
[0] << 24
3304 | (Bit32u
) buf
[1] << 16
3305 | (Bit32u
) buf
[2] << 8
3306 | (Bit32u
) buf
[3] << 0;
3308 BX_DEBUG_ATA("sectors=%u\n", sectors
);
3309 if (block_len
== 2048)
3310 sectors
<<= 2; /* # of sectors in 512-byte "soft" sector */
3311 if (sectors
!= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
))
3312 printf("%dMB medium detected\n", sectors
>>(20-9));
3313 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
3318 atapi_is_cdrom(device
)
3321 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3323 if (device
>= BX_MAX_ATA_DEVICES
)
3326 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3329 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3335 // ---------------------------------------------------------------------------
3336 // End of ATA/ATAPI generic functions
3337 // ---------------------------------------------------------------------------
3339 #endif // BX_USE_ATADRV
3341 #if BX_ELTORITO_BOOT
3343 // ---------------------------------------------------------------------------
3344 // Start of El-Torito boot functions
3345 // ---------------------------------------------------------------------------
3350 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3352 // the only important data is this one for now
3353 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3359 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3361 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3365 cdemu_emulated_drive()
3367 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3369 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3372 static char isotag
[6]="CD001";
3373 static char eltorito
[24]="EL TORITO SPECIFICATION";
3375 // Returns ah: emulated drive, al: error code
3380 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3381 Bit8u atacmd
[12], buffer
[2048];
3383 Bit16u boot_segment
, nbsectors
, i
, error
;
3386 // Find out the first cdrom
3387 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3388 if (atapi_is_cdrom(device
)) break;
3391 if(error
= atapi_is_ready(device
) != 0)
3392 BX_INFO("ata_is_ready returned %d\n",error
);
3395 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3397 // Read the Boot Record Volume Descriptor
3398 memsetb(get_SS(),atacmd
,0,12);
3399 atacmd
[0]=0x28; // READ command
3400 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3401 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3402 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3403 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3404 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3405 atacmd
[5]=(0x11 & 0x000000ff);
3406 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3410 if(buffer
[0]!=0)return 4;
3412 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3415 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3417 // ok, now we calculate the Boot catalog address
3418 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3420 // And we read the Boot Catalog
3421 memsetb(get_SS(),atacmd
,0,12);
3422 atacmd
[0]=0x28; // READ command
3423 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3424 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3425 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3426 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3427 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3428 atacmd
[5]=(lba
& 0x000000ff);
3429 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3433 if(buffer
[0x00]!=0x01)return 8; // Header
3434 if(buffer
[0x01]!=0x00)return 9; // Platform
3435 if(buffer
[0x1E]!=0x55)return 10; // key 1
3436 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3438 // Initial/Default Entry
3439 if(buffer
[0x20]!=0x88)return 11; // Bootable
3441 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3442 if(buffer
[0x21]==0){
3443 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3444 // Win2000 cd boot needs to know it booted from cd
3445 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3447 else if(buffer
[0x21]<4)
3448 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3450 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3452 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3453 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3455 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3456 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3458 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3459 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3461 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3462 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3464 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3465 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3467 // And we read the image in memory
3468 memsetb(get_SS(),atacmd
,0,12);
3469 atacmd
[0]=0x28; // READ command
3470 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3471 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3472 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3473 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3474 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3475 atacmd
[5]=(lba
& 0x000000ff);
3476 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3479 // Remember the media type
3480 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3481 case 0x01: // 1.2M floppy
3482 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3483 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3484 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3486 case 0x02: // 1.44M floppy
3487 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3488 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3489 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3491 case 0x03: // 2.88M floppy
3492 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3493 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3494 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3496 case 0x04: // Harddrive
3497 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3498 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3499 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3500 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3504 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3505 // Increase bios installed hardware number of devices
3506 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3507 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3509 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3513 // everything is ok, so from now on, the emulation is active
3514 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3515 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3517 // return the boot drive + no error
3518 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3521 // ---------------------------------------------------------------------------
3522 // End of El-Torito boot functions
3523 // ---------------------------------------------------------------------------
3524 #endif // BX_ELTORITO_BOOT
3527 int14_function(regs
, ds
, iret_addr
)
3528 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3529 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3530 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3532 Bit16u addr
,timer
,val16
;
3539 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3540 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3541 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3542 switch (regs
.u
.r8
.ah
) {
3544 outb(addr
+3, inb(addr
+3) | 0x80);
3545 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3549 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3550 outb(addr
, val16
& 0xFF);
3551 outb(addr
+1, val16
>> 8);
3553 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3554 regs
.u
.r8
.ah
= inb(addr
+5);
3555 regs
.u
.r8
.al
= inb(addr
+6);
3556 ClearCF(iret_addr
.flags
);
3559 timer
= read_word(0x0040, 0x006C);
3560 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3561 val16
= read_word(0x0040, 0x006C);
3562 if (val16
!= timer
) {
3567 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3568 regs
.u
.r8
.ah
= inb(addr
+5);
3569 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3570 ClearCF(iret_addr
.flags
);
3573 timer
= read_word(0x0040, 0x006C);
3574 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3575 val16
= read_word(0x0040, 0x006C);
3576 if (val16
!= timer
) {
3583 regs
.u
.r8
.al
= inb(addr
);
3585 regs
.u
.r8
.ah
= inb(addr
+5);
3587 ClearCF(iret_addr
.flags
);
3590 regs
.u
.r8
.ah
= inb(addr
+5);
3591 regs
.u
.r8
.al
= inb(addr
+6);
3592 ClearCF(iret_addr
.flags
);
3595 SetCF(iret_addr
.flags
); // Unsupported
3598 SetCF(iret_addr
.flags
); // Unsupported
3603 int15_function(regs
, ES
, DS
, FLAGS
)
3604 pusha_regs_t regs
; // REGS pushed via pusha
3605 Bit16u ES
, DS
, FLAGS
;
3607 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3608 bx_bool prev_a20_enable
;
3617 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3619 switch (regs
.u
.r8
.ah
) {
3620 case 0x24: /* A20 Control */
3621 switch (regs
.u
.r8
.al
) {
3633 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3643 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3645 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3651 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3655 /* keyboard intercept */
3657 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3664 case 0x52: // removable media eject
3666 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3670 if( regs
.u
.r8
.al
== 0 ) {
3671 // Set Interval requested.
3672 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3673 // Interval not already set.
3674 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3675 write_word( 0x40, 0x98, ES
); // Byte location, segment
3676 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3677 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3678 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3680 irqDisable
= inb( 0xA1 );
3681 outb( 0xA1, irqDisable
& 0xFE );
3682 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3683 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3685 // Interval already set.
3686 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3688 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3690 } else if( regs
.u
.r8
.al
== 1 ) {
3691 // Clear Interval requested
3692 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3694 bRegister
= inb_cmos( 0xB );
3695 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3697 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3699 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3708 # error "Int15 function 87h not supported on < 80386"
3710 // +++ should probably have descriptor checks
3711 // +++ should have exception handlers
3713 // turn off interrupts
3718 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3720 // 128K max of transfer on 386+ ???
3721 // source == destination ???
3723 // ES:SI points to descriptor table
3724 // offset use initially comments
3725 // ==============================================
3726 // 00..07 Unused zeros Null descriptor
3727 // 08..0f GDT zeros filled in by BIOS
3728 // 10..17 source ssssssss source of data
3729 // 18..1f dest dddddddd destination of data
3730 // 20..27 CS zeros filled in by BIOS
3731 // 28..2f SS zeros filled in by BIOS
3738 // check for access rights of source & dest here
3740 // Initialize GDT descriptor
3741 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3742 base23_16
= ES
>> 12;
3743 if (base15_00
< (ES
<<4))
3745 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3746 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3747 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3748 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3749 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3751 // Initialize CS descriptor
3752 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3753 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3754 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3755 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3756 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3758 // Initialize SS descriptor
3760 base15_00
= ss
<< 4;
3761 base23_16
= ss
>> 12;
3762 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3763 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3764 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3765 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3766 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3770 // Compile generates locals offset info relative to SP.
3771 // Get CX (word count) from stack.
3774 mov cx
, _int15_function
.CX
[bx
]
3776 // since we need to set SS:SP, save them to the BDA
3777 // for future restore
3787 lidt
[pmode_IDT_info
]
3788 ;; perhaps
do something with IDT here
3790 ;; set PE bit in CR0
3794 ;; far jump to flush CPU queue after transition to
protected mode
3795 JMP_AP(0x0020, protected_mode
)
3798 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3799 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3801 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3803 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3809 movsw
;; move CX words from DS
:SI to ES
:DI
3811 ;; make sure DS
and ES limits are
64KB
3816 ;; reset PG bit in CR0
???
3821 ;; far jump to flush CPU queue after transition to real mode
3822 JMP_AP(0xf000, real_mode
)
3825 ;; restore IDT to normal real
-mode defaults
3827 lidt
[rmode_IDT_info
]
3829 // restore SS:SP from the BDA
3837 set_enable_a20(prev_a20_enable
);
3839 // turn back on interrupts
3850 // Get the amount of extended memory (above 1M)
3852 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3855 regs
.u
.r8
.al
= inb_cmos(0x30);
3856 regs
.u
.r8
.ah
= inb_cmos(0x31);
3858 // According to Ralf Brown's interrupt the limit should be 15M,
3859 // but real machines mostly return max. 63M.
3860 if(regs
.u
.r16
.ax
> 0xffc0)
3861 regs
.u
.r16
.ax
= 0xffc0;
3868 /* Device busy interrupt. Called by Int 16h when no key available */
3872 /* Interrupt complete. Called by Int 16h when key becomes available */
3876 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3878 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3884 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3889 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3899 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3901 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3905 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3906 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3908 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3913 #if BX_USE_PS2_MOUSE
3915 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3916 pusha_regs_t regs
; // REGS pushed via pusha
3917 Bit16u ES
, DS
, FLAGS
;
3919 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3920 Bit8u mouse_flags_1
, mouse_flags_2
;
3921 Bit16u mouse_driver_seg
;
3922 Bit16u mouse_driver_offset
;
3923 Bit8u comm_byte
, prev_command_byte
;
3924 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3926 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3928 switch (regs
.u
.r8
.ah
) {
3930 // Return Codes status in AH
3931 // =========================
3933 // 01: invalid subfunction (AL > 7)
3934 // 02: invalid input value (out of allowable range)
3935 // 03: interface error
3936 // 04: resend command received from mouse controller,
3937 // device driver should attempt command again
3938 // 05: cannot enable mouse, since no far call has been installed
3939 // 80/86: mouse service not implemented
3941 switch (regs
.u
.r8
.al
) {
3942 case 0: // Disable/Enable Mouse
3943 BX_DEBUG_INT15("case 0:\n");
3944 switch (regs
.u
.r8
.bh
) {
3945 case 0: // Disable Mouse
3946 BX_DEBUG_INT15("case 0: disable mouse\n");
3947 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3948 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3950 ret
= get_mouse_data(&mouse_data1
);
3951 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3964 case 1: // Enable Mouse
3965 BX_DEBUG_INT15("case 1: enable mouse\n");
3966 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3967 if ( (mouse_flags_2
& 0x80) == 0 ) {
3968 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3970 regs
.u
.r8
.ah
= 5; // no far call installed
3973 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3974 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3976 ret
= get_mouse_data(&mouse_data1
);
3977 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3978 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3988 default: // invalid subfunction
3989 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3991 regs
.u
.r8
.ah
= 1; // invalid subfunction
3996 case 1: // Reset Mouse
3997 case 5: // Initialize Mouse
3998 BX_DEBUG_INT15("case 1 or 5:\n");
3999 if (regs
.u
.r8
.al
== 5) {
4000 if (regs
.u
.r8
.bh
!= 3) {
4002 regs
.u
.r8
.ah
= 0x02; // invalid input
4005 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4006 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
4007 mouse_flags_1
= 0x00;
4008 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4009 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4012 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4013 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
4015 ret
= get_mouse_data(&mouse_data3
);
4016 // if no mouse attached, it will return RESEND
4017 if (mouse_data3
== 0xfe) {
4021 if (mouse_data3
!= 0xfa)
4022 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
4024 ret
= get_mouse_data(&mouse_data1
);
4026 ret
= get_mouse_data(&mouse_data2
);
4028 // turn IRQ12 and packet generation on
4029 enable_mouse_int_and_events();
4032 regs
.u
.r8
.bl
= mouse_data1
;
4033 regs
.u
.r8
.bh
= mouse_data2
;
4045 case 2: // Set Sample Rate
4046 BX_DEBUG_INT15("case 2:\n");
4047 switch (regs
.u
.r8
.bh
) {
4048 case 0: mouse_data1
= 10; break; // 10 reports/sec
4049 case 1: mouse_data1
= 20; break; // 20 reports/sec
4050 case 2: mouse_data1
= 40; break; // 40 reports/sec
4051 case 3: mouse_data1
= 60; break; // 60 reports/sec
4052 case 4: mouse_data1
= 80; break; // 80 reports/sec
4053 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
4054 case 6: mouse_data1
= 200; break; // 200 reports/sec
4055 default: mouse_data1
= 0;
4057 if (mouse_data1
> 0) {
4058 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
4060 ret
= get_mouse_data(&mouse_data2
);
4061 ret
= send_to_mouse_ctrl(mouse_data1
);
4062 ret
= get_mouse_data(&mouse_data2
);
4068 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4073 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4077 case 3: // Set Resolution
4078 BX_DEBUG_INT15("case 3:\n");
4080 // 0 = 25 dpi, 1 count per millimeter
4081 // 1 = 50 dpi, 2 counts per millimeter
4082 // 2 = 100 dpi, 4 counts per millimeter
4083 // 3 = 200 dpi, 8 counts per millimeter
4084 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4085 if (regs
.u
.r8
.bh
< 4) {
4086 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
4088 ret
= get_mouse_data(&mouse_data1
);
4089 if (mouse_data1
!= 0xfa)
4090 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4091 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
4092 ret
= get_mouse_data(&mouse_data1
);
4093 if (mouse_data1
!= 0xfa)
4094 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4100 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4105 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4107 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4110 case 4: // Get Device ID
4111 BX_DEBUG_INT15("case 4:\n");
4112 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4113 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
4115 ret
= get_mouse_data(&mouse_data1
);
4116 ret
= get_mouse_data(&mouse_data2
);
4119 regs
.u
.r8
.bh
= mouse_data2
;
4123 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4127 case 6: // Return Status & Set Scaling Factor...
4128 BX_DEBUG_INT15("case 6:\n");
4129 switch (regs
.u
.r8
.bh
) {
4130 case 0: // Return Status
4131 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4132 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4134 ret
= get_mouse_data(&mouse_data1
);
4135 if (mouse_data1
!= 0xfa)
4136 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4138 ret
= get_mouse_data(&mouse_data1
);
4140 ret
= get_mouse_data(&mouse_data2
);
4142 ret
= get_mouse_data(&mouse_data3
);
4146 regs
.u
.r8
.bl
= mouse_data1
;
4147 regs
.u
.r8
.cl
= mouse_data2
;
4148 regs
.u
.r8
.dl
= mouse_data3
;
4149 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4160 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4163 case 1: // Set Scaling Factor to 1:1
4164 case 2: // Set Scaling Factor to 2:1
4165 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4166 if (regs
.u
.r8
.bh
== 1) {
4167 ret
= send_to_mouse_ctrl(0xE6);
4169 ret
= send_to_mouse_ctrl(0xE7);
4172 get_mouse_data(&mouse_data1
);
4173 ret
= (mouse_data1
!= 0xFA);
4181 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4183 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4187 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4191 case 7: // Set Mouse Handler Address
4192 BX_DEBUG_INT15("case 7:\n");
4193 mouse_driver_seg
= ES
;
4194 mouse_driver_offset
= regs
.u
.r16
.bx
;
4195 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4196 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4197 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4198 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4199 /* remove handler */
4200 if ( (mouse_flags_2
& 0x80) != 0 ) {
4201 mouse_flags_2
&= ~0x80;
4202 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4206 /* install handler */
4207 mouse_flags_2
|= 0x80;
4209 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4215 BX_DEBUG_INT15("case default:\n");
4216 regs
.u
.r8
.ah
= 1; // invalid function
4222 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4223 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4225 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4232 void set_e820_range(ES
, DI
, start
, end
, type
)
4239 write_word(ES
, DI
, start
);
4240 write_word(ES
, DI
+2, start
>> 16);
4241 write_word(ES
, DI
+4, 0x00);
4242 write_word(ES
, DI
+6, 0x00);
4245 write_word(ES
, DI
+8, end
);
4246 write_word(ES
, DI
+10, end
>> 16);
4247 write_word(ES
, DI
+12, 0x0000);
4248 write_word(ES
, DI
+14, 0x0000);
4250 write_word(ES
, DI
+16, type
);
4251 write_word(ES
, DI
+18, 0x0);
4255 int15_function32(regs
, ES
, DS
, FLAGS
)
4256 pushad_regs_t regs
; // REGS pushed via pushad
4257 Bit16u ES
, DS
, FLAGS
;
4259 Bit32u extended_memory_size
=0; // 64bits long
4262 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4264 switch (regs
.u
.r8
.ah
) {
4266 // Wait for CX:DX microseconds. currently using the
4267 // refresh request port 0x61 bit4, toggling every 15usec
4275 ;; Get the count in eax
4278 mov ax
, _int15_function32
.CX
[bx
]
4281 mov ax
, _int15_function32
.DX
[bx
]
4283 ;; convert to numbers of
15usec ticks
4289 ;; wait
for ecx number of refresh requests
4310 switch(regs
.u
.r8
.al
)
4312 case 0x20: // coded by osmaker aka K.J.
4313 if(regs
.u
.r32
.edx
== 0x534D4150)
4315 extended_memory_size
= inb_cmos(0x35);
4316 extended_memory_size
<<= 8;
4317 extended_memory_size
|= inb_cmos(0x34);
4318 extended_memory_size
*= 64;
4319 // greater than EFF00000???
4320 if(extended_memory_size
> 0x3bc000) {
4321 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4323 extended_memory_size
*= 1024;
4324 extended_memory_size
+= (16L * 1024 * 1024);
4326 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4327 extended_memory_size
= inb_cmos(0x31);
4328 extended_memory_size
<<= 8;
4329 extended_memory_size
|= inb_cmos(0x30);
4330 extended_memory_size
*= 1024;
4333 switch(regs
.u
.r16
.bx
)
4336 set_e820_range(ES
, regs
.u
.r16
.di
,
4337 0x0000000L
, 0x0009fc00L
, 1);
4339 regs
.u
.r32
.eax
= 0x534D4150;
4340 regs
.u
.r32
.ecx
= 0x14;
4345 set_e820_range(ES
, regs
.u
.r16
.di
,
4346 0x0009fc00L
, 0x000a0000L
, 2);
4348 regs
.u
.r32
.eax
= 0x534D4150;
4349 regs
.u
.r32
.ecx
= 0x14;
4354 set_e820_range(ES
, regs
.u
.r16
.di
,
4355 0x000e8000L
, 0x00100000L
, 2);
4357 regs
.u
.r32
.eax
= 0x534D4150;
4358 regs
.u
.r32
.ecx
= 0x14;
4363 set_e820_range(ES
, regs
.u
.r16
.di
,
4365 extended_memory_size
- ACPI_DATA_SIZE
, 1);
4367 regs
.u
.r32
.eax
= 0x534D4150;
4368 regs
.u
.r32
.ecx
= 0x14;
4373 set_e820_range(ES
, regs
.u
.r16
.di
,
4374 extended_memory_size
- ACPI_DATA_SIZE
,
4375 extended_memory_size
, 3); // ACPI RAM
4377 regs
.u
.r32
.eax
= 0x534D4150;
4378 regs
.u
.r32
.ecx
= 0x14;
4383 /* 256KB BIOS area at the end of 4 GB */
4384 set_e820_range(ES
, regs
.u
.r16
.di
,
4385 0xfffc0000L
, 0x00000000L
, 2);
4387 regs
.u
.r32
.eax
= 0x534D4150;
4388 regs
.u
.r32
.ecx
= 0x14;
4391 default: /* AX=E820, DX=534D4150, BX unrecognized */
4392 goto int15_unimplemented
;
4396 // if DX != 0x534D4150)
4397 goto int15_unimplemented
;
4402 // do we have any reason to fail here ?
4405 // my real system sets ax and bx to 0
4406 // this is confirmed by Ralph Brown list
4407 // but syslinux v1.48 is known to behave
4408 // strangely if ax is set to 0
4409 // regs.u.r16.ax = 0;
4410 // regs.u.r16.bx = 0;
4412 // Get the amount of extended memory (above 1M)
4413 regs
.u
.r8
.cl
= inb_cmos(0x30);
4414 regs
.u
.r8
.ch
= inb_cmos(0x31);
4417 if(regs
.u
.r16
.cx
> 0x3c00)
4419 regs
.u
.r16
.cx
= 0x3c00;
4422 // Get the amount of extended memory above 16M in 64k blocs
4423 regs
.u
.r8
.dl
= inb_cmos(0x34);
4424 regs
.u
.r8
.dh
= inb_cmos(0x35);
4426 // Set configured memory equal to extended memory
4427 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4428 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4430 default: /* AH=0xE8?? but not implemented */
4431 goto int15_unimplemented
;
4434 int15_unimplemented
:
4435 // fall into the default
4437 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4438 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4440 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4446 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4447 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4449 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4450 Bit16u kbd_code
, max
;
4452 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4454 shift_flags
= read_byte(0x0040, 0x17);
4455 led_flags
= read_byte(0x0040, 0x97);
4456 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4461 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4462 if ((inb(0x60) == 0xfa)) {
4464 led_flags
|= ((shift_flags
>> 4) & 0x07);
4465 outb(0x60, led_flags
& 0x07);
4466 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4468 write_byte(0x0040, 0x97, led_flags
);
4476 case 0x00: /* read keyboard input */
4478 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4479 BX_PANIC("KBD: int16h: out of keyboard input\n");
4481 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4482 else if (ascii_code
== 0xE0) ascii_code
= 0;
4483 AX
= (scan_code
<< 8) | ascii_code
;
4486 case 0x01: /* check keyboard status */
4487 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4491 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4492 else if (ascii_code
== 0xE0) ascii_code
= 0;
4493 AX
= (scan_code
<< 8) | ascii_code
;
4497 case 0x02: /* get shift flag status */
4498 shift_flags
= read_byte(0x0040, 0x17);
4499 SET_AL(shift_flags
);
4502 case 0x05: /* store key-stroke into buffer */
4503 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4511 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4512 // bit Bochs Description
4514 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4515 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4516 // 4 1 INT 16/AH=0Ah supported
4517 // 3 0 INT 16/AX=0306h supported
4518 // 2 0 INT 16/AX=0305h supported
4519 // 1 0 INT 16/AX=0304h supported
4520 // 0 0 INT 16/AX=0300h supported
4525 case 0x0A: /* GET KEYBOARD ID */
4531 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4533 if ((inb(0x60) == 0xfa)) {
4536 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4539 kbd_code
|= (inb(0x60) << 8);
4541 } while (--count
>0);
4547 case 0x10: /* read MF-II keyboard input */
4549 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4550 BX_PANIC("KBD: int16h: out of keyboard input\n");
4552 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4553 AX
= (scan_code
<< 8) | ascii_code
;
4556 case 0x11: /* check MF-II keyboard status */
4557 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4561 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4562 AX
= (scan_code
<< 8) | ascii_code
;
4566 case 0x12: /* get extended keyboard status */
4567 shift_flags
= read_byte(0x0040, 0x17);
4568 SET_AL(shift_flags
);
4569 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4570 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4571 SET_AH(shift_flags
);
4572 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4575 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4576 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4579 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4580 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4584 if (GET_AL() == 0x08)
4585 SET_AH(0x02); // unsupported, aka normal keyboard
4588 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4593 dequeue_key(scan_code
, ascii_code
, incr
)
4598 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4603 buffer_start
= 0x001E;
4604 buffer_end
= 0x003E;
4606 buffer_start
= read_word(0x0040, 0x0080);
4607 buffer_end
= read_word(0x0040, 0x0082);
4610 buffer_head
= read_word(0x0040, 0x001a);
4611 buffer_tail
= read_word(0x0040, 0x001c);
4613 if (buffer_head
!= buffer_tail
) {
4615 acode
= read_byte(0x0040, buffer_head
);
4616 scode
= read_byte(0x0040, buffer_head
+1);
4617 write_byte(ss
, ascii_code
, acode
);
4618 write_byte(ss
, scan_code
, scode
);
4622 if (buffer_head
>= buffer_end
)
4623 buffer_head
= buffer_start
;
4624 write_word(0x0040, 0x001a, buffer_head
);
4633 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4636 inhibit_mouse_int_and_events()
4638 Bit8u command_byte
, prev_command_byte
;
4640 // Turn off IRQ generation and aux data line
4641 if ( inb(0x64) & 0x02 )
4642 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4643 outb(0x64, 0x20); // get command byte
4644 while ( (inb(0x64) & 0x01) != 0x01 );
4645 prev_command_byte
= inb(0x60);
4646 command_byte
= prev_command_byte
;
4647 //while ( (inb(0x64) & 0x02) );
4648 if ( inb(0x64) & 0x02 )
4649 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4650 command_byte
&= 0xfd; // turn off IRQ 12 generation
4651 command_byte
|= 0x20; // disable mouse serial clock line
4652 outb(0x64, 0x60); // write command byte
4653 outb(0x60, command_byte
);
4654 return(prev_command_byte
);
4658 enable_mouse_int_and_events()
4662 // Turn on IRQ generation and aux data line
4663 if ( inb(0x64) & 0x02 )
4664 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4665 outb(0x64, 0x20); // get command byte
4666 while ( (inb(0x64) & 0x01) != 0x01 );
4667 command_byte
= inb(0x60);
4668 //while ( (inb(0x64) & 0x02) );
4669 if ( inb(0x64) & 0x02 )
4670 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4671 command_byte
|= 0x02; // turn on IRQ 12 generation
4672 command_byte
&= 0xdf; // enable mouse serial clock line
4673 outb(0x64, 0x60); // write command byte
4674 outb(0x60, command_byte
);
4678 send_to_mouse_ctrl(sendbyte
)
4683 // wait for chance to write to ctrl
4684 if ( inb(0x64) & 0x02 )
4685 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4687 outb(0x60, sendbyte
);
4693 get_mouse_data(data
)
4699 while ( (inb(0x64) & 0x21) != 0x21 ) {
4702 response
= inb(0x60);
4705 write_byte(ss
, data
, response
);
4710 set_kbd_command_byte(command_byte
)
4713 if ( inb(0x64) & 0x02 )
4714 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4717 outb(0x64, 0x60); // write command byte
4718 outb(0x60, command_byte
);
4722 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4723 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4725 Bit8u scancode
, asciicode
, shift_flags
;
4726 Bit8u mf2_flags
, mf2_state
;
4729 // DS has been set to F000 before call
4733 scancode
= GET_AL();
4735 if (scancode
== 0) {
4736 BX_INFO("KBD: int09 handler: AL=0\n");
4741 shift_flags
= read_byte(0x0040, 0x17);
4742 mf2_flags
= read_byte(0x0040, 0x18);
4743 mf2_state
= read_byte(0x0040, 0x96);
4747 case 0x3a: /* Caps Lock press */
4748 shift_flags
^= 0x40;
4749 write_byte(0x0040, 0x17, shift_flags
);
4751 write_byte(0x0040, 0x18, mf2_flags
);
4753 case 0xba: /* Caps Lock release */
4755 write_byte(0x0040, 0x18, mf2_flags
);
4758 case 0x2a: /* L Shift press */
4759 shift_flags
|= 0x02;
4760 write_byte(0x0040, 0x17, shift_flags
);
4762 case 0xaa: /* L Shift release */
4763 shift_flags
&= ~0x02;
4764 write_byte(0x0040, 0x17, shift_flags
);
4767 case 0x36: /* R Shift press */
4768 shift_flags
|= 0x01;
4769 write_byte(0x0040, 0x17, shift_flags
);
4771 case 0xb6: /* R Shift release */
4772 shift_flags
&= ~0x01;
4773 write_byte(0x0040, 0x17, shift_flags
);
4776 case 0x1d: /* Ctrl press */
4777 if ((mf2_state
& 0x01) == 0) {
4778 shift_flags
|= 0x04;
4779 write_byte(0x0040, 0x17, shift_flags
);
4780 if (mf2_state
& 0x02) {
4782 write_byte(0x0040, 0x96, mf2_state
);
4785 write_byte(0x0040, 0x18, mf2_flags
);
4789 case 0x9d: /* Ctrl release */
4790 if ((mf2_state
& 0x01) == 0) {
4791 shift_flags
&= ~0x04;
4792 write_byte(0x0040, 0x17, shift_flags
);
4793 if (mf2_state
& 0x02) {
4795 write_byte(0x0040, 0x96, mf2_state
);
4798 write_byte(0x0040, 0x18, mf2_flags
);
4803 case 0x38: /* Alt press */
4804 shift_flags
|= 0x08;
4805 write_byte(0x0040, 0x17, shift_flags
);
4806 if (mf2_state
& 0x02) {
4808 write_byte(0x0040, 0x96, mf2_state
);
4811 write_byte(0x0040, 0x18, mf2_flags
);
4814 case 0xb8: /* Alt release */
4815 shift_flags
&= ~0x08;
4816 write_byte(0x0040, 0x17, shift_flags
);
4817 if (mf2_state
& 0x02) {
4819 write_byte(0x0040, 0x96, mf2_state
);
4822 write_byte(0x0040, 0x18, mf2_flags
);
4826 case 0x45: /* Num Lock press */
4827 if ((mf2_state
& 0x03) == 0) {
4829 write_byte(0x0040, 0x18, mf2_flags
);
4830 shift_flags
^= 0x20;
4831 write_byte(0x0040, 0x17, shift_flags
);
4834 case 0xc5: /* Num Lock release */
4835 if ((mf2_state
& 0x03) == 0) {
4837 write_byte(0x0040, 0x18, mf2_flags
);
4841 case 0x46: /* Scroll Lock press */
4843 write_byte(0x0040, 0x18, mf2_flags
);
4844 shift_flags
^= 0x10;
4845 write_byte(0x0040, 0x17, shift_flags
);
4848 case 0xc6: /* Scroll Lock release */
4850 write_byte(0x0040, 0x18, mf2_flags
);
4854 if (scancode
& 0x80) {
4855 break; /* toss key releases ... */
4857 if (scancode
> MAX_SCAN_CODE
) {
4858 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4861 if (shift_flags
& 0x08) { /* ALT */
4862 asciicode
= scan_to_scanascii
[scancode
].alt
;
4863 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4864 } else if (shift_flags
& 0x04) { /* CONTROL */
4865 asciicode
= scan_to_scanascii
[scancode
].control
;
4866 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4867 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
4868 /* extended keys handling */
4870 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4871 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4872 /* check if lock state should be ignored
4873 * because a SHIFT key are pressed */
4875 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4876 asciicode
= scan_to_scanascii
[scancode
].normal
;
4877 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4879 asciicode
= scan_to_scanascii
[scancode
].shift
;
4880 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4883 /* check if lock is on */
4884 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4885 asciicode
= scan_to_scanascii
[scancode
].shift
;
4886 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4888 asciicode
= scan_to_scanascii
[scancode
].normal
;
4889 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4892 if (scancode
==0 && asciicode
==0) {
4893 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4895 enqueue_key(scancode
, asciicode
);
4898 if ((scancode
& 0x7f) != 0x1d) {
4902 write_byte(0x0040, 0x96, mf2_state
);
4906 enqueue_key(scan_code
, ascii_code
)
4907 Bit8u scan_code
, ascii_code
;
4909 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4912 buffer_start
= 0x001E;
4913 buffer_end
= 0x003E;
4915 buffer_start
= read_word(0x0040, 0x0080);
4916 buffer_end
= read_word(0x0040, 0x0082);
4919 buffer_head
= read_word(0x0040, 0x001A);
4920 buffer_tail
= read_word(0x0040, 0x001C);
4922 temp_tail
= buffer_tail
;
4924 if (buffer_tail
>= buffer_end
)
4925 buffer_tail
= buffer_start
;
4927 if (buffer_tail
== buffer_head
) {
4931 write_byte(0x0040, temp_tail
, ascii_code
);
4932 write_byte(0x0040, temp_tail
+1, scan_code
);
4933 write_word(0x0040, 0x001C, buffer_tail
);
4939 int74_function(make_farcall
, Z
, Y
, X
, status
)
4940 Bit16u make_farcall
, Z
, Y
, X
, status
;
4942 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4943 Bit8u in_byte
, index
, package_count
;
4944 Bit8u mouse_flags_1
, mouse_flags_2
;
4946 BX_DEBUG_INT74("entering int74_function\n");
4949 in_byte
= inb(0x64);
4950 if ( (in_byte
& 0x21) != 0x21 ) {
4953 in_byte
= inb(0x60);
4954 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4956 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4957 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4959 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4963 package_count
= mouse_flags_2
& 0x07;
4964 index
= mouse_flags_1
& 0x07;
4965 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4967 if ( (index
+1) >= package_count
) {
4968 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4969 status
= read_byte(ebda_seg
, 0x0028 + 0);
4970 X
= read_byte(ebda_seg
, 0x0028 + 1);
4971 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4974 // check if far call handler installed
4975 if (mouse_flags_2
& 0x80)
4981 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4984 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4989 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4990 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4993 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4994 Bit16u cylinder
, head
, sector
;
4995 Bit16u segment
, offset
;
4996 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4998 Bit8u device
, status
;
5000 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5002 write_byte(0x0040, 0x008e, 0); // clear completion flag
5004 // basic check : device has to be defined
5005 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
5006 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5010 // Get the ata channel
5011 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
5013 // basic check : device has to be valid
5014 if (device
>= BX_MAX_ATA_DEVICES
) {
5015 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5021 case 0x00: /* disk controller reset */
5026 case 0x01: /* read disk status */
5027 status
= read_byte(0x0040, 0x0074);
5029 SET_DISK_RET_STATUS(0);
5030 /* set CF if error status read */
5031 if (status
) goto int13_fail_nostatus
;
5032 else goto int13_success_noah
;
5035 case 0x02: // read disk sectors
5036 case 0x03: // write disk sectors
5037 case 0x04: // verify disk sectors
5040 cylinder
= GET_CH();
5041 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5042 sector
= (GET_CL() & 0x3f);
5048 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
5049 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5053 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5054 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5055 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5057 // sanity check on cyl heads, sec
5058 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
5059 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
5064 if ( GET_AH() == 0x04 ) goto int13_success
;
5066 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5067 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5069 // if needed, translate lchs to lba, and execute command
5070 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
5071 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
5072 sector
= 0; // this forces the command to be lba
5075 if ( GET_AH() == 0x02 )
5076 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5078 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5080 // Set nb of sector transferred
5081 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
5084 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5086 goto int13_fail_noah
;
5092 case 0x05: /* format disk track */
5093 BX_INFO("format disk track called\n");
5098 case 0x08: /* read disk drive parameters */
5100 // Get logical geometry from table
5101 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5102 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5103 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5104 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5106 nlc
= nlc
- 2; /* 0 based , last sector not used */
5109 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5111 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5113 // FIXME should set ES & DI
5118 case 0x10: /* check drive ready */
5119 // should look at 40:8E also???
5121 // Read the status from controller
5122 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5123 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5128 goto int13_fail_noah
;
5132 case 0x15: /* read disk drive size */
5134 // Get logical geometry from table
5135 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5136 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5137 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5139 // Compute sector count seen by int13
5140 lba
= (Bit32u
)(nlc
- 1) * (Bit32u
)nlh
* (Bit32u
)nlspt
;
5144 SET_AH(3); // hard disk accessible
5145 goto int13_success_noah
;
5148 case 0x41: // IBM/MS installation check
5149 BX
=0xaa55; // install check
5150 SET_AH(0x30); // EDD 3.0
5151 CX
=0x0007; // ext disk access and edd, removable supported
5152 goto int13_success_noah
;
5155 case 0x42: // IBM/MS extended read
5156 case 0x43: // IBM/MS extended write
5157 case 0x44: // IBM/MS verify
5158 case 0x47: // IBM/MS extended seek
5160 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5161 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5162 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5164 // Can't use 64 bits lba
5165 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5167 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5171 // Get 32 bits lba and check
5172 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5173 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
5174 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5178 // If verify or seek
5179 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5182 // Execute the command
5183 if ( GET_AH() == 0x42 )
5184 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5186 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5188 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5189 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5192 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5194 goto int13_fail_noah
;
5200 case 0x45: // IBM/MS lock/unlock drive
5201 case 0x49: // IBM/MS extended media change
5202 goto int13_success
; // Always success for HD
5205 case 0x46: // IBM/MS eject media
5206 SET_AH(0xb2); // Volume Not Removable
5207 goto int13_fail_noah
; // Always fail for HD
5210 case 0x48: // IBM/MS get drive parameters
5211 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5213 // Buffer is too small
5221 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5222 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5223 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5224 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
5225 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5227 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5228 if ((lba
/npspt
)/nph
> 0x3fff)
5230 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x00); // geometry is invalid
5231 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0x3fff);
5235 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5236 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5238 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5239 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5240 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
5241 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
5242 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5247 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5248 Bit16u iobase1
, iobase2
, options
;
5250 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5252 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5253 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5256 channel
= device
/ 2;
5257 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5258 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5259 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5260 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5261 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5263 options
= (translation
==ATA_TRANSLATION_NONE
?0:1)<<3; // chs translation
5264 options
|= (1<<4); // lba translation
5265 options
|= (mode
==ATA_MODE_PIO32
?1:0)<<7;
5266 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0)<<9;
5267 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0)<<9;
5269 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5270 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5271 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5272 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5273 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5274 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5275 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5276 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5277 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5278 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5280 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5282 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x10);
5285 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5286 checksum
= ~checksum
;
5287 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5292 Bit8u channel
, iface
, checksum
, i
;
5295 channel
= device
/ 2;
5296 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5297 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5299 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5300 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5301 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5302 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5303 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5305 if (iface
==ATA_IFACE_ISA
) {
5306 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5307 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5308 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5309 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5314 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5315 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5316 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5317 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5319 if (iface
==ATA_IFACE_ISA
) {
5320 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5321 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5322 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5327 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5328 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5329 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5330 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5333 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5334 checksum
= ~checksum
;
5335 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5341 case 0x4e: // // IBM/MS set hardware configuration
5342 // DMA, prefetch, PIO maximum not supported
5355 case 0x09: /* initialize drive parameters */
5356 case 0x0c: /* seek to specified cylinder */
5357 case 0x0d: /* alternate disk reset */
5358 case 0x11: /* recalibrate */
5359 case 0x14: /* controller internal diagnostic */
5360 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5364 case 0x0a: /* read disk sectors with ECC */
5365 case 0x0b: /* write disk sectors with ECC */
5366 case 0x18: // set media type for format
5367 case 0x50: // IBM/MS send packet command
5369 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5375 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5377 SET_DISK_RET_STATUS(GET_AH());
5378 int13_fail_nostatus
:
5379 SET_CF(); // error occurred
5383 SET_AH(0x00); // no error
5385 SET_DISK_RET_STATUS(0x00);
5386 CLEAR_CF(); // no error
5390 // ---------------------------------------------------------------------------
5391 // Start of int13 for cdrom
5392 // ---------------------------------------------------------------------------
5395 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5396 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5398 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5399 Bit8u device
, status
, locks
;
5402 Bit16u count
, segment
, offset
, i
, size
;
5404 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5406 SET_DISK_RET_STATUS(0x00);
5408 /* basic check : device should be 0xE0+ */
5409 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5410 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5414 // Get the ata channel
5415 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5417 /* basic check : device has to be valid */
5418 if (device
>= BX_MAX_ATA_DEVICES
) {
5419 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5425 // all those functions return SUCCESS
5426 case 0x00: /* disk controller reset */
5427 case 0x09: /* initialize drive parameters */
5428 case 0x0c: /* seek to specified cylinder */
5429 case 0x0d: /* alternate disk reset */
5430 case 0x10: /* check drive ready */
5431 case 0x11: /* recalibrate */
5432 case 0x14: /* controller internal diagnostic */
5433 case 0x16: /* detect disk change */
5437 // all those functions return disk write-protected
5438 case 0x03: /* write disk sectors */
5439 case 0x05: /* format disk track */
5440 case 0x43: // IBM/MS extended write
5442 goto int13_fail_noah
;
5445 case 0x01: /* read disk status */
5446 status
= read_byte(0x0040, 0x0074);
5448 SET_DISK_RET_STATUS(0);
5450 /* set CF if error status read */
5451 if (status
) goto int13_fail_nostatus
;
5452 else goto int13_success_noah
;
5455 case 0x15: /* read disk drive size */
5457 goto int13_fail_noah
;
5460 case 0x41: // IBM/MS installation check
5461 BX
=0xaa55; // install check
5462 SET_AH(0x30); // EDD 2.1
5463 CX
=0x0007; // ext disk access, removable and edd
5464 goto int13_success_noah
;
5467 case 0x42: // IBM/MS extended read
5468 case 0x44: // IBM/MS verify sectors
5469 case 0x47: // IBM/MS extended seek
5471 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5472 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5473 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5475 // Can't use 64 bits lba
5476 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5478 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5483 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5485 // If verify or seek
5486 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5489 memsetb(get_SS(),atacmd
,0,12);
5490 atacmd
[0]=0x28; // READ command
5491 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5492 atacmd
[8]=(count
& 0x00ff); // Sectors
5493 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5494 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5495 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5496 atacmd
[5]=(lba
& 0x000000ff);
5497 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5499 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5500 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5503 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5505 goto int13_fail_noah
;
5511 case 0x45: // IBM/MS lock/unlock drive
5512 if (GET_AL() > 2) goto int13_fail
;
5514 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5518 if (locks
== 0xff) {
5521 goto int13_fail_noah
;
5523 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5527 if (locks
== 0x00) {
5530 goto int13_fail_noah
;
5532 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5533 SET_AL(locks
==0?0:1);
5536 SET_AL(locks
==0?0:1);
5542 case 0x46: // IBM/MS eject media
5543 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5546 SET_AH(0xb1); // media locked
5547 goto int13_fail_noah
;
5549 // FIXME should handle 0x31 no media in device
5550 // FIXME should handle 0xb5 valid request failed
5552 // Call removable media eject
5559 mov _int13_cdrom
.status
+ 2[bp
], ah
5560 jnc int13_cdrom_rme_end
5561 mov _int13_cdrom
.status
, #1
5562 int13_cdrom_rme_end
:
5567 SET_AH(0xb1); // media locked
5568 goto int13_fail_noah
;
5574 case 0x48: // IBM/MS get drive parameters
5575 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5577 // Buffer is too small
5583 Bit16u cylinders
, heads
, spt
, blksize
;
5585 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5587 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5588 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5589 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5590 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5591 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5592 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5593 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5594 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5599 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5600 Bit16u iobase1
, iobase2
, options
;
5602 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5604 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5605 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5608 channel
= device
/ 2;
5609 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5610 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5611 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5612 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5614 // FIXME atapi device
5615 options
= (1<<4); // lba translation
5616 options
|= (1<<5); // removable device
5617 options
|= (1<<6); // atapi device
5618 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5620 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5621 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5622 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5623 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5624 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5625 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5626 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5627 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5628 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5629 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5630 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5633 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5634 checksum
= ~checksum
;
5635 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5640 Bit8u channel
, iface
, checksum
, i
;
5643 channel
= device
/ 2;
5644 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5645 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5647 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5648 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5649 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5650 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5651 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5653 if (iface
==ATA_IFACE_ISA
) {
5654 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5655 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5656 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5657 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5662 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5663 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5664 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5665 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5667 if (iface
==ATA_IFACE_ISA
) {
5668 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5669 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5670 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5675 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5676 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5677 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5678 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5681 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5682 checksum
= ~checksum
;
5683 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5689 case 0x49: // IBM/MS extended media change
5690 // always send changed ??
5692 goto int13_fail_nostatus
;
5695 case 0x4e: // // IBM/MS set hardware configuration
5696 // DMA, prefetch, PIO maximum not supported
5709 // all those functions return unimplemented
5710 case 0x02: /* read sectors */
5711 case 0x04: /* verify sectors */
5712 case 0x08: /* read disk drive parameters */
5713 case 0x0a: /* read disk sectors with ECC */
5714 case 0x0b: /* write disk sectors with ECC */
5715 case 0x18: /* set media type for format */
5716 case 0x50: // ? - send packet command
5718 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5724 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5726 SET_DISK_RET_STATUS(GET_AH());
5727 int13_fail_nostatus
:
5728 SET_CF(); // error occurred
5732 SET_AH(0x00); // no error
5734 SET_DISK_RET_STATUS(0x00);
5735 CLEAR_CF(); // no error
5739 // ---------------------------------------------------------------------------
5740 // End of int13 for cdrom
5741 // ---------------------------------------------------------------------------
5743 #if BX_ELTORITO_BOOT
5744 // ---------------------------------------------------------------------------
5745 // Start of int13 for eltorito functions
5746 // ---------------------------------------------------------------------------
5749 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5750 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5752 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5754 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5755 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5759 // FIXME ElTorito Various. Should be implemented
5760 case 0x4a: // ElTorito - Initiate disk emu
5761 case 0x4c: // ElTorito - Initiate disk emu and boot
5762 case 0x4d: // ElTorito - Return Boot catalog
5763 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5767 case 0x4b: // ElTorito - Terminate disk emu
5768 // FIXME ElTorito Hardcoded
5769 write_byte(DS
,SI
+0x00,0x13);
5770 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5771 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5772 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5773 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5774 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5775 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5776 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5777 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5778 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5779 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5780 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5782 // If we have to terminate emulation
5783 if(GET_AL() == 0x00) {
5784 // FIXME ElTorito Various. Should be handled accordingly to spec
5785 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5792 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5798 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5799 SET_DISK_RET_STATUS(GET_AH());
5800 SET_CF(); // error occurred
5804 SET_AH(0x00); // no error
5805 SET_DISK_RET_STATUS(0x00);
5806 CLEAR_CF(); // no error
5810 // ---------------------------------------------------------------------------
5811 // End of int13 for eltorito functions
5812 // ---------------------------------------------------------------------------
5814 // ---------------------------------------------------------------------------
5815 // Start of int13 when emulating a device from the cd
5816 // ---------------------------------------------------------------------------
5819 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5820 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5822 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5823 Bit8u device
, status
;
5824 Bit16u vheads
, vspt
, vcylinders
;
5825 Bit16u head
, sector
, cylinder
, nbsectors
;
5826 Bit32u vlba
, ilba
, slba
, elba
;
5827 Bit16u before
, segment
, offset
;
5830 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5832 /* at this point, we are emulating a floppy/harddisk */
5834 // Recompute the device number
5835 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5836 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5838 SET_DISK_RET_STATUS(0x00);
5840 /* basic checks : emulation should be active, dl should equal the emulated drive */
5841 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5842 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5843 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5849 // all those functions return SUCCESS
5850 case 0x00: /* disk controller reset */
5851 case 0x09: /* initialize drive parameters */
5852 case 0x0c: /* seek to specified cylinder */
5853 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5854 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5855 case 0x11: /* recalibrate */
5856 case 0x14: /* controller internal diagnostic */
5857 case 0x16: /* detect disk change */
5861 // all those functions return disk write-protected
5862 case 0x03: /* write disk sectors */
5863 case 0x05: /* format disk track */
5865 goto int13_fail_noah
;
5868 case 0x01: /* read disk status */
5869 status
=read_byte(0x0040, 0x0074);
5871 SET_DISK_RET_STATUS(0);
5873 /* set CF if error status read */
5874 if (status
) goto int13_fail_nostatus
;
5875 else goto int13_success_noah
;
5878 case 0x02: // read disk sectors
5879 case 0x04: // verify disk sectors
5880 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5881 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5882 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5884 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5886 sector
= GET_CL() & 0x003f;
5887 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5889 nbsectors
= GET_AL();
5893 // no sector to read ?
5894 if(nbsectors
==0) goto int13_success
;
5896 // sanity checks sco openserver needs this!
5898 || (cylinder
>= vcylinders
)
5899 || (head
>= vheads
)) {
5903 // After controls, verify do nothing
5904 if (GET_AH() == 0x04) goto int13_success
;
5906 segment
= ES
+(BX
/ 16);
5909 // calculate the virtual lba inside the image
5910 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5912 // In advance so we don't loose the count
5916 slba
= (Bit32u
)vlba
/4;
5917 before
= (Bit16u
)vlba
%4;
5920 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5922 memsetb(get_SS(),atacmd
,0,12);
5923 atacmd
[0]=0x28; // READ command
5924 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5925 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5926 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5927 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5928 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5929 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5930 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5931 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5934 goto int13_fail_noah
;
5940 case 0x08: /* read disk drive parameters */
5941 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5942 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5943 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5947 SET_CH( vcylinders
& 0xff );
5948 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5950 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5951 // FIXME ElTorito Harddisk. should send the HD count
5953 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5954 case 0x01: SET_BL( 0x02 ); break;
5955 case 0x02: SET_BL( 0x04 ); break;
5956 case 0x03: SET_BL( 0x06 ); break;
5962 mov ax
, #diskette_param_table2
5963 mov _int13_cdemu
.DI
+2[bp
], ax
5964 mov _int13_cdemu
.ES
+2[bp
], cs
5970 case 0x15: /* read disk drive size */
5971 // FIXME ElTorito Harddisk. What geometry to send ?
5973 goto int13_success_noah
;
5976 // all those functions return unimplemented
5977 case 0x0a: /* read disk sectors with ECC */
5978 case 0x0b: /* write disk sectors with ECC */
5979 case 0x18: /* set media type for format */
5980 case 0x41: // IBM/MS installation check
5981 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5982 case 0x42: // IBM/MS extended read
5983 case 0x43: // IBM/MS extended write
5984 case 0x44: // IBM/MS verify sectors
5985 case 0x45: // IBM/MS lock/unlock drive
5986 case 0x46: // IBM/MS eject media
5987 case 0x47: // IBM/MS extended seek
5988 case 0x48: // IBM/MS get drive parameters
5989 case 0x49: // IBM/MS extended media change
5990 case 0x4e: // ? - set hardware configuration
5991 case 0x50: // ? - send packet command
5993 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5999 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6001 SET_DISK_RET_STATUS(GET_AH());
6002 int13_fail_nostatus
:
6003 SET_CF(); // error occurred
6007 SET_AH(0x00); // no error
6009 SET_DISK_RET_STATUS(0x00);
6010 CLEAR_CF(); // no error
6014 // ---------------------------------------------------------------------------
6015 // End of int13 when emulating a device from the cd
6016 // ---------------------------------------------------------------------------
6018 #endif // BX_ELTORITO_BOOT
6020 #else //BX_USE_ATADRV
6023 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
6038 mov ax
,4[bp
] // cylinder
6040 mov bl
,6[bp
] // hd_heads
6043 mov bl
,8[bp
] // head
6045 mov bl
,10[bp
] // hd_sectors
6047 mov bl
,12[bp
] // sector
6076 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6077 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6079 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
6083 Bit16u max_cylinder
, cylinder
, total_sectors
;
6084 Bit16u hd_cylinders
;
6085 Bit8u hd_heads
, hd_sectors
;
6092 Bit16u count
, segment
, offset
;
6096 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6098 write_byte(0x0040, 0x008e, 0); // clear completion flag
6100 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6102 /* check how many disks first (cmos reg 0x12), return an error if
6103 drive not present */
6104 drive_map
= inb_cmos(0x12);
6105 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6106 (((drive_map
& 0x0f)==0) ? 0 : 2);
6107 n_drives
= (drive_map
==0) ? 0 :
6108 ((drive_map
==3) ? 2 : 1);
6110 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6112 SET_DISK_RET_STATUS(0x01);
6113 SET_CF(); /* error occurred */
6119 case 0x00: /* disk controller reset */
6120 BX_DEBUG_INT13_HD("int13_f00\n");
6123 SET_DISK_RET_STATUS(0);
6124 set_diskette_ret_status(0);
6125 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6126 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6127 CLEAR_CF(); /* successful */
6131 case 0x01: /* read disk status */
6132 BX_DEBUG_INT13_HD("int13_f01\n");
6133 status
= read_byte(0x0040, 0x0074);
6135 SET_DISK_RET_STATUS(0);
6136 /* set CF if error status read */
6137 if (status
) SET_CF();
6142 case 0x04: // verify disk sectors
6143 case 0x02: // read disk sectors
6145 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6147 num_sectors
= GET_AL();
6148 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6149 sector
= (GET_CL() & 0x3f);
6153 if (hd_cylinders
> 1024) {
6154 if (hd_cylinders
<= 2048) {
6157 else if (hd_cylinders
<= 4096) {
6160 else if (hd_cylinders
<= 8192) {
6163 else { // hd_cylinders <= 16384
6167 ax
= head
/ hd_heads
;
6168 cyl_mod
= ax
& 0xff;
6170 cylinder
|= cyl_mod
;
6173 if ( (cylinder
>= hd_cylinders
) ||
6174 (sector
> hd_sectors
) ||
6175 (head
>= hd_heads
) ) {
6177 SET_DISK_RET_STATUS(1);
6178 SET_CF(); /* error occurred */
6182 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6183 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6186 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6188 if ( GET_AH() == 0x04 ) {
6190 SET_DISK_RET_STATUS(0);
6195 status
= inb(0x1f7);
6196 if (status
& 0x80) {
6197 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6199 outb(0x01f2, num_sectors
);
6200 /* activate LBA? (tomv) */
6201 if (hd_heads
> 16) {
6202 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6203 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6206 outb(0x01f3, sector
);
6207 outb(0x01f4, cylinder
& 0x00ff);
6208 outb(0x01f5, cylinder
>> 8);
6209 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6214 status
= inb(0x1f7);
6215 if ( !(status
& 0x80) ) break;
6218 if (status
& 0x01) {
6219 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6220 } else if ( !(status
& 0x08) ) {
6221 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6222 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6229 sti
;; enable higher priority interrupts
6234 ;; store temp bx in real DI
register
6237 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6240 ;; adjust
if there will be an overrun
6242 jbe i13_f02_no_adjust
6244 sub di
, #0x0200 ; sub 512 bytes from offset
6246 add ax
, #0x0020 ; add 512 to segment
6250 mov cx
, #0x0100 ;; counter (256 words = 512b)
6251 mov dx
, #0x01f0 ;; AT data read port
6254 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6257 ;; store real DI
register back to temp bx
6260 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6266 if (num_sectors
== 0) {
6267 status
= inb(0x1f7);
6268 if ( (status
& 0xc9) != 0x40 )
6269 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6273 status
= inb(0x1f7);
6274 if ( (status
& 0xc9) != 0x48 )
6275 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6281 SET_DISK_RET_STATUS(0);
6282 SET_AL(sector_count
);
6283 CLEAR_CF(); /* successful */
6288 case 0x03: /* write disk sectors */
6289 BX_DEBUG_INT13_HD("int13_f03\n");
6290 drive
= GET_ELDL ();
6291 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6293 num_sectors
= GET_AL();
6294 cylinder
= GET_CH();
6295 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6296 sector
= (GET_CL() & 0x3f);
6299 if (hd_cylinders
> 1024) {
6300 if (hd_cylinders
<= 2048) {
6303 else if (hd_cylinders
<= 4096) {
6306 else if (hd_cylinders
<= 8192) {
6309 else { // hd_cylinders <= 16384
6313 ax
= head
/ hd_heads
;
6314 cyl_mod
= ax
& 0xff;
6316 cylinder
|= cyl_mod
;
6319 if ( (cylinder
>= hd_cylinders
) ||
6320 (sector
> hd_sectors
) ||
6321 (head
>= hd_heads
) ) {
6323 SET_DISK_RET_STATUS(1);
6324 SET_CF(); /* error occurred */
6328 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6329 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6332 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6334 status
= inb(0x1f7);
6335 if (status
& 0x80) {
6336 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6338 // should check for Drive Ready Bit also in status reg
6339 outb(0x01f2, num_sectors
);
6341 /* activate LBA? (tomv) */
6342 if (hd_heads
> 16) {
6343 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6344 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6347 outb(0x01f3, sector
);
6348 outb(0x01f4, cylinder
& 0x00ff);
6349 outb(0x01f5, cylinder
>> 8);
6350 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6354 // wait for busy bit to turn off after seeking
6356 status
= inb(0x1f7);
6357 if ( !(status
& 0x80) ) break;
6360 if ( !(status
& 0x08) ) {
6361 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6362 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6369 sti
;; enable higher priority interrupts
6374 ;; store temp bx in real SI
register
6377 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6380 ;; adjust
if there will be an overrun
6382 jbe i13_f03_no_adjust
6384 sub si
, #0x0200 ; sub 512 bytes from offset
6386 add ax
, #0x0020 ; add 512 to segment
6390 mov cx
, #0x0100 ;; counter (256 words = 512b)
6391 mov dx
, #0x01f0 ;; AT data read port
6395 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6397 ;; store real SI
register back to temp bx
6400 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6406 if (num_sectors
== 0) {
6407 status
= inb(0x1f7);
6408 if ( (status
& 0xe9) != 0x40 )
6409 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6413 status
= inb(0x1f7);
6414 if ( (status
& 0xc9) != 0x48 )
6415 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6421 SET_DISK_RET_STATUS(0);
6422 SET_AL(sector_count
);
6423 CLEAR_CF(); /* successful */
6427 case 0x05: /* format disk track */
6428 BX_DEBUG_INT13_HD("int13_f05\n");
6429 BX_PANIC("format disk track called\n");
6432 SET_DISK_RET_STATUS(0);
6433 CLEAR_CF(); /* successful */
6437 case 0x08: /* read disk drive parameters */
6438 BX_DEBUG_INT13_HD("int13_f08\n");
6440 drive
= GET_ELDL ();
6441 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6445 if (hd_cylinders
<= 1024) {
6446 // hd_cylinders >>= 0;
6449 else if (hd_cylinders
<= 2048) {
6453 else if (hd_cylinders
<= 4096) {
6457 else if (hd_cylinders
<= 8192) {
6461 else { // hd_cylinders <= 16384
6466 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6468 SET_CH(max_cylinder
& 0xff);
6469 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6470 SET_DH(hd_heads
- 1);
6471 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6473 SET_DISK_RET_STATUS(0);
6474 CLEAR_CF(); /* successful */
6479 case 0x09: /* initialize drive parameters */
6480 BX_DEBUG_INT13_HD("int13_f09\n");
6482 SET_DISK_RET_STATUS(0);
6483 CLEAR_CF(); /* successful */
6487 case 0x0a: /* read disk sectors with ECC */
6488 BX_DEBUG_INT13_HD("int13_f0a\n");
6489 case 0x0b: /* write disk sectors with ECC */
6490 BX_DEBUG_INT13_HD("int13_f0b\n");
6491 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6495 case 0x0c: /* seek to specified cylinder */
6496 BX_DEBUG_INT13_HD("int13_f0c\n");
6497 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6499 SET_DISK_RET_STATUS(0);
6500 CLEAR_CF(); /* successful */
6504 case 0x0d: /* alternate disk reset */
6505 BX_DEBUG_INT13_HD("int13_f0d\n");
6507 SET_DISK_RET_STATUS(0);
6508 CLEAR_CF(); /* successful */
6512 case 0x10: /* check drive ready */
6513 BX_DEBUG_INT13_HD("int13_f10\n");
6515 //SET_DISK_RET_STATUS(0);
6516 //CLEAR_CF(); /* successful */
6520 // should look at 40:8E also???
6521 status
= inb(0x01f7);
6522 if ( (status
& 0xc0) == 0x40 ) {
6524 SET_DISK_RET_STATUS(0);
6525 CLEAR_CF(); // drive ready
6530 SET_DISK_RET_STATUS(0xAA);
6531 SET_CF(); // not ready
6536 case 0x11: /* recalibrate */
6537 BX_DEBUG_INT13_HD("int13_f11\n");
6539 SET_DISK_RET_STATUS(0);
6540 CLEAR_CF(); /* successful */
6544 case 0x14: /* controller internal diagnostic */
6545 BX_DEBUG_INT13_HD("int13_f14\n");
6547 SET_DISK_RET_STATUS(0);
6548 CLEAR_CF(); /* successful */
6553 case 0x15: /* read disk drive size */
6555 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6559 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6560 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6561 mul al
, ah
;; ax
= heads
* sectors
6562 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6563 dec bx
;; use (cylinders
- 1) ???
6564 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6565 ;; now we need to move the
32bit result dx
:ax to what the
6566 ;; BIOS wants which is cx
:dx
.
6567 ;; and then into CX
:DX on the stack
6568 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6569 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6572 SET_AH(3); // hard disk accessible
6573 SET_DISK_RET_STATUS(0); // ??? should this be 0
6574 CLEAR_CF(); // successful
6578 case 0x18: // set media type for format
6579 case 0x41: // IBM/MS
6580 case 0x42: // IBM/MS
6581 case 0x43: // IBM/MS
6582 case 0x44: // IBM/MS
6583 case 0x45: // IBM/MS lock/unlock drive
6584 case 0x46: // IBM/MS eject media
6585 case 0x47: // IBM/MS extended seek
6586 case 0x49: // IBM/MS extended media change
6587 case 0x50: // IBM/MS send packet command
6589 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6591 SET_AH(1); // code=invalid function in AH or invalid parameter
6592 SET_DISK_RET_STATUS(1);
6593 SET_CF(); /* unsuccessful */
6599 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6600 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6603 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6605 Bit16u
*hd_cylinders
;
6615 if (drive
== 0x80) {
6616 hd_type
= inb_cmos(0x12) & 0xf0;
6617 if (hd_type
!= 0xf0)
6618 BX_INFO(panic_msg_reg12h
,0);
6619 hd_type
= inb_cmos(0x19); // HD0: extended type
6621 BX_INFO(panic_msg_reg19h
,0,0x19);
6624 hd_type
= inb_cmos(0x12) & 0x0f;
6625 if (hd_type
!= 0x0f)
6626 BX_INFO(panic_msg_reg12h
,1);
6627 hd_type
= inb_cmos(0x1a); // HD0: extended type
6629 BX_INFO(panic_msg_reg19h
,0,0x1a);
6634 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6635 write_word(ss
, hd_cylinders
, cylinders
);
6638 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6640 // sectors per track
6641 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6644 #endif //else BX_USE_ATADRV
6646 #if BX_SUPPORT_FLOPPY
6648 //////////////////////
6649 // FLOPPY functions //
6650 //////////////////////
6652 void floppy_reset_controller()
6658 outb(0x03f2, val8
& ~0x04);
6659 outb(0x03f2, val8
| 0x04);
6661 // Wait for controller to come out of reset
6664 } while ( (val8
& 0xc0) != 0x80 );
6667 void floppy_prepare_controller(drive
)
6670 Bit8u val8
, dor
, prev_reset
;
6672 // set 40:3e bit 7 to 0
6673 val8
= read_byte(0x0040, 0x003e);
6675 write_byte(0x0040, 0x003e, val8
);
6677 // turn on motor of selected drive, DMA & int enabled, normal operation
6678 prev_reset
= inb(0x03f2) & 0x04;
6687 // reset the disk motor timeout value of INT 08
6688 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6690 // wait for drive readiness
6693 } while ( (val8
& 0xc0) != 0x80 );
6695 if (prev_reset
== 0) {
6696 // turn on interrupts
6700 // wait on 40:3e bit 7 to become 1
6702 val8
= read_byte(0x0040, 0x003e);
6703 } while ( (val8
& 0x80) == 0 );
6708 write_byte(0x0040, 0x003e, val8
);
6713 floppy_media_known(drive
)
6717 Bit16u media_state_offset
;
6719 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6726 media_state_offset
= 0x0090;
6728 media_state_offset
+= 1;
6730 val8
= read_byte(0x0040, media_state_offset
);
6731 val8
= (val8
>> 4) & 0x01;
6735 // check pass, return KNOWN
6740 floppy_media_sense(drive
)
6744 Bit16u media_state_offset
;
6745 Bit8u drive_type
, config_data
, media_state
;
6747 if (floppy_drive_recal(drive
) == 0) {
6751 // for now cheat and get drive type from CMOS,
6752 // assume media is same as drive type
6754 // ** config_data **
6755 // Bitfields for diskette media control:
6756 // Bit(s) Description (Table M0028)
6757 // 7-6 last data rate set by controller
6758 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6759 // 5-4 last diskette drive step rate selected
6760 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6761 // 3-2 {data rate at start of operation}
6764 // ** media_state **
6765 // Bitfields for diskette drive media state:
6766 // Bit(s) Description (Table M0030)
6768 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6769 // 5 double stepping required (e.g. 360kB in 1.2MB)
6770 // 4 media type established
6771 // 3 drive capable of supporting 4MB media
6772 // 2-0 on exit from BIOS, contains
6773 // 000 trying 360kB in 360kB
6774 // 001 trying 360kB in 1.2MB
6775 // 010 trying 1.2MB in 1.2MB
6776 // 011 360kB in 360kB established
6777 // 100 360kB in 1.2MB established
6778 // 101 1.2MB in 1.2MB established
6780 // 111 all other formats/drives
6782 drive_type
= inb_cmos(0x10);
6787 if ( drive_type
== 1 ) {
6789 config_data
= 0x00; // 0000 0000
6790 media_state
= 0x25; // 0010 0101
6793 else if ( drive_type
== 2 ) {
6794 // 1.2 MB 5.25" drive
6795 config_data
= 0x00; // 0000 0000
6796 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6799 else if ( drive_type
== 3 ) {
6801 config_data
= 0x00; // 0000 0000 ???
6802 media_state
= 0x17; // 0001 0111
6805 else if ( drive_type
== 4 ) {
6806 // 1.44 MB 3.5" drive
6807 config_data
= 0x00; // 0000 0000
6808 media_state
= 0x17; // 0001 0111
6811 else if ( drive_type
== 5 ) {
6812 // 2.88 MB 3.5" drive
6813 config_data
= 0xCC; // 1100 1100
6814 media_state
= 0xD7; // 1101 0111
6818 // Extended floppy size uses special cmos setting
6819 else if ( drive_type
== 6 ) {
6821 config_data
= 0x00; // 0000 0000
6822 media_state
= 0x27; // 0010 0111
6825 else if ( drive_type
== 7 ) {
6827 config_data
= 0x00; // 0000 0000
6828 media_state
= 0x27; // 0010 0111
6831 else if ( drive_type
== 8 ) {
6833 config_data
= 0x00; // 0000 0000
6834 media_state
= 0x27; // 0010 0111
6840 config_data
= 0x00; // 0000 0000
6841 media_state
= 0x00; // 0000 0000
6846 media_state_offset
= 0x90;
6848 media_state_offset
= 0x91;
6849 write_byte(0x0040, 0x008B, config_data
);
6850 write_byte(0x0040, media_state_offset
, media_state
);
6856 floppy_drive_recal(drive
)
6860 Bit16u curr_cyl_offset
;
6862 floppy_prepare_controller(drive
);
6864 // send Recalibrate command (2 bytes) to controller
6865 outb(0x03f5, 0x07); // 07: Recalibrate
6866 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6868 // turn on interrupts
6873 // wait on 40:3e bit 7 to become 1
6875 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6876 } while ( val8
== 0 );
6878 val8
= 0; // separate asm from while() loop
6879 // turn off interrupts
6884 // set 40:3e bit 7 to 0, and calibrated bit
6885 val8
= read_byte(0x0040, 0x003e);
6888 val8
|= 0x02; // Drive 1 calibrated
6889 curr_cyl_offset
= 0x0095;
6891 val8
|= 0x01; // Drive 0 calibrated
6892 curr_cyl_offset
= 0x0094;
6894 write_byte(0x0040, 0x003e, val8
);
6895 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6903 floppy_drive_exists(drive
)
6908 // check CMOS to see if drive exists
6909 drive_type
= inb_cmos(0x10);
6914 if ( drive_type
== 0 )
6921 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6922 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6924 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6925 Bit16u base_address
, base_count
, base_es
;
6926 Bit8u page
, mode_register
, val8
, dor
;
6927 Bit8u return_status
[7];
6928 Bit8u drive_type
, num_floppies
, ah
;
6929 Bit16u es
, last_addr
;
6931 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6936 case 0x00: // diskette controller reset
6937 BX_DEBUG_INT13_FL("floppy f00\n");
6940 SET_AH(1); // invalid param
6941 set_diskette_ret_status(1);
6945 drive_type
= inb_cmos(0x10);
6951 if (drive_type
== 0) {
6952 SET_AH(0x80); // drive not responding
6953 set_diskette_ret_status(0x80);
6958 set_diskette_ret_status(0);
6959 CLEAR_CF(); // successful
6960 set_diskette_current_cyl(drive
, 0); // current cylinder
6963 case 0x01: // Read Diskette Status
6965 val8
= read_byte(0x0000, 0x0441);
6972 case 0x02: // Read Diskette Sectors
6973 case 0x03: // Write Diskette Sectors
6974 case 0x04: // Verify Diskette Sectors
6975 num_sectors
= GET_AL();
6981 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
6982 (num_sectors
== 0) || (num_sectors
> 72)) {
6983 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
6985 set_diskette_ret_status(1);
6986 SET_AL(0); // no sectors read
6987 SET_CF(); // error occurred
6991 // see if drive exists
6992 if (floppy_drive_exists(drive
) == 0) {
6993 SET_AH(0x80); // not responding
6994 set_diskette_ret_status(0x80);
6995 SET_AL(0); // no sectors read
6996 SET_CF(); // error occurred
7000 // see if media in drive, and type is known
7001 if (floppy_media_known(drive
) == 0) {
7002 if (floppy_media_sense(drive
) == 0) {
7003 SET_AH(0x0C); // Media type not found
7004 set_diskette_ret_status(0x0C);
7005 SET_AL(0); // no sectors read
7006 SET_CF(); // error occurred
7012 // Read Diskette Sectors
7014 //-----------------------------------
7015 // set up DMA controller for transfer
7016 //-----------------------------------
7018 // es:bx = pointer to where to place information from diskette
7019 // port 04: DMA-1 base and current address, channel 2
7020 // port 05: DMA-1 base and current count, channel 2
7021 page
= (ES
>> 12); // upper 4 bits
7022 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7023 base_address
= base_es
+ BX
; // lower 16 bits of address
7024 // contributed by ES:BX
7025 if ( base_address
< base_es
) {
7026 // in case of carry, adjust page by 1
7029 base_count
= (num_sectors
* 512) - 1;
7031 // check for 64K boundary overrun
7032 last_addr
= base_address
+ base_count
;
7033 if (last_addr
< base_address
) {
7035 set_diskette_ret_status(0x09);
7036 SET_AL(0); // no sectors read
7037 SET_CF(); // error occurred
7041 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7044 BX_DEBUG_INT13_FL("clear flip-flop\n");
7045 outb(0x000c, 0x00); // clear flip-flop
7046 outb(0x0004, base_address
);
7047 outb(0x0004, base_address
>>8);
7048 BX_DEBUG_INT13_FL("clear flip-flop\n");
7049 outb(0x000c, 0x00); // clear flip-flop
7050 outb(0x0005, base_count
);
7051 outb(0x0005, base_count
>>8);
7053 // port 0b: DMA-1 Mode Register
7054 mode_register
= 0x46; // single mode, increment, autoinit disable,
7055 // transfer type=write, channel 2
7056 BX_DEBUG_INT13_FL("setting mode register\n");
7057 outb(0x000b, mode_register
);
7059 BX_DEBUG_INT13_FL("setting page register\n");
7060 // port 81: DMA-1 Page Register, channel 2
7063 BX_DEBUG_INT13_FL("unmask chan 2\n");
7064 outb(0x000a, 0x02); // unmask channel 2
7066 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7069 //--------------------------------------
7070 // set up floppy controller for transfer
7071 //--------------------------------------
7072 floppy_prepare_controller(drive
);
7074 // send read-normal-data command (9 bytes) to controller
7075 outb(0x03f5, 0xe6); // e6: read normal data
7076 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7077 outb(0x03f5, track
);
7079 outb(0x03f5, sector
);
7080 outb(0x03f5, 2); // 512 byte sector size
7081 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
7082 outb(0x03f5, 0); // Gap length
7083 outb(0x03f5, 0xff); // Gap length
7085 // turn on interrupts
7090 // wait on 40:3e bit 7 to become 1
7092 val8
= read_byte(0x0040, 0x0040);
7094 floppy_reset_controller();
7095 SET_AH(0x80); // drive not ready (timeout)
7096 set_diskette_ret_status(0x80);
7097 SET_AL(0); // no sectors read
7098 SET_CF(); // error occurred
7101 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7102 } while ( val8
== 0 );
7104 val8
= 0; // separate asm from while() loop
7105 // turn off interrupts
7110 // set 40:3e bit 7 to 0
7111 val8
= read_byte(0x0040, 0x003e);
7113 write_byte(0x0040, 0x003e, val8
);
7115 // check port 3f4 for accessibility to status bytes
7117 if ( (val8
& 0xc0) != 0xc0 )
7118 BX_PANIC("int13_diskette: ctrl not ready\n");
7120 // read 7 return status bytes from controller
7121 // using loop index broken, have to unroll...
7122 return_status
[0] = inb(0x3f5);
7123 return_status
[1] = inb(0x3f5);
7124 return_status
[2] = inb(0x3f5);
7125 return_status
[3] = inb(0x3f5);
7126 return_status
[4] = inb(0x3f5);
7127 return_status
[5] = inb(0x3f5);
7128 return_status
[6] = inb(0x3f5);
7129 // record in BIOS Data Area
7130 write_byte(0x0040, 0x0042, return_status
[0]);
7131 write_byte(0x0040, 0x0043, return_status
[1]);
7132 write_byte(0x0040, 0x0044, return_status
[2]);
7133 write_byte(0x0040, 0x0045, return_status
[3]);
7134 write_byte(0x0040, 0x0046, return_status
[4]);
7135 write_byte(0x0040, 0x0047, return_status
[5]);
7136 write_byte(0x0040, 0x0048, return_status
[6]);
7138 if ( (return_status
[0] & 0xc0) != 0 ) {
7140 set_diskette_ret_status(0x20);
7141 SET_AL(0); // no sectors read
7142 SET_CF(); // error occurred
7146 // ??? should track be new val from return_status[3] ?
7147 set_diskette_current_cyl(drive
, track
);
7148 // AL = number of sectors read (same value as passed)
7149 SET_AH(0x00); // success
7150 CLEAR_CF(); // success
7152 } else if (ah
== 0x03) {
7153 // Write Diskette Sectors
7155 //-----------------------------------
7156 // set up DMA controller for transfer
7157 //-----------------------------------
7159 // es:bx = pointer to where to place information from diskette
7160 // port 04: DMA-1 base and current address, channel 2
7161 // port 05: DMA-1 base and current count, channel 2
7162 page
= (ES
>> 12); // upper 4 bits
7163 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7164 base_address
= base_es
+ BX
; // lower 16 bits of address
7165 // contributed by ES:BX
7166 if ( base_address
< base_es
) {
7167 // in case of carry, adjust page by 1
7170 base_count
= (num_sectors
* 512) - 1;
7172 // check for 64K boundary overrun
7173 last_addr
= base_address
+ base_count
;
7174 if (last_addr
< base_address
) {
7176 set_diskette_ret_status(0x09);
7177 SET_AL(0); // no sectors read
7178 SET_CF(); // error occurred
7182 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7185 outb(0x000c, 0x00); // clear flip-flop
7186 outb(0x0004, base_address
);
7187 outb(0x0004, base_address
>>8);
7188 outb(0x000c, 0x00); // clear flip-flop
7189 outb(0x0005, base_count
);
7190 outb(0x0005, base_count
>>8);
7192 // port 0b: DMA-1 Mode Register
7193 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7194 // transfer type=read, channel 2
7195 outb(0x000b, mode_register
);
7197 // port 81: DMA-1 Page Register, channel 2
7200 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7203 //--------------------------------------
7204 // set up floppy controller for transfer
7205 //--------------------------------------
7206 floppy_prepare_controller(drive
);
7208 // send write-normal-data command (9 bytes) to controller
7209 outb(0x03f5, 0xc5); // c5: write normal data
7210 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7211 outb(0x03f5, track
);
7213 outb(0x03f5, sector
);
7214 outb(0x03f5, 2); // 512 byte sector size
7215 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7216 outb(0x03f5, 0); // Gap length
7217 outb(0x03f5, 0xff); // Gap length
7219 // turn on interrupts
7224 // wait on 40:3e bit 7 to become 1
7226 val8
= read_byte(0x0040, 0x0040);
7228 floppy_reset_controller();
7229 SET_AH(0x80); // drive not ready (timeout)
7230 set_diskette_ret_status(0x80);
7231 SET_AL(0); // no sectors written
7232 SET_CF(); // error occurred
7235 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7236 } while ( val8
== 0 );
7238 val8
= 0; // separate asm from while() loop
7239 // turn off interrupts
7244 // set 40:3e bit 7 to 0
7245 val8
= read_byte(0x0040, 0x003e);
7247 write_byte(0x0040, 0x003e, val8
);
7249 // check port 3f4 for accessibility to status bytes
7251 if ( (val8
& 0xc0) != 0xc0 )
7252 BX_PANIC("int13_diskette: ctrl not ready\n");
7254 // read 7 return status bytes from controller
7255 // using loop index broken, have to unroll...
7256 return_status
[0] = inb(0x3f5);
7257 return_status
[1] = inb(0x3f5);
7258 return_status
[2] = inb(0x3f5);
7259 return_status
[3] = inb(0x3f5);
7260 return_status
[4] = inb(0x3f5);
7261 return_status
[5] = inb(0x3f5);
7262 return_status
[6] = inb(0x3f5);
7263 // record in BIOS Data Area
7264 write_byte(0x0040, 0x0042, return_status
[0]);
7265 write_byte(0x0040, 0x0043, return_status
[1]);
7266 write_byte(0x0040, 0x0044, return_status
[2]);
7267 write_byte(0x0040, 0x0045, return_status
[3]);
7268 write_byte(0x0040, 0x0046, return_status
[4]);
7269 write_byte(0x0040, 0x0047, return_status
[5]);
7270 write_byte(0x0040, 0x0048, return_status
[6]);
7272 if ( (return_status
[0] & 0xc0) != 0 ) {
7273 if ( (return_status
[1] & 0x02) != 0 ) {
7274 // diskette not writable.
7275 // AH=status code=0x03 (tried to write on write-protected disk)
7276 // AL=number of sectors written=0
7281 BX_PANIC("int13_diskette_function: read error\n");
7285 // ??? should track be new val from return_status[3] ?
7286 set_diskette_current_cyl(drive
, track
);
7287 // AL = number of sectors read (same value as passed)
7288 SET_AH(0x00); // success
7289 CLEAR_CF(); // success
7291 } else { // if (ah == 0x04)
7292 // Verify Diskette Sectors
7294 // ??? should track be new val from return_status[3] ?
7295 set_diskette_current_cyl(drive
, track
);
7296 // AL = number of sectors verified (same value as passed)
7297 CLEAR_CF(); // success
7298 SET_AH(0x00); // success
7303 case 0x05: // format diskette track
7304 BX_DEBUG_INT13_FL("floppy f05\n");
7306 num_sectors
= GET_AL();
7311 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7312 (num_sectors
== 0) || (num_sectors
> 18)) {
7314 set_diskette_ret_status(1);
7315 SET_CF(); // error occurred
7318 // see if drive exists
7319 if (floppy_drive_exists(drive
) == 0) {
7320 SET_AH(0x80); // drive not responding
7321 set_diskette_ret_status(0x80);
7322 SET_CF(); // error occurred
7326 // see if media in drive, and type is known
7327 if (floppy_media_known(drive
) == 0) {
7328 if (floppy_media_sense(drive
) == 0) {
7329 SET_AH(0x0C); // Media type not found
7330 set_diskette_ret_status(0x0C);
7331 SET_AL(0); // no sectors read
7332 SET_CF(); // error occurred
7337 // set up DMA controller for transfer
7338 page
= (ES
>> 12); // upper 4 bits
7339 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7340 base_address
= base_es
+ BX
; // lower 16 bits of address
7341 // contributed by ES:BX
7342 if ( base_address
< base_es
) {
7343 // in case of carry, adjust page by 1
7346 base_count
= (num_sectors
* 4) - 1;
7348 // check for 64K boundary overrun
7349 last_addr
= base_address
+ base_count
;
7350 if (last_addr
< base_address
) {
7352 set_diskette_ret_status(0x09);
7353 SET_AL(0); // no sectors read
7354 SET_CF(); // error occurred
7359 outb(0x000c, 0x00); // clear flip-flop
7360 outb(0x0004, base_address
);
7361 outb(0x0004, base_address
>>8);
7362 outb(0x000c, 0x00); // clear flip-flop
7363 outb(0x0005, base_count
);
7364 outb(0x0005, base_count
>>8);
7365 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7366 // transfer type=read, channel 2
7367 outb(0x000b, mode_register
);
7368 // port 81: DMA-1 Page Register, channel 2
7372 // set up floppy controller for transfer
7373 floppy_prepare_controller(drive
);
7375 // send format-track command (6 bytes) to controller
7376 outb(0x03f5, 0x4d); // 4d: format track
7377 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7378 outb(0x03f5, 2); // 512 byte sector size
7379 outb(0x03f5, num_sectors
); // number of sectors per track
7380 outb(0x03f5, 0); // Gap length
7381 outb(0x03f5, 0xf6); // Fill byte
7382 // turn on interrupts
7387 // wait on 40:3e bit 7 to become 1
7389 val8
= read_byte(0x0040, 0x0040);
7391 floppy_reset_controller();
7392 SET_AH(0x80); // drive not ready (timeout)
7393 set_diskette_ret_status(0x80);
7394 SET_CF(); // error occurred
7397 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7398 } while ( val8
== 0 );
7400 val8
= 0; // separate asm from while() loop
7401 // turn off interrupts
7405 // set 40:3e bit 7 to 0
7406 val8
= read_byte(0x0040, 0x003e);
7408 write_byte(0x0040, 0x003e, val8
);
7409 // check port 3f4 for accessibility to status bytes
7411 if ( (val8
& 0xc0) != 0xc0 )
7412 BX_PANIC("int13_diskette: ctrl not ready\n");
7414 // read 7 return status bytes from controller
7415 // using loop index broken, have to unroll...
7416 return_status
[0] = inb(0x3f5);
7417 return_status
[1] = inb(0x3f5);
7418 return_status
[2] = inb(0x3f5);
7419 return_status
[3] = inb(0x3f5);
7420 return_status
[4] = inb(0x3f5);
7421 return_status
[5] = inb(0x3f5);
7422 return_status
[6] = inb(0x3f5);
7423 // record in BIOS Data Area
7424 write_byte(0x0040, 0x0042, return_status
[0]);
7425 write_byte(0x0040, 0x0043, return_status
[1]);
7426 write_byte(0x0040, 0x0044, return_status
[2]);
7427 write_byte(0x0040, 0x0045, return_status
[3]);
7428 write_byte(0x0040, 0x0046, return_status
[4]);
7429 write_byte(0x0040, 0x0047, return_status
[5]);
7430 write_byte(0x0040, 0x0048, return_status
[6]);
7432 if ( (return_status
[0] & 0xc0) != 0 ) {
7433 if ( (return_status
[1] & 0x02) != 0 ) {
7434 // diskette not writable.
7435 // AH=status code=0x03 (tried to write on write-protected disk)
7436 // AL=number of sectors written=0
7441 BX_PANIC("int13_diskette_function: write error\n");
7446 set_diskette_ret_status(0);
7447 set_diskette_current_cyl(drive
, 0);
7448 CLEAR_CF(); // successful
7452 case 0x08: // read diskette drive parameters
7453 BX_DEBUG_INT13_FL("floppy f08\n");
7463 SET_DL(num_floppies
);
7468 drive_type
= inb_cmos(0x10);
7470 if (drive_type
& 0xf0)
7472 if (drive_type
& 0x0f)
7484 SET_DL(num_floppies
);
7486 switch (drive_type
) {
7489 SET_DH(0); // max head #
7492 case 1: // 360KB, 5.25"
7493 CX
= 0x2709; // 40 tracks, 9 sectors
7494 SET_DH(1); // max head #
7497 case 2: // 1.2MB, 5.25"
7498 CX
= 0x4f0f; // 80 tracks, 15 sectors
7499 SET_DH(1); // max head #
7502 case 3: // 720KB, 3.5"
7503 CX
= 0x4f09; // 80 tracks, 9 sectors
7504 SET_DH(1); // max head #
7507 case 4: // 1.44MB, 3.5"
7508 CX
= 0x4f12; // 80 tracks, 18 sectors
7509 SET_DH(1); // max head #
7512 case 5: // 2.88MB, 3.5"
7513 CX
= 0x4f24; // 80 tracks, 36 sectors
7514 SET_DH(1); // max head #
7517 case 6: // 160k, 5.25"
7518 CX
= 0x2708; // 40 tracks, 8 sectors
7519 SET_DH(0); // max head #
7522 case 7: // 180k, 5.25"
7523 CX
= 0x2709; // 40 tracks, 9 sectors
7524 SET_DH(0); // max head #
7527 case 8: // 320k, 5.25"
7528 CX
= 0x2708; // 40 tracks, 8 sectors
7529 SET_DH(1); // max head #
7533 BX_PANIC("floppy: int13: bad floppy type\n");
7536 /* set es & di to point to 11 byte diskette param table in ROM */
7540 mov ax
, #diskette_param_table2
7541 mov _int13_diskette_function
.DI
+2[bp
], ax
7542 mov _int13_diskette_function
.ES
+2[bp
], cs
7545 CLEAR_CF(); // success
7546 /* disk status not changed upon success */
7550 case 0x15: // read diskette drive type
7551 BX_DEBUG_INT13_FL("floppy f15\n");
7554 SET_AH(0); // only 2 drives supported
7555 // set_diskette_ret_status here ???
7559 drive_type
= inb_cmos(0x10);
7565 CLEAR_CF(); // successful, not present
7566 if (drive_type
==0) {
7567 SET_AH(0); // drive not present
7570 SET_AH(1); // drive present, does not support change line
7575 case 0x16: // get diskette change line status
7576 BX_DEBUG_INT13_FL("floppy f16\n");
7579 SET_AH(0x01); // invalid drive
7580 set_diskette_ret_status(0x01);
7585 SET_AH(0x06); // change line not supported
7586 set_diskette_ret_status(0x06);
7590 case 0x17: // set diskette type for format(old)
7591 BX_DEBUG_INT13_FL("floppy f17\n");
7592 /* not used for 1.44M floppies */
7593 SET_AH(0x01); // not supported
7594 set_diskette_ret_status(1); /* not supported */
7598 case 0x18: // set diskette type for format(new)
7599 BX_DEBUG_INT13_FL("floppy f18\n");
7600 SET_AH(0x01); // do later
7601 set_diskette_ret_status(1);
7606 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7608 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7609 SET_AH(0x01); // ???
7610 set_diskette_ret_status(1);
7616 #else // #if BX_SUPPORT_FLOPPY
7618 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7619 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7623 switch ( GET_AH() ) {
7625 case 0x01: // Read Diskette Status
7627 val8
= read_byte(0x0000, 0x0441);
7636 write_byte(0x0000, 0x0441, 0x01);
7640 #endif // #if BX_SUPPORT_FLOPPY
7643 set_diskette_ret_status(value
)
7646 write_byte(0x0040, 0x0041, value
);
7650 set_diskette_current_cyl(drive
, cyl
)
7655 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7656 write_byte(0x0040, 0x0094+drive
, cyl
);
7660 determine_floppy_media(drive
)
7664 Bit8u val8
, DOR
, ctrl_info
;
7666 ctrl_info
= read_byte(0x0040, 0x008F);
7674 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7677 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7681 if ( (ctrl_info
& 0x04) != 0x04 ) {
7682 // Drive not determined means no drive exists, done.
7687 // check Main Status Register for readiness
7688 val8
= inb(0x03f4) & 0x80; // Main Status Register
7690 BX_PANIC("d_f_m: MRQ bit not set\n");
7694 // existing BDA values
7696 // turn on drive motor
7697 outb(0x03f2, DOR
); // Digital Output Register
7700 BX_PANIC("d_f_m: OK so far\n");
7705 int17_function(regs
, ds
, iret_addr
)
7706 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7707 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7708 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7710 Bit16u addr
,timeout
;
7717 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7718 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7719 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7720 if (regs
.u
.r8
.ah
== 0) {
7721 outb(addr
, regs
.u
.r8
.al
);
7723 outb(addr
+2, val8
| 0x01); // send strobe
7727 outb(addr
+2, val8
& ~0x01);
7728 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7732 if (regs
.u
.r8
.ah
== 1) {
7734 outb(addr
+2, val8
& ~0x04); // send init
7738 outb(addr
+2, val8
| 0x04);
7741 regs
.u
.r8
.ah
= (val8
^ 0x48);
7742 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7743 ClearCF(iret_addr
.flags
);
7745 SetCF(iret_addr
.flags
); // Unsupported
7750 int19_function(seq_nr
)
7753 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7763 // if BX_ELTORITO_BOOT is not defined, old behavior
7764 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7765 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7766 // 0: system boot sequence, first drive C: then A:
7767 // 1: system boot sequence, first drive A: then C:
7768 // else BX_ELTORITO_BOOT is defined
7769 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7770 // CMOS reg 0x3D & 0x0f : 1st boot device
7771 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7772 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7773 // boot device codes:
7774 // 0x00 : not defined
7775 // 0x01 : first floppy
7776 // 0x02 : first harddrive
7777 // 0x03 : first cdrom
7778 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7779 // else : boot failure
7781 // Get the boot sequence
7782 #if BX_ELTORITO_BOOT
7783 bootdev
= inb_cmos(0x3d);
7784 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
7785 bootdev
>>= 4 * seq_nr
;
7787 if (bootdev
== 0) BX_PANIC("No bootable device.\n");
7789 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7792 if (seq_nr
==2) BX_PANIC("No more boot devices.");
7793 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
7794 /* Boot from floppy if the bit is set or it's the second boot */
7800 /* Read the boot device from the IPL table */
7801 if (get_boot_vector(bootdev
, &e
) == 0) {
7802 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
7806 /* Do the loading, and set up vector as a far pointer to the boot
7807 * address, and bootdrv as the boot drive */
7808 print_boot_device(e
.type
);
7811 case IPL_TYPE_FLOPPY
: /* FDD */
7812 case IPL_TYPE_HARDDISK
: /* HDD */
7814 bootdrv
= (e
.type
== IPL_TYPE_HARDDISK
) ? 0x80 : 0x00;
7826 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7827 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7828 mov es
, ax
;; segment
7829 xor bx
, bx
;; offset
7830 mov ah
, #0x02 ;; function 2, read diskette sector
7831 mov al
, #0x01 ;; read 1 sector
7832 mov ch
, #0x00 ;; track 0
7833 mov cl
, #0x01 ;; sector 1
7834 mov dh
, #0x00 ;; head 0
7835 int #0x13 ;; read sector
7838 mov _int19_function
.status
+ 2[bp
], ax
7849 print_boot_failure(e
.type
, 1);
7853 /* Always check the signature on a HDD boot sector; on FDD, only do
7854 * the check if the CMOS doesn't tell us to skip it */
7855 if ((e
.type
!= IPL_TYPE_FLOPPY
) || !((inb_cmos(0x38) & 0x01))) {
7856 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7857 print_boot_failure(e
.type
, 0);
7862 /* Canonicalize bootseg:bootip */
7863 bootip
= (bootseg
& 0x0fff) << 4;
7867 #if BX_ELTORITO_BOOT
7868 case IPL_TYPE_CDROM
: /* CD-ROM */
7869 status
= cdrom_boot();
7872 if ( (status
& 0x00ff) !=0 ) {
7873 print_cdromboot_failure(status
);
7874 print_boot_failure(e
.type
, 1);
7878 bootdrv
= (Bit8u
)(status
>>8);
7879 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7880 /* Canonicalize bootseg:bootip */
7881 bootip
= (bootseg
& 0x0fff) << 4;
7886 case IPL_TYPE_BEV
: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7887 bootseg
= e
.vector
>> 16;
7888 bootip
= e
.vector
& 0xffff;
7894 /* Debugging info */
7895 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
7897 /* Jump to the boot vector */
7900 ;; Build an iret stack frame that will take us to the boot vector
.
7901 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
7903 mov ax
, _int19_function
.bootseg
+ 0[bp
]
7905 mov ax
, _int19_function
.bootip
+ 0[bp
]
7907 ;; Set the magic number in ax
and the boot drive in dl
.
7909 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
7910 ;; Zero some of the other registers
.
7921 int1a_function(regs
, ds
, iret_addr
)
7922 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7923 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7924 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7928 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
);
7934 switch (regs
.u
.r8
.ah
) {
7935 case 0: // get current clock count
7939 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7940 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7941 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7942 BiosData
->midnight_flag
= 0; // reset flag
7947 ClearCF(iret_addr
.flags
); // OK
7950 case 1: // Set Current Clock Count
7954 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7955 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7956 BiosData
->midnight_flag
= 0; // reset flag
7961 ClearCF(iret_addr
.flags
); // OK
7965 case 2: // Read CMOS Time
7966 if (rtc_updating()) {
7967 SetCF(iret_addr
.flags
);
7971 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7972 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7973 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7974 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7976 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7977 ClearCF(iret_addr
.flags
); // OK
7980 case 3: // Set CMOS Time
7981 // Using a debugger, I notice the following masking/setting
7982 // of bits in Status Register B, by setting Reg B to
7983 // a few values and getting its value after INT 1A was called.
7985 // try#1 try#2 try#3
7986 // before 1111 1101 0111 1101 0000 0000
7987 // after 0110 0010 0110 0010 0000 0010
7989 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7990 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7991 if (rtc_updating()) {
7993 // fall through as if an update were not in progress
7995 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7996 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7997 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7998 // Set Daylight Savings time enabled bit to requested value
7999 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
8000 // (reg B already selected)
8001 outb_cmos(0x0b, val8
);
8003 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8004 ClearCF(iret_addr
.flags
); // OK
8007 case 4: // Read CMOS Date
8009 if (rtc_updating()) {
8010 SetCF(iret_addr
.flags
);
8013 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
8014 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
8015 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
8016 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
8017 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8018 ClearCF(iret_addr
.flags
); // OK
8021 case 5: // Set CMOS Date
8022 // Using a debugger, I notice the following masking/setting
8023 // of bits in Status Register B, by setting Reg B to
8024 // a few values and getting its value after INT 1A was called.
8026 // try#1 try#2 try#3 try#4
8027 // before 1111 1101 0111 1101 0000 0010 0000 0000
8028 // after 0110 1101 0111 1101 0000 0010 0000 0000
8030 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8031 // My assumption: RegB = (RegB & 01111111b)
8032 if (rtc_updating()) {
8034 SetCF(iret_addr
.flags
);
8037 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
8038 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
8039 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
8040 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
8041 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8042 outb_cmos(0x0b, val8
);
8044 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
8045 ClearCF(iret_addr
.flags
); // OK
8048 case 6: // Set Alarm Time in CMOS
8049 // Using a debugger, I notice the following masking/setting
8050 // of bits in Status Register B, by setting Reg B to
8051 // a few values and getting its value after INT 1A was called.
8053 // try#1 try#2 try#3
8054 // before 1101 1111 0101 1111 0000 0000
8055 // after 0110 1111 0111 1111 0010 0000
8057 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8058 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8059 val8
= inb_cmos(0x0b); // Get Status Reg B
8062 // Alarm interrupt enabled already
8063 SetCF(iret_addr
.flags
); // Error: alarm in use
8066 if (rtc_updating()) {
8068 // fall through as if an update were not in progress
8070 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
8071 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
8072 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
8073 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8074 // enable Status Reg B alarm bit, clear halt clock bit
8075 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
8076 ClearCF(iret_addr
.flags
); // OK
8079 case 7: // Turn off Alarm
8080 // Using a debugger, I notice the following masking/setting
8081 // of bits in Status Register B, by setting Reg B to
8082 // a few values and getting its value after INT 1A was called.
8084 // try#1 try#2 try#3 try#4
8085 // before 1111 1101 0111 1101 0010 0000 0010 0010
8086 // after 0100 0101 0101 0101 0000 0000 0000 0010
8088 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8089 // My assumption: RegB = (RegB & 01010111b)
8090 val8
= inb_cmos(0x0b); // Get Status Reg B
8091 // clear clock-halt bit, disable alarm bit
8092 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
8094 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8095 ClearCF(iret_addr
.flags
); // OK
8099 // real mode PCI BIOS functions now handled in assembler code
8100 // this C code handles the error code for information only
8101 if (regs
.u
.r8
.bl
== 0xff) {
8102 BX_INFO("PCI BIOS: PCI not present\n");
8103 } else if (regs
.u
.r8
.bl
== 0x81) {
8104 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8105 } else if (regs
.u
.r8
.bl
== 0x83) {
8106 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8107 } else if (regs
.u
.r8
.bl
== 0x86) {
8108 if (regs
.u
.r8
.al
== 0x02) {
8109 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8111 BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", regs
.u
.r8
.cl
, regs
.u
.r16
.dx
, regs
.u
.r16
.si
);
8114 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8115 SetCF(iret_addr
.flags
);
8120 SetCF(iret_addr
.flags
); // Unsupported
8125 int70_function(regs
, ds
, iret_addr
)
8126 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8127 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8128 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8130 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8131 Bit8u registerB
= 0, registerC
= 0;
8133 // Check which modes are enabled and have occurred.
8134 registerB
= inb_cmos( 0xB );
8135 registerC
= inb_cmos( 0xC );
8137 if( ( registerB
& 0x60 ) != 0 ) {
8138 if( ( registerC
& 0x20 ) != 0 ) {
8139 // Handle Alarm Interrupt.
8146 if( ( registerC
& 0x40 ) != 0 ) {
8147 // Handle Periodic Interrupt.
8149 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8150 // Wait Interval (Int 15, AH=83) active.
8151 Bit32u time
, toggle
;
8153 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8154 if( time
< 0x3D1 ) {
8156 Bit16u segment
, offset
;
8158 segment
= read_word( 0x40, 0x98 );
8159 offset
= read_word( 0x40, 0x9A );
8160 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8161 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8162 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8164 // Continue waiting.
8166 write_dword( 0x40, 0x9C, time
);
8179 ;------------------------------------------
8180 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8181 ;------------------------------------------
8186 push
#0x00 ;; placeholder for status
8187 push
#0x00 ;; placeholder for X
8188 push
#0x00 ;; placeholder for Y
8189 push
#0x00 ;; placeholder for Z
8190 push
#0x00 ;; placeholder for make_far_call boolean
8191 call _int74_function
8192 pop cx
;; remove make_far_call from stack
8195 ;; make far call to EBDA
:0022
8198 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8200 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8205 add sp
, #8 ;; pop status, x, y, z
8207 pop ds
;; restore DS
8212 ;; This will perform an IRET
, but will retain value of current CF
8213 ;; by altering flags on stack
. Better than RETF
#02.
8218 and BYTE
[bp
+ 0x06], #0xfe
8224 or BYTE
[bp
+ 0x06], #0x01
8229 ;----------------------
8230 ;- INT13h (relocated
) -
8231 ;----------------------
8233 ; int13_relocated is a little bit messed up since I played with it
8234 ; I have to rewrite it
:
8235 ; - call a function that detect which function to call
8236 ; - make all called C function get the same parameters list
8240 #if BX_ELTORITO_BOOT
8241 ;; check
for an eltorito function
8243 jb int13_not_eltorito
8245 ja int13_not_eltorito
8254 jmp _int13_eltorito
;; ELDX
not used
8262 ;; check
if emulation active
8263 call _cdemu_isactive
8265 je int13_cdemu_inactive
8267 ;; check
if access to the emulated drive
8268 call _cdemu_emulated_drive
8271 cmp al
,dl
;; int13 on emulated drive
8286 jmp _int13_cdemu
;; ELDX
not used
8289 and dl
,#0xE0 ;; mask to get device class, including cdroms
8290 cmp al
,dl
;; al is
0x00 or 0x80
8291 jne int13_cdemu_inactive
;; inactive
for device
class
8303 dec dl
;; real drive is dl
- 1
8306 int13_cdemu_inactive
:
8312 #endif // BX_ELTORITO_BOOT
8323 push dx
;; push eltorito value of dx instead of sp
8334 ;; now the
16-bit registers can be restored with
:
8335 ;; pop ds
; pop es
; popa
; iret
8336 ;; arguments passed to functions should be
8337 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8343 jmp _int13_diskette_function
8352 // ebx is modified: BSD 5.2.1 boot loader problem
8353 // someone should figure out which 32 bit register that actually are used
8370 ;; int13_harddisk modifies high word of EAX
8373 call _int13_harddisk
8386 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8394 ;; Get the boot sequence number out of the IPL memory
8396 mov ds
, bx
;; Set segment
8397 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8399 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8400 mov ds
, ax
;; and reset the segment to zero
.
8402 ;; Carry on in the INT
19h handler
, using the
new sequence number
8410 int19_relocated
: ;; Boot function
, relocated
8412 ;; int19 was beginning to be really
complex, so now it
8413 ;; just calls a C function that does the work
8424 ;; Start from the first boot
device (0, in AX
)
8426 mov ds
, bx
;; Set segment to write to the IPL memory
8427 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8428 mov ds
, ax
;; and reset the segment
.
8434 ;; Call the C code
for the next boot device
8435 call _int19_function
8437 ;; Boot failed
: invoke the boot recovery function
8443 int1c_handler
: ;; User Timer Tick
8447 ;----------------------
8448 ;- POST
: Floppy Drive
-
8449 ;----------------------
8455 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8457 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8459 mov
0x0440, al
;; diskette motor timeout counter
: not active
8460 mov
0x0441, al
;; diskette controller status
return code
8462 mov
0x0442, al
;; disk
& diskette controller status
register 0
8463 mov
0x0443, al
;; diskette controller status
register 1
8464 mov
0x0444, al
;; diskette controller status
register 2
8465 mov
0x0445, al
;; diskette controller cylinder number
8466 mov
0x0446, al
;; diskette controller head number
8467 mov
0x0447, al
;; diskette controller sector number
8468 mov
0x0448, al
;; diskette controller bytes written
8470 mov
0x048b, al
;; diskette configuration data
8472 ;; -----------------------------------------------------------------
8473 ;; (048F
) diskette controller information
8475 mov al
, #0x10 ;; get CMOS diskette drive type
8478 mov ah
, al
;; save byte to AH
8481 shr al
, #4 ;; look at top 4 bits for drive 0
8482 jz f0_missing
;; jump
if no drive0
8483 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8486 mov bl
, #0x00 ;; no drive0
8489 mov al
, ah
;; restore from AH
8490 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8491 jz f1_missing
;; jump
if no drive1
8492 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8494 ;; leave high bits in BL zerod
8495 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8496 ;; -----------------------------------------------------------------
8499 mov
0x0490, al
;; diskette
0 media state
8500 mov
0x0491, al
;; diskette
1 media state
8502 ;; diskette
0,1 operational starting state
8503 ;; drive type has
not been determined
,
8504 ;; has no changed detection line
8508 mov
0x0494, al
;; diskette
0 current cylinder
8509 mov
0x0495, al
;; diskette
1 current cylinder
8512 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8514 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8515 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8516 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8521 ;--------------------
8522 ;- POST
: HARD DRIVE
-
8523 ;--------------------
8524 ; relocated here because the primary POST area isnt big enough
.
8527 // INT 76h calls INT 15h function ax=9100
8529 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8535 mov
0x0474, al
/* hard disk status of last operation */
8536 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8537 mov
0x048c, al
/* hard disk status register */
8538 mov
0x048d, al
/* hard disk error register */
8539 mov
0x048e, al
/* hard disk task complete flag */
8541 mov
0x0475, al
/* hard disk number attached */
8543 mov
0x0476, al
/* hard disk control byte */
8544 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8545 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8546 ;; INT
41h
: hard disk
0 configuration pointer
8547 ;; INT
46h
: hard disk
1 configuration pointer
8548 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8549 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8551 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8563 cmp al
, #47 ;; decimal 47 - user definable
8567 ;; CMOS purpose param table offset
8568 ;; 1b cylinders low
0
8569 ;; 1c cylinders high
1
8571 ;; 1e write pre
-comp low
5
8572 ;; 1f write pre
-comp high
6
8573 ;; 20 retries
/bad map
/heads
>8 8
8574 ;; 21 landing zone low C
8575 ;; 22 landing zone high D
8576 ;; 23 sectors
/track E
8581 ;;; Filling EBDA table
for hard disk
0.
8589 mov (0x003d + 0x05), ax
;; write precomp word
8594 mov (0x003d + 0x08), al
;; drive control byte
8603 mov (0x003d + 0x0C), ax
;; landing zone word
8605 mov al
, #0x1c ;; get cylinders word in AX
8607 in al
, #0x71 ;; high byte
8611 in al
, #0x71 ;; low byte
8612 mov bx
, ax
;; BX
= cylinders
8617 mov cl
, al
;; CL
= heads
8622 mov dl
, al
;; DL
= sectors
8625 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8627 hd0_post_physical_chs
:
8628 ;; no logical CHS mapping used
, just physical CHS
8629 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8630 mov (0x003d + 0x00), bx
;; number of physical cylinders
8631 mov (0x003d + 0x02), cl
;; number of physical heads
8632 mov (0x003d + 0x0E), dl
;; number of physical sectors
8635 hd0_post_logical_chs
:
8636 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8637 mov (0x003d + 0x09), bx
;; number of physical cylinders
8638 mov (0x003d + 0x0b), cl
;; number of physical heads
8639 mov (0x003d + 0x04), dl
;; number of physical sectors
8640 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8642 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8645 jnbe hd0_post_above_2048
8646 ;; 1024 < c
<= 2048 cylinders
8649 jmp hd0_post_store_logical
8651 hd0_post_above_2048
:
8653 jnbe hd0_post_above_4096
8654 ;; 2048 < c
<= 4096 cylinders
8657 jmp hd0_post_store_logical
8659 hd0_post_above_4096
:
8661 jnbe hd0_post_above_8192
8662 ;; 4096 < c
<= 8192 cylinders
8665 jmp hd0_post_store_logical
8667 hd0_post_above_8192
:
8668 ;; 8192 < c
<= 16384 cylinders
8672 hd0_post_store_logical
:
8673 mov (0x003d + 0x00), bx
;; number of physical cylinders
8674 mov (0x003d + 0x02), cl
;; number of physical heads
8676 mov cl
, #0x0f ;; repeat count
8677 mov si
, #0x003d ;; offset to disk0 FDPT
8678 mov al
, #0x00 ;; sum
8679 hd0_post_checksum_loop
:
8683 jnz hd0_post_checksum_loop
8684 not al
;; now take
2s complement
8687 ;;; Done filling EBDA table
for hard disk
0.
8691 ;; is there really a second hard disk
? if not, return now
8699 ;; check that the hd type is really
0x0f.
8704 ;; check that the extended type is
47 - user definable
8708 cmp al
, #47 ;; decimal 47 - user definable
8713 ;; CMOS purpose param table offset
8714 ;; 0x24 cylinders low
0
8715 ;; 0x25 cylinders high
1
8717 ;; 0x27 write pre
-comp low
5
8718 ;; 0x28 write pre
-comp high
6
8720 ;; 0x2a landing zone low C
8721 ;; 0x2b landing zone high D
8722 ;; 0x2c sectors
/track E
8723 ;;; Fill EBDA table
for hard disk
1.
8733 mov (0x004d + 0x05), ax
;; write precomp word
8738 mov (0x004d + 0x08), al
;; drive control byte
8747 mov (0x004d + 0x0C), ax
;; landing zone word
8749 mov al
, #0x25 ;; get cylinders word in AX
8751 in al
, #0x71 ;; high byte
8755 in al
, #0x71 ;; low byte
8756 mov bx
, ax
;; BX
= cylinders
8761 mov cl
, al
;; CL
= heads
8766 mov dl
, al
;; DL
= sectors
8769 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8771 hd1_post_physical_chs
:
8772 ;; no logical CHS mapping used
, just physical CHS
8773 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8774 mov (0x004d + 0x00), bx
;; number of physical cylinders
8775 mov (0x004d + 0x02), cl
;; number of physical heads
8776 mov (0x004d + 0x0E), dl
;; number of physical sectors
8779 hd1_post_logical_chs
:
8780 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8781 mov (0x004d + 0x09), bx
;; number of physical cylinders
8782 mov (0x004d + 0x0b), cl
;; number of physical heads
8783 mov (0x004d + 0x04), dl
;; number of physical sectors
8784 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8786 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8789 jnbe hd1_post_above_2048
8790 ;; 1024 < c
<= 2048 cylinders
8793 jmp hd1_post_store_logical
8795 hd1_post_above_2048
:
8797 jnbe hd1_post_above_4096
8798 ;; 2048 < c
<= 4096 cylinders
8801 jmp hd1_post_store_logical
8803 hd1_post_above_4096
:
8805 jnbe hd1_post_above_8192
8806 ;; 4096 < c
<= 8192 cylinders
8809 jmp hd1_post_store_logical
8811 hd1_post_above_8192
:
8812 ;; 8192 < c
<= 16384 cylinders
8816 hd1_post_store_logical
:
8817 mov (0x004d + 0x00), bx
;; number of physical cylinders
8818 mov (0x004d + 0x02), cl
;; number of physical heads
8820 mov cl
, #0x0f ;; repeat count
8821 mov si
, #0x004d ;; offset to disk0 FDPT
8822 mov al
, #0x00 ;; sum
8823 hd1_post_checksum_loop
:
8827 jnz hd1_post_checksum_loop
8828 not al
;; now take
2s complement
8831 ;;; Done filling EBDA table
for hard disk
1.
8835 ;--------------------
8836 ;- POST
: EBDA segment
8837 ;--------------------
8838 ; relocated here because the primary POST area isnt big enough
.
8843 mov byte ptr
[0x0], #EBDA_SIZE
8845 xor ax
, ax
; mov EBDA seg into
40E
8847 mov word ptr
[0x40E], #EBDA_SEG
8850 ;--------------------
8851 ;- POST
: EOI
+ jmp via
[0x40:67)
8852 ;--------------------
8853 ; relocated here because the primary POST area isnt big enough
.
8863 ;--------------------
8866 out
#0xA0, al ;; slave PIC EOI
8869 out
#0x20, al ;; master PIC EOI
8872 ;--------------------
8874 ;; in
: AL in BCD format
8875 ;; out
: AL in binary format
, AH will always be
0
8878 and bl
, #0x0f ;; bl has low digit
8879 shr al
, #4 ;; al has high digit
8881 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8882 add al
, bl
;; then add low digit
8885 ;--------------------
8887 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8888 ;; Timer Ticks Roller
Flag (0x470:byte
)
8889 ;; The Timer Ticks Count needs to be set according to
8890 ;; the current CMOS time
, as
if ticks have been occurring
8891 ;; at
18.2hz since midnight up to
this point
. Calculating
8892 ;; this is a little complicated
. Here are the factors I gather
8893 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8894 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8895 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8896 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8897 ;; the timer
. With a maximum
16bit timer count
, this is again
8898 ;; divided down by
65536 to
18.2hz
.
8900 ;; 14,318,180 Hz clock
8901 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8902 ;; /4 = 1,193,181 Hz fed to timer
8903 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8904 ;; 1 second
= 18.20650736 ticks
8905 ;; 1 minute
= 1092.390442 ticks
8906 ;; 1 hour
= 65543.42651 ticks
8908 ;; Given the values in the CMOS clock
, one could calculate
8909 ;; the number of ticks by the following
:
8910 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8911 ;; (BcdToBin(minutes
) * 1092.3904)
8912 ;; (BcdToBin(hours
) * 65543.427)
8913 ;; To get a little more accuracy
, since Im
using integer
8914 ;; arithmatic
, I use
:
8915 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8916 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8917 ;; (BcdToBin(hours
) * 65543427) / 1000
8922 xor eax
, eax
;; clear EAX
8925 in al
, #0x71 ;; AL has CMOS seconds in BCD
8926 call BcdToBin
;; EAX now has seconds in binary
8932 mov ecx
, eax
;; ECX will accumulate total ticks
8935 xor eax
, eax
;; clear EAX
8938 in al
, #0x71 ;; AL has CMOS minutes in BCD
8939 call BcdToBin
;; EAX now has minutes in binary
8945 add ecx
, eax
;; add to total ticks
8948 xor eax
, eax
;; clear EAX
8951 in al
, #0x71 ;; AL has CMOS hours in BCD
8952 call BcdToBin
;; EAX now has hours in binary
8958 add ecx
, eax
;; add to total ticks
8960 mov
0x46C, ecx
;; Timer Ticks Count
8962 mov
0x470, al
;; Timer Ticks Rollover Flag
8965 ;--------------------
8967 ;; record completion in BIOS task complete flag
8979 ;--------------------
8984 #include "apmbios.S"
8988 #include "apmbios.S"
8991 #include "apmbios.S"
8995 ;--------------------
9000 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9001 dw bios32_entry_point
, 0xf ;; 32 bit physical address
9002 db
0 ;; revision level
9003 ;; length in paragraphs
and checksum stored in a word to prevent errors
9004 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
9005 & 0xff) << 8) + 0x01
9006 db
0,0,0,0,0 ;; reserved
9011 cmp eax
, #0x49435024 ;; "$PCI"
9013 mov eax
, #0x80000000
9018 #ifdef PCI_FIXED_HOST_BRIDGE
9019 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9022 ;; say ok
if a device is present
9023 cmp eax
, #0xffffffff
9026 mov ebx
, #0x000f0000
9028 mov edx
, #pcibios_protected
9035 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9046 cmp al
, #0x01 ;; installation check
9050 mov edx
, #0x20494350 ;; "PCI "
9053 pci_pro_f02
: ;; find pci device
9061 call pci_pro_select_reg
9075 pci_pro_f03
: ;; find
class code
9081 call pci_pro_select_reg
9086 jne pci_pro_nextdev2
9093 jne pci_pro_devloop2
9096 pci_pro_f08
: ;; read configuration byte
9099 call pci_pro_select_reg
9108 pci_pro_f09
: ;; read configuration word
9111 call pci_pro_select_reg
9120 pci_pro_f0a
: ;; read configuration dword
9123 call pci_pro_select_reg
9130 pci_pro_f0b
: ;; write configuration byte
9133 call pci_pro_select_reg
9142 pci_pro_f0c
: ;; write configuration word
9145 call pci_pro_select_reg
9154 pci_pro_f0d
: ;; write configuration dword
9157 call pci_pro_select_reg
9170 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9180 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9204 mov eax
, #0x80000000
9209 #ifdef PCI_FIXED_HOST_BRIDGE
9210 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9213 ;; say ok
if a device is present
9214 cmp eax
, #0xffffffff
9225 cmp al
, #0x01 ;; installation check
9230 mov edx
, #0x20494350 ;; "PCI "
9232 mov di
, #pcibios_protected
9235 pci_real_f02
: ;; find pci device
9245 call pci_real_select_reg
9249 jne pci_real_nextdev
9256 jne pci_real_devloop
9261 pci_real_f03
: ;; find
class code
9267 call pci_real_select_reg
9272 jne pci_real_nextdev2
9279 jne pci_real_devloop2
9284 pci_real_f08
: ;; read configuration byte
9287 call pci_real_select_reg
9296 pci_real_f09
: ;; read configuration word
9299 call pci_real_select_reg
9308 pci_real_f0a
: ;; read configuration dword
9311 call pci_real_select_reg
9318 pci_real_f0b
: ;; write configuration byte
9321 call pci_real_select_reg
9330 pci_real_f0c
: ;; write configuration word
9333 call pci_real_select_reg
9342 pci_real_f0d
: ;; write configuration dword
9345 call pci_real_select_reg
9352 pci_real_f0e
: ;; get irq routing options
9354 jne pci_real_unknown
9356 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9357 jb pci_real_too_small
9359 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9367 mov si
, #pci_routing_table_structure_start
9375 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9384 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9388 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9406 pci_real_select_reg
:
9420 pci_routing_table_structure
:
9421 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9423 dw
32 + (6 * 16) ;; table size
9424 db
0 ;; PCI interrupt router bus
9425 db
0x08 ;; PCI interrupt router DevFunc
9426 dw
0x0000 ;; PCI exclusive IRQs
9427 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9428 dw
0x7000 ;; compatible PCI interrupt router device ID
9429 dw
0,0 ;; Miniport data
9430 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9432 pci_routing_table_structure_start
:
9433 ;; first slot entry PCI
-to
-ISA (embedded
)
9434 db
0 ;; pci bus number
9435 db
0x08 ;; pci device
number (bit
7-3)
9436 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9437 dw
0xdef8 ;; IRQ bitmap INTA
#
9438 db
0x61 ;; link value INTB
#
9439 dw
0xdef8 ;; IRQ bitmap INTB
#
9440 db
0x62 ;; link value INTC
#
9441 dw
0xdef8 ;; IRQ bitmap INTC
#
9442 db
0x63 ;; link value INTD
#
9443 dw
0xdef8 ;; IRQ bitmap INTD
#
9444 db
0 ;; physical
slot (0 = embedded
)
9446 ;; second slot entry
: 1st PCI slot
9447 db
0 ;; pci bus number
9448 db
0x10 ;; pci device
number (bit
7-3)
9449 db
0x61 ;; link value INTA
#
9450 dw
0xdef8 ;; IRQ bitmap INTA
#
9451 db
0x62 ;; link value INTB
#
9452 dw
0xdef8 ;; IRQ bitmap INTB
#
9453 db
0x63 ;; link value INTC
#
9454 dw
0xdef8 ;; IRQ bitmap INTC
#
9455 db
0x60 ;; link value INTD
#
9456 dw
0xdef8 ;; IRQ bitmap INTD
#
9457 db
1 ;; physical
slot (0 = embedded
)
9459 ;; third slot entry
: 2nd PCI slot
9460 db
0 ;; pci bus number
9461 db
0x18 ;; pci device
number (bit
7-3)
9462 db
0x62 ;; link value INTA
#
9463 dw
0xdef8 ;; IRQ bitmap INTA
#
9464 db
0x63 ;; link value INTB
#
9465 dw
0xdef8 ;; IRQ bitmap INTB
#
9466 db
0x60 ;; link value INTC
#
9467 dw
0xdef8 ;; IRQ bitmap INTC
#
9468 db
0x61 ;; link value INTD
#
9469 dw
0xdef8 ;; IRQ bitmap INTD
#
9470 db
2 ;; physical
slot (0 = embedded
)
9472 ;; 4th slot entry
: 3rd PCI slot
9473 db
0 ;; pci bus number
9474 db
0x20 ;; pci device
number (bit
7-3)
9475 db
0x63 ;; link value INTA
#
9476 dw
0xdef8 ;; IRQ bitmap INTA
#
9477 db
0x60 ;; link value INTB
#
9478 dw
0xdef8 ;; IRQ bitmap INTB
#
9479 db
0x61 ;; link value INTC
#
9480 dw
0xdef8 ;; IRQ bitmap INTC
#
9481 db
0x62 ;; link value INTD
#
9482 dw
0xdef8 ;; IRQ bitmap INTD
#
9483 db
3 ;; physical
slot (0 = embedded
)
9485 ;; 5th slot entry
: 4rd PCI slot
9486 db
0 ;; pci bus number
9487 db
0x28 ;; pci device
number (bit
7-3)
9488 db
0x60 ;; link value INTA
#
9489 dw
0xdef8 ;; IRQ bitmap INTA
#
9490 db
0x61 ;; link value INTB
#
9491 dw
0xdef8 ;; IRQ bitmap INTB
#
9492 db
0x62 ;; link value INTC
#
9493 dw
0xdef8 ;; IRQ bitmap INTC
#
9494 db
0x63 ;; link value INTD
#
9495 dw
0xdef8 ;; IRQ bitmap INTD
#
9496 db
4 ;; physical
slot (0 = embedded
)
9498 ;; 6th slot entry
: 5rd PCI slot
9499 db
0 ;; pci bus number
9500 db
0x30 ;; pci device
number (bit
7-3)
9501 db
0x61 ;; link value INTA
#
9502 dw
0xdef8 ;; IRQ bitmap INTA
#
9503 db
0x62 ;; link value INTB
#
9504 dw
0xdef8 ;; IRQ bitmap INTB
#
9505 db
0x63 ;; link value INTC
#
9506 dw
0xdef8 ;; IRQ bitmap INTC
#
9507 db
0x60 ;; link value INTD
#
9508 dw
0xdef8 ;; IRQ bitmap INTD
#
9509 db
5 ;; physical
slot (0 = embedded
)
9511 pci_routing_table_structure_end
:
9517 pcibios_init_sel_reg
:
9529 pcibios_init_iomem_bases
:
9532 mov eax
, #0xe0000000 ;; base for memory init
9534 mov ax
, #0xc000 ;; base for i/o init
9536 mov ax
, #0x0010 ;; start at base address #0
9541 call pcibios_init_sel_reg
9546 mov dl
, #0x04 ;; disable i/o and memory space access
9547 call pcibios_init_sel_reg
9554 call pcibios_init_sel_reg
9560 mov eax
, #0xffffffff
9565 xor eax
, #0xffffffff
9569 add eax
, ecx
;; calculate next free mem base
9570 add eax
, #0x01000000
9571 and eax
, #0xff000000
9585 add ax
, cx
;; calculate next free i
/o base
9593 je enable_iomem_space
9594 mov byte ptr
[bp
-8], al
9595 jmp pci_init_io_loop2
9597 mov dl
, #0x04 ;; enable i/o and memory space access if available
9598 call pcibios_init_sel_reg
9604 mov byte ptr
[bp
-8], #0x10
9607 jne pci_init_io_loop1
9612 pcibios_init_set_elcr
:
9636 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9641 mov si
, #pci_routing_table_structure
9645 call pcibios_init_sel_reg
9648 cmp eax
, [si
+12] ;; check irq router
9651 call pcibios_init_sel_reg
9652 push bx
;; save irq router bus
+ devfunc
9655 out dx
, ax
;; reset PIRQ route control
9662 add si
, #0x20 ;; set pointer to 1st entry
9664 mov ax
, #pci_irq_list
9673 call pcibios_init_sel_reg
9677 jnz pci_test_int_pin
9683 call pcibios_init_sel_reg
9688 dec al
;; determine pirq reg
9697 call pcibios_init_sel_reg
9704 mov bx
, [bp
-2] ;; pci irq list pointer
9709 call pcibios_init_set_elcr
9713 add bl
, [bp
-3] ;; pci function number
9715 call pcibios_init_sel_reg
9722 jnz pci_init_irq_loop2
9725 mov byte ptr
[bp
-3], #0x00
9726 loop pci_init_irq_loop1
9733 #endif // BX_ROMBIOS32
9734 #endif // BX_PCIBIOS
9738 ;; save a20
and enable it
9744 ;; save SS
:SP to the BDA
9751 lidt
[pmode_IDT_info
]
9753 lgdt
[rombios32_gdt_48
]
9754 ;; set PE bit in CR0
9758 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
9761 dw
0x000f ;; high
16 bit address
9766 ;; init data segments
9776 ;; copy rombios32 code to
ram (ram offset
= 1MB
)
9777 mov esi
, #0xfffe0000
9778 mov edi
, #0x00040000
9779 mov ecx
, #0x10000 / 4
9783 ;; init the stack pointer
9784 mov esp
, #0x00080000
9786 ;; call rombios32 code
9787 mov eax
, #0x00040000
9790 ;; reset the
memory (some boot loaders such as syslinux suppose
9791 ;; that the memory is set to zero
)
9792 mov edi
, #0x00040000
9793 mov ecx
, #0x40000 / 4
9798 ;; return to
16 bit
protected mode first
9805 ;; restore data segment limits to
0xffff
9813 ;; reset PE bit in CR0
9818 ;; far jump to flush CPU queue after transition to real mode
9819 JMP_AP(0xf000, rombios32_real_mode
)
9821 rombios32_real_mode
:
9822 ;; restore IDT to normal real
-mode defaults
9824 lidt
[rmode_IDT_info
]
9832 ;; restore SS
:SP from the BDA
9849 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
9850 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
9851 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
9852 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
9856 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9861 and al
, #0xdf ; clear input mode
9871 mov
[bx
+0x408], dx
; Parallel I
/O address
9873 mov
[bx
+0x478], cl
; Parallel printer timeout
9878 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9897 mov
[bx
+0x400], dx
; Serial I
/O address
9899 mov
[bx
+0x47c], cl
; Serial timeout
9926 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
9927 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
9935 ;; Scan
for existence of valid expansion ROMS
.
9936 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9937 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9938 ;; System ROM
: only
0xE0000
9944 ;; 2 ROM length in
512-byte blocks
9945 ;; 3 ROM initialization entry
point (FAR CALL
)
9950 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9951 cmp
[0], #0xAA55 ;; look for signature
9952 jne rom_scan_increment
9954 jnz rom_scan_increment
9955 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9957 ;; We want our increment in
512-byte quantities
, rounded to
9958 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9960 jz block_count_rounded
9961 and al
, #0xfc ;; needs rounding up
9963 block_count_rounded
:
9965 xor bx
, bx
;; Restore DS back to
0000:
9969 ;; Push addr of ROM entry point
9971 push
#0x0003 ;; Push offset
9973 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
9974 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
9979 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9980 db
0xff ;; call_far ss
:[bp
+0]
9983 cli
;; In
case expansion ROM BIOS turns IF on
9984 add sp
, #2 ;; Pop offset value
9985 pop cx
;; Pop seg
value (restore CX
)
9987 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
9988 ;; to init all the ROMs
and then go back
and build an IPL table of
9989 ;; all the bootable devices
, but we can get away with one pass
.
9990 mov ds
, cx
;; ROM base
9991 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
9992 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
9993 cmp ax
, #0x5024 ;; we look for signature "$PnP"
9998 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
9999 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
10002 ;; Found a device that thinks it can boot the system
. Record its BEV
and product name string
.
10003 mov di
, 0x10[bx
] ;; Pointer to the product name string
or zero
if none
10004 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
10006 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
10007 cmp bx
, #IPL_TABLE_ENTRIES
10008 je no_bev
;; Get out
if the table is full
10009 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
10010 mov
0[bx
], #IPL_TYPE_BEV ;; This entry is a BEV device
10011 mov
6[bx
], cx
;; Build a far pointer from the segment
...
10012 mov
4[bx
], ax
;; and the offset
10015 mov
0xA[bx
], cx
;; Build a far pointer from the segment
...
10016 mov
8[bx
], di
;; and the offset
10018 shr bx
, #0x4 ;; Turn the offset back into a count
10019 inc bx
;; We have one more entry now
10020 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
10023 pop di
;; Restore DI
10024 pop ax
;; Restore AX
10025 rom_scan_increment
:
10026 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
10027 ;; because the segment selector is shifted left
4 bits
.
10029 pop ax
;; Restore AX
10033 xor ax
, ax
;; Restore DS back to
0000:
10037 ;; for 'C' strings
and other data
, insert them here with
10038 ;; a the following hack
:
10039 ;; DATA_SEG_DEFS_HERE
10042 ;; the following area can be used to write dynamically generated tables
10044 bios_table_area_start
:
10046 dd bios_table_area_end
- bios_table_area_start
- 8;
10051 .org
0xe05b ; POST Entry Point
10052 bios_table_area_end
:
10057 ;; first reset the DMA controllers
10061 ;; then initialize the DMA controllers
10063 out
0xD6, al
; cascade mode of channel
4 enabled
10065 out
0xD4, al
; unmask channel
4
10067 ;; Examine CMOS shutdown status
.
10075 ;; Reset CMOS shutdown status
.
10077 out
0x70, AL
; select CMOS
register Fh
10079 out
0x71, AL
; set shutdown action to normal
10081 ;; Examine CMOS shutdown status
.
10084 ;; 0x00, 0x09, 0x0D+ = normal startup
10092 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
10096 ;; Examine CMOS shutdown status
.
10097 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
10099 call _shutdown_status_panic
10105 ; 0xb0, 0x20, /* mov al, #0x20 */
10106 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10116 ; case 0: normal startup
10125 ;; zero out BIOS data
area (40:00..40:ff
)
10127 mov cx
, #0x0080 ;; 128 words
10133 call _log_bios_start
10135 ;; set all interrupts to
default handler
10136 xor bx
, bx
;; offset index
10137 mov cx
, #0x0100 ;; counter (256 interrupts)
10138 mov ax
, #dummy_iret_handler
10146 loop post_default_ints
10148 ;; set vector
0x79 to zero
10149 ;; this is used by
'gardian angel' protection system
10150 SET_INT_VECTOR(0x79, #0, #0)
10152 ;; base memory in K
40:13 (word
)
10153 mov ax
, #BASE_MEM_IN_K
10157 ;; Manufacturing Test
40:12
10160 ;; Warm Boot Flag
0040:0072
10161 ;; value of
1234h
= skip memory checks
10165 ;; Printer Services vector
10166 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10168 ;; Bootstrap failure vector
10169 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10171 ;; Bootstrap Loader vector
10172 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10174 ;; User Timer Tick vector
10175 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10177 ;; Memory Size Check vector
10178 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10180 ;; Equipment Configuration Check vector
10181 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10184 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10190 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10191 ;; int 1C already points at
dummy_iret_handler (above
)
10192 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10194 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10199 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10200 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10204 mov
0x0417, al
/* keyboard shift flags, set 1 */
10205 mov
0x0418, al
/* keyboard shift flags, set 2 */
10206 mov
0x0419, al
/* keyboard alt-numpad work area */
10207 mov
0x0471, al
/* keyboard ctrl-break flag */
10208 mov
0x0497, al
/* keyboard status flags 4 */
10210 mov
0x0496, al
/* keyboard status flags 3 */
10213 /* keyboard head of buffer pointer */
10217 /* keyboard end of buffer pointer */
10220 /* keyboard pointer to start of buffer */
10224 /* keyboard pointer to end of buffer */
10228 /* init the keyboard */
10229 call _keyboard_init
10231 ;; mov CMOS Equipment Byte to BDA Equipment Word
10240 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10244 mov cl
, #0x14 ; timeout value
10245 mov dx
, #0x378 ; Parallel I/O address, port 1
10246 call detect_parport
10247 mov dx
, #0x278 ; Parallel I/O address, port 2
10248 call detect_parport
10250 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10252 or ax
, bx
; set number of parallel ports
10256 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10257 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10259 mov cl
, #0x0a ; timeout value
10260 mov dx
, #0x03f8 ; Serial I/O address, port 1
10262 mov dx
, #0x02f8 ; Serial I/O address, port 2
10264 mov dx
, #0x03e8 ; Serial I/O address, port 3
10266 mov dx
, #0x02e8 ; Serial I/O address, port 4
10269 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10271 or ax
, bx
; set number of serial port
10275 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10276 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10277 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10278 ;; BIOS DATA AREA
0x4CE ???
10279 call timer_tick_post
10281 ;; PS
/2 mouse setup
10282 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10284 ;; IRQ13 (FPU exception
) setup
10285 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10288 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10291 mov al
, #0x11 ; send initialisation commands
10306 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10307 #if BX_USE_PS2_MOUSE
10312 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10314 mov cx
, #0xc000 ;; init vga bios
10318 call _print_bios_banner
10321 call rombios32_init
10324 call pcibios_init_iomem_bases
10325 call pcibios_init_irqs
10326 #endif //BX_PCIBIOS
10332 call floppy_drive_post
10337 ;; Hard Drive setup
10339 call hard_drive_post
10342 ;; ATA
/ATAPI driver setup
10347 #else // BX_USE_ATADRV
10350 ;; Hard Drive setup
10352 call hard_drive_post
10354 #endif // BX_USE_ATADRV
10356 #if BX_ELTORITO_BOOT
10358 ;; eltorito floppy
/harddisk emulation from cd
10362 #endif // BX_ELTORITO_BOOT
10364 call _init_boot_vectors
10366 mov cx
, #0xc800 ;; init option roms
10370 sti
;; enable interrupts
10373 .org
0xe2c3 ; NMI Handler Entry Point
10375 ;; FIXME the NMI handler should
not panic
10376 ;; but iret when called from
int75 (fpu exception
)
10377 call _nmi_handler_msg
10381 out
0xf0, al
// clear irq13
10382 call eoi_both_pics
// clear interrupt
10383 int 2 // legacy nmi call
10386 ;-------------------------------------------
10387 ;- INT
13h Fixed Disk Services Entry Point
-
10388 ;-------------------------------------------
10389 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10391 //JMPL(int13_relocated)
10392 jmp int13_relocated
10394 .org
0xe401 ; Fixed Disk Parameter Table
10399 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10402 jmp int19_relocated
10403 ;-------------------------------------------
10404 ;- System BIOS Configuration Data Table
10405 ;-------------------------------------------
10406 .org BIOS_CONFIG_TABLE
10407 db
0x08 ; Table
size (bytes
) -Lo
10408 db
0x00 ; Table
size (bytes
) -Hi
10413 ; b7
: 1=DMA channel
3 used by hard disk
10414 ; b6
: 1=2 interrupt controllers present
10415 ; b5
: 1=RTC present
10416 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10417 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10418 ; b2
: 1=extended BIOS data area used
10419 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10420 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10424 (BX_CALL_INT15_4F
<< 4) | \
10426 (BX_USE_EBDA
<< 2) | \
10430 ; b7
: 1=32-bit DMA supported
10431 ; b6
: 1=int16h
, function
9 supported
10432 ; b5
: 1=int15h
/C6h (get POS data
) supported
10433 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10434 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10435 ; b2
: 1=non
-8042 kb controller
10436 ; b1
: 1=data streaming supported
10450 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10451 ; b3
: SCSI on system board
10452 ; b2
: info panel installed
10453 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10454 ; b0
: SCSI supported in IML
10458 ; b6
: EEPROM present
10459 ; b5
-3: ABIOS
presence (011 = not supported
)
10461 ; b1
: memory split above
16Mb supported
10462 ; b0
: POSTEXT directly supported by POST
10464 ; Feature byte
5 (IBM
)
10465 ; b1
: enhanced mouse
10471 .org
0xe729 ; Baud Rate Generator Table
10476 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10482 call _int14_function
10488 ;----------------------------------------
10489 ;- INT
16h Keyboard Service Entry Point
-
10490 ;----------------------------------------
10506 call _int16_function
10516 and BYTE
[bp
+ 0x06], #0xbf
10524 or BYTE
[bp
+ 0x06], #0x40
10532 int16_wait_for_key
:
10536 jne int16_key_found
10540 /* no key yet, call int 15h, function AX=9002 */
10541 0x50, /* push AX */
10542 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10543 0xcd, 0x15, /* int 15h */
10545 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10547 jmp int16_wait_for_key
10552 call _int16_function
10557 /* notify int16 complete w/ int 15h, function AX=9102 */
10558 0x50, /* push AX */
10559 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10560 0xcd, 0x15, /* int 15h */
10567 ;-------------------------------------------------
10568 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10569 ;-------------------------------------------------
10575 mov al
, #0xAD ;;disable keyboard
10584 in al
, #0x60 ;;read key from keyboard controller
10588 #ifdef BX_CALL_INT15_4F
10589 mov ah
, #0x4f ;; allow for keyboard intercept
10595 ;; check
for extended key
10597 jne int09_check_pause
10600 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10602 mov BYTE
[0x496], al
10605 int09_check_pause
: ;; check
for pause key
10607 jne int09_process_key
10610 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10612 mov BYTE
[0x496], al
10618 call _int09_function
10624 call eoi_master_pic
10627 mov al
, #0xAE ;;enable keyboard
10633 ;----------------------------------------
10634 ;- INT
13h Diskette Service Entry Point
-
10635 ;----------------------------------------
10638 jmp int13_noeltorito
10640 ;---------------------------------------------
10641 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10642 ;---------------------------------------------
10643 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10653 mov al
, #0x08 ; sense interrupt status
10671 xor ax
, ax
;; segment
0000
10673 call eoi_master_pic
10675 or al
, #0x80 ;; diskette interrupt has occurred
10683 .org
0xefc7 ; Diskette Controller Parameter Table
10684 diskette_param_table
:
10685 ;; Since no provisions are made
for multiple drive types
, most
10686 ;; values in
this table are ignored
. I set parameters
for 1.44M
10689 db
0x02 ;; head load time
0000001, DMA used
10701 ;----------------------------------------
10702 ;- INT17h
: Printer Service Entry Point
-
10703 ;----------------------------------------
10710 call _int17_function
10715 diskette_param_table2
:
10716 ;; New diskette parameter table adding
3 parameters from IBM
10717 ;; Since no provisions are made
for multiple drive types
, most
10718 ;; values in
this table are ignored
. I set parameters
for 1.44M
10721 db
0x02 ;; head load time
0000001, DMA used
10731 db
79 ;; maximum track
10732 db
0 ;; data transfer rate
10733 db
4 ;; drive type in cmos
10735 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10742 .org
0xf065 ; INT
10h Video Support Service Entry Point
10744 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10747 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10752 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10753 ; ??? different
for Pentium (machine check
)?
10765 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10777 .org
0xf859 ; INT
15h System Services Entry Point
10791 #if BX_USE_PS2_MOUSE
10793 je int15_handler_mouse
10795 call _int15_function
10796 int15_handler_mouse_ret
:
10798 int15_handler32_ret
:
10808 #if BX_USE_PS2_MOUSE
10809 int15_handler_mouse
:
10810 call _int15_function_mouse
10811 jmp int15_handler_mouse_ret
10816 call _int15_function32
10818 jmp int15_handler32_ret
10820 ;; Protected mode IDT descriptor
10822 ;; I just make the limit
0, so the machine will shutdown
10823 ;; if an exception occurs during
protected mode memory
10826 ;; Set base to f0000 to correspond to beginning of BIOS
,
10827 ;; in
case I actually define an IDT later
10831 dw
0x0000 ;; limit
15:00
10832 dw
0x0000 ;; base
15:00
10833 db
0x0f ;; base
23:16
10835 ;; Real mode IDT descriptor
10837 ;; Set to typical real
-mode values
.
10842 dw
0x03ff ;; limit
15:00
10843 dw
0x0000 ;; base
15:00
10844 db
0x00 ;; base
23:16
10850 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10863 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10864 mov ds
, ax
; on
16bit
protected mode
.
10865 jmp int1a_callfunction
10872 int1a_callfunction
:
10873 call _int1a_function
10879 ;; int70h
: IRQ8
- CMOS RTC
10886 call _int70_function
10894 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10902 ;; time to turn off
drive(s
)?
10905 jz int08_floppy_off
10908 jnz int08_floppy_off
10909 ;; turn
motor(s
) off
10918 mov eax
, 0x046c ;; get ticks dword
10921 ;; compare eax to one days worth of timer ticks at
18.2 hz
10922 cmp eax
, #0x001800B0
10923 jb int08_store_ticks
10924 ;; there has been a midnight rollover at
this point
10925 xor eax
, eax
;; zero out counter
10926 inc BYTE
0x0470 ;; increment rollover flag
10929 mov
0x046c, eax
;; store
new ticks dword
10930 ;; chain to user timer tick INT
#0x1c
10932 //;; call_ep [ds:loc]
10933 //CALL_EP( 0x1c << 2 )
10936 call eoi_master_pic
10941 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10945 .ascii BIOS_COPYRIGHT_STRING
10947 ;------------------------------------------------
10948 ;- IRET Instruction
for Dummy Interrupt Handler
-
10949 ;------------------------------------------------
10950 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10951 dummy_iret_handler
:
10954 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10958 .org
0xfff0 ; Power
-up Entry Point
10961 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10962 .ascii BIOS_BUILD_DATE
10964 .org
0xfffe ; System Model ID
10968 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10971 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10972 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10973 * This font is public domain
10975 static Bit8u vgafont8
[128*8]=
10977 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10978 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10979 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10980 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10981 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10982 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10983 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10984 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10985 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10986 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10987 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10988 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10989 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10990 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10991 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10992 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10993 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10994 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10995 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10996 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10997 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10998 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10999 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11000 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11001 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11002 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11003 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11004 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11005 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11006 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11007 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11008 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11009 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11010 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11011 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11012 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11013 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11014 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11015 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11016 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11017 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11018 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11019 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11020 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11021 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11022 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11023 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11024 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11025 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11026 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11027 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11028 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11029 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11030 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11031 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11032 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11033 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11034 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11035 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11036 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11037 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11038 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11039 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11040 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11041 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11042 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11043 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11044 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11045 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11046 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11047 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11048 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11049 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11050 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11051 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11052 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11053 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11054 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11055 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11056 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11057 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11058 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11059 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11060 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11061 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11062 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11063 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11064 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11065 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11066 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11067 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11068 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11069 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11070 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11071 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11072 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11073 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11074 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11075 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11076 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11077 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11078 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11079 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11080 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11081 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11082 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11083 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11084 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11085 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11086 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11087 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11088 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11089 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11090 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11091 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11092 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11093 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11094 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11095 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11096 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11097 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11098 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11099 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11100 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11101 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11102 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11103 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11104 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11109 // bcc-generated data will be placed here