1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.182 2007/08/01 17:09:51 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 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 // Define the application NAME
174 # define BX_APPNAME "QEMU"
175 #elif defined(PLEX86)
176 # define BX_APPNAME "Plex86"
178 # define BX_APPNAME "Bochs"
182 #if BX_USE_ATADRV && BX_CPU<3
183 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
185 #if BX_USE_ATADRV && !BX_USE_EBDA
186 # error ATA/ATAPI Driver can only be used if EBDA is available
188 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
189 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
191 #if BX_PCIBIOS && BX_CPU<3
192 # error PCI BIOS can only be used with 386+ cpu
194 #if BX_APM && BX_CPU<3
195 # error APM BIOS can only be used with 386+ cpu
198 // define this if you want to make PCIBIOS working on a specific bridge only
199 // undef enables PCIBIOS when at least one PCI device is found
200 // i440FX is emulated by Bochs and QEMU
201 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
204 // #$20 is hex 20 = 32
205 // #0x20 is hex 20 = 32
212 // all hex literals should be prefixed with '0x'
213 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
214 // no mov SEG-REG, #value, must mov register into seg-reg
215 // grep -i "mov[ ]*.s" rombios.c
217 // This is for compiling with gcc2 and gcc3
218 #define ASM_START #asm
219 #define ASM_END #endasm
233 ;; the HALT macro is called with the line number of the HALT call
.
234 ;; The line number is then sent to the PANIC_PORT
, causing Bochs
/Plex
235 ;; to print a BX_PANIC message
. This will normally halt the simulation
236 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
237 ;; However
, users can choose to make panics non
-fatal
and continue.
264 typedef unsigned char Bit8u
;
265 typedef unsigned short Bit16u
;
266 typedef unsigned short bx_bool
;
267 typedef unsigned long Bit32u
;
270 void memsetb(seg
,offset
,value
,count
);
271 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
272 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
274 // memset of count bytes
276 memsetb(seg
,offset
,value
,count
)
291 mov cx
, 10[bp
] ; count
294 mov ax
, 4[bp
] ; segment
296 mov ax
, 6[bp
] ; offset
298 mov al
, 8[bp
] ; value
313 // memcpy of count bytes
315 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
333 mov cx
, 12[bp
] ; count
336 mov ax
, 4[bp
] ; dsegment
338 mov ax
, 6[bp
] ; doffset
340 mov ax
, 8[bp
] ; ssegment
342 mov ax
, 10[bp
] ; soffset
360 // memcpy of count dword
362 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
380 mov cx
, 12[bp
] ; count
383 mov ax
, 4[bp
] ; dsegment
385 mov ax
, 6[bp
] ; doffset
387 mov ax
, 8[bp
] ; ssegment
389 mov ax
, 10[bp
] ; soffset
407 // read_dword and write_dword functions
408 static Bit32u
read_dword();
409 static void write_dword();
412 read_dword(seg
, offset
)
422 mov ax
, 4[bp
] ; segment
424 mov bx
, 6[bp
] ; offset
429 ;; ax
= return value (word
)
430 ;; dx
= return value (word
)
439 write_dword(seg
, offset
, data
)
451 mov ax
, 4[bp
] ; segment
453 mov bx
, 6[bp
] ; offset
454 mov ax
, 8[bp
] ; data word
455 mov
[bx
], ax
; write data word
458 mov ax
, 10[bp
] ; data word
459 mov
[bx
], ax
; write data word
468 // Bit32u (unsigned long) and long helper functions
497 cmp eax
, dword ptr
[di
]
516 mul eax
, dword ptr
[di
]
612 // for access to RAM area which is used by interrupt vectors
613 // and BIOS Data Area
616 unsigned char filler1
[0x400];
617 unsigned char filler2
[0x6c];
623 #define BiosData ((bios_data_t *) 0)
627 Bit16u heads
; // # heads
628 Bit16u cylinders
; // # cylinders
629 Bit16u spt
; // # sectors / track
649 Bit8u iface
; // ISA or PCI
650 Bit16u iobase1
; // IO Base 1
651 Bit16u iobase2
; // IO Base 2
656 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
657 Bit8u device
; // Detected type of attached devices (hd/cd/none)
658 Bit8u removable
; // Removable device flag
659 Bit8u lock
; // Locks for removable devices
660 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
661 Bit8u mode
; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
662 Bit16u blksize
; // block size
664 Bit8u translation
; // type of translation
665 chs_t lchs
; // Logical CHS
666 chs_t pchs
; // Physical CHS
668 Bit32u sectors
; // Total sectors count
673 ata_channel_t channels
[BX_MAX_ATA_INTERFACES
];
676 ata_device_t devices
[BX_MAX_ATA_DEVICES
];
678 // map between (bios hd id - 0x80) and ata channels
679 Bit8u hdcount
, hdidmap
[BX_MAX_ATA_DEVICES
];
681 // map between (bios cd id - 0xE0) and ata channels
682 Bit8u cdcount
, cdidmap
[BX_MAX_ATA_DEVICES
];
684 // Buffer for DPTE table
687 // Count of transferred sectors and bytes
694 // ElTorito Device Emulation data
698 Bit8u emulated_drive
;
699 Bit8u controller_index
;
702 Bit16u buffer_segment
;
709 #endif // BX_ELTORITO_BOOT
711 // for access to EBDA area
712 // The EBDA structure should conform to
713 // http://www.frontiernet.net/~fys/rombios.htm document
714 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
715 // EBDA must be at most 768 bytes; it lives at 0x9fc00, and the boot
716 // device tables are at 0x9ff00 -- 0x9ffff
718 unsigned char filler1
[0x3D];
720 // FDPT - Can be splitted in data members if needed
721 unsigned char fdpt0
[0x10];
722 unsigned char fdpt1
[0x10];
724 unsigned char filler2
[0xC4];
730 // El Torito Emulation data
732 #endif // BX_ELTORITO_BOOT
736 #define EbdaData ((ebda_data_t *) 0)
738 // for access to the int13ext structure
749 #define Int13Ext ((int13ext_t *) 0)
751 // Disk Physical Table definition
758 Bit32u sector_count1
;
759 Bit32u sector_count2
;
770 Bit8u device_path
[8];
775 #define Int13DPT ((dpt_t *) 0)
777 #endif // BX_USE_ATADRV
782 Bit16u di
, si
, bp
, sp
;
783 Bit16u bx
, dx
, cx
, ax
;
787 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
795 Bit32u edi
, esi
, ebp
, esp
;
796 Bit32u ebx
, edx
, ecx
, eax
;
799 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
800 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
828 #define SetCF(x) x.u.r8.flagsl |= 0x01
829 #define SetZF(x) x.u.r8.flagsl |= 0x40
830 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
831 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
832 #define GetCF(x) (x.u.r8.flagsl & 0x01)
843 static Bit8u
inb_cmos();
845 static void outb_cmos();
848 static void init_rtc();
849 static bx_bool
rtc_updating();
851 static Bit8u
read_byte();
852 static Bit16u
read_word();
853 static void write_byte();
854 static void write_word();
855 static void bios_printf();
857 static Bit8u
inhibit_mouse_int_and_events();
858 static void enable_mouse_int_and_events();
859 static Bit8u
send_to_mouse_ctrl();
860 static Bit8u
get_mouse_data();
861 static void set_kbd_command_byte();
863 static void int09_function();
864 static void int13_harddisk();
865 static void int13_cdrom();
866 static void int13_cdemu();
867 static void int13_eltorito();
868 static void int13_diskette_function();
869 static void int14_function();
870 static void int15_function();
871 static void int16_function();
872 static void int17_function();
873 static void int19_function();
874 static void int1a_function();
875 static void int70_function();
876 static void int74_function();
877 static Bit16u
get_CS();
878 static Bit16u
get_SS();
879 static unsigned int enqueue_key();
880 static unsigned int dequeue_key();
881 static void get_hd_geometry();
882 static void set_diskette_ret_status();
883 static void set_diskette_current_cyl();
884 static void determine_floppy_media();
885 static bx_bool
floppy_drive_exists();
886 static bx_bool
floppy_drive_recal();
887 static bx_bool
floppy_media_known();
888 static bx_bool
floppy_media_sense();
889 static bx_bool
set_enable_a20();
890 static void debugger_on();
891 static void debugger_off();
892 static void keyboard_init();
893 static void keyboard_panic();
894 static void shutdown_status_panic();
895 static void nmi_handler_msg();
897 static void print_bios_banner();
898 static void print_boot_device();
899 static void print_boot_failure();
900 static void print_cdromboot_failure();
904 // ATA / ATAPI driver
909 Bit16u
ata_cmd_non_data();
910 Bit16u
ata_cmd_data_in();
911 Bit16u
ata_cmd_data_out();
912 Bit16u
ata_cmd_packet();
914 Bit16u
atapi_get_sense();
915 Bit16u
atapi_is_ready();
916 Bit16u
atapi_is_cdrom();
918 #endif // BX_USE_ATADRV
923 Bit8u
cdemu_isactive();
924 Bit8u
cdemu_emulated_drive();
928 #endif // BX_ELTORITO_BOOT
930 static char bios_cvs_version_string
[] = "$Revision: 1.182 $ $Date: 2007/08/01 17:09:51 $";
932 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
935 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
937 # define BX_DEBUG_ATA(a...)
940 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
942 # define BX_DEBUG_INT13_HD(a...)
945 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
947 # define BX_DEBUG_INT13_CD(a...)
950 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
952 # define BX_DEBUG_INT13_ET(a...)
955 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
957 # define BX_DEBUG_INT13_FL(a...)
960 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
962 # define BX_DEBUG_INT15(a...)
965 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
967 # define BX_DEBUG_INT16(a...)
970 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
972 # define BX_DEBUG_INT1A(a...)
975 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
977 # define BX_DEBUG_INT74(a...)
980 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
981 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
982 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
983 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
984 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
985 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
986 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
987 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
989 #define GET_AL() ( AX & 0x00ff )
990 #define GET_BL() ( BX & 0x00ff )
991 #define GET_CL() ( CX & 0x00ff )
992 #define GET_DL() ( DX & 0x00ff )
993 #define GET_AH() ( AX >> 8 )
994 #define GET_BH() ( BX >> 8 )
995 #define GET_CH() ( CX >> 8 )
996 #define GET_DH() ( DX >> 8 )
998 #define GET_ELDL() ( ELDX & 0x00ff )
999 #define GET_ELDH() ( ELDX >> 8 )
1001 #define SET_CF() FLAGS |= 0x0001
1002 #define CLEAR_CF() FLAGS &= 0xfffe
1003 #define GET_CF() (FLAGS & 0x0001)
1005 #define SET_ZF() FLAGS |= 0x0040
1006 #define CLEAR_ZF() FLAGS &= 0xffbf
1007 #define GET_ZF() (FLAGS & 0x0040)
1009 #define UNSUPPORTED_FUNCTION 0x86
1012 #define MAX_SCAN_CODE 0x58
1020 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1021 { none
, none
, none
, none
, none
},
1022 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1023 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1024 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1025 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1026 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1027 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1028 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1029 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1030 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1031 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1032 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1033 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1034 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1035 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1036 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1037 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1038 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1039 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1040 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1041 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1042 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1043 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1044 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1045 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1046 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1047 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1048 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1049 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1050 { none
, none
, none
, none
, none
}, /* L Ctrl */
1051 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1052 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1053 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1054 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1055 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1056 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1057 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1058 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1059 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1060 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1061 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1062 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1063 { none
, none
, none
, none
, none
}, /* L shift */
1064 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1065 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1066 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1067 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1068 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1069 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1070 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1071 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1072 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1073 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1074 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1075 { none
, none
, none
, none
, none
}, /* R Shift */
1076 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1077 { none
, none
, none
, none
, none
}, /* L Alt */
1078 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1079 { none
, none
, none
, none
, none
}, /* caps lock */
1080 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1081 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1082 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1083 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1084 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1085 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1086 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1087 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1088 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1089 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1090 { none
, none
, none
, none
, none
}, /* Num Lock */
1091 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1092 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1093 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1094 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1095 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1096 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1097 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1098 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1099 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1100 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1101 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1102 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1103 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1104 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1105 { none
, none
, none
, none
, none
},
1106 { none
, none
, none
, none
, none
},
1107 { 0x565c, 0x567c, none
, none
, none
}, /* \| */
1108 { 0x5700, 0x5700, none
, none
, none
}, /* F11 */
1109 { 0x5800, 0x5800, none
, none
, none
} /* F12 */
1193 outb_cmos(cmos_reg
, val
)
1201 mov al
, 4[bp
] ;; cmos_reg
1203 mov al
, 6[bp
] ;; val
1218 mov al
, 4[bp
] ;; cmos_reg
1229 outb_cmos(0x0a, 0x26);
1230 outb_cmos(0x0b, 0x02);
1238 // This function checks to see if the update-in-progress bit
1239 // is set in CMOS Status Register A. If not, it returns 0.
1240 // If it is set, it tries to wait until there is a transition
1241 // to 0, and will return 0 if such a transition occurs. A 1
1242 // is returned only after timing out. The maximum period
1243 // that this bit should be set is constrained to 244useconds.
1244 // The count I use below guarantees coverage or more than
1245 // this time, with any reasonable IPS setting.
1250 while (--count
!= 0) {
1251 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1254 return(1); // update-in-progress never transitioned to 0
1259 read_byte(seg
, offset
)
1269 mov ax
, 4[bp
] ; segment
1271 mov bx
, 6[bp
] ; offset
1273 ;; al
= return value (byte
)
1282 read_word(seg
, offset
)
1292 mov ax
, 4[bp
] ; segment
1294 mov bx
, 6[bp
] ; offset
1296 ;; ax
= return value (word
)
1305 write_byte(seg
, offset
, data
)
1317 mov ax
, 4[bp
] ; segment
1319 mov bx
, 6[bp
] ; offset
1320 mov al
, 8[bp
] ; data byte
1321 mov
[bx
], al
; write data byte
1331 write_word(seg
, offset
, data
)
1343 mov ax
, 4[bp
] ; segment
1345 mov bx
, 6[bp
] ; offset
1346 mov ax
, 8[bp
] ; data word
1347 mov
[bx
], ax
; write data word
1373 /* serial debug port*/
1374 #define BX_DEBUG_PORT 0x03f8
1377 #define UART_RBR 0x00
1378 #define UART_THR 0x00
1381 #define UART_IER 0x01
1382 #define UART_IIR 0x02
1383 #define UART_FCR 0x02
1384 #define UART_LCR 0x03
1385 #define UART_MCR 0x04
1386 #define UART_DLL 0x00
1387 #define UART_DLM 0x01
1390 #define UART_LSR 0x05
1391 #define UART_MSR 0x06
1392 #define UART_SCR 0x07
1394 int uart_can_tx_byte(base_port
)
1397 return inb(base_port
+ UART_LSR
) & 0x20;
1400 void uart_wait_to_tx_byte(base_port
)
1403 while (!uart_can_tx_byte(base_port
));
1406 void uart_wait_until_sent(base_port
)
1409 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1412 void uart_tx_byte(base_port
, data
)
1416 uart_wait_to_tx_byte(base_port
);
1417 outb(base_port
+ UART_THR
, data
);
1418 uart_wait_until_sent(base_port
);
1447 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1448 uart_tx_byte(BX_DEBUG_PORT
, c
);
1450 #if BX_VIRTUAL_PORTS
1451 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1452 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1454 if (action
& BIOS_PRINTF_SCREEN
) {
1455 if (c
== '\n') wrch('\r');
1461 put_int(action
, val
, width
, neg
)
1466 short nval
= val
/ 10;
1468 put_int(action
, nval
, width
- 1, neg
);
1470 while (--width
> 0) send(action
, ' ');
1471 if (neg
) send(action
, '-');
1473 send(action
, val
- (nval
* 10) + '0');
1477 put_uint(action
, val
, width
, neg
)
1483 unsigned short nval
= val
/ 10;
1485 put_uint(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_luint(action
, val
, width
, neg
)
1500 unsigned long nval
= val
/ 10;
1502 put_luint(action
, nval
, width
- 1, neg
);
1504 while (--width
> 0) send(action
, ' ');
1505 if (neg
) send(action
, '-');
1507 send(action
, val
- (nval
* 10) + '0');
1510 void put_str(action
, s
)
1518 while (c
= read_byte(get_CS(), s
)) {
1524 //--------------------------------------------------------------------------
1526 // A compact variable argument printf function which prints its output via
1527 // an I/O port so that it can be logged by Bochs/Plex.
1528 // Currently, only %x is supported (or %02x, %04x, etc).
1530 // Supports %[format_width][format]
1531 // where format can be d,x,c,s
1532 //--------------------------------------------------------------------------
1534 bios_printf(action
, s
)
1538 Bit8u c
, format_char
;
1542 Bit16u arg_seg
, arg
, nibble
, hibyte
, shift_count
, format_width
;
1550 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1551 #if BX_VIRTUAL_PORTS
1552 outb(PANIC_PORT2
, 0x00);
1554 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1557 while (c
= read_byte(get_CS(), s
)) {
1562 else if (in_format
) {
1563 if ( (c
>='0') && (c
<='9') ) {
1564 format_width
= (format_width
* 10) + (c
- '0');
1567 arg_ptr
++; // increment to next arg
1568 arg
= read_word(arg_seg
, arg_ptr
);
1570 if (format_width
== 0)
1572 for (i
=format_width
-1; i
>=0; i
--) {
1573 nibble
= (arg
>> (4 * i
)) & 0x000f;
1574 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+'A'));
1577 else if (c
== 'u') {
1578 put_uint(action
, arg
, format_width
, 0);
1580 else if (c
== 'l') {
1582 arg_ptr
++; /* increment to next arg */
1583 hibyte
= read_word(arg_seg
, arg_ptr
);
1584 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1586 else if (c
== 'd') {
1588 put_int(action
, -arg
, format_width
- 1, 1);
1590 put_int(action
, arg
, format_width
, 0);
1592 else if (c
== 's') {
1593 put_str(action
, arg
);
1595 else if (c
== 'c') {
1599 BX_PANIC("bios_printf: unknown format\n");
1609 if (action
& BIOS_PRINTF_HALT
) {
1610 // freeze in a busy loop.
1620 //--------------------------------------------------------------------------
1622 //--------------------------------------------------------------------------
1623 // this file is based on LinuxBIOS implementation of keyboard.c
1624 // could convert to #asm to gain space
1630 /* ------------------- Flush buffers ------------------------*/
1631 /* Wait until buffer is empty */
1633 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1635 /* flush incoming keys */
1639 if (inb(0x64) & 0x01) {
1645 // Due to timer issues, and if the IPS setting is > 15000000,
1646 // the incoming keys might not be flushed here. That will
1647 // cause a panic a few lines below. See sourceforge bug report :
1648 // [ 642031 ] FATAL: Keyboard RESET error:993
1650 /* ------------------- controller side ----------------------*/
1651 /* send cmd = 0xAA, self test 8042 */
1654 /* Wait until buffer is empty */
1656 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1657 if (max
==0x0) keyboard_panic(00);
1661 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1662 if (max
==0x0) keyboard_panic(01);
1664 /* read self-test result, 0x55 should be returned from 0x60 */
1665 if ((inb(0x60) != 0x55)){
1666 keyboard_panic(991);
1669 /* send cmd = 0xAB, keyboard interface test */
1672 /* Wait until buffer is empty */
1674 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1675 if (max
==0x0) keyboard_panic(10);
1679 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1680 if (max
==0x0) keyboard_panic(11);
1682 /* read keyboard interface test result, */
1683 /* 0x00 should be returned form 0x60 */
1684 if ((inb(0x60) != 0x00)) {
1685 keyboard_panic(992);
1688 /* Enable Keyboard clock */
1692 /* ------------------- keyboard side ------------------------*/
1693 /* reset kerboard and self test (keyboard side) */
1696 /* Wait until buffer is empty */
1698 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1699 if (max
==0x0) keyboard_panic(20);
1703 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1704 if (max
==0x0) keyboard_panic(21);
1706 /* keyboard should return ACK */
1707 if ((inb(0x60) != 0xfa)) {
1708 keyboard_panic(993);
1713 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1714 if (max
==0x0) keyboard_panic(31);
1716 if ((inb(0x60) != 0xaa)) {
1717 keyboard_panic(994);
1720 /* Disable keyboard */
1723 /* Wait until buffer is empty */
1725 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1726 if (max
==0x0) keyboard_panic(40);
1730 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1731 if (max
==0x0) keyboard_panic(41);
1733 /* keyboard should return ACK */
1734 if ((inb(0x60) != 0xfa)) {
1735 keyboard_panic(995);
1738 /* Write Keyboard Mode */
1741 /* Wait until buffer is empty */
1743 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1744 if (max
==0x0) keyboard_panic(50);
1746 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1749 /* Wait until buffer is empty */
1751 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1752 if (max
==0x0) keyboard_panic(60);
1754 /* Enable keyboard */
1757 /* Wait until buffer is empty */
1759 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1760 if (max
==0x0) keyboard_panic(70);
1764 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1765 if (max
==0x0) keyboard_panic(70);
1767 /* keyboard should return ACK */
1768 if ((inb(0x60) != 0xfa)) {
1769 keyboard_panic(996);
1775 //--------------------------------------------------------------------------
1777 //--------------------------------------------------------------------------
1779 keyboard_panic(status
)
1782 // If you're getting a 993 keyboard panic here,
1783 // please see the comment in keyboard_init
1785 BX_PANIC("Keyboard error:%u\n",status
);
1788 //--------------------------------------------------------------------------
1789 // shutdown_status_panic
1790 // called when the shutdown statsu is not implemented, displays the status
1791 //--------------------------------------------------------------------------
1793 shutdown_status_panic(status
)
1796 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1799 //--------------------------------------------------------------------------
1800 // print_bios_banner
1801 // displays a the bios version
1802 //--------------------------------------------------------------------------
1806 printf(BX_APPNAME
" BIOS - build: %s\n%s\nOptions: ",
1807 BIOS_BUILD_DATE
, bios_cvs_version_string
);
1815 #if BX_ELTORITO_BOOT
1824 //--------------------------------------------------------------------------
1825 // BIOS Boot Specification 1.0.1 compatibility
1827 // Very basic support for the BIOS Boot Specification, which allows expansion
1828 // ROMs to register themselves as boot devices, instead of just stealing the
1829 // INT 19h boot vector.
1831 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1832 // one; we just lie to the option ROMs to make them behave correctly.
1833 // We also don't support letting option ROMs register as bootable disk
1834 // drives (BCVs), only as bootable devices (BEVs).
1836 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1837 //--------------------------------------------------------------------------
1839 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
1840 #define IPL_SEG 0x9ff0
1841 #define IPL_TABLE_OFFSET 0x0000
1842 #define IPL_TABLE_ENTRIES 8
1843 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
1844 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
1859 Bit16u ss
= get_SS();
1861 /* Clear out the IPL table. */
1862 memsetb(IPL_SEG
, IPL_TABLE_OFFSET
, 0, 0xff);
1865 e
.type
= 1; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1866 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1870 e
.type
= 2; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1871 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1874 #if BX_ELTORITO_BOOT
1876 e
.type
= 3; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1877 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1881 /* Remember how many devices we have */
1882 write_word(IPL_SEG
, IPL_COUNT_OFFSET
, count
);
1883 /* Not tried booting anything yet */
1884 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xffff);
1888 get_boot_vector(i
, e
)
1889 Bit16u i
; struct ipl_entry
*e
;
1892 Bit16u ss
= get_SS();
1893 /* Get the count of boot devices, and refuse to overrun the array */
1894 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
1895 if (i
>= count
) return 0;
1896 /* OK to read this device */
1897 memcpyb(ss
, e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (*e
), sizeof (*e
));
1902 //--------------------------------------------------------------------------
1903 // print_boot_device
1904 // displays the boot device
1905 //--------------------------------------------------------------------------
1907 static char drivetypes
[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1910 print_boot_device(type
)
1913 /* NIC appears as type 0x80 */
1914 if (type
== 0x80 ) type
= 0x4;
1915 if (type
== 0 || type
> 0x4) BX_PANIC("Bad drive type\n");
1916 printf("Booting from %s...\n", drivetypes
[type
]);
1919 //--------------------------------------------------------------------------
1920 // print_boot_failure
1921 // displays the reason why boot failed
1922 //--------------------------------------------------------------------------
1924 print_boot_failure(type
, reason
)
1925 Bit16u type
; Bit8u reason
;
1927 if (type
== 0 || type
> 0x3) BX_PANIC("Bad drive type\n");
1929 printf("Boot from %s failed", drivetypes
[type
]);
1931 /* Report the reason too */
1933 printf(": not a bootable disk");
1935 printf(": could not read the boot disk");
1940 //--------------------------------------------------------------------------
1941 // print_cdromboot_failure
1942 // displays the reason why boot failed
1943 //--------------------------------------------------------------------------
1945 print_cdromboot_failure( code
)
1948 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1956 BX_PANIC("NMI Handler called\n");
1962 BX_PANIC("INT18: BOOT FAILURE\n");
1969 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
1971 BX_INFO("%s\n", bios_cvs_version_string
);
1980 // Use PS2 System Control port A to set A20 enable
1982 // get current setting first
1985 // change A20 status
1987 outb(0x92, oldval
| 0x02);
1989 outb(0x92, oldval
& 0xfd);
1991 return((oldval
& 0x02) != 0);
2008 // ---------------------------------------------------------------------------
2009 // Start of ATA/ATAPI Driver
2010 // ---------------------------------------------------------------------------
2012 // Global defines -- ATA register and register bits.
2013 // command block & control block regs
2014 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2015 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2016 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2017 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2018 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2019 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2020 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2021 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2022 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2023 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2024 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2025 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2026 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2028 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2029 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2030 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2031 #define ATA_CB_ER_MC 0x20 // ATA media change
2032 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2033 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2034 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2035 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2036 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2038 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2039 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2040 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2041 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2042 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2044 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2045 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2046 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2047 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2048 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2050 // bits 7-4 of the device/head (CB_DH) reg
2051 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2052 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2054 // status reg (CB_STAT and CB_ASTAT) bits
2055 #define ATA_CB_STAT_BSY 0x80 // busy
2056 #define ATA_CB_STAT_RDY 0x40 // ready
2057 #define ATA_CB_STAT_DF 0x20 // device fault
2058 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2059 #define ATA_CB_STAT_SKC 0x10 // seek complete
2060 #define ATA_CB_STAT_SERV 0x10 // service
2061 #define ATA_CB_STAT_DRQ 0x08 // data request
2062 #define ATA_CB_STAT_CORR 0x04 // corrected
2063 #define ATA_CB_STAT_IDX 0x02 // index
2064 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2065 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2067 // device control reg (CB_DC) bits
2068 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2069 #define ATA_CB_DC_SRST 0x04 // soft reset
2070 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2072 // Most mandtory and optional ATA commands (from ATA-3),
2073 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2074 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2075 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2076 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2077 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2078 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2079 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2080 #define ATA_CMD_DEVICE_RESET 0x08
2081 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2082 #define ATA_CMD_FLUSH_CACHE 0xE7
2083 #define ATA_CMD_FORMAT_TRACK 0x50
2084 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2085 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2086 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2087 #define ATA_CMD_IDLE1 0xE3
2088 #define ATA_CMD_IDLE2 0x97
2089 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2090 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2091 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2092 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2093 #define ATA_CMD_NOP 0x00
2094 #define ATA_CMD_PACKET 0xA0
2095 #define ATA_CMD_READ_BUFFER 0xE4
2096 #define ATA_CMD_READ_DMA 0xC8
2097 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2098 #define ATA_CMD_READ_MULTIPLE 0xC4
2099 #define ATA_CMD_READ_SECTORS 0x20
2100 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2101 #define ATA_CMD_RECALIBRATE 0x10
2102 #define ATA_CMD_SEEK 0x70
2103 #define ATA_CMD_SET_FEATURES 0xEF
2104 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2105 #define ATA_CMD_SLEEP1 0xE6
2106 #define ATA_CMD_SLEEP2 0x99
2107 #define ATA_CMD_STANDBY1 0xE2
2108 #define ATA_CMD_STANDBY2 0x96
2109 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2110 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2111 #define ATA_CMD_WRITE_BUFFER 0xE8
2112 #define ATA_CMD_WRITE_DMA 0xCA
2113 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2114 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2115 #define ATA_CMD_WRITE_SECTORS 0x30
2116 #define ATA_CMD_WRITE_VERIFY 0x3C
2118 #define ATA_IFACE_NONE 0x00
2119 #define ATA_IFACE_ISA 0x00
2120 #define ATA_IFACE_PCI 0x01
2122 #define ATA_TYPE_NONE 0x00
2123 #define ATA_TYPE_UNKNOWN 0x01
2124 #define ATA_TYPE_ATA 0x02
2125 #define ATA_TYPE_ATAPI 0x03
2127 #define ATA_DEVICE_NONE 0x00
2128 #define ATA_DEVICE_HD 0xFF
2129 #define ATA_DEVICE_CDROM 0x05
2131 #define ATA_MODE_NONE 0x00
2132 #define ATA_MODE_PIO16 0x00
2133 #define ATA_MODE_PIO32 0x01
2134 #define ATA_MODE_ISADMA 0x02
2135 #define ATA_MODE_PCIDMA 0x03
2136 #define ATA_MODE_USEIRQ 0x10
2138 #define ATA_TRANSLATION_NONE 0
2139 #define ATA_TRANSLATION_LBA 1
2140 #define ATA_TRANSLATION_LARGE 2
2141 #define ATA_TRANSLATION_RECHS 3
2143 #define ATA_DATA_NO 0x00
2144 #define ATA_DATA_IN 0x01
2145 #define ATA_DATA_OUT 0x02
2147 // ---------------------------------------------------------------------------
2148 // ATA/ATAPI driver : initialization
2149 // ---------------------------------------------------------------------------
2152 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2153 Bit8u channel
, device
;
2155 // Channels info init.
2156 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2157 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2158 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2159 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2160 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2163 // Devices info init.
2164 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2165 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2166 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2167 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2168 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2169 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2170 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2171 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2172 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2173 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2174 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2175 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2176 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2177 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2179 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2182 // hdidmap and cdidmap init.
2183 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2184 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2185 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2188 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2189 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2192 // ---------------------------------------------------------------------------
2193 // ATA/ATAPI driver : device detection
2194 // ---------------------------------------------------------------------------
2198 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2199 Bit8u hdcount
, cdcount
, device
, type
;
2200 Bit8u buffer
[0x0200];
2202 #if BX_MAX_ATA_INTERFACES > 0
2203 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2204 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2205 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2206 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2208 #if BX_MAX_ATA_INTERFACES > 1
2209 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2210 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2211 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2212 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2214 #if BX_MAX_ATA_INTERFACES > 2
2215 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2216 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2217 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2218 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2220 #if BX_MAX_ATA_INTERFACES > 3
2221 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2222 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2223 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2224 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2226 #if BX_MAX_ATA_INTERFACES > 4
2227 #error Please fill the ATA interface informations
2233 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2234 Bit16u iobase1
, iobase2
;
2235 Bit8u channel
, slave
, shift
;
2236 Bit8u sc
, sn
, cl
, ch
, st
;
2238 channel
= device
/ 2;
2241 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2242 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2244 // Disable interrupts
2245 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2248 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2249 outb(iobase1
+ATA_CB_SC
, 0x55);
2250 outb(iobase1
+ATA_CB_SN
, 0xaa);
2251 outb(iobase1
+ATA_CB_SC
, 0xaa);
2252 outb(iobase1
+ATA_CB_SN
, 0x55);
2253 outb(iobase1
+ATA_CB_SC
, 0x55);
2254 outb(iobase1
+ATA_CB_SN
, 0xaa);
2256 // If we found something
2257 sc
= inb(iobase1
+ATA_CB_SC
);
2258 sn
= inb(iobase1
+ATA_CB_SN
);
2260 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2261 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2263 // reset the channel
2266 // check for ATA or ATAPI
2267 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2268 sc
= inb(iobase1
+ATA_CB_SC
);
2269 sn
= inb(iobase1
+ATA_CB_SN
);
2270 if ((sc
==0x01) && (sn
==0x01)) {
2271 cl
= inb(iobase1
+ATA_CB_CL
);
2272 ch
= inb(iobase1
+ATA_CB_CH
);
2273 st
= inb(iobase1
+ATA_CB_STAT
);
2275 if ((cl
==0x14) && (ch
==0xeb)) {
2276 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2277 } else if ((cl
==0x00) && (ch
==0x00) && (st
!=0x00)) {
2278 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2279 } else if ((cl
==0xff) && (ch
==0xff)) {
2280 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2285 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2287 // Now we send a IDENTIFY command to ATA device
2288 if(type
== ATA_TYPE_ATA
) {
2290 Bit16u cylinders
, heads
, spt
, blksize
;
2291 Bit8u translation
, removable
, mode
;
2293 //Temporary values to do the transfer
2294 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2295 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2297 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2298 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2300 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2301 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2302 blksize
= read_word(get_SS(),buffer
+10);
2304 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2305 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2306 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2308 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2310 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2311 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2312 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2313 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2314 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2315 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2316 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2317 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2318 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2320 translation
= inb_cmos(0x39 + channel
/2);
2321 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2322 translation
&= 0x03;
2324 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2326 switch (translation
) {
2327 case ATA_TRANSLATION_NONE
:
2330 case ATA_TRANSLATION_LBA
:
2333 case ATA_TRANSLATION_LARGE
:
2336 case ATA_TRANSLATION_RECHS
:
2340 switch (translation
) {
2341 case ATA_TRANSLATION_NONE
:
2343 case ATA_TRANSLATION_LBA
:
2346 heads
= sectors
/ 1024;
2347 if (heads
>128) heads
= 255;
2348 else if (heads
>64) heads
= 128;
2349 else if (heads
>32) heads
= 64;
2350 else if (heads
>16) heads
= 32;
2352 cylinders
= sectors
/ heads
;
2354 case ATA_TRANSLATION_RECHS
:
2355 // Take care not to overflow
2357 if(cylinders
>61439) cylinders
=61439;
2359 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2361 // then go through the large bitshift process
2362 case ATA_TRANSLATION_LARGE
:
2363 while(cylinders
> 1024) {
2367 // If we max out the head count
2368 if (heads
> 127) break;
2372 // clip to 1024 cylinders in lchs
2373 if (cylinders
> 1024) cylinders
=1024;
2374 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2376 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2377 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2378 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2381 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2385 // Now we send a IDENTIFY command to ATAPI device
2386 if(type
== ATA_TYPE_ATAPI
) {
2388 Bit8u type
, removable
, mode
;
2391 //Temporary values to do the transfer
2392 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2393 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2395 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2396 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2398 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2399 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2400 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2403 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2404 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2405 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2406 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2409 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2416 Bit8u c
, i
, version
, model
[41];
2420 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2422 case ATA_TYPE_ATAPI
:
2423 // Read ATA/ATAPI version
2424 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2425 for(version
=15;version
>0;version
--) {
2426 if((ataversion
&(1<<version
))!=0)
2432 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2433 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2437 write_byte(get_SS(),model
+40,0x00);
2439 if(read_byte(get_SS(),model
+i
)==0x20)
2440 write_byte(get_SS(),model
+i
,0x00);
2448 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2449 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2450 if (sizeinmb
< 1UL<<16)
2451 printf(" ATA-%d Hard-Disk (%04u MBytes)\n",version
,(Bit16u
)sizeinmb
);
2453 printf(" ATA-%d Hard-Disk (%04u GBytes)\n",version
,(Bit16u
)(sizeinmb
>>10));
2455 case ATA_TYPE_ATAPI
:
2456 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2457 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2458 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2459 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2461 printf(" ATAPI-%d Device\n",version
);
2463 case ATA_TYPE_UNKNOWN
:
2464 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2470 // Store the devices counts
2471 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2472 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2473 write_byte(0x40,0x75, hdcount
);
2477 // FIXME : should use bios=cmos|auto|disable bits
2478 // FIXME : should know about translation bits
2479 // FIXME : move hard_drive_post here
2483 // ---------------------------------------------------------------------------
2484 // ATA/ATAPI driver : software reset
2485 // ---------------------------------------------------------------------------
2487 // 8.2.1 Software reset - Device 0
2489 void ata_reset(device
)
2492 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2493 Bit16u iobase1
, iobase2
;
2494 Bit8u channel
, slave
, sn
, sc
;
2497 channel
= device
/ 2;
2500 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2501 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2505 // 8.2.1 (a) -- set SRST in DC
2506 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2508 // 8.2.1 (b) -- wait for BSY
2511 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2512 if ((status
& ATA_CB_STAT_BSY
) != 0) break;
2515 // 8.2.1 (f) -- clear SRST
2516 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2518 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_NONE
) {
2520 // 8.2.1 (g) -- check for sc==sn==0x01
2522 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2523 sc
= inb(iobase1
+ATA_CB_SC
);
2524 sn
= inb(iobase1
+ATA_CB_SN
);
2526 if ( (sc
==0x01) && (sn
==0x01) ) {
2528 // 8.2.1 (h) -- wait for not BSY
2531 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2532 if ((status
& ATA_CB_STAT_BSY
) == 0) break;
2537 // 8.2.1 (i) -- wait for DRDY
2540 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2541 if ((status
& ATA_CB_STAT_RDY
) != 0) break;
2544 // Enable interrupts
2545 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2548 // ---------------------------------------------------------------------------
2549 // ATA/ATAPI driver : execute a non data command
2550 // ---------------------------------------------------------------------------
2552 Bit16u
ata_cmd_non_data()
2555 // ---------------------------------------------------------------------------
2556 // ATA/ATAPI driver : execute a data-in command
2557 // ---------------------------------------------------------------------------
2562 // 3 : expected DRQ=1
2563 // 4 : no sectors left to read/verify
2564 // 5 : more sectors to read/verify
2565 // 6 : no sectors left to write
2566 // 7 : more sectors to write
2567 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2568 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2571 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2572 Bit16u iobase1
, iobase2
, blksize
;
2573 Bit8u channel
, slave
;
2574 Bit8u status
, current
, mode
;
2576 channel
= device
/ 2;
2579 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2580 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2581 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2582 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2583 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2586 // Reset count of transferred data
2587 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2588 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2591 status
= inb(iobase1
+ ATA_CB_STAT
);
2592 if (status
& ATA_CB_STAT_BSY
) return 1;
2594 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2596 // sector will be 0 only on lba access. Convert to lba-chs
2598 if ((count
>= 1 << 8) || (lba
+ count
>= 1UL << 28)) {
2599 outb(iobase1
+ ATA_CB_FR
, 0x00);
2600 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2601 outb(iobase1
+ ATA_CB_SN
, lba
>> 24);
2602 outb(iobase1
+ ATA_CB_CL
, 0);
2603 outb(iobase1
+ ATA_CB_CH
, 0);
2605 count
&= (1UL << 8) - 1;
2606 lba
&= (1UL << 24) - 1;
2608 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2610 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2612 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2615 outb(iobase1
+ ATA_CB_FR
, 0x00);
2616 outb(iobase1
+ ATA_CB_SC
, count
);
2617 outb(iobase1
+ ATA_CB_SN
, sector
);
2618 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2619 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2620 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2621 outb(iobase1
+ ATA_CB_CMD
, command
);
2624 status
= inb(iobase1
+ ATA_CB_STAT
);
2625 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2628 if (status
& ATA_CB_STAT_ERR
) {
2629 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2631 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2632 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2636 // FIXME : move seg/off translation here
2639 sti
;; enable higher priority interrupts
2647 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2648 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2649 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2651 ;; adjust
if there will be an overrun
. 2K max sector size
2653 jbe ata_in_no_adjust
2656 sub di
, #0x0800 ;; sub 2 kbytes from offset
2657 add ax
, #0x0080 ;; add 2 Kbytes to segment
2660 mov es
, ax
;; segment in es
2662 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2664 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2665 cmp ah
, #ATA_MODE_PIO32
2670 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2675 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2678 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2679 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2684 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2686 status
= inb(iobase1
+ ATA_CB_STAT
);
2688 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2689 != ATA_CB_STAT_RDY
) {
2690 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2696 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2697 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2698 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2704 // Enable interrupts
2705 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2709 // ---------------------------------------------------------------------------
2710 // ATA/ATAPI driver : execute a data-out command
2711 // ---------------------------------------------------------------------------
2716 // 3 : expected DRQ=1
2717 // 4 : no sectors left to read/verify
2718 // 5 : more sectors to read/verify
2719 // 6 : no sectors left to write
2720 // 7 : more sectors to write
2721 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2722 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2725 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2726 Bit16u iobase1
, iobase2
, blksize
;
2727 Bit8u channel
, slave
;
2728 Bit8u status
, current
, mode
;
2730 channel
= device
/ 2;
2733 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2734 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2735 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2736 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2737 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2740 // Reset count of transferred data
2741 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2742 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2745 status
= inb(iobase1
+ ATA_CB_STAT
);
2746 if (status
& ATA_CB_STAT_BSY
) return 1;
2748 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2750 // sector will be 0 only on lba access. Convert to lba-chs
2752 if ((count
>= 1 << 8) || (lba
+ count
>= 1UL << 28)) {
2753 outb(iobase1
+ ATA_CB_FR
, 0x00);
2754 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2755 outb(iobase1
+ ATA_CB_SN
, lba
>> 24);
2756 outb(iobase1
+ ATA_CB_CL
, 0);
2757 outb(iobase1
+ ATA_CB_CH
, 0);
2759 count
&= (1UL << 8) - 1;
2760 lba
&= (1UL << 24) - 1;
2762 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2764 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2766 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2769 outb(iobase1
+ ATA_CB_FR
, 0x00);
2770 outb(iobase1
+ ATA_CB_SC
, count
);
2771 outb(iobase1
+ ATA_CB_SN
, sector
);
2772 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2773 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2774 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2775 outb(iobase1
+ ATA_CB_CMD
, command
);
2778 status
= inb(iobase1
+ ATA_CB_STAT
);
2779 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2782 if (status
& ATA_CB_STAT_ERR
) {
2783 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2785 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2786 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2790 // FIXME : move seg/off translation here
2793 sti
;; enable higher priority interrupts
2801 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2802 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2803 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2805 ;; adjust
if there will be an overrun
. 2K max sector size
2807 jbe ata_out_no_adjust
2810 sub si
, #0x0800 ;; sub 2 kbytes from offset
2811 add ax
, #0x0080 ;; add 2 Kbytes to segment
2814 mov es
, ax
;; segment in es
2816 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2818 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2819 cmp ah
, #ATA_MODE_PIO32
2825 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2831 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2834 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2835 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2840 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2842 status
= inb(iobase1
+ ATA_CB_STAT
);
2844 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2845 != ATA_CB_STAT_RDY
) {
2846 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2852 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2853 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2854 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2860 // Enable interrupts
2861 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2865 // ---------------------------------------------------------------------------
2866 // ATA/ATAPI driver : execute a packet command
2867 // ---------------------------------------------------------------------------
2870 // 1 : error in parameters
2874 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2876 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2880 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2881 Bit16u iobase1
, iobase2
;
2882 Bit16u lcount
, lbefore
, lafter
, count
;
2883 Bit8u channel
, slave
;
2884 Bit8u status
, mode
, lmode
;
2885 Bit32u total
, transfer
;
2887 channel
= device
/ 2;
2890 // Data out is not supported yet
2891 if (inout
== ATA_DATA_OUT
) {
2892 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2896 // The header length must be even
2898 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2902 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2903 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2904 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2907 if (cmdlen
< 12) cmdlen
=12;
2908 if (cmdlen
> 12) cmdlen
=16;
2911 // Reset count of transferred data
2912 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2913 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2915 status
= inb(iobase1
+ ATA_CB_STAT
);
2916 if (status
& ATA_CB_STAT_BSY
) return 2;
2918 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2919 // outb(iobase1 + ATA_CB_FR, 0x00);
2920 // outb(iobase1 + ATA_CB_SC, 0x00);
2921 // outb(iobase1 + ATA_CB_SN, 0x00);
2922 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2923 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2924 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2925 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2927 // Device should ok to receive command
2929 status
= inb(iobase1
+ ATA_CB_STAT
);
2930 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2933 if (status
& ATA_CB_STAT_ERR
) {
2934 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2936 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2937 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2941 // Normalize address
2942 cmdseg
+= (cmdoff
/ 16);
2945 // Send command to device
2947 sti
;; enable higher priority interrupts
2952 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
2953 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
2954 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
2955 mov es
, ax
;; segment in es
2957 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
2961 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2966 if (inout
== ATA_DATA_NO
) {
2967 status
= inb(iobase1
+ ATA_CB_STAT
);
2972 status
= inb(iobase1
+ ATA_CB_STAT
);
2974 // Check if command completed
2975 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_DRQ
) ) ==0 ) break;
2977 if (status
& ATA_CB_STAT_ERR
) {
2978 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
2982 // Device must be ready to send data
2983 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2984 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2985 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status
);
2989 // Normalize address
2990 bufseg
+= (bufoff
/ 16);
2993 // Get the byte count
2994 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
2996 // adjust to read what we want
3009 lafter
=lcount
-length
;
3021 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
3022 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
3024 // If counts not dividable by 4, use 16bits mode
3026 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
3027 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
3028 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
3030 // adds an extra byte if count are odd. before is always even
3031 if (lcount
& 0x01) {
3033 if ((lafter
> 0) && (lafter
& 0x01)) {
3038 if (lmode
== ATA_MODE_PIO32
) {
3039 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
3042 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
3051 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
3053 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
3054 jcxz ata_packet_no_before
3056 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3057 cmp ah
, #ATA_MODE_PIO32
3058 je ata_packet_in_before_32
3060 ata_packet_in_before_16
:
3062 loop ata_packet_in_before_16
3063 jmp ata_packet_no_before
3065 ata_packet_in_before_32
:
3067 ata_packet_in_before_32_loop
:
3069 loop ata_packet_in_before_32_loop
3072 ata_packet_no_before
:
3073 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3074 jcxz ata_packet_after
3076 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3077 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3080 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3081 cmp ah
, #ATA_MODE_PIO32
3086 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3087 jmp ata_packet_after
3091 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3094 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3095 jcxz ata_packet_done
3097 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3098 cmp ah
, #ATA_MODE_PIO32
3099 je ata_packet_in_after_32
3101 ata_packet_in_after_16
:
3103 loop ata_packet_in_after_16
3106 ata_packet_in_after_32
:
3108 ata_packet_in_after_32_loop
:
3110 loop ata_packet_in_after_32_loop
3117 // Compute new buffer address
3120 // Save transferred bytes count
3122 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3126 // Final check, device must be ready
3127 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3128 != ATA_CB_STAT_RDY
) {
3129 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3133 // Enable interrupts
3134 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3138 // ---------------------------------------------------------------------------
3139 // End of ATA/ATAPI Driver
3140 // ---------------------------------------------------------------------------
3142 // ---------------------------------------------------------------------------
3143 // Start of ATA/ATAPI generic functions
3144 // ---------------------------------------------------------------------------
3147 atapi_get_sense(device
)
3154 memsetb(get_SS(),atacmd
,0,12);
3159 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 16L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3162 if ((buffer
[0] & 0x7e) == 0x70) {
3163 return (((Bit16u
)buffer
[2]&0x0f)*0x100)+buffer
[12];
3170 atapi_is_ready(device
)
3176 memsetb(get_SS(),atacmd
,0,12);
3179 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3182 if (atapi_get_sense(device
) !=0 ) {
3183 memsetb(get_SS(),atacmd
,0,12);
3185 // try to send Test Unit Ready again
3186 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3189 return atapi_get_sense(device
);
3195 atapi_is_cdrom(device
)
3198 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3200 if (device
>= BX_MAX_ATA_DEVICES
)
3203 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3206 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3212 // ---------------------------------------------------------------------------
3213 // End of ATA/ATAPI generic functions
3214 // ---------------------------------------------------------------------------
3216 #endif // BX_USE_ATADRV
3218 #if BX_ELTORITO_BOOT
3220 // ---------------------------------------------------------------------------
3221 // Start of El-Torito boot functions
3222 // ---------------------------------------------------------------------------
3227 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3229 // the only important data is this one for now
3230 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3236 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3238 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3242 cdemu_emulated_drive()
3244 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3246 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3249 static char isotag
[6]="CD001";
3250 static char eltorito
[24]="EL TORITO SPECIFICATION";
3252 // Returns ah: emulated drive, al: error code
3257 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3258 Bit8u atacmd
[12], buffer
[2048];
3260 Bit16u boot_segment
, nbsectors
, i
, error
;
3263 // Find out the first cdrom
3264 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3265 if (atapi_is_cdrom(device
)) break;
3269 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3271 // Read the Boot Record Volume Descriptor
3272 memsetb(get_SS(),atacmd
,0,12);
3273 atacmd
[0]=0x28; // READ command
3274 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3275 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3276 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3277 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3278 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3279 atacmd
[5]=(0x11 & 0x000000ff);
3280 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3284 if(buffer
[0]!=0)return 4;
3286 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3289 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3291 // ok, now we calculate the Boot catalog address
3292 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3294 // And we read the Boot Catalog
3295 memsetb(get_SS(),atacmd
,0,12);
3296 atacmd
[0]=0x28; // READ command
3297 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3298 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3299 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3300 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3301 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3302 atacmd
[5]=(lba
& 0x000000ff);
3303 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3307 if(buffer
[0x00]!=0x01)return 8; // Header
3308 if(buffer
[0x01]!=0x00)return 9; // Platform
3309 if(buffer
[0x1E]!=0x55)return 10; // key 1
3310 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3312 // Initial/Default Entry
3313 if(buffer
[0x20]!=0x88)return 11; // Bootable
3315 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3316 if(buffer
[0x21]==0){
3317 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3318 // Win2000 cd boot needs to know it booted from cd
3319 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3321 else if(buffer
[0x21]<4)
3322 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3324 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3326 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3327 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3329 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3330 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3332 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3333 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3335 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3336 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3338 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3339 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3341 // And we read the image in memory
3342 memsetb(get_SS(),atacmd
,0,12);
3343 atacmd
[0]=0x28; // READ command
3344 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3345 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3346 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3347 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3348 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3349 atacmd
[5]=(lba
& 0x000000ff);
3350 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3353 // Remember the media type
3354 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3355 case 0x01: // 1.2M floppy
3356 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3357 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3358 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3360 case 0x02: // 1.44M floppy
3361 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3362 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3363 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3365 case 0x03: // 2.88M floppy
3366 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3367 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3368 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3370 case 0x04: // Harddrive
3371 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3372 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3373 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3374 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3378 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3379 // Increase bios installed hardware number of devices
3380 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3381 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3383 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3387 // everything is ok, so from now on, the emulation is active
3388 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3389 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3391 // return the boot drive + no error
3392 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3395 // ---------------------------------------------------------------------------
3396 // End of El-Torito boot functions
3397 // ---------------------------------------------------------------------------
3398 #endif // BX_ELTORITO_BOOT
3401 int14_function(regs
, ds
, iret_addr
)
3402 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3403 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3404 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3406 Bit16u addr
,timer
,val16
;
3413 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3414 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3415 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3416 switch (regs
.u
.r8
.ah
) {
3418 outb(addr
+3, inb(addr
+3) | 0x80);
3419 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3423 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3424 outb(addr
, val16
& 0xFF);
3425 outb(addr
+1, val16
>> 8);
3427 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3428 regs
.u
.r8
.ah
= inb(addr
+5);
3429 regs
.u
.r8
.al
= inb(addr
+6);
3430 ClearCF(iret_addr
.flags
);
3433 timer
= read_word(0x0040, 0x006C);
3434 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3435 val16
= read_word(0x0040, 0x006C);
3436 if (val16
!= timer
) {
3441 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3442 regs
.u
.r8
.ah
= inb(addr
+5);
3443 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3444 ClearCF(iret_addr
.flags
);
3447 timer
= read_word(0x0040, 0x006C);
3448 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3449 val16
= read_word(0x0040, 0x006C);
3450 if (val16
!= timer
) {
3457 regs
.u
.r8
.al
= inb(addr
);
3459 regs
.u
.r8
.ah
= inb(addr
+5);
3461 ClearCF(iret_addr
.flags
);
3464 regs
.u
.r8
.ah
= inb(addr
+5);
3465 regs
.u
.r8
.al
= inb(addr
+6);
3466 ClearCF(iret_addr
.flags
);
3469 SetCF(iret_addr
.flags
); // Unsupported
3472 SetCF(iret_addr
.flags
); // Unsupported
3477 int15_function(regs
, ES
, DS
, FLAGS
)
3478 pusha_regs_t regs
; // REGS pushed via pusha
3479 Bit16u ES
, DS
, FLAGS
;
3481 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3482 bx_bool prev_a20_enable
;
3491 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3493 switch (regs
.u
.r8
.ah
) {
3494 case 0x24: /* A20 Control */
3495 switch (regs
.u
.r8
.al
) {
3507 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3517 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3519 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3525 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3529 /* keyboard intercept */
3531 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3538 case 0x52: // removable media eject
3540 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3544 if( regs
.u
.r8
.al
== 0 ) {
3545 // Set Interval requested.
3546 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3547 // Interval not already set.
3548 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3549 write_word( 0x40, 0x98, ES
); // Byte location, segment
3550 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3551 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3552 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3554 irqDisable
= inb( 0xA1 );
3555 outb( 0xA1, irqDisable
& 0xFE );
3556 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3557 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3559 // Interval already set.
3560 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3562 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3564 } else if( regs
.u
.r8
.al
== 1 ) {
3565 // Clear Interval requested
3566 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3568 bRegister
= inb_cmos( 0xB );
3569 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3571 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3573 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3582 # error "Int15 function 87h not supported on < 80386"
3584 // +++ should probably have descriptor checks
3585 // +++ should have exception handlers
3587 // turn off interrupts
3592 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3594 // 128K max of transfer on 386+ ???
3595 // source == destination ???
3597 // ES:SI points to descriptor table
3598 // offset use initially comments
3599 // ==============================================
3600 // 00..07 Unused zeros Null descriptor
3601 // 08..0f GDT zeros filled in by BIOS
3602 // 10..17 source ssssssss source of data
3603 // 18..1f dest dddddddd destination of data
3604 // 20..27 CS zeros filled in by BIOS
3605 // 28..2f SS zeros filled in by BIOS
3612 // check for access rights of source & dest here
3614 // Initialize GDT descriptor
3615 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3616 base23_16
= ES
>> 12;
3617 if (base15_00
< (ES
<<4))
3619 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3620 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3621 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3622 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3623 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3625 // Initialize CS descriptor
3626 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3627 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3628 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3629 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3630 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3632 // Initialize SS descriptor
3634 base15_00
= ss
<< 4;
3635 base23_16
= ss
>> 12;
3636 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3637 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3638 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3639 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3640 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3644 // Compile generates locals offset info relative to SP.
3645 // Get CX (word count) from stack.
3648 mov cx
, _int15_function
.CX
[bx
]
3650 // since we need to set SS:SP, save them to the BDA
3651 // for future restore
3661 lidt
[pmode_IDT_info
]
3662 ;; perhaps
do something with IDT here
3664 ;; set PE bit in CR0
3668 ;; far jump to flush CPU queue after transition to
protected mode
3669 JMP_AP(0x0020, protected_mode
)
3672 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3673 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3675 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3677 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3683 movsw
;; move CX words from DS
:SI to ES
:DI
3685 ;; make sure DS
and ES limits are
64KB
3690 ;; reset PG bit in CR0
???
3695 ;; far jump to flush CPU queue after transition to real mode
3696 JMP_AP(0xf000, real_mode
)
3699 ;; restore IDT to normal real
-mode defaults
3701 lidt
[rmode_IDT_info
]
3703 // restore SS:SP from the BDA
3711 set_enable_a20(prev_a20_enable
);
3713 // turn back on interrupts
3724 // Get the amount of extended memory (above 1M)
3726 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3729 regs
.u
.r8
.al
= inb_cmos(0x30);
3730 regs
.u
.r8
.ah
= inb_cmos(0x31);
3732 // According to Ralf Brown's interrupt the limit should be 15M,
3733 // but real machines mostly return max. 63M.
3734 if(regs
.u
.r16
.ax
> 0xffc0)
3735 regs
.u
.r16
.ax
= 0xffc0;
3742 /* Device busy interrupt. Called by Int 16h when no key available */
3746 /* Interrupt complete. Called by Int 16h when key becomes available */
3750 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3752 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3758 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3763 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3773 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3775 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3779 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3780 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3782 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3787 #if BX_USE_PS2_MOUSE
3789 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3790 pusha_regs_t regs
; // REGS pushed via pusha
3791 Bit16u ES
, DS
, FLAGS
;
3793 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3794 Bit8u mouse_flags_1
, mouse_flags_2
;
3795 Bit16u mouse_driver_seg
;
3796 Bit16u mouse_driver_offset
;
3797 Bit8u comm_byte
, prev_command_byte
;
3798 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3800 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3802 switch (regs
.u
.r8
.ah
) {
3804 // Return Codes status in AH
3805 // =========================
3807 // 01: invalid subfunction (AL > 7)
3808 // 02: invalid input value (out of allowable range)
3809 // 03: interface error
3810 // 04: resend command received from mouse controller,
3811 // device driver should attempt command again
3812 // 05: cannot enable mouse, since no far call has been installed
3813 // 80/86: mouse service not implemented
3815 switch (regs
.u
.r8
.al
) {
3816 case 0: // Disable/Enable Mouse
3817 BX_DEBUG_INT15("case 0:\n");
3818 switch (regs
.u
.r8
.bh
) {
3819 case 0: // Disable Mouse
3820 BX_DEBUG_INT15("case 0: disable mouse\n");
3821 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3822 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3824 ret
= get_mouse_data(&mouse_data1
);
3825 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3838 case 1: // Enable Mouse
3839 BX_DEBUG_INT15("case 1: enable mouse\n");
3840 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3841 if ( (mouse_flags_2
& 0x80) == 0 ) {
3842 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3844 regs
.u
.r8
.ah
= 5; // no far call installed
3847 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3848 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3850 ret
= get_mouse_data(&mouse_data1
);
3851 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3852 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3862 default: // invalid subfunction
3863 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3865 regs
.u
.r8
.ah
= 1; // invalid subfunction
3870 case 1: // Reset Mouse
3871 case 5: // Initialize Mouse
3872 BX_DEBUG_INT15("case 1 or 5:\n");
3873 if (regs
.u
.r8
.al
== 5) {
3874 if (regs
.u
.r8
.bh
!= 3) {
3876 regs
.u
.r8
.ah
= 0x02; // invalid input
3879 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3880 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3881 mouse_flags_1
= 0x00;
3882 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3883 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3886 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3887 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
3889 ret
= get_mouse_data(&mouse_data3
);
3890 // if no mouse attached, it will return RESEND
3891 if (mouse_data3
== 0xfe) {
3895 if (mouse_data3
!= 0xfa)
3896 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
3898 ret
= get_mouse_data(&mouse_data1
);
3900 ret
= get_mouse_data(&mouse_data2
);
3902 // turn IRQ12 and packet generation on
3903 enable_mouse_int_and_events();
3906 regs
.u
.r8
.bl
= mouse_data1
;
3907 regs
.u
.r8
.bh
= mouse_data2
;
3919 case 2: // Set Sample Rate
3920 BX_DEBUG_INT15("case 2:\n");
3921 switch (regs
.u
.r8
.bh
) {
3922 case 0: mouse_data1
= 10; break; // 10 reports/sec
3923 case 1: mouse_data1
= 20; break; // 20 reports/sec
3924 case 2: mouse_data1
= 40; break; // 40 reports/sec
3925 case 3: mouse_data1
= 60; break; // 60 reports/sec
3926 case 4: mouse_data1
= 80; break; // 80 reports/sec
3927 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
3928 case 6: mouse_data1
= 200; break; // 200 reports/sec
3929 default: mouse_data1
= 0;
3931 if (mouse_data1
> 0) {
3932 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
3934 ret
= get_mouse_data(&mouse_data2
);
3935 ret
= send_to_mouse_ctrl(mouse_data1
);
3936 ret
= get_mouse_data(&mouse_data2
);
3942 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3947 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3951 case 3: // Set Resolution
3952 BX_DEBUG_INT15("case 3:\n");
3954 // 0 = 25 dpi, 1 count per millimeter
3955 // 1 = 50 dpi, 2 counts per millimeter
3956 // 2 = 100 dpi, 4 counts per millimeter
3957 // 3 = 200 dpi, 8 counts per millimeter
3958 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3959 if (regs
.u
.r8
.bh
< 4) {
3960 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
3962 ret
= get_mouse_data(&mouse_data1
);
3963 if (mouse_data1
!= 0xfa)
3964 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3965 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
3966 ret
= get_mouse_data(&mouse_data1
);
3967 if (mouse_data1
!= 0xfa)
3968 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3974 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3979 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3981 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3984 case 4: // Get Device ID
3985 BX_DEBUG_INT15("case 4:\n");
3986 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3987 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
3989 ret
= get_mouse_data(&mouse_data1
);
3990 ret
= get_mouse_data(&mouse_data2
);
3993 regs
.u
.r8
.bh
= mouse_data2
;
3997 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4001 case 6: // Return Status & Set Scaling Factor...
4002 BX_DEBUG_INT15("case 6:\n");
4003 switch (regs
.u
.r8
.bh
) {
4004 case 0: // Return Status
4005 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4006 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4008 ret
= get_mouse_data(&mouse_data1
);
4009 if (mouse_data1
!= 0xfa)
4010 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4012 ret
= get_mouse_data(&mouse_data1
);
4014 ret
= get_mouse_data(&mouse_data2
);
4016 ret
= get_mouse_data(&mouse_data3
);
4020 regs
.u
.r8
.bl
= mouse_data1
;
4021 regs
.u
.r8
.cl
= mouse_data2
;
4022 regs
.u
.r8
.dl
= mouse_data3
;
4023 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4034 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4037 case 1: // Set Scaling Factor to 1:1
4038 case 2: // Set Scaling Factor to 2:1
4039 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4040 if (regs
.u
.r8
.bh
== 1) {
4041 ret
= send_to_mouse_ctrl(0xE6);
4043 ret
= send_to_mouse_ctrl(0xE7);
4046 get_mouse_data(&mouse_data1
);
4047 ret
= (mouse_data1
!= 0xFA);
4055 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4057 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4061 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4065 case 7: // Set Mouse Handler Address
4066 BX_DEBUG_INT15("case 7:\n");
4067 mouse_driver_seg
= ES
;
4068 mouse_driver_offset
= regs
.u
.r16
.bx
;
4069 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4070 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4071 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4072 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4073 /* remove handler */
4074 if ( (mouse_flags_2
& 0x80) != 0 ) {
4075 mouse_flags_2
&= ~0x80;
4076 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4080 /* install handler */
4081 mouse_flags_2
|= 0x80;
4083 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4089 BX_DEBUG_INT15("case default:\n");
4090 regs
.u
.r8
.ah
= 1; // invalid function
4096 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4097 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4099 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4106 void set_e820_range(ES
, DI
, start
, end
, extra_start
, extra_end
, type
)
4115 write_word(ES
, DI
, start
);
4116 write_word(ES
, DI
+2, start
>> 16);
4117 write_word(ES
, DI
+4, extra_start
);
4118 write_word(ES
, DI
+6, 0x00);
4121 extra_end
-= extra_start
;
4122 write_word(ES
, DI
+8, end
);
4123 write_word(ES
, DI
+10, end
>> 16);
4124 write_word(ES
, DI
+12, extra_end
);
4125 write_word(ES
, DI
+14, 0x0000);
4127 write_word(ES
, DI
+16, type
);
4128 write_word(ES
, DI
+18, 0x0);
4132 int15_function32(regs
, ES
, DS
, FLAGS
)
4133 pushad_regs_t regs
; // REGS pushed via pushad
4134 Bit16u ES
, DS
, FLAGS
;
4136 Bit32u extended_memory_size
=0; // 64bits long
4137 Bit32u extra_lowbits_memory_size
=0;
4139 Bit8u extra_highbits_memory_size
=0;
4141 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4143 switch (regs
.u
.r8
.ah
) {
4145 // Wait for CX:DX microseconds. currently using the
4146 // refresh request port 0x61 bit4, toggling every 15usec
4154 ;; Get the count in eax
4157 mov ax
, _int15_function
.CX
[bx
]
4160 mov ax
, _int15_function
.DX
[bx
]
4162 ;; convert to numbers of
15usec ticks
4168 ;; wait
for ecx number of refresh requests
4189 switch(regs
.u
.r8
.al
)
4191 case 0x20: // coded by osmaker aka K.J.
4192 if(regs
.u
.r32
.edx
== 0x534D4150)
4194 extended_memory_size
= inb_cmos(0x35);
4195 extended_memory_size
<<= 8;
4196 extended_memory_size
|= inb_cmos(0x34);
4197 extended_memory_size
*= 64;
4198 // greater than EFF00000???
4199 if(extended_memory_size
> 0x3bc000) {
4200 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4202 extended_memory_size
*= 1024;
4203 extended_memory_size
+= (16L * 1024 * 1024);
4205 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4206 extended_memory_size
= inb_cmos(0x31);
4207 extended_memory_size
<<= 8;
4208 extended_memory_size
|= inb_cmos(0x30);
4209 extended_memory_size
*= 1024;
4212 extra_lowbits_memory_size
= inb_cmos(0x5c);
4213 extra_lowbits_memory_size
<<= 8;
4214 extra_lowbits_memory_size
|= inb_cmos(0x5b);
4215 extra_lowbits_memory_size
*= 64;
4216 extra_lowbits_memory_size
*= 1024;
4217 extra_highbits_memory_size
= inb_cmos(0x5d);
4219 switch(regs
.u
.r16
.bx
)
4222 set_e820_range(ES
, regs
.u
.r16
.di
,
4223 0x0000000L
, 0x0009fc00L
, 0, 0, 1);
4225 regs
.u
.r32
.eax
= 0x534D4150;
4226 regs
.u
.r32
.ecx
= 0x14;
4231 set_e820_range(ES
, regs
.u
.r16
.di
,
4232 0x0009fc00L
, 0x000a0000L
, 0, 0, 2);
4234 regs
.u
.r32
.eax
= 0x534D4150;
4235 regs
.u
.r32
.ecx
= 0x14;
4240 set_e820_range(ES
, regs
.u
.r16
.di
,
4241 0x000e8000L
, 0x00100000L
, 0, 0, 2);
4243 regs
.u
.r32
.eax
= 0x534D4150;
4244 regs
.u
.r32
.ecx
= 0x14;
4249 set_e820_range(ES
, regs
.u
.r16
.di
,
4251 extended_memory_size
- ACPI_DATA_SIZE
,0, 0, 1);
4253 regs
.u
.r32
.eax
= 0x534D4150;
4254 regs
.u
.r32
.ecx
= 0x14;
4259 set_e820_range(ES
, regs
.u
.r16
.di
,
4260 extended_memory_size
- ACPI_DATA_SIZE
,
4261 extended_memory_size
,0, 0, 3); // ACPI RAM
4263 regs
.u
.r32
.eax
= 0x534D4150;
4264 regs
.u
.r32
.ecx
= 0x14;
4269 /* 3 pages before the bios, we map the vmx tss pages */
4270 set_e820_range(ES
, regs
.u
.r16
.di
, 0xfffbd000L
,
4271 0xfffc0000L
, 0, 0, 2);
4273 regs
.u
.r32
.eax
= 0x534D4150;
4274 regs
.u
.r32
.ecx
= 0x14;
4278 /* 256KB BIOS area at the end of 4 GB */
4279 set_e820_range(ES
, regs
.u
.r16
.di
,
4280 0xfffc0000L
, 0x00000000L
,0, 0, 2);
4281 if (extra_highbits_memory_size
|| extra_lowbits_memory_size
)
4285 regs
.u
.r32
.eax
= 0x534D4150;
4286 regs
.u
.r32
.ecx
= 0x14;
4290 /* Maping of memory above 4 GB */
4291 set_e820_range(ES
, regs
.u
.r16
.di
, 0x00000000L
,
4292 extra_lowbits_memory_size
, 1, extra_highbits_memory_size
4295 regs
.u
.r32
.eax
= 0x534D4150;
4296 regs
.u
.r32
.ecx
= 0x14;
4299 default: /* AX=E820, DX=534D4150, BX unrecognized */
4300 goto int15_unimplemented
;
4304 // if DX != 0x534D4150)
4305 goto int15_unimplemented
;
4310 // do we have any reason to fail here ?
4313 // my real system sets ax and bx to 0
4314 // this is confirmed by Ralph Brown list
4315 // but syslinux v1.48 is known to behave
4316 // strangely if ax is set to 0
4317 // regs.u.r16.ax = 0;
4318 // regs.u.r16.bx = 0;
4320 // Get the amount of extended memory (above 1M)
4321 regs
.u
.r8
.cl
= inb_cmos(0x30);
4322 regs
.u
.r8
.ch
= inb_cmos(0x31);
4325 if(regs
.u
.r16
.cx
> 0x3c00)
4327 regs
.u
.r16
.cx
= 0x3c00;
4330 // Get the amount of extended memory above 16M in 64k blocs
4331 regs
.u
.r8
.dl
= inb_cmos(0x34);
4332 regs
.u
.r8
.dh
= inb_cmos(0x35);
4334 // Set configured memory equal to extended memory
4335 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4336 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4338 default: /* AH=0xE8?? but not implemented */
4339 goto int15_unimplemented
;
4342 int15_unimplemented
:
4343 // fall into the default
4345 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4346 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4348 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4354 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4355 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4357 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4358 Bit16u kbd_code
, max
;
4360 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4362 shift_flags
= read_byte(0x0040, 0x17);
4363 led_flags
= read_byte(0x0040, 0x97);
4364 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4369 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4370 if ((inb(0x60) == 0xfa)) {
4372 led_flags
|= ((shift_flags
>> 4) & 0x07);
4373 outb(0x60, led_flags
& 0x07);
4374 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4376 write_byte(0x0040, 0x97, led_flags
);
4384 case 0x00: /* read keyboard input */
4386 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4387 BX_PANIC("KBD: int16h: out of keyboard input\n");
4389 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4390 else if (ascii_code
== 0xE0) ascii_code
= 0;
4391 AX
= (scan_code
<< 8) | ascii_code
;
4394 case 0x01: /* check keyboard status */
4395 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4399 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4400 else if (ascii_code
== 0xE0) ascii_code
= 0;
4401 AX
= (scan_code
<< 8) | ascii_code
;
4405 case 0x02: /* get shift flag status */
4406 shift_flags
= read_byte(0x0040, 0x17);
4407 SET_AL(shift_flags
);
4410 case 0x05: /* store key-stroke into buffer */
4411 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4419 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4420 // bit Bochs Description
4422 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4423 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4424 // 4 1 INT 16/AH=0Ah supported
4425 // 3 0 INT 16/AX=0306h supported
4426 // 2 0 INT 16/AX=0305h supported
4427 // 1 0 INT 16/AX=0304h supported
4428 // 0 0 INT 16/AX=0300h supported
4433 case 0x0A: /* GET KEYBOARD ID */
4439 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4441 if ((inb(0x60) == 0xfa)) {
4444 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4447 kbd_code
|= (inb(0x60) << 8);
4449 } while (--count
>0);
4455 case 0x10: /* read MF-II keyboard input */
4457 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4458 BX_PANIC("KBD: int16h: out of keyboard input\n");
4460 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4461 AX
= (scan_code
<< 8) | ascii_code
;
4464 case 0x11: /* check MF-II keyboard status */
4465 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4469 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4470 AX
= (scan_code
<< 8) | ascii_code
;
4474 case 0x12: /* get extended keyboard status */
4475 shift_flags
= read_byte(0x0040, 0x17);
4476 SET_AL(shift_flags
);
4477 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4478 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4479 SET_AH(shift_flags
);
4480 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4483 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4484 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4487 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4488 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4492 if (GET_AL() == 0x08)
4493 SET_AH(0x02); // unsupported, aka normal keyboard
4496 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4501 dequeue_key(scan_code
, ascii_code
, incr
)
4506 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4511 buffer_start
= 0x001E;
4512 buffer_end
= 0x003E;
4514 buffer_start
= read_word(0x0040, 0x0080);
4515 buffer_end
= read_word(0x0040, 0x0082);
4518 buffer_head
= read_word(0x0040, 0x001a);
4519 buffer_tail
= read_word(0x0040, 0x001c);
4521 if (buffer_head
!= buffer_tail
) {
4523 acode
= read_byte(0x0040, buffer_head
);
4524 scode
= read_byte(0x0040, buffer_head
+1);
4525 write_byte(ss
, ascii_code
, acode
);
4526 write_byte(ss
, scan_code
, scode
);
4530 if (buffer_head
>= buffer_end
)
4531 buffer_head
= buffer_start
;
4532 write_word(0x0040, 0x001a, buffer_head
);
4541 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4544 inhibit_mouse_int_and_events()
4546 Bit8u command_byte
, prev_command_byte
;
4548 // Turn off IRQ generation and aux data line
4549 if ( inb(0x64) & 0x02 )
4550 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4551 outb(0x64, 0x20); // get command byte
4552 while ( (inb(0x64) & 0x01) != 0x01 );
4553 prev_command_byte
= inb(0x60);
4554 command_byte
= prev_command_byte
;
4555 //while ( (inb(0x64) & 0x02) );
4556 if ( inb(0x64) & 0x02 )
4557 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4558 command_byte
&= 0xfd; // turn off IRQ 12 generation
4559 command_byte
|= 0x20; // disable mouse serial clock line
4560 outb(0x64, 0x60); // write command byte
4561 outb(0x60, command_byte
);
4562 return(prev_command_byte
);
4566 enable_mouse_int_and_events()
4570 // Turn on IRQ generation and aux data line
4571 if ( inb(0x64) & 0x02 )
4572 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4573 outb(0x64, 0x20); // get command byte
4574 while ( (inb(0x64) & 0x01) != 0x01 );
4575 command_byte
= inb(0x60);
4576 //while ( (inb(0x64) & 0x02) );
4577 if ( inb(0x64) & 0x02 )
4578 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4579 command_byte
|= 0x02; // turn on IRQ 12 generation
4580 command_byte
&= 0xdf; // enable mouse serial clock line
4581 outb(0x64, 0x60); // write command byte
4582 outb(0x60, command_byte
);
4586 send_to_mouse_ctrl(sendbyte
)
4591 // wait for chance to write to ctrl
4592 if ( inb(0x64) & 0x02 )
4593 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4595 outb(0x60, sendbyte
);
4601 get_mouse_data(data
)
4607 while ( (inb(0x64) & 0x21) != 0x21 ) {
4610 response
= inb(0x60);
4613 write_byte(ss
, data
, response
);
4618 set_kbd_command_byte(command_byte
)
4621 if ( inb(0x64) & 0x02 )
4622 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4625 outb(0x64, 0x60); // write command byte
4626 outb(0x60, command_byte
);
4630 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4631 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4633 Bit8u scancode
, asciicode
, shift_flags
;
4634 Bit8u mf2_flags
, mf2_state
;
4637 // DS has been set to F000 before call
4641 scancode
= GET_AL();
4643 if (scancode
== 0) {
4644 BX_INFO("KBD: int09 handler: AL=0\n");
4649 shift_flags
= read_byte(0x0040, 0x17);
4650 mf2_flags
= read_byte(0x0040, 0x18);
4651 mf2_state
= read_byte(0x0040, 0x96);
4655 case 0x3a: /* Caps Lock press */
4656 shift_flags
^= 0x40;
4657 write_byte(0x0040, 0x17, shift_flags
);
4659 write_byte(0x0040, 0x18, mf2_flags
);
4661 case 0xba: /* Caps Lock release */
4663 write_byte(0x0040, 0x18, mf2_flags
);
4666 case 0x2a: /* L Shift press */
4667 shift_flags
|= 0x02;
4668 write_byte(0x0040, 0x17, shift_flags
);
4670 case 0xaa: /* L Shift release */
4671 shift_flags
&= ~0x02;
4672 write_byte(0x0040, 0x17, shift_flags
);
4675 case 0x36: /* R Shift press */
4676 shift_flags
|= 0x01;
4677 write_byte(0x0040, 0x17, shift_flags
);
4679 case 0xb6: /* R Shift release */
4680 shift_flags
&= ~0x01;
4681 write_byte(0x0040, 0x17, shift_flags
);
4684 case 0x1d: /* Ctrl press */
4685 if ((mf2_state
& 0x01) == 0) {
4686 shift_flags
|= 0x04;
4687 write_byte(0x0040, 0x17, shift_flags
);
4688 if (mf2_state
& 0x02) {
4690 write_byte(0x0040, 0x96, mf2_state
);
4693 write_byte(0x0040, 0x18, mf2_flags
);
4697 case 0x9d: /* Ctrl release */
4698 if ((mf2_state
& 0x01) == 0) {
4699 shift_flags
&= ~0x04;
4700 write_byte(0x0040, 0x17, shift_flags
);
4701 if (mf2_state
& 0x02) {
4703 write_byte(0x0040, 0x96, mf2_state
);
4706 write_byte(0x0040, 0x18, mf2_flags
);
4711 case 0x38: /* Alt press */
4712 shift_flags
|= 0x08;
4713 write_byte(0x0040, 0x17, shift_flags
);
4714 if (mf2_state
& 0x02) {
4716 write_byte(0x0040, 0x96, mf2_state
);
4719 write_byte(0x0040, 0x18, mf2_flags
);
4722 case 0xb8: /* Alt release */
4723 shift_flags
&= ~0x08;
4724 write_byte(0x0040, 0x17, shift_flags
);
4725 if (mf2_state
& 0x02) {
4727 write_byte(0x0040, 0x96, mf2_state
);
4730 write_byte(0x0040, 0x18, mf2_flags
);
4734 case 0x45: /* Num Lock press */
4735 if ((mf2_state
& 0x03) == 0) {
4737 write_byte(0x0040, 0x18, mf2_flags
);
4738 shift_flags
^= 0x20;
4739 write_byte(0x0040, 0x17, shift_flags
);
4742 case 0xc5: /* Num Lock release */
4743 if ((mf2_state
& 0x03) == 0) {
4745 write_byte(0x0040, 0x18, mf2_flags
);
4749 case 0x46: /* Scroll Lock press */
4751 write_byte(0x0040, 0x18, mf2_flags
);
4752 shift_flags
^= 0x10;
4753 write_byte(0x0040, 0x17, shift_flags
);
4756 case 0xc6: /* Scroll Lock release */
4758 write_byte(0x0040, 0x18, mf2_flags
);
4762 if (scancode
& 0x80) {
4763 break; /* toss key releases ... */
4765 if (scancode
> MAX_SCAN_CODE
) {
4766 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4769 if (shift_flags
& 0x08) { /* ALT */
4770 asciicode
= scan_to_scanascii
[scancode
].alt
;
4771 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4772 } else if (shift_flags
& 0x04) { /* CONTROL */
4773 asciicode
= scan_to_scanascii
[scancode
].control
;
4774 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4775 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
4776 /* extended keys handling */
4778 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4779 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4780 /* check if lock state should be ignored
4781 * because a SHIFT key are pressed */
4783 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4784 asciicode
= scan_to_scanascii
[scancode
].normal
;
4785 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4787 asciicode
= scan_to_scanascii
[scancode
].shift
;
4788 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4791 /* check if lock is on */
4792 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4793 asciicode
= scan_to_scanascii
[scancode
].shift
;
4794 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4796 asciicode
= scan_to_scanascii
[scancode
].normal
;
4797 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4800 if (scancode
==0 && asciicode
==0) {
4801 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4803 enqueue_key(scancode
, asciicode
);
4806 if ((scancode
& 0x7f) != 0x1d) {
4810 write_byte(0x0040, 0x96, mf2_state
);
4814 enqueue_key(scan_code
, ascii_code
)
4815 Bit8u scan_code
, ascii_code
;
4817 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4820 buffer_start
= 0x001E;
4821 buffer_end
= 0x003E;
4823 buffer_start
= read_word(0x0040, 0x0080);
4824 buffer_end
= read_word(0x0040, 0x0082);
4827 buffer_head
= read_word(0x0040, 0x001A);
4828 buffer_tail
= read_word(0x0040, 0x001C);
4830 temp_tail
= buffer_tail
;
4832 if (buffer_tail
>= buffer_end
)
4833 buffer_tail
= buffer_start
;
4835 if (buffer_tail
== buffer_head
) {
4839 write_byte(0x0040, temp_tail
, ascii_code
);
4840 write_byte(0x0040, temp_tail
+1, scan_code
);
4841 write_word(0x0040, 0x001C, buffer_tail
);
4847 int74_function(make_farcall
, Z
, Y
, X
, status
)
4848 Bit16u make_farcall
, Z
, Y
, X
, status
;
4850 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4851 Bit8u in_byte
, index
, package_count
;
4852 Bit8u mouse_flags_1
, mouse_flags_2
;
4854 BX_DEBUG_INT74("entering int74_function\n");
4857 in_byte
= inb(0x64);
4858 if ( (in_byte
& 0x21) != 0x21 ) {
4861 in_byte
= inb(0x60);
4862 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4864 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4865 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4867 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4871 package_count
= mouse_flags_2
& 0x07;
4872 index
= mouse_flags_1
& 0x07;
4873 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4875 if ( (index
+1) >= package_count
) {
4876 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4877 status
= read_byte(ebda_seg
, 0x0028 + 0);
4878 X
= read_byte(ebda_seg
, 0x0028 + 1);
4879 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4882 // check if far call handler installed
4883 if (mouse_flags_2
& 0x80)
4889 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4892 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4897 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4898 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4901 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4902 Bit16u cylinder
, head
, sector
;
4903 Bit16u segment
, offset
;
4904 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4906 Bit8u device
, status
;
4908 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4910 write_byte(0x0040, 0x008e, 0); // clear completion flag
4912 // basic check : device has to be defined
4913 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4914 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4918 // Get the ata channel
4919 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
4921 // basic check : device has to be valid
4922 if (device
>= BX_MAX_ATA_DEVICES
) {
4923 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4929 case 0x00: /* disk controller reset */
4934 case 0x01: /* read disk status */
4935 status
= read_byte(0x0040, 0x0074);
4937 SET_DISK_RET_STATUS(0);
4938 /* set CF if error status read */
4939 if (status
) goto int13_fail_nostatus
;
4940 else goto int13_success_noah
;
4943 case 0x02: // read disk sectors
4944 case 0x03: // write disk sectors
4945 case 0x04: // verify disk sectors
4948 cylinder
= GET_CH();
4949 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
4950 sector
= (GET_CL() & 0x3f);
4956 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
4957 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
4961 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4962 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4963 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4965 // sanity check on cyl heads, sec
4966 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
4967 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
4972 if ( GET_AH() == 0x04 ) goto int13_success
;
4974 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4975 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4977 // if needed, translate lchs to lba, and execute command
4978 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
4979 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
4980 sector
= 0; // this forces the command to be lba
4983 if ( GET_AH() == 0x02 )
4984 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4986 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4988 // Set nb of sector transferred
4989 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
4992 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4994 goto int13_fail_noah
;
5000 case 0x05: /* format disk track */
5001 BX_INFO("format disk track called\n");
5006 case 0x08: /* read disk drive parameters */
5008 // Get logical geometry from table
5009 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5010 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5011 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5012 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5014 nlc
= nlc
- 2; /* 0 based , last sector not used */
5017 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5019 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5021 // FIXME should set ES & DI
5026 case 0x10: /* check drive ready */
5027 // should look at 40:8E also???
5029 // Read the status from controller
5030 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5031 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5036 goto int13_fail_noah
;
5040 case 0x15: /* read disk drive size */
5042 // Get physical geometry from table
5043 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5044 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5045 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5047 // Compute sector count seen by int13
5048 lba
= (Bit32u
)(npc
- 1) * (Bit32u
)nph
* (Bit32u
)npspt
;
5052 SET_AH(3); // hard disk accessible
5053 goto int13_success_noah
;
5056 case 0x41: // IBM/MS installation check
5057 BX
=0xaa55; // install check
5058 SET_AH(0x30); // EDD 3.0
5059 CX
=0x0007; // ext disk access and edd, removable supported
5060 goto int13_success_noah
;
5063 case 0x42: // IBM/MS extended read
5064 case 0x43: // IBM/MS extended write
5065 case 0x44: // IBM/MS verify
5066 case 0x47: // IBM/MS extended seek
5068 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5069 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5070 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5072 // Can't use 64 bits lba
5073 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5075 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5079 // Get 32 bits lba and check
5080 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5081 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
5082 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5086 // If verify or seek
5087 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5090 // Execute the command
5091 if ( GET_AH() == 0x42 )
5092 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5094 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5096 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5097 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5100 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5102 goto int13_fail_noah
;
5108 case 0x45: // IBM/MS lock/unlock drive
5109 case 0x49: // IBM/MS extended media change
5110 goto int13_success
; // Always success for HD
5113 case 0x46: // IBM/MS eject media
5114 SET_AH(0xb2); // Volume Not Removable
5115 goto int13_fail_noah
; // Always fail for HD
5118 case 0x48: // IBM/MS get drive parameters
5119 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5121 // Buffer is too small
5129 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5130 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5131 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5132 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
5133 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5135 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5136 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5137 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5138 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5139 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5140 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
5141 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
5142 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5147 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5148 Bit16u iobase1
, iobase2
, options
;
5150 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5152 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5153 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5156 channel
= device
/ 2;
5157 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5158 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5159 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5160 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5161 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5163 options
= (translation
==ATA_TRANSLATION_NONE
?0:1<<3); // chs translation
5164 options
|= (1<<4); // lba translation
5165 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5166 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0<<9);
5167 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0<<9);
5169 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5170 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5171 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5172 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5173 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5174 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5175 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5176 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5177 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5178 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5179 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5182 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5183 checksum
= ~checksum
;
5184 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5189 Bit8u channel
, iface
, checksum
, i
;
5192 channel
= device
/ 2;
5193 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5194 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5196 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5197 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5198 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5199 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5200 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5202 if (iface
==ATA_IFACE_ISA
) {
5203 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5204 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5205 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5206 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5211 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5212 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5213 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5214 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5216 if (iface
==ATA_IFACE_ISA
) {
5217 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5218 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5219 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5224 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5225 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5226 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5227 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5230 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5231 checksum
= ~checksum
;
5232 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5238 case 0x4e: // // IBM/MS set hardware configuration
5239 // DMA, prefetch, PIO maximum not supported
5252 case 0x09: /* initialize drive parameters */
5253 case 0x0c: /* seek to specified cylinder */
5254 case 0x0d: /* alternate disk reset */
5255 case 0x11: /* recalibrate */
5256 case 0x14: /* controller internal diagnostic */
5257 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5261 case 0x0a: /* read disk sectors with ECC */
5262 case 0x0b: /* write disk sectors with ECC */
5263 case 0x18: // set media type for format
5264 case 0x50: // IBM/MS send packet command
5266 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5272 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5274 SET_DISK_RET_STATUS(GET_AH());
5275 int13_fail_nostatus
:
5276 SET_CF(); // error occurred
5280 SET_AH(0x00); // no error
5282 SET_DISK_RET_STATUS(0x00);
5283 CLEAR_CF(); // no error
5287 // ---------------------------------------------------------------------------
5288 // Start of int13 for cdrom
5289 // ---------------------------------------------------------------------------
5292 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5293 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5295 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5296 Bit8u device
, status
, locks
;
5299 Bit16u count
, segment
, offset
, i
, size
;
5301 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5303 SET_DISK_RET_STATUS(0x00);
5305 /* basic check : device should be 0xE0+ */
5306 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5307 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5311 // Get the ata channel
5312 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5314 /* basic check : device has to be valid */
5315 if (device
>= BX_MAX_ATA_DEVICES
) {
5316 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5322 // all those functions return SUCCESS
5323 case 0x00: /* disk controller reset */
5324 case 0x09: /* initialize drive parameters */
5325 case 0x0c: /* seek to specified cylinder */
5326 case 0x0d: /* alternate disk reset */
5327 case 0x10: /* check drive ready */
5328 case 0x11: /* recalibrate */
5329 case 0x14: /* controller internal diagnostic */
5330 case 0x16: /* detect disk change */
5334 // all those functions return disk write-protected
5335 case 0x03: /* write disk sectors */
5336 case 0x05: /* format disk track */
5337 case 0x43: // IBM/MS extended write
5339 goto int13_fail_noah
;
5342 case 0x01: /* read disk status */
5343 status
= read_byte(0x0040, 0x0074);
5345 SET_DISK_RET_STATUS(0);
5347 /* set CF if error status read */
5348 if (status
) goto int13_fail_nostatus
;
5349 else goto int13_success_noah
;
5352 case 0x15: /* read disk drive size */
5354 goto int13_fail_noah
;
5357 case 0x41: // IBM/MS installation check
5358 BX
=0xaa55; // install check
5359 SET_AH(0x30); // EDD 2.1
5360 CX
=0x0007; // ext disk access, removable and edd
5361 goto int13_success_noah
;
5364 case 0x42: // IBM/MS extended read
5365 case 0x44: // IBM/MS verify sectors
5366 case 0x47: // IBM/MS extended seek
5368 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5369 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5370 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5372 // Can't use 64 bits lba
5373 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5375 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5380 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5382 // If verify or seek
5383 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5386 memsetb(get_SS(),atacmd
,0,12);
5387 atacmd
[0]=0x28; // READ command
5388 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5389 atacmd
[8]=(count
& 0x00ff); // Sectors
5390 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5391 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5392 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5393 atacmd
[5]=(lba
& 0x000000ff);
5394 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5396 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5397 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5400 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5402 goto int13_fail_noah
;
5408 case 0x45: // IBM/MS lock/unlock drive
5409 if (GET_AL() > 2) goto int13_fail
;
5411 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5415 if (locks
== 0xff) {
5418 goto int13_fail_noah
;
5420 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5424 if (locks
== 0x00) {
5427 goto int13_fail_noah
;
5429 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5430 SET_AL(locks
==0?0:1);
5433 SET_AL(locks
==0?0:1);
5439 case 0x46: // IBM/MS eject media
5440 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5443 SET_AH(0xb1); // media locked
5444 goto int13_fail_noah
;
5446 // FIXME should handle 0x31 no media in device
5447 // FIXME should handle 0xb5 valid request failed
5449 // Call removable media eject
5456 mov _int13_cdrom
.status
+ 2[bp
], ah
5457 jnc int13_cdrom_rme_end
5458 mov _int13_cdrom
.status
, #1
5459 int13_cdrom_rme_end
:
5464 SET_AH(0xb1); // media locked
5465 goto int13_fail_noah
;
5471 case 0x48: // IBM/MS get drive parameters
5472 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5474 // Buffer is too small
5480 Bit16u cylinders
, heads
, spt
, blksize
;
5482 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5484 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5485 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5486 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5487 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5488 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5489 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5490 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5491 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5496 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5497 Bit16u iobase1
, iobase2
, options
;
5499 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5501 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5502 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5505 channel
= device
/ 2;
5506 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5507 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5508 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5509 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5511 // FIXME atapi device
5512 options
= (1<<4); // lba translation
5513 options
|= (1<<5); // removable device
5514 options
|= (1<<6); // atapi device
5515 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5517 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5518 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5519 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5520 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5521 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5522 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5523 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5524 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5525 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5526 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5527 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5530 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5531 checksum
= ~checksum
;
5532 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5537 Bit8u channel
, iface
, checksum
, i
;
5540 channel
= device
/ 2;
5541 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5542 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5544 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5545 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5546 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5547 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5548 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5550 if (iface
==ATA_IFACE_ISA
) {
5551 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5552 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5553 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5554 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5559 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5560 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5561 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5562 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5564 if (iface
==ATA_IFACE_ISA
) {
5565 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5566 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5567 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5572 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5573 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5574 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5575 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5578 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5579 checksum
= ~checksum
;
5580 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5586 case 0x49: // IBM/MS extended media change
5587 // always send changed ??
5589 goto int13_fail_nostatus
;
5592 case 0x4e: // // IBM/MS set hardware configuration
5593 // DMA, prefetch, PIO maximum not supported
5606 // all those functions return unimplemented
5607 case 0x02: /* read sectors */
5608 case 0x04: /* verify sectors */
5609 case 0x08: /* read disk drive parameters */
5610 case 0x0a: /* read disk sectors with ECC */
5611 case 0x0b: /* write disk sectors with ECC */
5612 case 0x18: /* set media type for format */
5613 case 0x50: // ? - send packet command
5615 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5621 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5623 SET_DISK_RET_STATUS(GET_AH());
5624 int13_fail_nostatus
:
5625 SET_CF(); // error occurred
5629 SET_AH(0x00); // no error
5631 SET_DISK_RET_STATUS(0x00);
5632 CLEAR_CF(); // no error
5636 // ---------------------------------------------------------------------------
5637 // End of int13 for cdrom
5638 // ---------------------------------------------------------------------------
5640 #if BX_ELTORITO_BOOT
5641 // ---------------------------------------------------------------------------
5642 // Start of int13 for eltorito functions
5643 // ---------------------------------------------------------------------------
5646 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5647 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5649 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5651 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5652 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5656 // FIXME ElTorito Various. Should be implemented
5657 case 0x4a: // ElTorito - Initiate disk emu
5658 case 0x4c: // ElTorito - Initiate disk emu and boot
5659 case 0x4d: // ElTorito - Return Boot catalog
5660 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5664 case 0x4b: // ElTorito - Terminate disk emu
5665 // FIXME ElTorito Hardcoded
5666 write_byte(DS
,SI
+0x00,0x13);
5667 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5668 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5669 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5670 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5671 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5672 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5673 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5674 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5675 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5676 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5677 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5679 // If we have to terminate emulation
5680 if(GET_AL() == 0x00) {
5681 // FIXME ElTorito Various. Should be handled accordingly to spec
5682 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5689 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5695 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5696 SET_DISK_RET_STATUS(GET_AH());
5697 SET_CF(); // error occurred
5701 SET_AH(0x00); // no error
5702 SET_DISK_RET_STATUS(0x00);
5703 CLEAR_CF(); // no error
5707 // ---------------------------------------------------------------------------
5708 // End of int13 for eltorito functions
5709 // ---------------------------------------------------------------------------
5711 // ---------------------------------------------------------------------------
5712 // Start of int13 when emulating a device from the cd
5713 // ---------------------------------------------------------------------------
5716 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5717 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5719 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5720 Bit8u device
, status
;
5721 Bit16u vheads
, vspt
, vcylinders
;
5722 Bit16u head
, sector
, cylinder
, nbsectors
;
5723 Bit32u vlba
, ilba
, slba
, elba
;
5724 Bit16u before
, segment
, offset
;
5727 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5729 /* at this point, we are emulating a floppy/harddisk */
5731 // Recompute the device number
5732 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5733 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5735 SET_DISK_RET_STATUS(0x00);
5737 /* basic checks : emulation should be active, dl should equal the emulated drive */
5738 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5739 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5740 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5746 // all those functions return SUCCESS
5747 case 0x00: /* disk controller reset */
5748 case 0x09: /* initialize drive parameters */
5749 case 0x0c: /* seek to specified cylinder */
5750 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5751 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5752 case 0x11: /* recalibrate */
5753 case 0x14: /* controller internal diagnostic */
5754 case 0x16: /* detect disk change */
5758 // all those functions return disk write-protected
5759 case 0x03: /* write disk sectors */
5760 case 0x05: /* format disk track */
5762 goto int13_fail_noah
;
5765 case 0x01: /* read disk status */
5766 status
=read_byte(0x0040, 0x0074);
5768 SET_DISK_RET_STATUS(0);
5770 /* set CF if error status read */
5771 if (status
) goto int13_fail_nostatus
;
5772 else goto int13_success_noah
;
5775 case 0x02: // read disk sectors
5776 case 0x04: // verify disk sectors
5777 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5778 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5779 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5781 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5783 sector
= GET_CL() & 0x003f;
5784 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5786 nbsectors
= GET_AL();
5790 // no sector to read ?
5791 if(nbsectors
==0) goto int13_success
;
5793 // sanity checks sco openserver needs this!
5795 || (cylinder
>= vcylinders
)
5796 || (head
>= vheads
)) {
5800 // After controls, verify do nothing
5801 if (GET_AH() == 0x04) goto int13_success
;
5803 segment
= ES
+(BX
/ 16);
5806 // calculate the virtual lba inside the image
5807 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5809 // In advance so we don't loose the count
5813 slba
= (Bit32u
)vlba
/4;
5814 before
= (Bit16u
)vlba
%4;
5817 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5819 memsetb(get_SS(),atacmd
,0,12);
5820 atacmd
[0]=0x28; // READ command
5821 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5822 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5823 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5824 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5825 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5826 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5827 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5828 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5831 goto int13_fail_noah
;
5837 case 0x08: /* read disk drive parameters */
5838 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5839 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5840 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5844 SET_CH( vcylinders
& 0xff );
5845 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5847 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5848 // FIXME ElTorito Harddisk. should send the HD count
5850 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5851 case 0x01: SET_BL( 0x02 ); break;
5852 case 0x02: SET_BL( 0x04 ); break;
5853 case 0x03: SET_BL( 0x06 ); break;
5859 mov ax
, #diskette_param_table2
5860 mov _int13_cdemu
.DI
+2[bp
], ax
5861 mov _int13_cdemu
.ES
+2[bp
], cs
5867 case 0x15: /* read disk drive size */
5868 // FIXME ElTorito Harddisk. What geometry to send ?
5870 goto int13_success_noah
;
5873 // all those functions return unimplemented
5874 case 0x0a: /* read disk sectors with ECC */
5875 case 0x0b: /* write disk sectors with ECC */
5876 case 0x18: /* set media type for format */
5877 case 0x41: // IBM/MS installation check
5878 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5879 case 0x42: // IBM/MS extended read
5880 case 0x43: // IBM/MS extended write
5881 case 0x44: // IBM/MS verify sectors
5882 case 0x45: // IBM/MS lock/unlock drive
5883 case 0x46: // IBM/MS eject media
5884 case 0x47: // IBM/MS extended seek
5885 case 0x48: // IBM/MS get drive parameters
5886 case 0x49: // IBM/MS extended media change
5887 case 0x4e: // ? - set hardware configuration
5888 case 0x50: // ? - send packet command
5890 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5896 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5898 SET_DISK_RET_STATUS(GET_AH());
5899 int13_fail_nostatus
:
5900 SET_CF(); // error occurred
5904 SET_AH(0x00); // no error
5906 SET_DISK_RET_STATUS(0x00);
5907 CLEAR_CF(); // no error
5911 // ---------------------------------------------------------------------------
5912 // End of int13 when emulating a device from the cd
5913 // ---------------------------------------------------------------------------
5915 #endif // BX_ELTORITO_BOOT
5917 #else //BX_USE_ATADRV
5920 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
5935 mov ax
,4[bp
] // cylinder
5937 mov bl
,6[bp
] // hd_heads
5940 mov bl
,8[bp
] // head
5942 mov bl
,10[bp
] // hd_sectors
5944 mov bl
,12[bp
] // sector
5973 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5974 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5976 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
5980 Bit16u max_cylinder
, cylinder
, total_sectors
;
5981 Bit16u hd_cylinders
;
5982 Bit8u hd_heads
, hd_sectors
;
5989 Bit16u count
, segment
, offset
;
5993 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5995 write_byte(0x0040, 0x008e, 0); // clear completion flag
5997 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5999 /* check how many disks first (cmos reg 0x12), return an error if
6000 drive not present */
6001 drive_map
= inb_cmos(0x12);
6002 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6003 (((drive_map
& 0x0f)==0) ? 0 : 2);
6004 n_drives
= (drive_map
==0) ? 0 :
6005 ((drive_map
==3) ? 2 : 1);
6007 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6009 SET_DISK_RET_STATUS(0x01);
6010 SET_CF(); /* error occurred */
6016 case 0x00: /* disk controller reset */
6017 BX_DEBUG_INT13_HD("int13_f00\n");
6020 SET_DISK_RET_STATUS(0);
6021 set_diskette_ret_status(0);
6022 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6023 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6024 CLEAR_CF(); /* successful */
6028 case 0x01: /* read disk status */
6029 BX_DEBUG_INT13_HD("int13_f01\n");
6030 status
= read_byte(0x0040, 0x0074);
6032 SET_DISK_RET_STATUS(0);
6033 /* set CF if error status read */
6034 if (status
) SET_CF();
6039 case 0x04: // verify disk sectors
6040 case 0x02: // read disk sectors
6042 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6044 num_sectors
= GET_AL();
6045 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6046 sector
= (GET_CL() & 0x3f);
6050 if (hd_cylinders
> 1024) {
6051 if (hd_cylinders
<= 2048) {
6054 else if (hd_cylinders
<= 4096) {
6057 else if (hd_cylinders
<= 8192) {
6060 else { // hd_cylinders <= 16384
6064 ax
= head
/ hd_heads
;
6065 cyl_mod
= ax
& 0xff;
6067 cylinder
|= cyl_mod
;
6070 if ( (cylinder
>= hd_cylinders
) ||
6071 (sector
> hd_sectors
) ||
6072 (head
>= hd_heads
) ) {
6074 SET_DISK_RET_STATUS(1);
6075 SET_CF(); /* error occurred */
6079 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6080 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6083 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6085 if ( GET_AH() == 0x04 ) {
6087 SET_DISK_RET_STATUS(0);
6092 status
= inb(0x1f7);
6093 if (status
& 0x80) {
6094 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6096 outb(0x01f2, num_sectors
);
6097 /* activate LBA? (tomv) */
6098 if (hd_heads
> 16) {
6099 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6100 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6103 outb(0x01f3, sector
);
6104 outb(0x01f4, cylinder
& 0x00ff);
6105 outb(0x01f5, cylinder
>> 8);
6106 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6111 status
= inb(0x1f7);
6112 if ( !(status
& 0x80) ) break;
6115 if (status
& 0x01) {
6116 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6117 } else if ( !(status
& 0x08) ) {
6118 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6119 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6126 sti
;; enable higher priority interrupts
6131 ;; store temp bx in real DI
register
6134 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6137 ;; adjust
if there will be an overrun
6139 jbe i13_f02_no_adjust
6141 sub di
, #0x0200 ; sub 512 bytes from offset
6143 add ax
, #0x0020 ; add 512 to segment
6147 mov cx
, #0x0100 ;; counter (256 words = 512b)
6148 mov dx
, #0x01f0 ;; AT data read port
6151 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6154 ;; store real DI
register back to temp bx
6157 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6163 if (num_sectors
== 0) {
6164 status
= inb(0x1f7);
6165 if ( (status
& 0xc9) != 0x40 )
6166 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6170 status
= inb(0x1f7);
6171 if ( (status
& 0xc9) != 0x48 )
6172 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6178 SET_DISK_RET_STATUS(0);
6179 SET_AL(sector_count
);
6180 CLEAR_CF(); /* successful */
6185 case 0x03: /* write disk sectors */
6186 BX_DEBUG_INT13_HD("int13_f03\n");
6187 drive
= GET_ELDL ();
6188 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6190 num_sectors
= GET_AL();
6191 cylinder
= GET_CH();
6192 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6193 sector
= (GET_CL() & 0x3f);
6196 if (hd_cylinders
> 1024) {
6197 if (hd_cylinders
<= 2048) {
6200 else if (hd_cylinders
<= 4096) {
6203 else if (hd_cylinders
<= 8192) {
6206 else { // hd_cylinders <= 16384
6210 ax
= head
/ hd_heads
;
6211 cyl_mod
= ax
& 0xff;
6213 cylinder
|= cyl_mod
;
6216 if ( (cylinder
>= hd_cylinders
) ||
6217 (sector
> hd_sectors
) ||
6218 (head
>= hd_heads
) ) {
6220 SET_DISK_RET_STATUS(1);
6221 SET_CF(); /* error occurred */
6225 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6226 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6229 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6231 status
= inb(0x1f7);
6232 if (status
& 0x80) {
6233 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6235 // should check for Drive Ready Bit also in status reg
6236 outb(0x01f2, num_sectors
);
6238 /* activate LBA? (tomv) */
6239 if (hd_heads
> 16) {
6240 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6241 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6244 outb(0x01f3, sector
);
6245 outb(0x01f4, cylinder
& 0x00ff);
6246 outb(0x01f5, cylinder
>> 8);
6247 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6251 // wait for busy bit to turn off after seeking
6253 status
= inb(0x1f7);
6254 if ( !(status
& 0x80) ) break;
6257 if ( !(status
& 0x08) ) {
6258 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6259 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6266 sti
;; enable higher priority interrupts
6271 ;; store temp bx in real SI
register
6274 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6277 ;; adjust
if there will be an overrun
6279 jbe i13_f03_no_adjust
6281 sub si
, #0x0200 ; sub 512 bytes from offset
6283 add ax
, #0x0020 ; add 512 to segment
6287 mov cx
, #0x0100 ;; counter (256 words = 512b)
6288 mov dx
, #0x01f0 ;; AT data read port
6292 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6294 ;; store real SI
register back to temp bx
6297 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6303 if (num_sectors
== 0) {
6304 status
= inb(0x1f7);
6305 if ( (status
& 0xe9) != 0x40 )
6306 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6310 status
= inb(0x1f7);
6311 if ( (status
& 0xc9) != 0x48 )
6312 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6318 SET_DISK_RET_STATUS(0);
6319 SET_AL(sector_count
);
6320 CLEAR_CF(); /* successful */
6324 case 0x05: /* format disk track */
6325 BX_DEBUG_INT13_HD("int13_f05\n");
6326 BX_PANIC("format disk track called\n");
6329 SET_DISK_RET_STATUS(0);
6330 CLEAR_CF(); /* successful */
6334 case 0x08: /* read disk drive parameters */
6335 BX_DEBUG_INT13_HD("int13_f08\n");
6337 drive
= GET_ELDL ();
6338 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6342 if (hd_cylinders
<= 1024) {
6343 // hd_cylinders >>= 0;
6346 else if (hd_cylinders
<= 2048) {
6350 else if (hd_cylinders
<= 4096) {
6354 else if (hd_cylinders
<= 8192) {
6358 else { // hd_cylinders <= 16384
6363 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6365 SET_CH(max_cylinder
& 0xff);
6366 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6367 SET_DH(hd_heads
- 1);
6368 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6370 SET_DISK_RET_STATUS(0);
6371 CLEAR_CF(); /* successful */
6376 case 0x09: /* initialize drive parameters */
6377 BX_DEBUG_INT13_HD("int13_f09\n");
6379 SET_DISK_RET_STATUS(0);
6380 CLEAR_CF(); /* successful */
6384 case 0x0a: /* read disk sectors with ECC */
6385 BX_DEBUG_INT13_HD("int13_f0a\n");
6386 case 0x0b: /* write disk sectors with ECC */
6387 BX_DEBUG_INT13_HD("int13_f0b\n");
6388 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6392 case 0x0c: /* seek to specified cylinder */
6393 BX_DEBUG_INT13_HD("int13_f0c\n");
6394 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6396 SET_DISK_RET_STATUS(0);
6397 CLEAR_CF(); /* successful */
6401 case 0x0d: /* alternate disk reset */
6402 BX_DEBUG_INT13_HD("int13_f0d\n");
6404 SET_DISK_RET_STATUS(0);
6405 CLEAR_CF(); /* successful */
6409 case 0x10: /* check drive ready */
6410 BX_DEBUG_INT13_HD("int13_f10\n");
6412 //SET_DISK_RET_STATUS(0);
6413 //CLEAR_CF(); /* successful */
6417 // should look at 40:8E also???
6418 status
= inb(0x01f7);
6419 if ( (status
& 0xc0) == 0x40 ) {
6421 SET_DISK_RET_STATUS(0);
6422 CLEAR_CF(); // drive ready
6427 SET_DISK_RET_STATUS(0xAA);
6428 SET_CF(); // not ready
6433 case 0x11: /* recalibrate */
6434 BX_DEBUG_INT13_HD("int13_f11\n");
6436 SET_DISK_RET_STATUS(0);
6437 CLEAR_CF(); /* successful */
6441 case 0x14: /* controller internal diagnostic */
6442 BX_DEBUG_INT13_HD("int13_f14\n");
6444 SET_DISK_RET_STATUS(0);
6445 CLEAR_CF(); /* successful */
6450 case 0x15: /* read disk drive size */
6452 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6456 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6457 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6458 mul al
, ah
;; ax
= heads
* sectors
6459 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6460 dec bx
;; use (cylinders
- 1) ???
6461 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6462 ;; now we need to move the
32bit result dx
:ax to what the
6463 ;; BIOS wants which is cx
:dx
.
6464 ;; and then into CX
:DX on the stack
6465 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6466 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6469 SET_AH(3); // hard disk accessible
6470 SET_DISK_RET_STATUS(0); // ??? should this be 0
6471 CLEAR_CF(); // successful
6475 case 0x18: // set media type for format
6476 case 0x41: // IBM/MS
6477 case 0x42: // IBM/MS
6478 case 0x43: // IBM/MS
6479 case 0x44: // IBM/MS
6480 case 0x45: // IBM/MS lock/unlock drive
6481 case 0x46: // IBM/MS eject media
6482 case 0x47: // IBM/MS extended seek
6483 case 0x49: // IBM/MS extended media change
6484 case 0x50: // IBM/MS send packet command
6486 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6488 SET_AH(1); // code=invalid function in AH or invalid parameter
6489 SET_DISK_RET_STATUS(1);
6490 SET_CF(); /* unsuccessful */
6496 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6497 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6500 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6502 Bit16u
*hd_cylinders
;
6512 if (drive
== 0x80) {
6513 hd_type
= inb_cmos(0x12) & 0xf0;
6514 if (hd_type
!= 0xf0)
6515 BX_INFO(panic_msg_reg12h
,0);
6516 hd_type
= inb_cmos(0x19); // HD0: extended type
6518 BX_INFO(panic_msg_reg19h
,0,0x19);
6521 hd_type
= inb_cmos(0x12) & 0x0f;
6522 if (hd_type
!= 0x0f)
6523 BX_INFO(panic_msg_reg12h
,1);
6524 hd_type
= inb_cmos(0x1a); // HD0: extended type
6526 BX_INFO(panic_msg_reg19h
,0,0x1a);
6531 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6532 write_word(ss
, hd_cylinders
, cylinders
);
6535 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6537 // sectors per track
6538 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6541 #endif //else BX_USE_ATADRV
6544 //////////////////////
6545 // FLOPPY functions //
6546 //////////////////////
6548 void floppy_reset_controller()
6554 outb(0x03f2, val8
& ~0x04);
6555 outb(0x03f2, val8
| 0x04);
6557 // Wait for controller to come out of reset
6560 } while ( (val8
& 0xc0) != 0x80 );
6563 void floppy_prepare_controller(drive
)
6566 Bit8u val8
, dor
, prev_reset
;
6568 // set 40:3e bit 7 to 0
6569 val8
= read_byte(0x0040, 0x003e);
6571 write_byte(0x0040, 0x003e, val8
);
6573 // turn on motor of selected drive, DMA & int enabled, normal operation
6574 prev_reset
= inb(0x03f2) & 0x04;
6583 // reset the disk motor timeout value of INT 08
6584 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6586 // wait for drive readiness
6589 } while ( (val8
& 0xc0) != 0x80 );
6591 if (prev_reset
== 0) {
6592 // turn on interrupts
6596 // wait on 40:3e bit 7 to become 1
6598 val8
= read_byte(0x0040, 0x003e);
6599 } while ( (val8
& 0x80) == 0 );
6604 write_byte(0x0040, 0x003e, val8
);
6609 floppy_media_known(drive
)
6613 Bit16u media_state_offset
;
6615 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6622 media_state_offset
= 0x0090;
6624 media_state_offset
+= 1;
6626 val8
= read_byte(0x0040, media_state_offset
);
6627 val8
= (val8
>> 4) & 0x01;
6631 // check pass, return KNOWN
6636 floppy_media_sense(drive
)
6640 Bit16u media_state_offset
;
6641 Bit8u drive_type
, config_data
, media_state
;
6643 if (floppy_drive_recal(drive
) == 0) {
6647 // for now cheat and get drive type from CMOS,
6648 // assume media is same as drive type
6650 // ** config_data **
6651 // Bitfields for diskette media control:
6652 // Bit(s) Description (Table M0028)
6653 // 7-6 last data rate set by controller
6654 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6655 // 5-4 last diskette drive step rate selected
6656 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6657 // 3-2 {data rate at start of operation}
6660 // ** media_state **
6661 // Bitfields for diskette drive media state:
6662 // Bit(s) Description (Table M0030)
6664 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6665 // 5 double stepping required (e.g. 360kB in 1.2MB)
6666 // 4 media type established
6667 // 3 drive capable of supporting 4MB media
6668 // 2-0 on exit from BIOS, contains
6669 // 000 trying 360kB in 360kB
6670 // 001 trying 360kB in 1.2MB
6671 // 010 trying 1.2MB in 1.2MB
6672 // 011 360kB in 360kB established
6673 // 100 360kB in 1.2MB established
6674 // 101 1.2MB in 1.2MB established
6676 // 111 all other formats/drives
6678 drive_type
= inb_cmos(0x10);
6683 if ( drive_type
== 1 ) {
6685 config_data
= 0x00; // 0000 0000
6686 media_state
= 0x25; // 0010 0101
6689 else if ( drive_type
== 2 ) {
6690 // 1.2 MB 5.25" drive
6691 config_data
= 0x00; // 0000 0000
6692 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6695 else if ( drive_type
== 3 ) {
6697 config_data
= 0x00; // 0000 0000 ???
6698 media_state
= 0x17; // 0001 0111
6701 else if ( drive_type
== 4 ) {
6702 // 1.44 MB 3.5" drive
6703 config_data
= 0x00; // 0000 0000
6704 media_state
= 0x17; // 0001 0111
6707 else if ( drive_type
== 5 ) {
6708 // 2.88 MB 3.5" drive
6709 config_data
= 0xCC; // 1100 1100
6710 media_state
= 0xD7; // 1101 0111
6714 // Extended floppy size uses special cmos setting
6715 else if ( drive_type
== 6 ) {
6717 config_data
= 0x00; // 0000 0000
6718 media_state
= 0x27; // 0010 0111
6721 else if ( drive_type
== 7 ) {
6723 config_data
= 0x00; // 0000 0000
6724 media_state
= 0x27; // 0010 0111
6727 else if ( drive_type
== 8 ) {
6729 config_data
= 0x00; // 0000 0000
6730 media_state
= 0x27; // 0010 0111
6736 config_data
= 0x00; // 0000 0000
6737 media_state
= 0x00; // 0000 0000
6742 media_state_offset
= 0x90;
6744 media_state_offset
= 0x91;
6745 write_byte(0x0040, 0x008B, config_data
);
6746 write_byte(0x0040, media_state_offset
, media_state
);
6752 floppy_drive_recal(drive
)
6756 Bit16u curr_cyl_offset
;
6758 floppy_prepare_controller(drive
);
6760 // send Recalibrate command (2 bytes) to controller
6761 outb(0x03f5, 0x07); // 07: Recalibrate
6762 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6764 // turn on interrupts
6769 // wait on 40:3e bit 7 to become 1
6771 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6772 } while ( val8
== 0 );
6774 val8
= 0; // separate asm from while() loop
6775 // turn off interrupts
6780 // set 40:3e bit 7 to 0, and calibrated bit
6781 val8
= read_byte(0x0040, 0x003e);
6784 val8
|= 0x02; // Drive 1 calibrated
6785 curr_cyl_offset
= 0x0095;
6787 val8
|= 0x01; // Drive 0 calibrated
6788 curr_cyl_offset
= 0x0094;
6790 write_byte(0x0040, 0x003e, val8
);
6791 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6799 floppy_drive_exists(drive
)
6804 // check CMOS to see if drive exists
6805 drive_type
= inb_cmos(0x10);
6810 if ( drive_type
== 0 )
6816 #if BX_SUPPORT_FLOPPY
6818 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6819 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6821 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6822 Bit16u base_address
, base_count
, base_es
;
6823 Bit8u page
, mode_register
, val8
, dor
;
6824 Bit8u return_status
[7];
6825 Bit8u drive_type
, num_floppies
, ah
;
6826 Bit16u es
, last_addr
;
6828 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6833 case 0x00: // diskette controller reset
6834 BX_DEBUG_INT13_FL("floppy f00\n");
6837 SET_AH(1); // invalid param
6838 set_diskette_ret_status(1);
6842 drive_type
= inb_cmos(0x10);
6848 if (drive_type
== 0) {
6849 SET_AH(0x80); // drive not responding
6850 set_diskette_ret_status(0x80);
6855 set_diskette_ret_status(0);
6856 CLEAR_CF(); // successful
6857 set_diskette_current_cyl(drive
, 0); // current cylinder
6860 case 0x01: // Read Diskette Status
6862 val8
= read_byte(0x0000, 0x0441);
6869 case 0x02: // Read Diskette Sectors
6870 case 0x03: // Write Diskette Sectors
6871 case 0x04: // Verify Diskette Sectors
6872 num_sectors
= GET_AL();
6878 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
6879 (num_sectors
== 0) || (num_sectors
> 72)) {
6880 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
6882 set_diskette_ret_status(1);
6883 SET_AL(0); // no sectors read
6884 SET_CF(); // error occurred
6888 // see if drive exists
6889 if (floppy_drive_exists(drive
) == 0) {
6890 SET_AH(0x80); // not responding
6891 set_diskette_ret_status(0x80);
6892 SET_AL(0); // no sectors read
6893 SET_CF(); // error occurred
6897 // see if media in drive, and type is known
6898 if (floppy_media_known(drive
) == 0) {
6899 if (floppy_media_sense(drive
) == 0) {
6900 SET_AH(0x0C); // Media type not found
6901 set_diskette_ret_status(0x0C);
6902 SET_AL(0); // no sectors read
6903 SET_CF(); // error occurred
6909 // Read Diskette Sectors
6911 //-----------------------------------
6912 // set up DMA controller for transfer
6913 //-----------------------------------
6915 // es:bx = pointer to where to place information from diskette
6916 // port 04: DMA-1 base and current address, channel 2
6917 // port 05: DMA-1 base and current count, channel 2
6918 page
= (ES
>> 12); // upper 4 bits
6919 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6920 base_address
= base_es
+ BX
; // lower 16 bits of address
6921 // contributed by ES:BX
6922 if ( base_address
< base_es
) {
6923 // in case of carry, adjust page by 1
6926 base_count
= (num_sectors
* 512) - 1;
6928 // check for 64K boundary overrun
6929 last_addr
= base_address
+ base_count
;
6930 if (last_addr
< base_address
) {
6932 set_diskette_ret_status(0x09);
6933 SET_AL(0); // no sectors read
6934 SET_CF(); // error occurred
6938 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6941 BX_DEBUG_INT13_FL("clear flip-flop\n");
6942 outb(0x000c, 0x00); // clear flip-flop
6943 outb(0x0004, base_address
);
6944 outb(0x0004, base_address
>>8);
6945 BX_DEBUG_INT13_FL("clear flip-flop\n");
6946 outb(0x000c, 0x00); // clear flip-flop
6947 outb(0x0005, base_count
);
6948 outb(0x0005, base_count
>>8);
6950 // port 0b: DMA-1 Mode Register
6951 mode_register
= 0x46; // single mode, increment, autoinit disable,
6952 // transfer type=write, channel 2
6953 BX_DEBUG_INT13_FL("setting mode register\n");
6954 outb(0x000b, mode_register
);
6956 BX_DEBUG_INT13_FL("setting page register\n");
6957 // port 81: DMA-1 Page Register, channel 2
6960 BX_DEBUG_INT13_FL("unmask chan 2\n");
6961 outb(0x000a, 0x02); // unmask channel 2
6963 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6966 //--------------------------------------
6967 // set up floppy controller for transfer
6968 //--------------------------------------
6969 floppy_prepare_controller(drive
);
6971 // send read-normal-data command (9 bytes) to controller
6972 outb(0x03f5, 0xe6); // e6: read normal data
6973 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6974 outb(0x03f5, track
);
6976 outb(0x03f5, sector
);
6977 outb(0x03f5, 2); // 512 byte sector size
6978 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
6979 outb(0x03f5, 0); // Gap length
6980 outb(0x03f5, 0xff); // Gap length
6982 // turn on interrupts
6987 // wait on 40:3e bit 7 to become 1
6989 val8
= read_byte(0x0040, 0x0040);
6991 floppy_reset_controller();
6992 SET_AH(0x80); // drive not ready (timeout)
6993 set_diskette_ret_status(0x80);
6994 SET_AL(0); // no sectors read
6995 SET_CF(); // error occurred
6998 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6999 } while ( val8
== 0 );
7001 val8
= 0; // separate asm from while() loop
7002 // turn off interrupts
7007 // set 40:3e bit 7 to 0
7008 val8
= read_byte(0x0040, 0x003e);
7010 write_byte(0x0040, 0x003e, val8
);
7012 // check port 3f4 for accessibility to status bytes
7014 if ( (val8
& 0xc0) != 0xc0 )
7015 BX_PANIC("int13_diskette: ctrl not ready\n");
7017 // read 7 return status bytes from controller
7018 // using loop index broken, have to unroll...
7019 return_status
[0] = inb(0x3f5);
7020 return_status
[1] = inb(0x3f5);
7021 return_status
[2] = inb(0x3f5);
7022 return_status
[3] = inb(0x3f5);
7023 return_status
[4] = inb(0x3f5);
7024 return_status
[5] = inb(0x3f5);
7025 return_status
[6] = inb(0x3f5);
7026 // record in BIOS Data Area
7027 write_byte(0x0040, 0x0042, return_status
[0]);
7028 write_byte(0x0040, 0x0043, return_status
[1]);
7029 write_byte(0x0040, 0x0044, return_status
[2]);
7030 write_byte(0x0040, 0x0045, return_status
[3]);
7031 write_byte(0x0040, 0x0046, return_status
[4]);
7032 write_byte(0x0040, 0x0047, return_status
[5]);
7033 write_byte(0x0040, 0x0048, return_status
[6]);
7035 if ( (return_status
[0] & 0xc0) != 0 ) {
7037 set_diskette_ret_status(0x20);
7038 SET_AL(0); // no sectors read
7039 SET_CF(); // error occurred
7043 // ??? should track be new val from return_status[3] ?
7044 set_diskette_current_cyl(drive
, track
);
7045 // AL = number of sectors read (same value as passed)
7046 SET_AH(0x00); // success
7047 CLEAR_CF(); // success
7049 } else if (ah
== 0x03) {
7050 // Write Diskette Sectors
7052 //-----------------------------------
7053 // set up DMA controller for transfer
7054 //-----------------------------------
7056 // es:bx = pointer to where to place information from diskette
7057 // port 04: DMA-1 base and current address, channel 2
7058 // port 05: DMA-1 base and current count, channel 2
7059 page
= (ES
>> 12); // upper 4 bits
7060 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7061 base_address
= base_es
+ BX
; // lower 16 bits of address
7062 // contributed by ES:BX
7063 if ( base_address
< base_es
) {
7064 // in case of carry, adjust page by 1
7067 base_count
= (num_sectors
* 512) - 1;
7069 // check for 64K boundary overrun
7070 last_addr
= base_address
+ base_count
;
7071 if (last_addr
< base_address
) {
7073 set_diskette_ret_status(0x09);
7074 SET_AL(0); // no sectors read
7075 SET_CF(); // error occurred
7079 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7082 outb(0x000c, 0x00); // clear flip-flop
7083 outb(0x0004, base_address
);
7084 outb(0x0004, base_address
>>8);
7085 outb(0x000c, 0x00); // clear flip-flop
7086 outb(0x0005, base_count
);
7087 outb(0x0005, base_count
>>8);
7089 // port 0b: DMA-1 Mode Register
7090 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7091 // transfer type=read, channel 2
7092 outb(0x000b, mode_register
);
7094 // port 81: DMA-1 Page Register, channel 2
7097 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7100 //--------------------------------------
7101 // set up floppy controller for transfer
7102 //--------------------------------------
7103 floppy_prepare_controller(drive
);
7105 // send write-normal-data command (9 bytes) to controller
7106 outb(0x03f5, 0xc5); // c5: write normal data
7107 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7108 outb(0x03f5, track
);
7110 outb(0x03f5, sector
);
7111 outb(0x03f5, 2); // 512 byte sector size
7112 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7113 outb(0x03f5, 0); // Gap length
7114 outb(0x03f5, 0xff); // Gap length
7116 // turn on interrupts
7121 // wait on 40:3e bit 7 to become 1
7123 val8
= read_byte(0x0040, 0x0040);
7125 floppy_reset_controller();
7126 SET_AH(0x80); // drive not ready (timeout)
7127 set_diskette_ret_status(0x80);
7128 SET_AL(0); // no sectors written
7129 SET_CF(); // error occurred
7132 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7133 } while ( val8
== 0 );
7135 val8
= 0; // separate asm from while() loop
7136 // turn off interrupts
7141 // set 40:3e bit 7 to 0
7142 val8
= read_byte(0x0040, 0x003e);
7144 write_byte(0x0040, 0x003e, val8
);
7146 // check port 3f4 for accessibility to status bytes
7148 if ( (val8
& 0xc0) != 0xc0 )
7149 BX_PANIC("int13_diskette: ctrl not ready\n");
7151 // read 7 return status bytes from controller
7152 // using loop index broken, have to unroll...
7153 return_status
[0] = inb(0x3f5);
7154 return_status
[1] = inb(0x3f5);
7155 return_status
[2] = inb(0x3f5);
7156 return_status
[3] = inb(0x3f5);
7157 return_status
[4] = inb(0x3f5);
7158 return_status
[5] = inb(0x3f5);
7159 return_status
[6] = inb(0x3f5);
7160 // record in BIOS Data Area
7161 write_byte(0x0040, 0x0042, return_status
[0]);
7162 write_byte(0x0040, 0x0043, return_status
[1]);
7163 write_byte(0x0040, 0x0044, return_status
[2]);
7164 write_byte(0x0040, 0x0045, return_status
[3]);
7165 write_byte(0x0040, 0x0046, return_status
[4]);
7166 write_byte(0x0040, 0x0047, return_status
[5]);
7167 write_byte(0x0040, 0x0048, return_status
[6]);
7169 if ( (return_status
[0] & 0xc0) != 0 ) {
7170 if ( (return_status
[1] & 0x02) != 0 ) {
7171 // diskette not writable.
7172 // AH=status code=0x03 (tried to write on write-protected disk)
7173 // AL=number of sectors written=0
7178 BX_PANIC("int13_diskette_function: read error\n");
7182 // ??? should track be new val from return_status[3] ?
7183 set_diskette_current_cyl(drive
, track
);
7184 // AL = number of sectors read (same value as passed)
7185 SET_AH(0x00); // success
7186 CLEAR_CF(); // success
7188 } else { // if (ah == 0x04)
7189 // Verify Diskette Sectors
7191 // ??? should track be new val from return_status[3] ?
7192 set_diskette_current_cyl(drive
, track
);
7193 // AL = number of sectors verified (same value as passed)
7194 CLEAR_CF(); // success
7195 SET_AH(0x00); // success
7200 case 0x05: // format diskette track
7201 BX_DEBUG_INT13_FL("floppy f05\n");
7203 num_sectors
= GET_AL();
7208 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7209 (num_sectors
== 0) || (num_sectors
> 18)) {
7211 set_diskette_ret_status(1);
7212 SET_CF(); // error occurred
7215 // see if drive exists
7216 if (floppy_drive_exists(drive
) == 0) {
7217 SET_AH(0x80); // drive not responding
7218 set_diskette_ret_status(0x80);
7219 SET_CF(); // error occurred
7223 // see if media in drive, and type is known
7224 if (floppy_media_known(drive
) == 0) {
7225 if (floppy_media_sense(drive
) == 0) {
7226 SET_AH(0x0C); // Media type not found
7227 set_diskette_ret_status(0x0C);
7228 SET_AL(0); // no sectors read
7229 SET_CF(); // error occurred
7234 // set up DMA controller for transfer
7235 page
= (ES
>> 12); // upper 4 bits
7236 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7237 base_address
= base_es
+ BX
; // lower 16 bits of address
7238 // contributed by ES:BX
7239 if ( base_address
< base_es
) {
7240 // in case of carry, adjust page by 1
7243 base_count
= (num_sectors
* 4) - 1;
7245 // check for 64K boundary overrun
7246 last_addr
= base_address
+ base_count
;
7247 if (last_addr
< base_address
) {
7249 set_diskette_ret_status(0x09);
7250 SET_AL(0); // no sectors read
7251 SET_CF(); // error occurred
7256 outb(0x000c, 0x00); // clear flip-flop
7257 outb(0x0004, base_address
);
7258 outb(0x0004, base_address
>>8);
7259 outb(0x000c, 0x00); // clear flip-flop
7260 outb(0x0005, base_count
);
7261 outb(0x0005, base_count
>>8);
7262 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7263 // transfer type=read, channel 2
7264 outb(0x000b, mode_register
);
7265 // port 81: DMA-1 Page Register, channel 2
7269 // set up floppy controller for transfer
7270 floppy_prepare_controller(drive
);
7272 // send format-track command (6 bytes) to controller
7273 outb(0x03f5, 0x4d); // 4d: format track
7274 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7275 outb(0x03f5, 2); // 512 byte sector size
7276 outb(0x03f5, num_sectors
); // number of sectors per track
7277 outb(0x03f5, 0); // Gap length
7278 outb(0x03f5, 0xf6); // Fill byte
7279 // turn on interrupts
7284 // wait on 40:3e bit 7 to become 1
7286 val8
= read_byte(0x0040, 0x0040);
7288 floppy_reset_controller();
7289 SET_AH(0x80); // drive not ready (timeout)
7290 set_diskette_ret_status(0x80);
7291 SET_CF(); // error occurred
7294 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7295 } while ( val8
== 0 );
7297 val8
= 0; // separate asm from while() loop
7298 // turn off interrupts
7302 // set 40:3e bit 7 to 0
7303 val8
= read_byte(0x0040, 0x003e);
7305 write_byte(0x0040, 0x003e, val8
);
7306 // check port 3f4 for accessibility to status bytes
7308 if ( (val8
& 0xc0) != 0xc0 )
7309 BX_PANIC("int13_diskette: ctrl not ready\n");
7311 // read 7 return status bytes from controller
7312 // using loop index broken, have to unroll...
7313 return_status
[0] = inb(0x3f5);
7314 return_status
[1] = inb(0x3f5);
7315 return_status
[2] = inb(0x3f5);
7316 return_status
[3] = inb(0x3f5);
7317 return_status
[4] = inb(0x3f5);
7318 return_status
[5] = inb(0x3f5);
7319 return_status
[6] = inb(0x3f5);
7320 // record in BIOS Data Area
7321 write_byte(0x0040, 0x0042, return_status
[0]);
7322 write_byte(0x0040, 0x0043, return_status
[1]);
7323 write_byte(0x0040, 0x0044, return_status
[2]);
7324 write_byte(0x0040, 0x0045, return_status
[3]);
7325 write_byte(0x0040, 0x0046, return_status
[4]);
7326 write_byte(0x0040, 0x0047, return_status
[5]);
7327 write_byte(0x0040, 0x0048, return_status
[6]);
7329 if ( (return_status
[0] & 0xc0) != 0 ) {
7330 if ( (return_status
[1] & 0x02) != 0 ) {
7331 // diskette not writable.
7332 // AH=status code=0x03 (tried to write on write-protected disk)
7333 // AL=number of sectors written=0
7338 BX_PANIC("int13_diskette_function: write error\n");
7343 set_diskette_ret_status(0);
7344 set_diskette_current_cyl(drive
, 0);
7345 CLEAR_CF(); // successful
7349 case 0x08: // read diskette drive parameters
7350 BX_DEBUG_INT13_FL("floppy f08\n");
7360 SET_DL(num_floppies
);
7365 drive_type
= inb_cmos(0x10);
7367 if (drive_type
& 0xf0)
7369 if (drive_type
& 0x0f)
7381 SET_DL(num_floppies
);
7383 switch (drive_type
) {
7386 SET_DH(0); // max head #
7389 case 1: // 360KB, 5.25"
7390 CX
= 0x2709; // 40 tracks, 9 sectors
7391 SET_DH(1); // max head #
7394 case 2: // 1.2MB, 5.25"
7395 CX
= 0x4f0f; // 80 tracks, 15 sectors
7396 SET_DH(1); // max head #
7399 case 3: // 720KB, 3.5"
7400 CX
= 0x4f09; // 80 tracks, 9 sectors
7401 SET_DH(1); // max head #
7404 case 4: // 1.44MB, 3.5"
7405 CX
= 0x4f12; // 80 tracks, 18 sectors
7406 SET_DH(1); // max head #
7409 case 5: // 2.88MB, 3.5"
7410 CX
= 0x4f24; // 80 tracks, 36 sectors
7411 SET_DH(1); // max head #
7414 case 6: // 160k, 5.25"
7415 CX
= 0x2708; // 40 tracks, 8 sectors
7416 SET_DH(0); // max head #
7419 case 7: // 180k, 5.25"
7420 CX
= 0x2709; // 40 tracks, 9 sectors
7421 SET_DH(0); // max head #
7424 case 8: // 320k, 5.25"
7425 CX
= 0x2708; // 40 tracks, 8 sectors
7426 SET_DH(1); // max head #
7430 BX_PANIC("floppy: int13: bad floppy type\n");
7433 /* set es & di to point to 11 byte diskette param table in ROM */
7437 mov ax
, #diskette_param_table2
7438 mov _int13_diskette_function
.DI
+2[bp
], ax
7439 mov _int13_diskette_function
.ES
+2[bp
], cs
7442 CLEAR_CF(); // success
7443 /* disk status not changed upon success */
7447 case 0x15: // read diskette drive type
7448 BX_DEBUG_INT13_FL("floppy f15\n");
7451 SET_AH(0); // only 2 drives supported
7452 // set_diskette_ret_status here ???
7456 drive_type
= inb_cmos(0x10);
7462 CLEAR_CF(); // successful, not present
7463 if (drive_type
==0) {
7464 SET_AH(0); // drive not present
7467 SET_AH(1); // drive present, does not support change line
7472 case 0x16: // get diskette change line status
7473 BX_DEBUG_INT13_FL("floppy f16\n");
7476 SET_AH(0x01); // invalid drive
7477 set_diskette_ret_status(0x01);
7482 SET_AH(0x06); // change line not supported
7483 set_diskette_ret_status(0x06);
7487 case 0x17: // set diskette type for format(old)
7488 BX_DEBUG_INT13_FL("floppy f17\n");
7489 /* not used for 1.44M floppies */
7490 SET_AH(0x01); // not supported
7491 set_diskette_ret_status(1); /* not supported */
7495 case 0x18: // set diskette type for format(new)
7496 BX_DEBUG_INT13_FL("floppy f18\n");
7497 SET_AH(0x01); // do later
7498 set_diskette_ret_status(1);
7503 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7505 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7506 SET_AH(0x01); // ???
7507 set_diskette_ret_status(1);
7513 #else // #if BX_SUPPORT_FLOPPY
7515 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7516 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7520 switch ( GET_AH() ) {
7522 case 0x01: // Read Diskette Status
7524 val8
= read_byte(0x0000, 0x0441);
7533 write_byte(0x0000, 0x0441, 0x01);
7537 #endif // #if BX_SUPPORT_FLOPPY
7540 set_diskette_ret_status(value
)
7543 write_byte(0x0040, 0x0041, value
);
7547 set_diskette_current_cyl(drive
, cyl
)
7552 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7553 write_byte(0x0040, 0x0094+drive
, cyl
);
7557 determine_floppy_media(drive
)
7561 Bit8u val8
, DOR
, ctrl_info
;
7563 ctrl_info
= read_byte(0x0040, 0x008F);
7571 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7574 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7578 if ( (ctrl_info
& 0x04) != 0x04 ) {
7579 // Drive not determined means no drive exists, done.
7584 // check Main Status Register for readiness
7585 val8
= inb(0x03f4) & 0x80; // Main Status Register
7587 BX_PANIC("d_f_m: MRQ bit not set\n");
7591 // existing BDA values
7593 // turn on drive motor
7594 outb(0x03f2, DOR
); // Digital Output Register
7597 BX_PANIC("d_f_m: OK so far\n");
7602 int17_function(regs
, ds
, iret_addr
)
7603 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7604 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7605 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7607 Bit16u addr
,timeout
;
7614 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7615 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7616 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7617 if (regs
.u
.r8
.ah
== 0) {
7618 outb(addr
, regs
.u
.r8
.al
);
7620 outb(addr
+2, val8
| 0x01); // send strobe
7624 outb(addr
+2, val8
& ~0x01);
7625 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7629 if (regs
.u
.r8
.ah
== 1) {
7631 outb(addr
+2, val8
& ~0x04); // send init
7635 outb(addr
+2, val8
| 0x04);
7638 regs
.u
.r8
.ah
= (val8
^ 0x48);
7639 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7640 ClearCF(iret_addr
.flags
);
7642 SetCF(iret_addr
.flags
); // Unsupported
7647 int19_function(seq_nr
)
7650 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7660 // if BX_ELTORITO_BOOT is not defined, old behavior
7661 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7662 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7663 // 0: system boot sequence, first drive C: then A:
7664 // 1: system boot sequence, first drive A: then C:
7665 // else BX_ELTORITO_BOOT is defined
7666 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7667 // CMOS reg 0x3D & 0x0f : 1st boot device
7668 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7669 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7670 // boot device codes:
7671 // 0x00 : not defined
7672 // 0x01 : first floppy
7673 // 0x02 : first harddrive
7674 // 0x03 : first cdrom
7675 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7676 // else : boot failure
7678 // Get the boot sequence
7679 #if BX_ELTORITO_BOOT
7680 bootdev
= inb_cmos(0x3d);
7681 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
7682 bootdev
>>= 4 * seq_nr
;
7684 if (bootdev
== 0) BX_PANIC("No bootable device.\n");
7686 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7689 if (seq_nr
==2) BX_PANIC("No more boot devices.");
7690 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
7691 /* Boot from floppy if the bit is set or it's the second boot */
7697 /* Read the boot device from the IPL table */
7698 if (get_boot_vector(bootdev
, &e
) == 0) {
7699 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
7703 /* Do the loading, and set up vector as a far pointer to the boot
7704 * address, and bootdrv as the boot drive */
7705 print_boot_device(e
.type
);
7708 case 0x01: /* FDD */
7709 case 0x02: /* HDD */
7711 bootdrv
= (e
.type
== 0x02) ? 0x80 : 0x00;
7723 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7724 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7725 mov es
, ax
;; segment
7726 xor bx
, bx
;; offset
7727 mov ah
, #0x02 ;; function 2, read diskette sector
7728 mov al
, #0x01 ;; read 1 sector
7729 mov ch
, #0x00 ;; track 0
7730 mov cl
, #0x01 ;; sector 1
7731 mov dh
, #0x00 ;; head 0
7732 int #0x13 ;; read sector
7735 mov _int19_function
.status
+ 2[bp
], ax
7746 print_boot_failure(e
.type
, 1);
7750 /* Always check the signature on a HDD boot sector; on FDD, only do
7751 * the check if the CMOS doesn't tell us to skip it */
7752 if ((e
.type
!= 0x01) || !((inb_cmos(0x38) & 0x01))) {
7753 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7754 print_boot_failure(e
.type
, 0);
7759 /* Canonicalize bootseg:bootip */
7760 bootip
= (bootseg
& 0x0fff) << 4;
7764 #if BX_ELTORITO_BOOT
7765 case 0x03: /* CD-ROM */
7766 status
= cdrom_boot();
7769 if ( (status
& 0x00ff) !=0 ) {
7770 print_cdromboot_failure(status
);
7771 print_boot_failure(e
.type
, 1);
7775 bootdrv
= (Bit8u
)(status
>>8);
7776 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7777 /* Canonicalize bootseg:bootip */
7778 bootip
= (bootseg
& 0x0fff) << 4;
7783 case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7784 bootseg
= e
.vector
>> 16;
7785 bootip
= e
.vector
& 0xffff;
7791 /* Debugging info */
7792 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
7794 /* Jump to the boot vector */
7797 ;; Build an iret stack frame that will take us to the boot vector
.
7798 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
7800 mov ax
, _int19_function
.bootseg
+ 0[bp
]
7802 mov ax
, _int19_function
.bootip
+ 0[bp
]
7804 ;; Set the magic number in ax
and the boot drive in dl
.
7806 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
7807 ;; Zero some of the other registers
.
7818 int1a_function(regs
, ds
, iret_addr
)
7819 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7820 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7821 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7825 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
);
7831 switch (regs
.u
.r8
.ah
) {
7832 case 0: // get current clock count
7836 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7837 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7838 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7839 BiosData
->midnight_flag
= 0; // reset flag
7844 ClearCF(iret_addr
.flags
); // OK
7847 case 1: // Set Current Clock Count
7851 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7852 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7853 BiosData
->midnight_flag
= 0; // reset flag
7858 ClearCF(iret_addr
.flags
); // OK
7862 case 2: // Read CMOS Time
7863 if (rtc_updating()) {
7864 SetCF(iret_addr
.flags
);
7868 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7869 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7870 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7871 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7873 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7874 ClearCF(iret_addr
.flags
); // OK
7877 case 3: // Set CMOS Time
7878 // Using a debugger, I notice the following masking/setting
7879 // of bits in Status Register B, by setting Reg B to
7880 // a few values and getting its value after INT 1A was called.
7882 // try#1 try#2 try#3
7883 // before 1111 1101 0111 1101 0000 0000
7884 // after 0110 0010 0110 0010 0000 0010
7886 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7887 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7888 if (rtc_updating()) {
7890 // fall through as if an update were not in progress
7892 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7893 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7894 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7895 // Set Daylight Savings time enabled bit to requested value
7896 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7897 // (reg B already selected)
7898 outb_cmos(0x0b, val8
);
7900 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7901 ClearCF(iret_addr
.flags
); // OK
7904 case 4: // Read CMOS Date
7906 if (rtc_updating()) {
7907 SetCF(iret_addr
.flags
);
7910 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
7911 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
7912 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
7913 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
7914 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7915 ClearCF(iret_addr
.flags
); // OK
7918 case 5: // Set CMOS Date
7919 // Using a debugger, I notice the following masking/setting
7920 // of bits in Status Register B, by setting Reg B to
7921 // a few values and getting its value after INT 1A was called.
7923 // try#1 try#2 try#3 try#4
7924 // before 1111 1101 0111 1101 0000 0010 0000 0000
7925 // after 0110 1101 0111 1101 0000 0010 0000 0000
7927 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7928 // My assumption: RegB = (RegB & 01111111b)
7929 if (rtc_updating()) {
7931 SetCF(iret_addr
.flags
);
7934 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
7935 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
7936 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
7937 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
7938 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7939 outb_cmos(0x0b, val8
);
7941 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
7942 ClearCF(iret_addr
.flags
); // OK
7945 case 6: // Set Alarm Time in CMOS
7946 // Using a debugger, I notice the following masking/setting
7947 // of bits in Status Register B, by setting Reg B to
7948 // a few values and getting its value after INT 1A was called.
7950 // try#1 try#2 try#3
7951 // before 1101 1111 0101 1111 0000 0000
7952 // after 0110 1111 0111 1111 0010 0000
7954 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7955 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7956 val8
= inb_cmos(0x0b); // Get Status Reg B
7959 // Alarm interrupt enabled already
7960 SetCF(iret_addr
.flags
); // Error: alarm in use
7963 if (rtc_updating()) {
7965 // fall through as if an update were not in progress
7967 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
7968 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
7969 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
7970 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7971 // enable Status Reg B alarm bit, clear halt clock bit
7972 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
7973 ClearCF(iret_addr
.flags
); // OK
7976 case 7: // Turn off Alarm
7977 // Using a debugger, I notice the following masking/setting
7978 // of bits in Status Register B, by setting Reg B to
7979 // a few values and getting its value after INT 1A was called.
7981 // try#1 try#2 try#3 try#4
7982 // before 1111 1101 0111 1101 0010 0000 0010 0010
7983 // after 0100 0101 0101 0101 0000 0000 0000 0010
7985 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7986 // My assumption: RegB = (RegB & 01010111b)
7987 val8
= inb_cmos(0x0b); // Get Status Reg B
7988 // clear clock-halt bit, disable alarm bit
7989 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
7991 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7992 ClearCF(iret_addr
.flags
); // OK
7996 // real mode PCI BIOS functions now handled in assembler code
7997 // this C code handles the error code for information only
7998 if (regs
.u
.r8
.bl
== 0xff) {
7999 BX_INFO("PCI BIOS: PCI not present\n");
8000 } else if (regs
.u
.r8
.bl
== 0x81) {
8001 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8002 } else if (regs
.u
.r8
.bl
== 0x83) {
8003 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8004 } else if (regs
.u
.r8
.bl
== 0x86) {
8005 if (regs
.u
.r8
.al
== 0x02) {
8006 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8008 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
);
8011 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8012 SetCF(iret_addr
.flags
);
8017 SetCF(iret_addr
.flags
); // Unsupported
8022 int70_function(regs
, ds
, iret_addr
)
8023 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8024 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8025 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8027 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8028 Bit8u registerB
= 0, registerC
= 0;
8030 // Check which modes are enabled and have occurred.
8031 registerB
= inb_cmos( 0xB );
8032 registerC
= inb_cmos( 0xC );
8034 if( ( registerB
& 0x60 ) != 0 ) {
8035 if( ( registerC
& 0x20 ) != 0 ) {
8036 // Handle Alarm Interrupt.
8043 if( ( registerC
& 0x40 ) != 0 ) {
8044 // Handle Periodic Interrupt.
8046 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8047 // Wait Interval (Int 15, AH=83) active.
8048 Bit32u time
, toggle
;
8050 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8051 if( time
< 0x3D1 ) {
8053 Bit16u segment
, offset
;
8055 segment
= read_word( 0x40, 0x98 );
8056 offset
= read_word( 0x40, 0x9A );
8057 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8058 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8059 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8061 // Continue waiting.
8063 write_dword( 0x40, 0x9C, time
);
8076 ;------------------------------------------
8077 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8078 ;------------------------------------------
8083 push
#0x00 ;; placeholder for status
8084 push
#0x00 ;; placeholder for X
8085 push
#0x00 ;; placeholder for Y
8086 push
#0x00 ;; placeholder for Z
8087 push
#0x00 ;; placeholder for make_far_call boolean
8088 call _int74_function
8089 pop cx
;; remove make_far_call from stack
8092 ;; make far call to EBDA
:0022
8095 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8097 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8102 add sp
, #8 ;; pop status, x, y, z
8104 pop ds
;; restore DS
8109 ;; This will perform an IRET
, but will retain value of current CF
8110 ;; by altering flags on stack
. Better than RETF
#02.
8115 and BYTE
[bp
+ 0x06], #0xfe
8121 or BYTE
[bp
+ 0x06], #0x01
8126 ;----------------------
8127 ;- INT13h (relocated
) -
8128 ;----------------------
8130 ; int13_relocated is a little bit messed up since I played with it
8131 ; I have to rewrite it
:
8132 ; - call a function that detect which function to call
8133 ; - make all called C function get the same parameters list
8137 #if BX_ELTORITO_BOOT
8138 ;; check
for an eltorito function
8140 jb int13_not_eltorito
8142 ja int13_not_eltorito
8151 jmp _int13_eltorito
;; ELDX
not used
8159 ;; check
if emulation active
8160 call _cdemu_isactive
8162 je int13_cdemu_inactive
8164 ;; check
if access to the emulated drive
8165 call _cdemu_emulated_drive
8168 cmp al
,dl
;; int13 on emulated drive
8183 jmp _int13_cdemu
;; ELDX
not used
8186 and dl
,#0xE0 ;; mask to get device class, including cdroms
8187 cmp al
,dl
;; al is
0x00 or 0x80
8188 jne int13_cdemu_inactive
;; inactive
for device
class
8200 dec dl
;; real drive is dl
- 1
8203 int13_cdemu_inactive
:
8209 #endif // BX_ELTORITO_BOOT
8220 push dx
;; push eltorito value of dx instead of sp
8231 ;; now the
16-bit registers can be restored with
:
8232 ;; pop ds
; pop es
; popa
; iret
8233 ;; arguments passed to functions should be
8234 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8240 jmp _int13_diskette_function
8249 // ebx is modified: BSD 5.2.1 boot loader problem
8250 // someone should figure out which 32 bit register that actually are used
8267 ;; int13_harddisk modifies high word of EAX
8270 call _int13_harddisk
8283 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8291 ;; Get the boot sequence number out of the IPL memory
8293 mov ds
, bx
;; Set segment
8294 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8296 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8297 mov ds
, ax
;; and reset the segment to zero
.
8299 ;; Carry on in the INT
19h handler
, using the
new sequence number
8307 int19_relocated
: ;; Boot function
, relocated
8309 ;; int19 was beginning to be really
complex, so now it
8310 ;; just calls a C function that does the work
8321 ;; Start from the first boot
device (0, in AX
)
8323 mov ds
, bx
;; Set segment to write to the IPL memory
8324 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8325 mov ds
, ax
;; and reset the segment
.
8331 ;; Call the C code
for the next boot device
8332 call _int19_function
8334 ;; Boot failed
: invoke the boot recovery function
8340 int1c_handler
: ;; User Timer Tick
8344 ;----------------------
8345 ;- POST
: Floppy Drive
-
8346 ;----------------------
8352 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8354 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8356 mov
0x0440, al
;; diskette motor timeout counter
: not active
8357 mov
0x0441, al
;; diskette controller status
return code
8359 mov
0x0442, al
;; disk
& diskette controller status
register 0
8360 mov
0x0443, al
;; diskette controller status
register 1
8361 mov
0x0444, al
;; diskette controller status
register 2
8362 mov
0x0445, al
;; diskette controller cylinder number
8363 mov
0x0446, al
;; diskette controller head number
8364 mov
0x0447, al
;; diskette controller sector number
8365 mov
0x0448, al
;; diskette controller bytes written
8367 mov
0x048b, al
;; diskette configuration data
8369 ;; -----------------------------------------------------------------
8370 ;; (048F
) diskette controller information
8372 mov al
, #0x10 ;; get CMOS diskette drive type
8375 mov ah
, al
;; save byte to AH
8378 shr al
, #4 ;; look at top 4 bits for drive 0
8379 jz f0_missing
;; jump
if no drive0
8380 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8383 mov bl
, #0x00 ;; no drive0
8386 mov al
, ah
;; restore from AH
8387 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8388 jz f1_missing
;; jump
if no drive1
8389 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8391 ;; leave high bits in BL zerod
8392 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8393 ;; -----------------------------------------------------------------
8396 mov
0x0490, al
;; diskette
0 media state
8397 mov
0x0491, al
;; diskette
1 media state
8399 ;; diskette
0,1 operational starting state
8400 ;; drive type has
not been determined
,
8401 ;; has no changed detection line
8405 mov
0x0494, al
;; diskette
0 current cylinder
8406 mov
0x0495, al
;; diskette
1 current cylinder
8409 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8411 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8412 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8413 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8418 ;--------------------
8419 ;- POST
: HARD DRIVE
-
8420 ;--------------------
8421 ; relocated here because the primary POST area isnt big enough
.
8424 // INT 76h calls INT 15h function ax=9100
8426 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8432 mov
0x0474, al
/* hard disk status of last operation */
8433 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8434 mov
0x048c, al
/* hard disk status register */
8435 mov
0x048d, al
/* hard disk error register */
8436 mov
0x048e, al
/* hard disk task complete flag */
8438 mov
0x0475, al
/* hard disk number attached */
8440 mov
0x0476, al
/* hard disk control byte */
8441 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8442 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8443 ;; INT
41h
: hard disk
0 configuration pointer
8444 ;; INT
46h
: hard disk
1 configuration pointer
8445 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8446 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8448 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8460 cmp al
, #47 ;; decimal 47 - user definable
8464 ;; CMOS purpose param table offset
8465 ;; 1b cylinders low
0
8466 ;; 1c cylinders high
1
8468 ;; 1e write pre
-comp low
5
8469 ;; 1f write pre
-comp high
6
8470 ;; 20 retries
/bad map
/heads
>8 8
8471 ;; 21 landing zone low C
8472 ;; 22 landing zone high D
8473 ;; 23 sectors
/track E
8478 ;;; Filling EBDA table
for hard disk
0.
8486 mov (0x003d + 0x05), ax
;; write precomp word
8491 mov (0x003d + 0x08), al
;; drive control byte
8500 mov (0x003d + 0x0C), ax
;; landing zone word
8502 mov al
, #0x1c ;; get cylinders word in AX
8504 in al
, #0x71 ;; high byte
8508 in al
, #0x71 ;; low byte
8509 mov bx
, ax
;; BX
= cylinders
8514 mov cl
, al
;; CL
= heads
8519 mov dl
, al
;; DL
= sectors
8522 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8524 hd0_post_physical_chs
:
8525 ;; no logical CHS mapping used
, just physical CHS
8526 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8527 mov (0x003d + 0x00), bx
;; number of physical cylinders
8528 mov (0x003d + 0x02), cl
;; number of physical heads
8529 mov (0x003d + 0x0E), dl
;; number of physical sectors
8532 hd0_post_logical_chs
:
8533 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8534 mov (0x003d + 0x09), bx
;; number of physical cylinders
8535 mov (0x003d + 0x0b), cl
;; number of physical heads
8536 mov (0x003d + 0x04), dl
;; number of physical sectors
8537 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8539 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8542 jnbe hd0_post_above_2048
8543 ;; 1024 < c
<= 2048 cylinders
8546 jmp hd0_post_store_logical
8548 hd0_post_above_2048
:
8550 jnbe hd0_post_above_4096
8551 ;; 2048 < c
<= 4096 cylinders
8554 jmp hd0_post_store_logical
8556 hd0_post_above_4096
:
8558 jnbe hd0_post_above_8192
8559 ;; 4096 < c
<= 8192 cylinders
8562 jmp hd0_post_store_logical
8564 hd0_post_above_8192
:
8565 ;; 8192 < c
<= 16384 cylinders
8569 hd0_post_store_logical
:
8570 mov (0x003d + 0x00), bx
;; number of physical cylinders
8571 mov (0x003d + 0x02), cl
;; number of physical heads
8573 mov cl
, #0x0f ;; repeat count
8574 mov si
, #0x003d ;; offset to disk0 FDPT
8575 mov al
, #0x00 ;; sum
8576 hd0_post_checksum_loop
:
8580 jnz hd0_post_checksum_loop
8581 not al
;; now take
2s complement
8584 ;;; Done filling EBDA table
for hard disk
0.
8588 ;; is there really a second hard disk
? if not, return now
8596 ;; check that the hd type is really
0x0f.
8601 ;; check that the extended type is
47 - user definable
8605 cmp al
, #47 ;; decimal 47 - user definable
8610 ;; CMOS purpose param table offset
8611 ;; 0x24 cylinders low
0
8612 ;; 0x25 cylinders high
1
8614 ;; 0x27 write pre
-comp low
5
8615 ;; 0x28 write pre
-comp high
6
8617 ;; 0x2a landing zone low C
8618 ;; 0x2b landing zone high D
8619 ;; 0x2c sectors
/track E
8620 ;;; Fill EBDA table
for hard disk
1.
8630 mov (0x004d + 0x05), ax
;; write precomp word
8635 mov (0x004d + 0x08), al
;; drive control byte
8644 mov (0x004d + 0x0C), ax
;; landing zone word
8646 mov al
, #0x25 ;; get cylinders word in AX
8648 in al
, #0x71 ;; high byte
8652 in al
, #0x71 ;; low byte
8653 mov bx
, ax
;; BX
= cylinders
8658 mov cl
, al
;; CL
= heads
8663 mov dl
, al
;; DL
= sectors
8666 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8668 hd1_post_physical_chs
:
8669 ;; no logical CHS mapping used
, just physical CHS
8670 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8671 mov (0x004d + 0x00), bx
;; number of physical cylinders
8672 mov (0x004d + 0x02), cl
;; number of physical heads
8673 mov (0x004d + 0x0E), dl
;; number of physical sectors
8676 hd1_post_logical_chs
:
8677 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8678 mov (0x004d + 0x09), bx
;; number of physical cylinders
8679 mov (0x004d + 0x0b), cl
;; number of physical heads
8680 mov (0x004d + 0x04), dl
;; number of physical sectors
8681 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8683 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8686 jnbe hd1_post_above_2048
8687 ;; 1024 < c
<= 2048 cylinders
8690 jmp hd1_post_store_logical
8692 hd1_post_above_2048
:
8694 jnbe hd1_post_above_4096
8695 ;; 2048 < c
<= 4096 cylinders
8698 jmp hd1_post_store_logical
8700 hd1_post_above_4096
:
8702 jnbe hd1_post_above_8192
8703 ;; 4096 < c
<= 8192 cylinders
8706 jmp hd1_post_store_logical
8708 hd1_post_above_8192
:
8709 ;; 8192 < c
<= 16384 cylinders
8713 hd1_post_store_logical
:
8714 mov (0x004d + 0x00), bx
;; number of physical cylinders
8715 mov (0x004d + 0x02), cl
;; number of physical heads
8717 mov cl
, #0x0f ;; repeat count
8718 mov si
, #0x004d ;; offset to disk0 FDPT
8719 mov al
, #0x00 ;; sum
8720 hd1_post_checksum_loop
:
8724 jnz hd1_post_checksum_loop
8725 not al
;; now take
2s complement
8728 ;;; Done filling EBDA table
for hard disk
1.
8732 ;--------------------
8733 ;- POST
: EBDA segment
8734 ;--------------------
8735 ; relocated here because the primary POST area isnt big enough
.
8740 mov byte ptr
[0x0], #EBDA_SIZE
8742 xor ax
, ax
; mov EBDA seg into
40E
8744 mov word ptr
[0x40E], #EBDA_SEG
8747 ;--------------------
8748 ;- POST
: EOI
+ jmp via
[0x40:67)
8749 ;--------------------
8750 ; relocated here because the primary POST area isnt big enough
.
8760 ;--------------------
8763 out
#0xA0, al ;; slave PIC EOI
8766 out
#0x20, al ;; master PIC EOI
8769 ;--------------------
8771 ;; in
: AL in BCD format
8772 ;; out
: AL in binary format
, AH will always be
0
8775 and bl
, #0x0f ;; bl has low digit
8776 shr al
, #4 ;; al has high digit
8778 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8779 add al
, bl
;; then add low digit
8782 ;--------------------
8784 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8785 ;; Timer Ticks Roller
Flag (0x470:byte
)
8786 ;; The Timer Ticks Count needs to be set according to
8787 ;; the current CMOS time
, as
if ticks have been occurring
8788 ;; at
18.2hz since midnight up to
this point
. Calculating
8789 ;; this is a little complicated
. Here are the factors I gather
8790 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8791 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8792 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8793 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8794 ;; the timer
. With a maximum
16bit timer count
, this is again
8795 ;; divided down by
65536 to
18.2hz
.
8797 ;; 14,318,180 Hz clock
8798 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8799 ;; /4 = 1,193,181 Hz fed to timer
8800 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8801 ;; 1 second
= 18.20650736 ticks
8802 ;; 1 minute
= 1092.390442 ticks
8803 ;; 1 hour
= 65543.42651 ticks
8805 ;; Given the values in the CMOS clock
, one could calculate
8806 ;; the number of ticks by the following
:
8807 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8808 ;; (BcdToBin(minutes
) * 1092.3904)
8809 ;; (BcdToBin(hours
) * 65543.427)
8810 ;; To get a little more accuracy
, since Im
using integer
8811 ;; arithmatic
, I use
:
8812 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8813 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8814 ;; (BcdToBin(hours
) * 65543427) / 1000
8819 xor eax
, eax
;; clear EAX
8822 in al
, #0x71 ;; AL has CMOS seconds in BCD
8823 call BcdToBin
;; EAX now has seconds in binary
8829 mov ecx
, eax
;; ECX will accumulate total ticks
8832 xor eax
, eax
;; clear EAX
8835 in al
, #0x71 ;; AL has CMOS minutes in BCD
8836 call BcdToBin
;; EAX now has minutes in binary
8842 add ecx
, eax
;; add to total ticks
8845 xor eax
, eax
;; clear EAX
8848 in al
, #0x71 ;; AL has CMOS hours in BCD
8849 call BcdToBin
;; EAX now has hours in binary
8855 add ecx
, eax
;; add to total ticks
8857 mov
0x46C, ecx
;; Timer Ticks Count
8859 mov
0x470, al
;; Timer Ticks Rollover Flag
8862 ;--------------------
8864 ;; record completion in BIOS task complete flag
8876 ;--------------------
8881 #include "apmbios.S"
8885 #include "apmbios.S"
8888 #include "apmbios.S"
8892 ;--------------------
8897 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8898 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8899 db
0 ;; revision level
8900 ;; length in paragraphs
and checksum stored in a word to prevent errors
8901 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8902 & 0xff) << 8) + 0x01
8903 db
0,0,0,0,0 ;; reserved
8908 cmp eax
, #0x49435024 ;; "$PCI"
8910 mov eax
, #0x80000000
8915 #ifdef PCI_FIXED_HOST_BRIDGE
8916 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8919 ;; say ok
if a device is present
8920 cmp eax
, #0xffffffff
8923 mov ebx
, #0x000f0000
8925 mov edx
, #pcibios_protected
8932 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
8943 cmp al
, #0x01 ;; installation check
8947 mov edx
, #0x20494350 ;; "PCI "
8950 pci_pro_f02
: ;; find pci device
8958 call pci_pro_select_reg
8972 pci_pro_f03
: ;; find
class code
8978 call pci_pro_select_reg
8983 jne pci_pro_nextdev2
8990 jne pci_pro_devloop2
8993 pci_pro_f08
: ;; read configuration byte
8996 call pci_pro_select_reg
9005 pci_pro_f09
: ;; read configuration word
9008 call pci_pro_select_reg
9017 pci_pro_f0a
: ;; read configuration dword
9020 call pci_pro_select_reg
9027 pci_pro_f0b
: ;; write configuration byte
9030 call pci_pro_select_reg
9039 pci_pro_f0c
: ;; write configuration word
9042 call pci_pro_select_reg
9051 pci_pro_f0d
: ;; write configuration dword
9054 call pci_pro_select_reg
9067 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9077 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9101 mov eax
, #0x80000000
9106 #ifdef PCI_FIXED_HOST_BRIDGE
9107 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9110 ;; say ok
if a device is present
9111 cmp eax
, #0xffffffff
9122 cmp al
, #0x01 ;; installation check
9127 mov edx
, #0x20494350 ;; "PCI "
9129 mov di
, #pcibios_protected
9132 pci_real_f02
: ;; find pci device
9142 call pci_real_select_reg
9146 jne pci_real_nextdev
9153 jne pci_real_devloop
9158 pci_real_f03
: ;; find
class code
9164 call pci_real_select_reg
9169 jne pci_real_nextdev2
9176 jne pci_real_devloop2
9181 pci_real_f08
: ;; read configuration byte
9184 call pci_real_select_reg
9193 pci_real_f09
: ;; read configuration word
9196 call pci_real_select_reg
9205 pci_real_f0a
: ;; read configuration dword
9208 call pci_real_select_reg
9215 pci_real_f0b
: ;; write configuration byte
9218 call pci_real_select_reg
9227 pci_real_f0c
: ;; write configuration word
9230 call pci_real_select_reg
9239 pci_real_f0d
: ;; write configuration dword
9242 call pci_real_select_reg
9249 pci_real_f0e
: ;; get irq routing options
9251 jne pci_real_unknown
9253 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9254 jb pci_real_too_small
9256 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9264 mov si
, #pci_routing_table_structure_start
9272 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9281 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9285 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9303 pci_real_select_reg
:
9317 pci_routing_table_structure
:
9318 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9320 dw
32 + (6 * 16) ;; table size
9321 db
0 ;; PCI interrupt router bus
9322 db
0x08 ;; PCI interrupt router DevFunc
9323 dw
0x0000 ;; PCI exclusive IRQs
9324 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9325 dw
0x7000 ;; compatible PCI interrupt router device ID
9326 dw
0,0 ;; Miniport data
9327 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9329 pci_routing_table_structure_start
:
9330 ;; first slot entry PCI
-to
-ISA (embedded
)
9331 db
0 ;; pci bus number
9332 db
0x08 ;; pci device
number (bit
7-3)
9333 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9334 dw
0xdef8 ;; IRQ bitmap INTA
#
9335 db
0x61 ;; link value INTB
#
9336 dw
0xdef8 ;; IRQ bitmap INTB
#
9337 db
0x62 ;; link value INTC
#
9338 dw
0xdef8 ;; IRQ bitmap INTC
#
9339 db
0x63 ;; link value INTD
#
9340 dw
0xdef8 ;; IRQ bitmap INTD
#
9341 db
0 ;; physical
slot (0 = embedded
)
9343 ;; second slot entry
: 1st PCI slot
9344 db
0 ;; pci bus number
9345 db
0x10 ;; pci device
number (bit
7-3)
9346 db
0x61 ;; link value INTA
#
9347 dw
0xdef8 ;; IRQ bitmap INTA
#
9348 db
0x62 ;; link value INTB
#
9349 dw
0xdef8 ;; IRQ bitmap INTB
#
9350 db
0x63 ;; link value INTC
#
9351 dw
0xdef8 ;; IRQ bitmap INTC
#
9352 db
0x60 ;; link value INTD
#
9353 dw
0xdef8 ;; IRQ bitmap INTD
#
9354 db
1 ;; physical
slot (0 = embedded
)
9356 ;; third slot entry
: 2nd PCI slot
9357 db
0 ;; pci bus number
9358 db
0x18 ;; pci device
number (bit
7-3)
9359 db
0x62 ;; link value INTA
#
9360 dw
0xdef8 ;; IRQ bitmap INTA
#
9361 db
0x63 ;; link value INTB
#
9362 dw
0xdef8 ;; IRQ bitmap INTB
#
9363 db
0x60 ;; link value INTC
#
9364 dw
0xdef8 ;; IRQ bitmap INTC
#
9365 db
0x61 ;; link value INTD
#
9366 dw
0xdef8 ;; IRQ bitmap INTD
#
9367 db
2 ;; physical
slot (0 = embedded
)
9369 ;; 4th slot entry
: 3rd PCI slot
9370 db
0 ;; pci bus number
9371 db
0x20 ;; pci device
number (bit
7-3)
9372 db
0x63 ;; link value INTA
#
9373 dw
0xdef8 ;; IRQ bitmap INTA
#
9374 db
0x60 ;; link value INTB
#
9375 dw
0xdef8 ;; IRQ bitmap INTB
#
9376 db
0x61 ;; link value INTC
#
9377 dw
0xdef8 ;; IRQ bitmap INTC
#
9378 db
0x62 ;; link value INTD
#
9379 dw
0xdef8 ;; IRQ bitmap INTD
#
9380 db
3 ;; physical
slot (0 = embedded
)
9382 ;; 5th slot entry
: 4rd PCI slot
9383 db
0 ;; pci bus number
9384 db
0x28 ;; pci device
number (bit
7-3)
9385 db
0x60 ;; link value INTA
#
9386 dw
0xdef8 ;; IRQ bitmap INTA
#
9387 db
0x61 ;; link value INTB
#
9388 dw
0xdef8 ;; IRQ bitmap INTB
#
9389 db
0x62 ;; link value INTC
#
9390 dw
0xdef8 ;; IRQ bitmap INTC
#
9391 db
0x63 ;; link value INTD
#
9392 dw
0xdef8 ;; IRQ bitmap INTD
#
9393 db
4 ;; physical
slot (0 = embedded
)
9395 ;; 6th slot entry
: 5rd PCI slot
9396 db
0 ;; pci bus number
9397 db
0x30 ;; pci device
number (bit
7-3)
9398 db
0x61 ;; link value INTA
#
9399 dw
0xdef8 ;; IRQ bitmap INTA
#
9400 db
0x62 ;; link value INTB
#
9401 dw
0xdef8 ;; IRQ bitmap INTB
#
9402 db
0x63 ;; link value INTC
#
9403 dw
0xdef8 ;; IRQ bitmap INTC
#
9404 db
0x60 ;; link value INTD
#
9405 dw
0xdef8 ;; IRQ bitmap INTD
#
9406 db
5 ;; physical
slot (0 = embedded
)
9408 pci_routing_table_structure_end
:
9414 pcibios_init_sel_reg
:
9426 pcibios_init_iomem_bases
:
9429 mov eax
, #0xe0000000 ;; base for memory init
9431 mov ax
, #0xc000 ;; base for i/o init
9433 mov ax
, #0x0010 ;; start at base address #0
9438 call pcibios_init_sel_reg
9443 mov dl
, #0x04 ;; disable i/o and memory space access
9444 call pcibios_init_sel_reg
9451 call pcibios_init_sel_reg
9457 mov eax
, #0xffffffff
9462 xor eax
, #0xffffffff
9466 add eax
, ecx
;; calculate next free mem base
9467 add eax
, #0x01000000
9468 and eax
, #0xff000000
9482 add ax
, cx
;; calculate next free i
/o base
9490 je enable_iomem_space
9491 mov byte ptr
[bp
-8], al
9492 jmp pci_init_io_loop2
9494 mov dl
, #0x04 ;; enable i/o and memory space access if available
9495 call pcibios_init_sel_reg
9501 mov byte ptr
[bp
-8], #0x10
9504 jne pci_init_io_loop1
9509 pcibios_init_set_elcr
:
9533 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9538 mov si
, #pci_routing_table_structure
9542 call pcibios_init_sel_reg
9545 cmp eax
, [si
+12] ;; check irq router
9548 call pcibios_init_sel_reg
9549 push bx
;; save irq router bus
+ devfunc
9552 out dx
, ax
;; reset PIRQ route control
9560 add si
, #0x20 ;; set pointer to 1st entry
9562 mov ax
, #pci_irq_list
9571 call pcibios_init_sel_reg
9575 jnz pci_test_int_pin
9581 call pcibios_init_sel_reg
9586 dec al
;; determine pirq reg
9595 call pcibios_init_sel_reg
9602 mov bx
, [bp
-2] ;; pci irq list pointer
9607 call pcibios_init_set_elcr
9611 add bl
, [bp
-3] ;; pci function number
9613 call pcibios_init_sel_reg
9620 jnz pci_init_irq_loop2
9623 mov byte ptr
[bp
-3], #0x00
9624 loop pci_init_irq_loop1
9631 #endif // BX_ROMBIOS32
9632 #endif // BX_PCIBIOS
9636 ;; save a20
and enable it
9642 ;; save SS
:SP to the BDA
9649 lidt
[pmode_IDT_info
]
9651 lgdt
[rombios32_gdt_48
]
9652 ;; set PE bit in CR0
9656 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
9659 dw
0x000f ;; high
16 bit address
9664 ;; init data segments
9674 ;; copy rombios32 code to
ram (ram offset
= 1MB
)
9675 mov esi
, #0xfffe0000
9676 mov edi
, #0x00040000
9677 mov ecx
, #0x10000 / 4
9681 ;; init the stack pointer
9682 mov esp
, #0x00080000
9684 ;; call rombios32 code
9685 mov eax
, #0x00040000
9688 ;; reset the
memory (some boot loaders such as syslinux suppose
9689 ;; that the memory is set to zero
)
9690 mov edi
, #0x00040000
9691 mov ecx
, #0x40000 / 4
9696 ;; reset the
memory (some boot loaders such as syslinux suppose
9697 ;; that the memory is set to zero
)
9698 mov edi
, #0x00040000
9699 mov ecx
, #0x40000 / 4
9704 ;; return to
16 bit
protected mode first
9711 ;; restore data segment limits to
0xffff
9719 ;; reset PE bit in CR0
9724 ;; far jump to flush CPU queue after transition to real mode
9725 JMP_AP(0xf000, rombios32_real_mode
)
9727 rombios32_real_mode
:
9728 ;; restore IDT to normal real
-mode defaults
9730 lidt
[rmode_IDT_info
]
9738 ;; restore SS
:SP from the BDA
9755 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
9756 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
9757 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
9758 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
9762 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9767 and al
, #0xdf ; clear input mode
9777 mov
[bx
+0x408], dx
; Parallel I
/O address
9779 mov
[bx
+0x478], cl
; Parallel printer timeout
9784 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9803 mov
[bx
+0x400], dx
; Serial I
/O address
9805 mov
[bx
+0x47c], cl
; Serial timeout
9832 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
9833 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
9841 ;; Scan
for existence of valid expansion ROMS
.
9842 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9843 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9844 ;; System ROM
: only
0xE0000
9850 ;; 2 ROM length in
512-byte blocks
9851 ;; 3 ROM initialization entry
point (FAR CALL
)
9856 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9857 cmp
[0], #0xAA55 ;; look for signature
9858 jne rom_scan_increment
9860 jnz rom_scan_increment
9861 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9863 ;; We want our increment in
512-byte quantities
, rounded to
9864 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9866 jz block_count_rounded
9867 and al
, #0xfc ;; needs rounding up
9869 block_count_rounded
:
9871 xor bx
, bx
;; Restore DS back to
0000:
9875 ;; Push addr of ROM entry point
9877 push
#0x0003 ;; Push offset
9879 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
9880 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
9885 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9886 db
0xff ;; call_far ss
:[bp
+0]
9889 cli
;; In
case expansion ROM BIOS turns IF on
9890 add sp
, #2 ;; Pop offset value
9891 pop cx
;; Pop seg
value (restore CX
)
9893 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
9894 ;; to init all the ROMs
and then go back
and build an IPL table of
9895 ;; all the bootable devices
, but we can get away with one pass
.
9896 mov ds
, cx
;; ROM base
9897 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
9898 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
9899 cmp ax
, #0x5024 ;; we look for signature "$PnP"
9904 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
9905 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
9908 ;; Found a device that thinks it can boot the system
. Record its BEV
.
9909 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
9911 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
9912 cmp bx
, #IPL_TABLE_ENTRIES
9913 je no_bev
;; Get out
if the table is full
9914 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
9915 mov
0[bx
], #0x80 ;; This entry is a BEV device
9916 mov
6[bx
], cx
;; Build a far pointer from the segment
...
9917 mov
4[bx
], ax
;; and the offset
9918 shr bx
, #0x4 ;; Turn the offset back into a count
9919 inc bx
;; We have one more entry now
9920 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
9923 pop di
;; Restore DI
9924 pop ax
;; Restore AX
9926 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
9927 ;; because the segment selector is shifted left
4 bits
.
9932 xor ax
, ax
;; Restore DS back to
0000:
9936 ;; for 'C' strings
and other data
, insert them here with
9937 ;; a the following hack
:
9938 ;; DATA_SEG_DEFS_HERE
9941 ;; the following area can be used to write dynamically generated tables
9943 bios_table_area_start
:
9945 dd bios_table_area_end
- bios_table_area_start
- 8;
9950 .org
0xe05b ; POST Entry Point
9951 bios_table_area_end
:
9955 and eax
, #0x9fffffff
9960 ;; first reset the DMA controllers
9964 ;; then initialize the DMA controllers
9966 out
0xD6, al
; cascade mode of channel
4 enabled
9968 out
0xD4, al
; unmask channel
4
9970 ;; Examine CMOS shutdown status
.
9978 ;; Reset CMOS shutdown status
.
9980 out
0x70, AL
; select CMOS
register Fh
9982 out
0x71, AL
; set shutdown action to normal
9984 ;; Examine CMOS shutdown status
.
9987 ;; 0x00, 0x09, 0x0D+ = normal startup
9995 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
9999 ;; Examine CMOS shutdown status
.
10000 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
10002 call _shutdown_status_panic
10008 ; 0xb0, 0x20, /* mov al, #0x20 */
10009 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10019 ; case 0: normal startup
10028 ;; zero out BIOS data
area (40:00..40:ff
)
10030 mov cx
, #0x0080 ;; 128 words
10036 call _log_bios_start
10038 ;; set all interrupts to
default handler
10039 xor bx
, bx
;; offset index
10040 mov cx
, #0x0100 ;; counter (256 interrupts)
10041 mov ax
, #dummy_iret_handler
10051 loop post_default_ints
10053 ;; set vector
0x79 to zero
10054 ;; this is used by
'gardian angel' protection system
10055 SET_INT_VECTOR(0x79, #0, #0)
10057 ;; base memory in K
40:13 (word
)
10058 mov ax
, #BASE_MEM_IN_K
10062 ;; Manufacturing Test
40:12
10065 ;; Warm Boot Flag
0040:0072
10066 ;; value of
1234h
= skip memory checks
10070 ;; Printer Services vector
10071 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10073 ;; Bootstrap failure vector
10074 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10076 ;; Bootstrap Loader vector
10077 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10079 ;; User Timer Tick vector
10080 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10082 ;; Memory Size Check vector
10083 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10085 ;; Equipment Configuration Check vector
10086 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10089 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10095 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10096 ;; int 1C already points at
dummy_iret_handler (above
)
10097 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10099 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10104 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10105 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10109 mov
0x0417, al
/* keyboard shift flags, set 1 */
10110 mov
0x0418, al
/* keyboard shift flags, set 2 */
10111 mov
0x0419, al
/* keyboard alt-numpad work area */
10112 mov
0x0471, al
/* keyboard ctrl-break flag */
10113 mov
0x0497, al
/* keyboard status flags 4 */
10115 mov
0x0496, al
/* keyboard status flags 3 */
10118 /* keyboard head of buffer pointer */
10122 /* keyboard end of buffer pointer */
10125 /* keyboard pointer to start of buffer */
10129 /* keyboard pointer to end of buffer */
10133 /* init the keyboard */
10134 call _keyboard_init
10136 ;; mov CMOS Equipment Byte to BDA Equipment Word
10145 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10149 mov cl
, #0x14 ; timeout value
10150 mov dx
, #0x378 ; Parallel I/O address, port 1
10151 call detect_parport
10152 mov dx
, #0x278 ; Parallel I/O address, port 2
10153 call detect_parport
10155 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10157 or ax
, bx
; set number of parallel ports
10161 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10162 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10164 mov cl
, #0x0a ; timeout value
10165 mov dx
, #0x03f8 ; Serial I/O address, port 1
10167 mov dx
, #0x02f8 ; Serial I/O address, port 2
10169 mov dx
, #0x03e8 ; Serial I/O address, port 3
10171 mov dx
, #0x02e8 ; Serial I/O address, port 4
10174 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10176 or ax
, bx
; set number of serial port
10180 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10181 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10182 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10183 ;; BIOS DATA AREA
0x4CE ???
10184 call timer_tick_post
10186 ;; PS
/2 mouse setup
10187 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10189 ;; IRQ13 (FPU exception
) setup
10190 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10193 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10196 mov al
, #0x11 ; send initialisation commands
10211 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10212 #if BX_USE_PS2_MOUSE
10217 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10220 call rombios32_init
10222 call pcibios_init_iomem_bases
10223 call pcibios_init_irqs
10226 call _init_boot_vectors
10230 call _print_bios_banner
10235 call floppy_drive_post
10240 ;; Hard Drive setup
10242 call hard_drive_post
10245 ;; ATA
/ATAPI driver setup
10250 #else // BX_USE_ATADRV
10253 ;; Hard Drive setup
10255 call hard_drive_post
10257 #endif // BX_USE_ATADRV
10259 #if BX_ELTORITO_BOOT
10261 ;; eltorito floppy
/harddisk emulation from cd
10265 #endif // BX_ELTORITO_BOOT
10267 sti
;; enable interrupts
10271 .org
0xe2c3 ; NMI Handler Entry Point
10273 ;; FIXME the NMI handler should
not panic
10274 ;; but iret when called from
int75 (fpu exception
)
10275 call _nmi_handler_msg
10279 out
0xf0, al
// clear irq13
10280 call eoi_both_pics
// clear interrupt
10281 int 2 // legacy nmi call
10284 ;-------------------------------------------
10285 ;- INT
13h Fixed Disk Services Entry Point
-
10286 ;-------------------------------------------
10287 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10289 //JMPL(int13_relocated)
10290 jmp int13_relocated
10292 .org
0xe401 ; Fixed Disk Parameter Table
10297 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10300 jmp int19_relocated
10301 ;-------------------------------------------
10302 ;- System BIOS Configuration Data Table
10303 ;-------------------------------------------
10304 .org BIOS_CONFIG_TABLE
10305 db
0x08 ; Table
size (bytes
) -Lo
10306 db
0x00 ; Table
size (bytes
) -Hi
10311 ; b7
: 1=DMA channel
3 used by hard disk
10312 ; b6
: 1=2 interrupt controllers present
10313 ; b5
: 1=RTC present
10314 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10315 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10316 ; b2
: 1=extended BIOS data area used
10317 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10318 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10322 (BX_CALL_INT15_4F
<< 4) | \
10324 (BX_USE_EBDA
<< 2) | \
10328 ; b7
: 1=32-bit DMA supported
10329 ; b6
: 1=int16h
, function
9 supported
10330 ; b5
: 1=int15h
/C6h (get POS data
) supported
10331 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10332 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10333 ; b2
: 1=non
-8042 kb controller
10334 ; b1
: 1=data streaming supported
10348 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10349 ; b3
: SCSI on system board
10350 ; b2
: info panel installed
10351 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10352 ; b0
: SCSI supported in IML
10356 ; b6
: EEPROM present
10357 ; b5
-3: ABIOS
presence (011 = not supported
)
10359 ; b1
: memory split above
16Mb supported
10360 ; b0
: POSTEXT directly supported by POST
10362 ; Feature byte
5 (IBM
)
10363 ; b1
: enhanced mouse
10369 .org
0xe729 ; Baud Rate Generator Table
10374 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10380 call _int14_function
10386 ;----------------------------------------
10387 ;- INT
16h Keyboard Service Entry Point
-
10388 ;----------------------------------------
10404 call _int16_function
10414 and BYTE
[bp
+ 0x06], #0xbf
10422 or BYTE
[bp
+ 0x06], #0x40
10430 int16_wait_for_key
:
10434 jne int16_key_found
10438 /* no key yet, call int 15h, function AX=9002 */
10439 0x50, /* push AX */
10440 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10441 0xcd, 0x15, /* int 15h */
10443 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10445 jmp int16_wait_for_key
10450 call _int16_function
10455 /* notify int16 complete w/ int 15h, function AX=9102 */
10456 0x50, /* push AX */
10457 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10458 0xcd, 0x15, /* int 15h */
10465 ;-------------------------------------------------
10466 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10467 ;-------------------------------------------------
10473 mov al
, #0xAD ;;disable keyboard
10482 in al
, #0x60 ;;read key from keyboard controller
10486 #ifdef BX_CALL_INT15_4F
10487 mov ah
, #0x4f ;; allow for keyboard intercept
10493 ;; check
for extended key
10495 jne int09_check_pause
10498 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10500 mov BYTE
[0x496], al
10503 int09_check_pause
: ;; check
for pause key
10505 jne int09_process_key
10508 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10510 mov BYTE
[0x496], al
10516 call _int09_function
10522 call eoi_master_pic
10525 mov al
, #0xAE ;;enable keyboard
10531 ;----------------------------------------
10532 ;- INT
13h Diskette Service Entry Point
-
10533 ;----------------------------------------
10536 jmp int13_noeltorito
10538 ;---------------------------------------------
10539 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10540 ;---------------------------------------------
10541 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10551 mov al
, #0x08 ; sense interrupt status
10569 xor ax
, ax
;; segment
0000
10571 call eoi_master_pic
10573 or al
, #0x80 ;; diskette interrupt has occurred
10581 .org
0xefc7 ; Diskette Controller Parameter Table
10582 diskette_param_table
:
10583 ;; Since no provisions are made
for multiple drive types
, most
10584 ;; values in
this table are ignored
. I set parameters
for 1.44M
10587 db
0x02 ;; head load time
0000001, DMA used
10599 ;----------------------------------------
10600 ;- INT17h
: Printer Service Entry Point
-
10601 ;----------------------------------------
10608 call _int17_function
10613 diskette_param_table2
:
10614 ;; New diskette parameter table adding
3 parameters from IBM
10615 ;; Since no provisions are made
for multiple drive types
, most
10616 ;; values in
this table are ignored
. I set parameters
for 1.44M
10619 db
0x02 ;; head load time
0000001, DMA used
10629 db
79 ;; maximum track
10630 db
0 ;; data transfer rate
10631 db
4 ;; drive type in cmos
10633 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10640 .org
0xf065 ; INT
10h Video Support Service Entry Point
10642 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10645 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10650 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10651 ; ??? different
for Pentium (machine check
)?
10663 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10675 .org
0xf859 ; INT
15h System Services Entry Point
10689 #if BX_USE_PS2_MOUSE
10691 je int15_handler_mouse
10693 call _int15_function
10694 int15_handler_mouse_ret
:
10696 int15_handler32_ret
:
10706 #if BX_USE_PS2_MOUSE
10707 int15_handler_mouse
:
10708 call _int15_function_mouse
10709 jmp int15_handler_mouse_ret
10714 call _int15_function32
10716 jmp int15_handler32_ret
10718 ;; Protected mode IDT descriptor
10720 ;; I just make the limit
0, so the machine will shutdown
10721 ;; if an exception occurs during
protected mode memory
10724 ;; Set base to f0000 to correspond to beginning of BIOS
,
10725 ;; in
case I actually define an IDT later
10729 dw
0x0000 ;; limit
15:00
10730 dw
0x0000 ;; base
15:00
10731 db
0x0f ;; base
23:16
10733 ;; Real mode IDT descriptor
10735 ;; Set to typical real
-mode values
.
10740 dw
0x03ff ;; limit
15:00
10741 dw
0x0000 ;; base
15:00
10742 db
0x00 ;; base
23:16
10748 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10761 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10762 mov ds
, ax
; on
16bit
protected mode
.
10763 jmp int1a_callfunction
10770 int1a_callfunction
:
10771 call _int1a_function
10777 ;; int70h
: IRQ8
- CMOS RTC
10784 call _int70_function
10792 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10800 ;; time to turn off
drive(s
)?
10803 jz int08_floppy_off
10806 jnz int08_floppy_off
10807 ;; turn
motor(s
) off
10816 mov eax
, 0x046c ;; get ticks dword
10819 ;; compare eax to one days worth of timer ticks at
18.2 hz
10820 cmp eax
, #0x001800B0
10821 jb int08_store_ticks
10822 ;; there has been a midnight rollover at
this point
10823 xor eax
, eax
;; zero out counter
10824 inc BYTE
0x0470 ;; increment rollover flag
10827 mov
0x046c, eax
;; store
new ticks dword
10828 ;; chain to user timer tick INT
#0x1c
10830 //;; call_ep [ds:loc]
10831 //CALL_EP( 0x1c << 2 )
10834 call eoi_master_pic
10839 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10843 .ascii BIOS_COPYRIGHT_STRING
10845 ;------------------------------------------------
10846 ;- IRET Instruction
for Dummy Interrupt Handler
-
10847 ;------------------------------------------------
10848 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10849 dummy_iret_handler
:
10852 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10856 .org
0xfff0 ; Power
-up Entry Point
10859 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10860 .ascii BIOS_BUILD_DATE
10862 .org
0xfffe ; System Model ID
10866 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10869 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10870 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10871 * This font is public domain
10873 static Bit8u vgafont8
[128*8]=
10875 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10876 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10877 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10878 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10879 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10880 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10881 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10882 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10883 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10884 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10885 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10886 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10887 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10888 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10889 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10890 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10891 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10892 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10893 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10894 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10895 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10896 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10897 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10898 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10899 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10900 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10901 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10902 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10903 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10904 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10905 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10906 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10907 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10908 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10909 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10910 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10911 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10912 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10913 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10914 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10915 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10916 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10917 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10918 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10919 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10920 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10921 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10922 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10923 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10924 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10925 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10926 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10927 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10928 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10929 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10930 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10931 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10932 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10933 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10934 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10935 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10936 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10937 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10938 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10939 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10940 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10941 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10942 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10943 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10944 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10945 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10946 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10947 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10948 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10949 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10950 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10951 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10952 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10953 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10954 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10955 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10956 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10957 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10958 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10959 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10960 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10961 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10962 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10963 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10964 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10965 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10966 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10967 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10968 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10969 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10970 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10971 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10972 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10973 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10974 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10975 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10976 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10977 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10978 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10979 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10980 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10981 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10982 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10983 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10984 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10985 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10986 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10987 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10988 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10989 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10990 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10991 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10992 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10993 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10994 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10995 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10996 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10997 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10998 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10999 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11000 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11001 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11002 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11007 // bcc-generated data will be placed here