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 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version
, sizeinmb
);
2452 case ATA_TYPE_ATAPI
:
2453 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2454 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2455 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2456 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2458 printf(" ATAPI-%d Device\n",version
);
2460 case ATA_TYPE_UNKNOWN
:
2461 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2467 // Store the devices counts
2468 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2469 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2470 write_byte(0x40,0x75, hdcount
);
2474 // FIXME : should use bios=cmos|auto|disable bits
2475 // FIXME : should know about translation bits
2476 // FIXME : move hard_drive_post here
2480 // ---------------------------------------------------------------------------
2481 // ATA/ATAPI driver : software reset
2482 // ---------------------------------------------------------------------------
2484 // 8.2.1 Software reset - Device 0
2486 void ata_reset(device
)
2489 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2490 Bit16u iobase1
, iobase2
;
2491 Bit8u channel
, slave
, sn
, sc
;
2494 channel
= device
/ 2;
2497 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2498 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2502 // 8.2.1 (a) -- set SRST in DC
2503 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2505 // 8.2.1 (b) -- wait for BSY
2508 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2509 if ((status
& ATA_CB_STAT_BSY
) != 0) break;
2512 // 8.2.1 (f) -- clear SRST
2513 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2515 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_NONE
) {
2517 // 8.2.1 (g) -- check for sc==sn==0x01
2519 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2520 sc
= inb(iobase1
+ATA_CB_SC
);
2521 sn
= inb(iobase1
+ATA_CB_SN
);
2523 if ( (sc
==0x01) && (sn
==0x01) ) {
2525 // 8.2.1 (h) -- wait for not BSY
2528 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2529 if ((status
& ATA_CB_STAT_BSY
) == 0) break;
2534 // 8.2.1 (i) -- wait for DRDY
2537 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2538 if ((status
& ATA_CB_STAT_RDY
) != 0) break;
2541 // Enable interrupts
2542 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2545 // ---------------------------------------------------------------------------
2546 // ATA/ATAPI driver : execute a non data command
2547 // ---------------------------------------------------------------------------
2549 Bit16u
ata_cmd_non_data()
2552 // ---------------------------------------------------------------------------
2553 // ATA/ATAPI driver : execute a data-in command
2554 // ---------------------------------------------------------------------------
2559 // 3 : expected DRQ=1
2560 // 4 : no sectors left to read/verify
2561 // 5 : more sectors to read/verify
2562 // 6 : no sectors left to write
2563 // 7 : more sectors to write
2564 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2565 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2568 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2569 Bit16u iobase1
, iobase2
, blksize
;
2570 Bit8u channel
, slave
;
2571 Bit8u status
, current
, mode
;
2573 channel
= device
/ 2;
2576 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2577 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2578 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2579 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2580 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2583 // sector will be 0 only on lba access. Convert to lba-chs
2585 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2587 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2589 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2592 // Reset count of transferred data
2593 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2594 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2597 status
= inb(iobase1
+ ATA_CB_STAT
);
2598 if (status
& ATA_CB_STAT_BSY
) return 1;
2600 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2601 outb(iobase1
+ ATA_CB_FR
, 0x00);
2602 outb(iobase1
+ ATA_CB_SC
, count
);
2603 outb(iobase1
+ ATA_CB_SN
, sector
);
2604 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2605 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2606 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2607 outb(iobase1
+ ATA_CB_CMD
, command
);
2610 status
= inb(iobase1
+ ATA_CB_STAT
);
2611 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2614 if (status
& ATA_CB_STAT_ERR
) {
2615 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2617 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2618 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2622 // FIXME : move seg/off translation here
2625 sti
;; enable higher priority interrupts
2633 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2634 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2635 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2637 ;; adjust
if there will be an overrun
. 2K max sector size
2639 jbe ata_in_no_adjust
2642 sub di
, #0x0800 ;; sub 2 kbytes from offset
2643 add ax
, #0x0080 ;; add 2 Kbytes to segment
2646 mov es
, ax
;; segment in es
2648 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2650 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2651 cmp ah
, #ATA_MODE_PIO32
2656 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2661 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2664 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2665 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2670 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2672 status
= inb(iobase1
+ ATA_CB_STAT
);
2674 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2675 != ATA_CB_STAT_RDY
) {
2676 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2682 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2683 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2684 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2690 // Enable interrupts
2691 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2695 // ---------------------------------------------------------------------------
2696 // ATA/ATAPI driver : execute a data-out command
2697 // ---------------------------------------------------------------------------
2702 // 3 : expected DRQ=1
2703 // 4 : no sectors left to read/verify
2704 // 5 : more sectors to read/verify
2705 // 6 : no sectors left to write
2706 // 7 : more sectors to write
2707 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2708 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2711 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2712 Bit16u iobase1
, iobase2
, blksize
;
2713 Bit8u channel
, slave
;
2714 Bit8u status
, current
, mode
;
2716 channel
= device
/ 2;
2719 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2720 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2721 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2722 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2723 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2726 // sector will be 0 only on lba access. Convert to lba-chs
2728 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2730 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2732 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2735 // Reset count of transferred data
2736 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2737 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2740 status
= inb(iobase1
+ ATA_CB_STAT
);
2741 if (status
& ATA_CB_STAT_BSY
) return 1;
2743 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2744 outb(iobase1
+ ATA_CB_FR
, 0x00);
2745 outb(iobase1
+ ATA_CB_SC
, count
);
2746 outb(iobase1
+ ATA_CB_SN
, sector
);
2747 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2748 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2749 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2750 outb(iobase1
+ ATA_CB_CMD
, command
);
2753 status
= inb(iobase1
+ ATA_CB_STAT
);
2754 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2757 if (status
& ATA_CB_STAT_ERR
) {
2758 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2760 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2761 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2765 // FIXME : move seg/off translation here
2768 sti
;; enable higher priority interrupts
2776 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2777 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2778 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2780 ;; adjust
if there will be an overrun
. 2K max sector size
2782 jbe ata_out_no_adjust
2785 sub si
, #0x0800 ;; sub 2 kbytes from offset
2786 add ax
, #0x0080 ;; add 2 Kbytes to segment
2789 mov es
, ax
;; segment in es
2791 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2793 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2794 cmp ah
, #ATA_MODE_PIO32
2800 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2806 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2809 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2810 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2815 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2817 status
= inb(iobase1
+ ATA_CB_STAT
);
2819 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2820 != ATA_CB_STAT_RDY
) {
2821 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2827 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2828 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2829 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2835 // Enable interrupts
2836 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2840 // ---------------------------------------------------------------------------
2841 // ATA/ATAPI driver : execute a packet command
2842 // ---------------------------------------------------------------------------
2845 // 1 : error in parameters
2849 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2851 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2855 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2856 Bit16u iobase1
, iobase2
;
2857 Bit16u lcount
, lbefore
, lafter
, count
;
2858 Bit8u channel
, slave
;
2859 Bit8u status
, mode
, lmode
;
2860 Bit32u total
, transfer
;
2862 channel
= device
/ 2;
2865 // Data out is not supported yet
2866 if (inout
== ATA_DATA_OUT
) {
2867 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2871 // The header length must be even
2873 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2877 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2878 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2879 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2882 if (cmdlen
< 12) cmdlen
=12;
2883 if (cmdlen
> 12) cmdlen
=16;
2886 // Reset count of transferred data
2887 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2888 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2890 status
= inb(iobase1
+ ATA_CB_STAT
);
2891 if (status
& ATA_CB_STAT_BSY
) return 2;
2893 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2894 // outb(iobase1 + ATA_CB_FR, 0x00);
2895 // outb(iobase1 + ATA_CB_SC, 0x00);
2896 // outb(iobase1 + ATA_CB_SN, 0x00);
2897 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2898 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2899 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2900 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2902 // Device should ok to receive command
2904 status
= inb(iobase1
+ ATA_CB_STAT
);
2905 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2908 if (status
& ATA_CB_STAT_ERR
) {
2909 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2911 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2912 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2916 // Normalize address
2917 cmdseg
+= (cmdoff
/ 16);
2920 // Send command to device
2922 sti
;; enable higher priority interrupts
2927 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
2928 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
2929 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
2930 mov es
, ax
;; segment in es
2932 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
2936 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2941 if (inout
== ATA_DATA_NO
) {
2942 status
= inb(iobase1
+ ATA_CB_STAT
);
2947 status
= inb(iobase1
+ ATA_CB_STAT
);
2949 // Check if command completed
2950 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_DRQ
) ) ==0 ) break;
2952 if (status
& ATA_CB_STAT_ERR
) {
2953 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
2957 // Device must be ready to send data
2958 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2959 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2960 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status
);
2964 // Normalize address
2965 bufseg
+= (bufoff
/ 16);
2968 // Get the byte count
2969 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
2971 // adjust to read what we want
2984 lafter
=lcount
-length
;
2996 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
2997 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
2999 // If counts not dividable by 4, use 16bits mode
3001 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
3002 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
3003 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
3005 // adds an extra byte if count are odd. before is always even
3006 if (lcount
& 0x01) {
3008 if ((lafter
> 0) && (lafter
& 0x01)) {
3013 if (lmode
== ATA_MODE_PIO32
) {
3014 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
3017 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
3026 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
3028 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
3029 jcxz ata_packet_no_before
3031 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3032 cmp ah
, #ATA_MODE_PIO32
3033 je ata_packet_in_before_32
3035 ata_packet_in_before_16
:
3037 loop ata_packet_in_before_16
3038 jmp ata_packet_no_before
3040 ata_packet_in_before_32
:
3042 ata_packet_in_before_32_loop
:
3044 loop ata_packet_in_before_32_loop
3047 ata_packet_no_before
:
3048 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3049 jcxz ata_packet_after
3051 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3052 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3055 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3056 cmp ah
, #ATA_MODE_PIO32
3061 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3062 jmp ata_packet_after
3066 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3069 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3070 jcxz ata_packet_done
3072 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3073 cmp ah
, #ATA_MODE_PIO32
3074 je ata_packet_in_after_32
3076 ata_packet_in_after_16
:
3078 loop ata_packet_in_after_16
3081 ata_packet_in_after_32
:
3083 ata_packet_in_after_32_loop
:
3085 loop ata_packet_in_after_32_loop
3092 // Compute new buffer address
3095 // Save transferred bytes count
3097 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3101 // Final check, device must be ready
3102 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3103 != ATA_CB_STAT_RDY
) {
3104 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3108 // Enable interrupts
3109 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3113 // ---------------------------------------------------------------------------
3114 // End of ATA/ATAPI Driver
3115 // ---------------------------------------------------------------------------
3117 // ---------------------------------------------------------------------------
3118 // Start of ATA/ATAPI generic functions
3119 // ---------------------------------------------------------------------------
3122 atapi_get_sense(device
)
3129 memsetb(get_SS(),atacmd
,0,12);
3134 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 16L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3137 if ((buffer
[0] & 0x7e) == 0x70) {
3138 return (((Bit16u
)buffer
[2]&0x0f)*0x100)+buffer
[12];
3145 atapi_is_ready(device
)
3151 memsetb(get_SS(),atacmd
,0,12);
3154 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3157 if (atapi_get_sense(device
) !=0 ) {
3158 memsetb(get_SS(),atacmd
,0,12);
3160 // try to send Test Unit Ready again
3161 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3164 return atapi_get_sense(device
);
3170 atapi_is_cdrom(device
)
3173 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3175 if (device
>= BX_MAX_ATA_DEVICES
)
3178 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3181 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3187 // ---------------------------------------------------------------------------
3188 // End of ATA/ATAPI generic functions
3189 // ---------------------------------------------------------------------------
3191 #endif // BX_USE_ATADRV
3193 #if BX_ELTORITO_BOOT
3195 // ---------------------------------------------------------------------------
3196 // Start of El-Torito boot functions
3197 // ---------------------------------------------------------------------------
3202 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3204 // the only important data is this one for now
3205 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3211 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3213 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3217 cdemu_emulated_drive()
3219 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3221 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3224 static char isotag
[6]="CD001";
3225 static char eltorito
[24]="EL TORITO SPECIFICATION";
3227 // Returns ah: emulated drive, al: error code
3232 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3233 Bit8u atacmd
[12], buffer
[2048];
3235 Bit16u boot_segment
, nbsectors
, i
, error
;
3238 // Find out the first cdrom
3239 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3240 if (atapi_is_cdrom(device
)) break;
3244 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3246 // Read the Boot Record Volume Descriptor
3247 memsetb(get_SS(),atacmd
,0,12);
3248 atacmd
[0]=0x28; // READ command
3249 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3250 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3251 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3252 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3253 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3254 atacmd
[5]=(0x11 & 0x000000ff);
3255 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3259 if(buffer
[0]!=0)return 4;
3261 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3264 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3266 // ok, now we calculate the Boot catalog address
3267 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3269 // And we read the Boot Catalog
3270 memsetb(get_SS(),atacmd
,0,12);
3271 atacmd
[0]=0x28; // READ command
3272 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3273 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3274 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3275 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3276 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3277 atacmd
[5]=(lba
& 0x000000ff);
3278 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3282 if(buffer
[0x00]!=0x01)return 8; // Header
3283 if(buffer
[0x01]!=0x00)return 9; // Platform
3284 if(buffer
[0x1E]!=0x55)return 10; // key 1
3285 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3287 // Initial/Default Entry
3288 if(buffer
[0x20]!=0x88)return 11; // Bootable
3290 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3291 if(buffer
[0x21]==0){
3292 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3293 // Win2000 cd boot needs to know it booted from cd
3294 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3296 else if(buffer
[0x21]<4)
3297 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3299 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3301 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3302 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3304 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3305 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3307 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3308 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3310 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3311 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3313 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3314 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3316 // And we read the image in memory
3317 memsetb(get_SS(),atacmd
,0,12);
3318 atacmd
[0]=0x28; // READ command
3319 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3320 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3321 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3322 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3323 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3324 atacmd
[5]=(lba
& 0x000000ff);
3325 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3328 // Remember the media type
3329 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3330 case 0x01: // 1.2M floppy
3331 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3332 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3333 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3335 case 0x02: // 1.44M floppy
3336 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3337 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3338 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3340 case 0x03: // 2.88M floppy
3341 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3342 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3343 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3345 case 0x04: // Harddrive
3346 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3347 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3348 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3349 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3353 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3354 // Increase bios installed hardware number of devices
3355 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3356 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3358 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3362 // everything is ok, so from now on, the emulation is active
3363 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3364 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3366 // return the boot drive + no error
3367 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3370 // ---------------------------------------------------------------------------
3371 // End of El-Torito boot functions
3372 // ---------------------------------------------------------------------------
3373 #endif // BX_ELTORITO_BOOT
3376 int14_function(regs
, ds
, iret_addr
)
3377 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3378 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3379 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3381 Bit16u addr
,timer
,val16
;
3388 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3389 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3390 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3391 switch (regs
.u
.r8
.ah
) {
3393 outb(addr
+3, inb(addr
+3) | 0x80);
3394 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3398 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3399 outb(addr
, val16
& 0xFF);
3400 outb(addr
+1, val16
>> 8);
3402 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3403 regs
.u
.r8
.ah
= inb(addr
+5);
3404 regs
.u
.r8
.al
= inb(addr
+6);
3405 ClearCF(iret_addr
.flags
);
3408 timer
= read_word(0x0040, 0x006C);
3409 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3410 val16
= read_word(0x0040, 0x006C);
3411 if (val16
!= timer
) {
3416 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3417 regs
.u
.r8
.ah
= inb(addr
+5);
3418 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3419 ClearCF(iret_addr
.flags
);
3422 timer
= read_word(0x0040, 0x006C);
3423 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3424 val16
= read_word(0x0040, 0x006C);
3425 if (val16
!= timer
) {
3432 regs
.u
.r8
.al
= inb(addr
);
3434 regs
.u
.r8
.ah
= inb(addr
+5);
3436 ClearCF(iret_addr
.flags
);
3439 regs
.u
.r8
.ah
= inb(addr
+5);
3440 regs
.u
.r8
.al
= inb(addr
+6);
3441 ClearCF(iret_addr
.flags
);
3444 SetCF(iret_addr
.flags
); // Unsupported
3447 SetCF(iret_addr
.flags
); // Unsupported
3452 int15_function(regs
, ES
, DS
, FLAGS
)
3453 pusha_regs_t regs
; // REGS pushed via pusha
3454 Bit16u ES
, DS
, FLAGS
;
3456 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3457 bx_bool prev_a20_enable
;
3466 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3468 switch (regs
.u
.r8
.ah
) {
3469 case 0x24: /* A20 Control */
3470 switch (regs
.u
.r8
.al
) {
3482 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3492 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3494 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3500 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3504 /* keyboard intercept */
3506 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3513 case 0x52: // removable media eject
3515 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3519 if( regs
.u
.r8
.al
== 0 ) {
3520 // Set Interval requested.
3521 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3522 // Interval not already set.
3523 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3524 write_word( 0x40, 0x98, ES
); // Byte location, segment
3525 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3526 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3527 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3529 irqDisable
= inb( 0xA1 );
3530 outb( 0xA1, irqDisable
& 0xFE );
3531 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3532 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3534 // Interval already set.
3535 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3537 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3539 } else if( regs
.u
.r8
.al
== 1 ) {
3540 // Clear Interval requested
3541 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3543 bRegister
= inb_cmos( 0xB );
3544 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3546 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3548 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3557 # error "Int15 function 87h not supported on < 80386"
3559 // +++ should probably have descriptor checks
3560 // +++ should have exception handlers
3562 // turn off interrupts
3567 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3569 // 128K max of transfer on 386+ ???
3570 // source == destination ???
3572 // ES:SI points to descriptor table
3573 // offset use initially comments
3574 // ==============================================
3575 // 00..07 Unused zeros Null descriptor
3576 // 08..0f GDT zeros filled in by BIOS
3577 // 10..17 source ssssssss source of data
3578 // 18..1f dest dddddddd destination of data
3579 // 20..27 CS zeros filled in by BIOS
3580 // 28..2f SS zeros filled in by BIOS
3587 // check for access rights of source & dest here
3589 // Initialize GDT descriptor
3590 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3591 base23_16
= ES
>> 12;
3592 if (base15_00
< (ES
<<4))
3594 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3595 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3596 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3597 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3598 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3600 // Initialize CS descriptor
3601 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3602 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3603 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3604 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3605 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3607 // Initialize SS descriptor
3609 base15_00
= ss
<< 4;
3610 base23_16
= ss
>> 12;
3611 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3612 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3613 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3614 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3615 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3619 // Compile generates locals offset info relative to SP.
3620 // Get CX (word count) from stack.
3623 mov cx
, _int15_function
.CX
[bx
]
3625 // since we need to set SS:SP, save them to the BDA
3626 // for future restore
3636 lidt
[pmode_IDT_info
]
3637 ;; perhaps
do something with IDT here
3639 ;; set PE bit in CR0
3643 ;; far jump to flush CPU queue after transition to
protected mode
3644 JMP_AP(0x0020, protected_mode
)
3647 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3648 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3650 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3652 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3658 movsw
;; move CX words from DS
:SI to ES
:DI
3660 ;; make sure DS
and ES limits are
64KB
3665 ;; reset PG bit in CR0
???
3670 ;; far jump to flush CPU queue after transition to real mode
3671 JMP_AP(0xf000, real_mode
)
3674 ;; restore IDT to normal real
-mode defaults
3676 lidt
[rmode_IDT_info
]
3678 // restore SS:SP from the BDA
3686 set_enable_a20(prev_a20_enable
);
3688 // turn back on interrupts
3699 // Get the amount of extended memory (above 1M)
3701 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3704 regs
.u
.r8
.al
= inb_cmos(0x30);
3705 regs
.u
.r8
.ah
= inb_cmos(0x31);
3707 // According to Ralf Brown's interrupt the limit should be 15M,
3708 // but real machines mostly return max. 63M.
3709 if(regs
.u
.r16
.ax
> 0xffc0)
3710 regs
.u
.r16
.ax
= 0xffc0;
3717 /* Device busy interrupt. Called by Int 16h when no key available */
3721 /* Interrupt complete. Called by Int 16h when key becomes available */
3725 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3727 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3733 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3738 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3748 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3750 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3754 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3755 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3757 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3762 #if BX_USE_PS2_MOUSE
3764 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3765 pusha_regs_t regs
; // REGS pushed via pusha
3766 Bit16u ES
, DS
, FLAGS
;
3768 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3769 Bit8u mouse_flags_1
, mouse_flags_2
;
3770 Bit16u mouse_driver_seg
;
3771 Bit16u mouse_driver_offset
;
3772 Bit8u comm_byte
, prev_command_byte
;
3773 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3775 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3777 switch (regs
.u
.r8
.ah
) {
3779 // Return Codes status in AH
3780 // =========================
3782 // 01: invalid subfunction (AL > 7)
3783 // 02: invalid input value (out of allowable range)
3784 // 03: interface error
3785 // 04: resend command received from mouse controller,
3786 // device driver should attempt command again
3787 // 05: cannot enable mouse, since no far call has been installed
3788 // 80/86: mouse service not implemented
3790 switch (regs
.u
.r8
.al
) {
3791 case 0: // Disable/Enable Mouse
3792 BX_DEBUG_INT15("case 0:\n");
3793 switch (regs
.u
.r8
.bh
) {
3794 case 0: // Disable Mouse
3795 BX_DEBUG_INT15("case 0: disable mouse\n");
3796 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3797 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3799 ret
= get_mouse_data(&mouse_data1
);
3800 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3813 case 1: // Enable Mouse
3814 BX_DEBUG_INT15("case 1: enable mouse\n");
3815 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3816 if ( (mouse_flags_2
& 0x80) == 0 ) {
3817 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3819 regs
.u
.r8
.ah
= 5; // no far call installed
3822 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3823 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3825 ret
= get_mouse_data(&mouse_data1
);
3826 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3827 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3837 default: // invalid subfunction
3838 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3840 regs
.u
.r8
.ah
= 1; // invalid subfunction
3845 case 1: // Reset Mouse
3846 case 5: // Initialize Mouse
3847 BX_DEBUG_INT15("case 1 or 5:\n");
3848 if (regs
.u
.r8
.al
== 5) {
3849 if (regs
.u
.r8
.bh
!= 3) {
3851 regs
.u
.r8
.ah
= 0x02; // invalid input
3854 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3855 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3856 mouse_flags_1
= 0x00;
3857 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3858 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3861 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3862 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
3864 ret
= get_mouse_data(&mouse_data3
);
3865 // if no mouse attached, it will return RESEND
3866 if (mouse_data3
== 0xfe) {
3870 if (mouse_data3
!= 0xfa)
3871 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
3873 ret
= get_mouse_data(&mouse_data1
);
3875 ret
= get_mouse_data(&mouse_data2
);
3877 // turn IRQ12 and packet generation on
3878 enable_mouse_int_and_events();
3881 regs
.u
.r8
.bl
= mouse_data1
;
3882 regs
.u
.r8
.bh
= mouse_data2
;
3894 case 2: // Set Sample Rate
3895 BX_DEBUG_INT15("case 2:\n");
3896 switch (regs
.u
.r8
.bh
) {
3897 case 0: mouse_data1
= 10; break; // 10 reports/sec
3898 case 1: mouse_data1
= 20; break; // 20 reports/sec
3899 case 2: mouse_data1
= 40; break; // 40 reports/sec
3900 case 3: mouse_data1
= 60; break; // 60 reports/sec
3901 case 4: mouse_data1
= 80; break; // 80 reports/sec
3902 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
3903 case 6: mouse_data1
= 200; break; // 200 reports/sec
3904 default: mouse_data1
= 0;
3906 if (mouse_data1
> 0) {
3907 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
3909 ret
= get_mouse_data(&mouse_data2
);
3910 ret
= send_to_mouse_ctrl(mouse_data1
);
3911 ret
= get_mouse_data(&mouse_data2
);
3917 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3922 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3926 case 3: // Set Resolution
3927 BX_DEBUG_INT15("case 3:\n");
3929 // 0 = 25 dpi, 1 count per millimeter
3930 // 1 = 50 dpi, 2 counts per millimeter
3931 // 2 = 100 dpi, 4 counts per millimeter
3932 // 3 = 200 dpi, 8 counts per millimeter
3933 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3934 if (regs
.u
.r8
.bh
< 4) {
3935 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
3937 ret
= get_mouse_data(&mouse_data1
);
3938 if (mouse_data1
!= 0xfa)
3939 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3940 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
3941 ret
= get_mouse_data(&mouse_data1
);
3942 if (mouse_data1
!= 0xfa)
3943 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3949 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3954 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3956 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3959 case 4: // Get Device ID
3960 BX_DEBUG_INT15("case 4:\n");
3961 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3962 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
3964 ret
= get_mouse_data(&mouse_data1
);
3965 ret
= get_mouse_data(&mouse_data2
);
3968 regs
.u
.r8
.bh
= mouse_data2
;
3972 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3976 case 6: // Return Status & Set Scaling Factor...
3977 BX_DEBUG_INT15("case 6:\n");
3978 switch (regs
.u
.r8
.bh
) {
3979 case 0: // Return Status
3980 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3981 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
3983 ret
= get_mouse_data(&mouse_data1
);
3984 if (mouse_data1
!= 0xfa)
3985 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3987 ret
= get_mouse_data(&mouse_data1
);
3989 ret
= get_mouse_data(&mouse_data2
);
3991 ret
= get_mouse_data(&mouse_data3
);
3995 regs
.u
.r8
.bl
= mouse_data1
;
3996 regs
.u
.r8
.cl
= mouse_data2
;
3997 regs
.u
.r8
.dl
= mouse_data3
;
3998 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4009 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4012 case 1: // Set Scaling Factor to 1:1
4013 case 2: // Set Scaling Factor to 2:1
4014 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4015 if (regs
.u
.r8
.bh
== 1) {
4016 ret
= send_to_mouse_ctrl(0xE6);
4018 ret
= send_to_mouse_ctrl(0xE7);
4021 get_mouse_data(&mouse_data1
);
4022 ret
= (mouse_data1
!= 0xFA);
4030 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4032 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4036 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4040 case 7: // Set Mouse Handler Address
4041 BX_DEBUG_INT15("case 7:\n");
4042 mouse_driver_seg
= ES
;
4043 mouse_driver_offset
= regs
.u
.r16
.bx
;
4044 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4045 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4046 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4047 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4048 /* remove handler */
4049 if ( (mouse_flags_2
& 0x80) != 0 ) {
4050 mouse_flags_2
&= ~0x80;
4051 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4055 /* install handler */
4056 mouse_flags_2
|= 0x80;
4058 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4064 BX_DEBUG_INT15("case default:\n");
4065 regs
.u
.r8
.ah
= 1; // invalid function
4071 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4072 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4074 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4081 void set_e820_range(ES
, DI
, start
, end
, extra_start
, extra_end
, type
)
4090 write_word(ES
, DI
, start
);
4091 write_word(ES
, DI
+2, start
>> 16);
4092 write_word(ES
, DI
+4, extra_start
);
4093 write_word(ES
, DI
+6, 0x00);
4096 extra_end
-= extra_start
;
4097 write_word(ES
, DI
+8, end
);
4098 write_word(ES
, DI
+10, end
>> 16);
4099 write_word(ES
, DI
+12, extra_end
);
4100 write_word(ES
, DI
+14, 0x0000);
4102 write_word(ES
, DI
+16, type
);
4103 write_word(ES
, DI
+18, 0x0);
4107 int15_function32(regs
, ES
, DS
, FLAGS
)
4108 pushad_regs_t regs
; // REGS pushed via pushad
4109 Bit16u ES
, DS
, FLAGS
;
4111 Bit32u extended_memory_size
=0; // 64bits long
4112 Bit32u extra_lowbits_memory_size
=0;
4114 Bit8u extra_highbits_memory_size
=0;
4116 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4118 switch (regs
.u
.r8
.ah
) {
4120 // Wait for CX:DX microseconds. currently using the
4121 // refresh request port 0x61 bit4, toggling every 15usec
4129 ;; Get the count in eax
4132 mov ax
, _int15_function
.CX
[bx
]
4135 mov ax
, _int15_function
.DX
[bx
]
4137 ;; convert to numbers of
15usec ticks
4143 ;; wait
for ecx number of refresh requests
4164 switch(regs
.u
.r8
.al
)
4166 case 0x20: // coded by osmaker aka K.J.
4167 if(regs
.u
.r32
.edx
== 0x534D4150)
4169 extended_memory_size
= inb_cmos(0x35);
4170 extended_memory_size
<<= 8;
4171 extended_memory_size
|= inb_cmos(0x34);
4172 extended_memory_size
*= 64;
4173 // greater than EFF00000???
4174 if(extended_memory_size
> 0x3bc000) {
4175 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4177 extended_memory_size
*= 1024;
4178 extended_memory_size
+= (16L * 1024 * 1024);
4180 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4181 extended_memory_size
= inb_cmos(0x31);
4182 extended_memory_size
<<= 8;
4183 extended_memory_size
|= inb_cmos(0x30);
4184 extended_memory_size
*= 1024;
4187 extra_lowbits_memory_size
= inb_cmos(0x5c);
4188 extra_lowbits_memory_size
<<= 8;
4189 extra_lowbits_memory_size
|= inb_cmos(0x5b);
4190 extra_lowbits_memory_size
*= 64;
4191 extra_lowbits_memory_size
*= 1024;
4192 extra_highbits_memory_size
= inb_cmos(0x5d);
4194 switch(regs
.u
.r16
.bx
)
4197 set_e820_range(ES
, regs
.u
.r16
.di
,
4198 0x0000000L
, 0x0009fc00L
, 0, 0, 1);
4200 regs
.u
.r32
.eax
= 0x534D4150;
4201 regs
.u
.r32
.ecx
= 0x14;
4206 set_e820_range(ES
, regs
.u
.r16
.di
,
4207 0x0009fc00L
, 0x000a0000L
, 0, 0, 2);
4209 regs
.u
.r32
.eax
= 0x534D4150;
4210 regs
.u
.r32
.ecx
= 0x14;
4215 set_e820_range(ES
, regs
.u
.r16
.di
,
4216 0x000e8000L
, 0x00100000L
, 0, 0, 2);
4218 regs
.u
.r32
.eax
= 0x534D4150;
4219 regs
.u
.r32
.ecx
= 0x14;
4224 set_e820_range(ES
, regs
.u
.r16
.di
,
4226 extended_memory_size
- ACPI_DATA_SIZE
,0, 0, 1);
4228 regs
.u
.r32
.eax
= 0x534D4150;
4229 regs
.u
.r32
.ecx
= 0x14;
4234 set_e820_range(ES
, regs
.u
.r16
.di
,
4235 extended_memory_size
- ACPI_DATA_SIZE
,
4236 extended_memory_size
,0, 0, 3); // ACPI RAM
4238 regs
.u
.r32
.eax
= 0x534D4150;
4239 regs
.u
.r32
.ecx
= 0x14;
4244 /* 3 pages before the bios, we map the vmx tss pages */
4245 set_e820_range(ES
, regs
.u
.r16
.di
, 0xfffbd000L
,
4246 0xfffc0000L
, 0, 0, 2);
4248 regs
.u
.r32
.eax
= 0x534D4150;
4249 regs
.u
.r32
.ecx
= 0x14;
4253 /* 256KB BIOS area at the end of 4 GB */
4254 set_e820_range(ES
, regs
.u
.r16
.di
,
4255 0xfffc0000L
, 0x00000000L
,0, 0, 2);
4256 if (extra_highbits_memory_size
|| extra_lowbits_memory_size
)
4260 regs
.u
.r32
.eax
= 0x534D4150;
4261 regs
.u
.r32
.ecx
= 0x14;
4265 /* Maping of memory above 4 GB */
4266 set_e820_range(ES
, regs
.u
.r16
.di
, 0x00000000L
,
4267 extra_lowbits_memory_size
, 1, extra_highbits_memory_size
4270 regs
.u
.r32
.eax
= 0x534D4150;
4271 regs
.u
.r32
.ecx
= 0x14;
4274 default: /* AX=E820, DX=534D4150, BX unrecognized */
4275 goto int15_unimplemented
;
4279 // if DX != 0x534D4150)
4280 goto int15_unimplemented
;
4285 // do we have any reason to fail here ?
4288 // my real system sets ax and bx to 0
4289 // this is confirmed by Ralph Brown list
4290 // but syslinux v1.48 is known to behave
4291 // strangely if ax is set to 0
4292 // regs.u.r16.ax = 0;
4293 // regs.u.r16.bx = 0;
4295 // Get the amount of extended memory (above 1M)
4296 regs
.u
.r8
.cl
= inb_cmos(0x30);
4297 regs
.u
.r8
.ch
= inb_cmos(0x31);
4300 if(regs
.u
.r16
.cx
> 0x3c00)
4302 regs
.u
.r16
.cx
= 0x3c00;
4305 // Get the amount of extended memory above 16M in 64k blocs
4306 regs
.u
.r8
.dl
= inb_cmos(0x34);
4307 regs
.u
.r8
.dh
= inb_cmos(0x35);
4309 // Set configured memory equal to extended memory
4310 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4311 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4313 default: /* AH=0xE8?? but not implemented */
4314 goto int15_unimplemented
;
4317 int15_unimplemented
:
4318 // fall into the default
4320 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4321 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4323 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4329 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4330 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4332 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4333 Bit16u kbd_code
, max
;
4335 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4337 shift_flags
= read_byte(0x0040, 0x17);
4338 led_flags
= read_byte(0x0040, 0x97);
4339 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4344 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4345 if ((inb(0x60) == 0xfa)) {
4347 led_flags
|= ((shift_flags
>> 4) & 0x07);
4348 outb(0x60, led_flags
& 0x07);
4349 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4351 write_byte(0x0040, 0x97, led_flags
);
4359 case 0x00: /* read keyboard input */
4361 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4362 BX_PANIC("KBD: int16h: out of keyboard input\n");
4364 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4365 else if (ascii_code
== 0xE0) ascii_code
= 0;
4366 AX
= (scan_code
<< 8) | ascii_code
;
4369 case 0x01: /* check keyboard status */
4370 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4374 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4375 else if (ascii_code
== 0xE0) ascii_code
= 0;
4376 AX
= (scan_code
<< 8) | ascii_code
;
4380 case 0x02: /* get shift flag status */
4381 shift_flags
= read_byte(0x0040, 0x17);
4382 SET_AL(shift_flags
);
4385 case 0x05: /* store key-stroke into buffer */
4386 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4394 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4395 // bit Bochs Description
4397 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4398 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4399 // 4 1 INT 16/AH=0Ah supported
4400 // 3 0 INT 16/AX=0306h supported
4401 // 2 0 INT 16/AX=0305h supported
4402 // 1 0 INT 16/AX=0304h supported
4403 // 0 0 INT 16/AX=0300h supported
4408 case 0x0A: /* GET KEYBOARD ID */
4414 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4416 if ((inb(0x60) == 0xfa)) {
4419 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4422 kbd_code
|= (inb(0x60) << 8);
4424 } while (--count
>0);
4430 case 0x10: /* read MF-II keyboard input */
4432 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4433 BX_PANIC("KBD: int16h: out of keyboard input\n");
4435 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4436 AX
= (scan_code
<< 8) | ascii_code
;
4439 case 0x11: /* check MF-II keyboard status */
4440 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4444 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4445 AX
= (scan_code
<< 8) | ascii_code
;
4449 case 0x12: /* get extended keyboard status */
4450 shift_flags
= read_byte(0x0040, 0x17);
4451 SET_AL(shift_flags
);
4452 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4453 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4454 SET_AH(shift_flags
);
4455 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4458 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4459 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4462 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4463 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4467 if (GET_AL() == 0x08)
4468 SET_AH(0x02); // unsupported, aka normal keyboard
4471 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4476 dequeue_key(scan_code
, ascii_code
, incr
)
4481 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4486 buffer_start
= 0x001E;
4487 buffer_end
= 0x003E;
4489 buffer_start
= read_word(0x0040, 0x0080);
4490 buffer_end
= read_word(0x0040, 0x0082);
4493 buffer_head
= read_word(0x0040, 0x001a);
4494 buffer_tail
= read_word(0x0040, 0x001c);
4496 if (buffer_head
!= buffer_tail
) {
4498 acode
= read_byte(0x0040, buffer_head
);
4499 scode
= read_byte(0x0040, buffer_head
+1);
4500 write_byte(ss
, ascii_code
, acode
);
4501 write_byte(ss
, scan_code
, scode
);
4505 if (buffer_head
>= buffer_end
)
4506 buffer_head
= buffer_start
;
4507 write_word(0x0040, 0x001a, buffer_head
);
4516 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4519 inhibit_mouse_int_and_events()
4521 Bit8u command_byte
, prev_command_byte
;
4523 // Turn off IRQ generation and aux data line
4524 if ( inb(0x64) & 0x02 )
4525 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4526 outb(0x64, 0x20); // get command byte
4527 while ( (inb(0x64) & 0x01) != 0x01 );
4528 prev_command_byte
= inb(0x60);
4529 command_byte
= prev_command_byte
;
4530 //while ( (inb(0x64) & 0x02) );
4531 if ( inb(0x64) & 0x02 )
4532 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4533 command_byte
&= 0xfd; // turn off IRQ 12 generation
4534 command_byte
|= 0x20; // disable mouse serial clock line
4535 outb(0x64, 0x60); // write command byte
4536 outb(0x60, command_byte
);
4537 return(prev_command_byte
);
4541 enable_mouse_int_and_events()
4545 // Turn on IRQ generation and aux data line
4546 if ( inb(0x64) & 0x02 )
4547 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4548 outb(0x64, 0x20); // get command byte
4549 while ( (inb(0x64) & 0x01) != 0x01 );
4550 command_byte
= inb(0x60);
4551 //while ( (inb(0x64) & 0x02) );
4552 if ( inb(0x64) & 0x02 )
4553 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4554 command_byte
|= 0x02; // turn on IRQ 12 generation
4555 command_byte
&= 0xdf; // enable mouse serial clock line
4556 outb(0x64, 0x60); // write command byte
4557 outb(0x60, command_byte
);
4561 send_to_mouse_ctrl(sendbyte
)
4566 // wait for chance to write to ctrl
4567 if ( inb(0x64) & 0x02 )
4568 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4570 outb(0x60, sendbyte
);
4576 get_mouse_data(data
)
4582 while ( (inb(0x64) & 0x21) != 0x21 ) {
4585 response
= inb(0x60);
4588 write_byte(ss
, data
, response
);
4593 set_kbd_command_byte(command_byte
)
4596 if ( inb(0x64) & 0x02 )
4597 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4600 outb(0x64, 0x60); // write command byte
4601 outb(0x60, command_byte
);
4605 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4606 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4608 Bit8u scancode
, asciicode
, shift_flags
;
4609 Bit8u mf2_flags
, mf2_state
;
4612 // DS has been set to F000 before call
4616 scancode
= GET_AL();
4618 if (scancode
== 0) {
4619 BX_INFO("KBD: int09 handler: AL=0\n");
4624 shift_flags
= read_byte(0x0040, 0x17);
4625 mf2_flags
= read_byte(0x0040, 0x18);
4626 mf2_state
= read_byte(0x0040, 0x96);
4630 case 0x3a: /* Caps Lock press */
4631 shift_flags
^= 0x40;
4632 write_byte(0x0040, 0x17, shift_flags
);
4634 write_byte(0x0040, 0x18, mf2_flags
);
4636 case 0xba: /* Caps Lock release */
4638 write_byte(0x0040, 0x18, mf2_flags
);
4641 case 0x2a: /* L Shift press */
4642 shift_flags
|= 0x02;
4643 write_byte(0x0040, 0x17, shift_flags
);
4645 case 0xaa: /* L Shift release */
4646 shift_flags
&= ~0x02;
4647 write_byte(0x0040, 0x17, shift_flags
);
4650 case 0x36: /* R Shift press */
4651 shift_flags
|= 0x01;
4652 write_byte(0x0040, 0x17, shift_flags
);
4654 case 0xb6: /* R Shift release */
4655 shift_flags
&= ~0x01;
4656 write_byte(0x0040, 0x17, shift_flags
);
4659 case 0x1d: /* Ctrl press */
4660 if ((mf2_state
& 0x01) == 0) {
4661 shift_flags
|= 0x04;
4662 write_byte(0x0040, 0x17, shift_flags
);
4663 if (mf2_state
& 0x02) {
4665 write_byte(0x0040, 0x96, mf2_state
);
4668 write_byte(0x0040, 0x18, mf2_flags
);
4672 case 0x9d: /* Ctrl release */
4673 if ((mf2_state
& 0x01) == 0) {
4674 shift_flags
&= ~0x04;
4675 write_byte(0x0040, 0x17, shift_flags
);
4676 if (mf2_state
& 0x02) {
4678 write_byte(0x0040, 0x96, mf2_state
);
4681 write_byte(0x0040, 0x18, mf2_flags
);
4686 case 0x38: /* Alt press */
4687 shift_flags
|= 0x08;
4688 write_byte(0x0040, 0x17, shift_flags
);
4689 if (mf2_state
& 0x02) {
4691 write_byte(0x0040, 0x96, mf2_state
);
4694 write_byte(0x0040, 0x18, mf2_flags
);
4697 case 0xb8: /* Alt release */
4698 shift_flags
&= ~0x08;
4699 write_byte(0x0040, 0x17, shift_flags
);
4700 if (mf2_state
& 0x02) {
4702 write_byte(0x0040, 0x96, mf2_state
);
4705 write_byte(0x0040, 0x18, mf2_flags
);
4709 case 0x45: /* Num Lock press */
4710 if ((mf2_state
& 0x03) == 0) {
4712 write_byte(0x0040, 0x18, mf2_flags
);
4713 shift_flags
^= 0x20;
4714 write_byte(0x0040, 0x17, shift_flags
);
4717 case 0xc5: /* Num Lock release */
4718 if ((mf2_state
& 0x03) == 0) {
4720 write_byte(0x0040, 0x18, mf2_flags
);
4724 case 0x46: /* Scroll Lock press */
4726 write_byte(0x0040, 0x18, mf2_flags
);
4727 shift_flags
^= 0x10;
4728 write_byte(0x0040, 0x17, shift_flags
);
4731 case 0xc6: /* Scroll Lock release */
4733 write_byte(0x0040, 0x18, mf2_flags
);
4737 if (scancode
& 0x80) {
4738 break; /* toss key releases ... */
4740 if (scancode
> MAX_SCAN_CODE
) {
4741 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4744 if (shift_flags
& 0x08) { /* ALT */
4745 asciicode
= scan_to_scanascii
[scancode
].alt
;
4746 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4747 } else if (shift_flags
& 0x04) { /* CONTROL */
4748 asciicode
= scan_to_scanascii
[scancode
].control
;
4749 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4750 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
4751 /* extended keys handling */
4753 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4754 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4755 /* check if lock state should be ignored
4756 * because a SHIFT key are pressed */
4758 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4759 asciicode
= scan_to_scanascii
[scancode
].normal
;
4760 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4762 asciicode
= scan_to_scanascii
[scancode
].shift
;
4763 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4766 /* check if lock is on */
4767 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4768 asciicode
= scan_to_scanascii
[scancode
].shift
;
4769 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4771 asciicode
= scan_to_scanascii
[scancode
].normal
;
4772 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4775 if (scancode
==0 && asciicode
==0) {
4776 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4778 enqueue_key(scancode
, asciicode
);
4781 if ((scancode
& 0x7f) != 0x1d) {
4785 write_byte(0x0040, 0x96, mf2_state
);
4789 enqueue_key(scan_code
, ascii_code
)
4790 Bit8u scan_code
, ascii_code
;
4792 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4795 buffer_start
= 0x001E;
4796 buffer_end
= 0x003E;
4798 buffer_start
= read_word(0x0040, 0x0080);
4799 buffer_end
= read_word(0x0040, 0x0082);
4802 buffer_head
= read_word(0x0040, 0x001A);
4803 buffer_tail
= read_word(0x0040, 0x001C);
4805 temp_tail
= buffer_tail
;
4807 if (buffer_tail
>= buffer_end
)
4808 buffer_tail
= buffer_start
;
4810 if (buffer_tail
== buffer_head
) {
4814 write_byte(0x0040, temp_tail
, ascii_code
);
4815 write_byte(0x0040, temp_tail
+1, scan_code
);
4816 write_word(0x0040, 0x001C, buffer_tail
);
4822 int74_function(make_farcall
, Z
, Y
, X
, status
)
4823 Bit16u make_farcall
, Z
, Y
, X
, status
;
4825 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4826 Bit8u in_byte
, index
, package_count
;
4827 Bit8u mouse_flags_1
, mouse_flags_2
;
4829 BX_DEBUG_INT74("entering int74_function\n");
4832 in_byte
= inb(0x64);
4833 if ( (in_byte
& 0x21) != 0x21 ) {
4836 in_byte
= inb(0x60);
4837 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4839 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4840 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4842 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4846 package_count
= mouse_flags_2
& 0x07;
4847 index
= mouse_flags_1
& 0x07;
4848 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4850 if ( (index
+1) >= package_count
) {
4851 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4852 status
= read_byte(ebda_seg
, 0x0028 + 0);
4853 X
= read_byte(ebda_seg
, 0x0028 + 1);
4854 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4857 // check if far call handler installed
4858 if (mouse_flags_2
& 0x80)
4864 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4867 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4872 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4873 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4876 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4877 Bit16u cylinder
, head
, sector
;
4878 Bit16u segment
, offset
;
4879 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4881 Bit8u device
, status
;
4883 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4885 write_byte(0x0040, 0x008e, 0); // clear completion flag
4887 // basic check : device has to be defined
4888 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4889 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4893 // Get the ata channel
4894 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
4896 // basic check : device has to be valid
4897 if (device
>= BX_MAX_ATA_DEVICES
) {
4898 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4904 case 0x00: /* disk controller reset */
4909 case 0x01: /* read disk status */
4910 status
= read_byte(0x0040, 0x0074);
4912 SET_DISK_RET_STATUS(0);
4913 /* set CF if error status read */
4914 if (status
) goto int13_fail_nostatus
;
4915 else goto int13_success_noah
;
4918 case 0x02: // read disk sectors
4919 case 0x03: // write disk sectors
4920 case 0x04: // verify disk sectors
4923 cylinder
= GET_CH();
4924 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
4925 sector
= (GET_CL() & 0x3f);
4931 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
4932 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
4936 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4937 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4938 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4940 // sanity check on cyl heads, sec
4941 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
4942 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
4947 if ( GET_AH() == 0x04 ) goto int13_success
;
4949 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4950 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4952 // if needed, translate lchs to lba, and execute command
4953 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
4954 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
4955 sector
= 0; // this forces the command to be lba
4958 if ( GET_AH() == 0x02 )
4959 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4961 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4963 // Set nb of sector transferred
4964 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
4967 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4969 goto int13_fail_noah
;
4975 case 0x05: /* format disk track */
4976 BX_INFO("format disk track called\n");
4981 case 0x08: /* read disk drive parameters */
4983 // Get logical geometry from table
4984 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4985 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4986 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4987 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
4989 nlc
= nlc
- 2; /* 0 based , last sector not used */
4992 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
4994 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
4996 // FIXME should set ES & DI
5001 case 0x10: /* check drive ready */
5002 // should look at 40:8E also???
5004 // Read the status from controller
5005 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5006 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5011 goto int13_fail_noah
;
5015 case 0x15: /* read disk drive size */
5017 // Get physical geometry from table
5018 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5019 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5020 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5022 // Compute sector count seen by int13
5023 lba
= (Bit32u
)(npc
- 1) * (Bit32u
)nph
* (Bit32u
)npspt
;
5027 SET_AH(3); // hard disk accessible
5028 goto int13_success_noah
;
5031 case 0x41: // IBM/MS installation check
5032 BX
=0xaa55; // install check
5033 SET_AH(0x30); // EDD 3.0
5034 CX
=0x0007; // ext disk access and edd, removable supported
5035 goto int13_success_noah
;
5038 case 0x42: // IBM/MS extended read
5039 case 0x43: // IBM/MS extended write
5040 case 0x44: // IBM/MS verify
5041 case 0x47: // IBM/MS extended seek
5043 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5044 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5045 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5047 // Can't use 64 bits lba
5048 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5050 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5054 // Get 32 bits lba and check
5055 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5056 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
5057 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5061 // If verify or seek
5062 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5065 // Execute the command
5066 if ( GET_AH() == 0x42 )
5067 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5069 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5071 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5072 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5075 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5077 goto int13_fail_noah
;
5083 case 0x45: // IBM/MS lock/unlock drive
5084 case 0x49: // IBM/MS extended media change
5085 goto int13_success
; // Always success for HD
5088 case 0x46: // IBM/MS eject media
5089 SET_AH(0xb2); // Volume Not Removable
5090 goto int13_fail_noah
; // Always fail for HD
5093 case 0x48: // IBM/MS get drive parameters
5094 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5096 // Buffer is too small
5104 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5105 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5106 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5107 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
5108 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5110 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5111 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5112 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5113 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5114 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5115 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
5116 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
5117 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5122 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5123 Bit16u iobase1
, iobase2
, options
;
5125 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5127 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5128 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5131 channel
= device
/ 2;
5132 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5133 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5134 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5135 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5136 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5138 options
= (translation
==ATA_TRANSLATION_NONE
?0:1<<3); // chs translation
5139 options
|= (1<<4); // lba translation
5140 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5141 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0<<9);
5142 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0<<9);
5144 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5145 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5146 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5147 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5148 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5149 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5150 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5151 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5152 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5153 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5154 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5157 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5158 checksum
= ~checksum
;
5159 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5164 Bit8u channel
, iface
, checksum
, i
;
5167 channel
= device
/ 2;
5168 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5169 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5171 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5172 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5173 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5174 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5175 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5177 if (iface
==ATA_IFACE_ISA
) {
5178 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5179 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5180 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5181 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5186 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5187 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5188 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5189 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5191 if (iface
==ATA_IFACE_ISA
) {
5192 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5193 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5194 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5199 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5200 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5201 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5202 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5205 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5206 checksum
= ~checksum
;
5207 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5213 case 0x4e: // // IBM/MS set hardware configuration
5214 // DMA, prefetch, PIO maximum not supported
5227 case 0x09: /* initialize drive parameters */
5228 case 0x0c: /* seek to specified cylinder */
5229 case 0x0d: /* alternate disk reset */
5230 case 0x11: /* recalibrate */
5231 case 0x14: /* controller internal diagnostic */
5232 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5236 case 0x0a: /* read disk sectors with ECC */
5237 case 0x0b: /* write disk sectors with ECC */
5238 case 0x18: // set media type for format
5239 case 0x50: // IBM/MS send packet command
5241 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5247 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5249 SET_DISK_RET_STATUS(GET_AH());
5250 int13_fail_nostatus
:
5251 SET_CF(); // error occurred
5255 SET_AH(0x00); // no error
5257 SET_DISK_RET_STATUS(0x00);
5258 CLEAR_CF(); // no error
5262 // ---------------------------------------------------------------------------
5263 // Start of int13 for cdrom
5264 // ---------------------------------------------------------------------------
5267 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5268 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5270 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5271 Bit8u device
, status
, locks
;
5274 Bit16u count
, segment
, offset
, i
, size
;
5276 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5278 SET_DISK_RET_STATUS(0x00);
5280 /* basic check : device should be 0xE0+ */
5281 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5282 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5286 // Get the ata channel
5287 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5289 /* basic check : device has to be valid */
5290 if (device
>= BX_MAX_ATA_DEVICES
) {
5291 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5297 // all those functions return SUCCESS
5298 case 0x00: /* disk controller reset */
5299 case 0x09: /* initialize drive parameters */
5300 case 0x0c: /* seek to specified cylinder */
5301 case 0x0d: /* alternate disk reset */
5302 case 0x10: /* check drive ready */
5303 case 0x11: /* recalibrate */
5304 case 0x14: /* controller internal diagnostic */
5305 case 0x16: /* detect disk change */
5309 // all those functions return disk write-protected
5310 case 0x03: /* write disk sectors */
5311 case 0x05: /* format disk track */
5312 case 0x43: // IBM/MS extended write
5314 goto int13_fail_noah
;
5317 case 0x01: /* read disk status */
5318 status
= read_byte(0x0040, 0x0074);
5320 SET_DISK_RET_STATUS(0);
5322 /* set CF if error status read */
5323 if (status
) goto int13_fail_nostatus
;
5324 else goto int13_success_noah
;
5327 case 0x15: /* read disk drive size */
5329 goto int13_fail_noah
;
5332 case 0x41: // IBM/MS installation check
5333 BX
=0xaa55; // install check
5334 SET_AH(0x30); // EDD 2.1
5335 CX
=0x0007; // ext disk access, removable and edd
5336 goto int13_success_noah
;
5339 case 0x42: // IBM/MS extended read
5340 case 0x44: // IBM/MS verify sectors
5341 case 0x47: // IBM/MS extended seek
5343 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5344 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5345 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5347 // Can't use 64 bits lba
5348 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5350 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5355 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5357 // If verify or seek
5358 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5361 memsetb(get_SS(),atacmd
,0,12);
5362 atacmd
[0]=0x28; // READ command
5363 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5364 atacmd
[8]=(count
& 0x00ff); // Sectors
5365 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5366 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5367 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5368 atacmd
[5]=(lba
& 0x000000ff);
5369 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5371 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5372 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5375 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5377 goto int13_fail_noah
;
5383 case 0x45: // IBM/MS lock/unlock drive
5384 if (GET_AL() > 2) goto int13_fail
;
5386 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5390 if (locks
== 0xff) {
5393 goto int13_fail_noah
;
5395 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5399 if (locks
== 0x00) {
5402 goto int13_fail_noah
;
5404 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5405 SET_AL(locks
==0?0:1);
5408 SET_AL(locks
==0?0:1);
5414 case 0x46: // IBM/MS eject media
5415 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5418 SET_AH(0xb1); // media locked
5419 goto int13_fail_noah
;
5421 // FIXME should handle 0x31 no media in device
5422 // FIXME should handle 0xb5 valid request failed
5424 // Call removable media eject
5431 mov _int13_cdrom
.status
+ 2[bp
], ah
5432 jnc int13_cdrom_rme_end
5433 mov _int13_cdrom
.status
, #1
5434 int13_cdrom_rme_end
:
5439 SET_AH(0xb1); // media locked
5440 goto int13_fail_noah
;
5446 case 0x48: // IBM/MS get drive parameters
5447 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5449 // Buffer is too small
5455 Bit16u cylinders
, heads
, spt
, blksize
;
5457 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5459 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5460 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5461 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5462 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5463 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5464 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5465 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5466 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5471 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5472 Bit16u iobase1
, iobase2
, options
;
5474 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5476 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5477 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5480 channel
= device
/ 2;
5481 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5482 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5483 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5484 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5486 // FIXME atapi device
5487 options
= (1<<4); // lba translation
5488 options
|= (1<<5); // removable device
5489 options
|= (1<<6); // atapi device
5490 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5492 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5493 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5494 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5495 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5496 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5497 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5498 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5499 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5500 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5501 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5502 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5505 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5506 checksum
= ~checksum
;
5507 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5512 Bit8u channel
, iface
, checksum
, i
;
5515 channel
= device
/ 2;
5516 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5517 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5519 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5520 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5521 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5522 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5523 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5525 if (iface
==ATA_IFACE_ISA
) {
5526 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5527 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5528 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5529 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5534 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5535 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5536 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5537 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5539 if (iface
==ATA_IFACE_ISA
) {
5540 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5541 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5542 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5547 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5548 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5549 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5550 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5553 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5554 checksum
= ~checksum
;
5555 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5561 case 0x49: // IBM/MS extended media change
5562 // always send changed ??
5564 goto int13_fail_nostatus
;
5567 case 0x4e: // // IBM/MS set hardware configuration
5568 // DMA, prefetch, PIO maximum not supported
5581 // all those functions return unimplemented
5582 case 0x02: /* read sectors */
5583 case 0x04: /* verify sectors */
5584 case 0x08: /* read disk drive parameters */
5585 case 0x0a: /* read disk sectors with ECC */
5586 case 0x0b: /* write disk sectors with ECC */
5587 case 0x18: /* set media type for format */
5588 case 0x50: // ? - send packet command
5590 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5596 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5598 SET_DISK_RET_STATUS(GET_AH());
5599 int13_fail_nostatus
:
5600 SET_CF(); // error occurred
5604 SET_AH(0x00); // no error
5606 SET_DISK_RET_STATUS(0x00);
5607 CLEAR_CF(); // no error
5611 // ---------------------------------------------------------------------------
5612 // End of int13 for cdrom
5613 // ---------------------------------------------------------------------------
5615 #if BX_ELTORITO_BOOT
5616 // ---------------------------------------------------------------------------
5617 // Start of int13 for eltorito functions
5618 // ---------------------------------------------------------------------------
5621 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5622 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5624 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5626 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5627 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5631 // FIXME ElTorito Various. Should be implemented
5632 case 0x4a: // ElTorito - Initiate disk emu
5633 case 0x4c: // ElTorito - Initiate disk emu and boot
5634 case 0x4d: // ElTorito - Return Boot catalog
5635 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5639 case 0x4b: // ElTorito - Terminate disk emu
5640 // FIXME ElTorito Hardcoded
5641 write_byte(DS
,SI
+0x00,0x13);
5642 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5643 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5644 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5645 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5646 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5647 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5648 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5649 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5650 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5651 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5652 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5654 // If we have to terminate emulation
5655 if(GET_AL() == 0x00) {
5656 // FIXME ElTorito Various. Should be handled accordingly to spec
5657 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5664 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5670 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5671 SET_DISK_RET_STATUS(GET_AH());
5672 SET_CF(); // error occurred
5676 SET_AH(0x00); // no error
5677 SET_DISK_RET_STATUS(0x00);
5678 CLEAR_CF(); // no error
5682 // ---------------------------------------------------------------------------
5683 // End of int13 for eltorito functions
5684 // ---------------------------------------------------------------------------
5686 // ---------------------------------------------------------------------------
5687 // Start of int13 when emulating a device from the cd
5688 // ---------------------------------------------------------------------------
5691 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5692 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5694 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5695 Bit8u device
, status
;
5696 Bit16u vheads
, vspt
, vcylinders
;
5697 Bit16u head
, sector
, cylinder
, nbsectors
;
5698 Bit32u vlba
, ilba
, slba
, elba
;
5699 Bit16u before
, segment
, offset
;
5702 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5704 /* at this point, we are emulating a floppy/harddisk */
5706 // Recompute the device number
5707 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5708 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5710 SET_DISK_RET_STATUS(0x00);
5712 /* basic checks : emulation should be active, dl should equal the emulated drive */
5713 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5714 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5715 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5721 // all those functions return SUCCESS
5722 case 0x00: /* disk controller reset */
5723 case 0x09: /* initialize drive parameters */
5724 case 0x0c: /* seek to specified cylinder */
5725 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5726 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5727 case 0x11: /* recalibrate */
5728 case 0x14: /* controller internal diagnostic */
5729 case 0x16: /* detect disk change */
5733 // all those functions return disk write-protected
5734 case 0x03: /* write disk sectors */
5735 case 0x05: /* format disk track */
5737 goto int13_fail_noah
;
5740 case 0x01: /* read disk status */
5741 status
=read_byte(0x0040, 0x0074);
5743 SET_DISK_RET_STATUS(0);
5745 /* set CF if error status read */
5746 if (status
) goto int13_fail_nostatus
;
5747 else goto int13_success_noah
;
5750 case 0x02: // read disk sectors
5751 case 0x04: // verify disk sectors
5752 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5753 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5754 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5756 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5758 sector
= GET_CL() & 0x003f;
5759 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5761 nbsectors
= GET_AL();
5765 // no sector to read ?
5766 if(nbsectors
==0) goto int13_success
;
5768 // sanity checks sco openserver needs this!
5770 || (cylinder
>= vcylinders
)
5771 || (head
>= vheads
)) {
5775 // After controls, verify do nothing
5776 if (GET_AH() == 0x04) goto int13_success
;
5778 segment
= ES
+(BX
/ 16);
5781 // calculate the virtual lba inside the image
5782 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5784 // In advance so we don't loose the count
5788 slba
= (Bit32u
)vlba
/4;
5789 before
= (Bit16u
)vlba
%4;
5792 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5794 memsetb(get_SS(),atacmd
,0,12);
5795 atacmd
[0]=0x28; // READ command
5796 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5797 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5798 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5799 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5800 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5801 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5802 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5803 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5806 goto int13_fail_noah
;
5812 case 0x08: /* read disk drive parameters */
5813 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5814 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5815 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5819 SET_CH( vcylinders
& 0xff );
5820 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5822 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5823 // FIXME ElTorito Harddisk. should send the HD count
5825 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5826 case 0x01: SET_BL( 0x02 ); break;
5827 case 0x02: SET_BL( 0x04 ); break;
5828 case 0x03: SET_BL( 0x06 ); break;
5834 mov ax
, #diskette_param_table2
5835 mov _int13_cdemu
.DI
+2[bp
], ax
5836 mov _int13_cdemu
.ES
+2[bp
], cs
5842 case 0x15: /* read disk drive size */
5843 // FIXME ElTorito Harddisk. What geometry to send ?
5845 goto int13_success_noah
;
5848 // all those functions return unimplemented
5849 case 0x0a: /* read disk sectors with ECC */
5850 case 0x0b: /* write disk sectors with ECC */
5851 case 0x18: /* set media type for format */
5852 case 0x41: // IBM/MS installation check
5853 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5854 case 0x42: // IBM/MS extended read
5855 case 0x43: // IBM/MS extended write
5856 case 0x44: // IBM/MS verify sectors
5857 case 0x45: // IBM/MS lock/unlock drive
5858 case 0x46: // IBM/MS eject media
5859 case 0x47: // IBM/MS extended seek
5860 case 0x48: // IBM/MS get drive parameters
5861 case 0x49: // IBM/MS extended media change
5862 case 0x4e: // ? - set hardware configuration
5863 case 0x50: // ? - send packet command
5865 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5871 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5873 SET_DISK_RET_STATUS(GET_AH());
5874 int13_fail_nostatus
:
5875 SET_CF(); // error occurred
5879 SET_AH(0x00); // no error
5881 SET_DISK_RET_STATUS(0x00);
5882 CLEAR_CF(); // no error
5886 // ---------------------------------------------------------------------------
5887 // End of int13 when emulating a device from the cd
5888 // ---------------------------------------------------------------------------
5890 #endif // BX_ELTORITO_BOOT
5892 #else //BX_USE_ATADRV
5895 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
5910 mov ax
,4[bp
] // cylinder
5912 mov bl
,6[bp
] // hd_heads
5915 mov bl
,8[bp
] // head
5917 mov bl
,10[bp
] // hd_sectors
5919 mov bl
,12[bp
] // sector
5948 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5949 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5951 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
5955 Bit16u max_cylinder
, cylinder
, total_sectors
;
5956 Bit16u hd_cylinders
;
5957 Bit8u hd_heads
, hd_sectors
;
5964 Bit16u count
, segment
, offset
;
5968 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5970 write_byte(0x0040, 0x008e, 0); // clear completion flag
5972 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5974 /* check how many disks first (cmos reg 0x12), return an error if
5975 drive not present */
5976 drive_map
= inb_cmos(0x12);
5977 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
5978 (((drive_map
& 0x0f)==0) ? 0 : 2);
5979 n_drives
= (drive_map
==0) ? 0 :
5980 ((drive_map
==3) ? 2 : 1);
5982 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5984 SET_DISK_RET_STATUS(0x01);
5985 SET_CF(); /* error occurred */
5991 case 0x00: /* disk controller reset */
5992 BX_DEBUG_INT13_HD("int13_f00\n");
5995 SET_DISK_RET_STATUS(0);
5996 set_diskette_ret_status(0);
5997 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5998 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5999 CLEAR_CF(); /* successful */
6003 case 0x01: /* read disk status */
6004 BX_DEBUG_INT13_HD("int13_f01\n");
6005 status
= read_byte(0x0040, 0x0074);
6007 SET_DISK_RET_STATUS(0);
6008 /* set CF if error status read */
6009 if (status
) SET_CF();
6014 case 0x04: // verify disk sectors
6015 case 0x02: // read disk sectors
6017 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6019 num_sectors
= GET_AL();
6020 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6021 sector
= (GET_CL() & 0x3f);
6025 if (hd_cylinders
> 1024) {
6026 if (hd_cylinders
<= 2048) {
6029 else if (hd_cylinders
<= 4096) {
6032 else if (hd_cylinders
<= 8192) {
6035 else { // hd_cylinders <= 16384
6039 ax
= head
/ hd_heads
;
6040 cyl_mod
= ax
& 0xff;
6042 cylinder
|= cyl_mod
;
6045 if ( (cylinder
>= hd_cylinders
) ||
6046 (sector
> hd_sectors
) ||
6047 (head
>= hd_heads
) ) {
6049 SET_DISK_RET_STATUS(1);
6050 SET_CF(); /* error occurred */
6054 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6055 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6058 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6060 if ( GET_AH() == 0x04 ) {
6062 SET_DISK_RET_STATUS(0);
6067 status
= inb(0x1f7);
6068 if (status
& 0x80) {
6069 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6071 outb(0x01f2, num_sectors
);
6072 /* activate LBA? (tomv) */
6073 if (hd_heads
> 16) {
6074 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6075 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6078 outb(0x01f3, sector
);
6079 outb(0x01f4, cylinder
& 0x00ff);
6080 outb(0x01f5, cylinder
>> 8);
6081 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6086 status
= inb(0x1f7);
6087 if ( !(status
& 0x80) ) break;
6090 if (status
& 0x01) {
6091 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6092 } else if ( !(status
& 0x08) ) {
6093 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6094 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6101 sti
;; enable higher priority interrupts
6106 ;; store temp bx in real DI
register
6109 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6112 ;; adjust
if there will be an overrun
6114 jbe i13_f02_no_adjust
6116 sub di
, #0x0200 ; sub 512 bytes from offset
6118 add ax
, #0x0020 ; add 512 to segment
6122 mov cx
, #0x0100 ;; counter (256 words = 512b)
6123 mov dx
, #0x01f0 ;; AT data read port
6126 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6129 ;; store real DI
register back to temp bx
6132 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6138 if (num_sectors
== 0) {
6139 status
= inb(0x1f7);
6140 if ( (status
& 0xc9) != 0x40 )
6141 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6145 status
= inb(0x1f7);
6146 if ( (status
& 0xc9) != 0x48 )
6147 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6153 SET_DISK_RET_STATUS(0);
6154 SET_AL(sector_count
);
6155 CLEAR_CF(); /* successful */
6160 case 0x03: /* write disk sectors */
6161 BX_DEBUG_INT13_HD("int13_f03\n");
6162 drive
= GET_ELDL ();
6163 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6165 num_sectors
= GET_AL();
6166 cylinder
= GET_CH();
6167 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6168 sector
= (GET_CL() & 0x3f);
6171 if (hd_cylinders
> 1024) {
6172 if (hd_cylinders
<= 2048) {
6175 else if (hd_cylinders
<= 4096) {
6178 else if (hd_cylinders
<= 8192) {
6181 else { // hd_cylinders <= 16384
6185 ax
= head
/ hd_heads
;
6186 cyl_mod
= ax
& 0xff;
6188 cylinder
|= cyl_mod
;
6191 if ( (cylinder
>= hd_cylinders
) ||
6192 (sector
> hd_sectors
) ||
6193 (head
>= hd_heads
) ) {
6195 SET_DISK_RET_STATUS(1);
6196 SET_CF(); /* error occurred */
6200 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6201 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6204 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6206 status
= inb(0x1f7);
6207 if (status
& 0x80) {
6208 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6210 // should check for Drive Ready Bit also in status reg
6211 outb(0x01f2, num_sectors
);
6213 /* activate LBA? (tomv) */
6214 if (hd_heads
> 16) {
6215 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6216 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6219 outb(0x01f3, sector
);
6220 outb(0x01f4, cylinder
& 0x00ff);
6221 outb(0x01f5, cylinder
>> 8);
6222 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6226 // wait for busy bit to turn off after seeking
6228 status
= inb(0x1f7);
6229 if ( !(status
& 0x80) ) break;
6232 if ( !(status
& 0x08) ) {
6233 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6234 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6241 sti
;; enable higher priority interrupts
6246 ;; store temp bx in real SI
register
6249 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6252 ;; adjust
if there will be an overrun
6254 jbe i13_f03_no_adjust
6256 sub si
, #0x0200 ; sub 512 bytes from offset
6258 add ax
, #0x0020 ; add 512 to segment
6262 mov cx
, #0x0100 ;; counter (256 words = 512b)
6263 mov dx
, #0x01f0 ;; AT data read port
6267 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6269 ;; store real SI
register back to temp bx
6272 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6278 if (num_sectors
== 0) {
6279 status
= inb(0x1f7);
6280 if ( (status
& 0xe9) != 0x40 )
6281 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6285 status
= inb(0x1f7);
6286 if ( (status
& 0xc9) != 0x48 )
6287 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6293 SET_DISK_RET_STATUS(0);
6294 SET_AL(sector_count
);
6295 CLEAR_CF(); /* successful */
6299 case 0x05: /* format disk track */
6300 BX_DEBUG_INT13_HD("int13_f05\n");
6301 BX_PANIC("format disk track called\n");
6304 SET_DISK_RET_STATUS(0);
6305 CLEAR_CF(); /* successful */
6309 case 0x08: /* read disk drive parameters */
6310 BX_DEBUG_INT13_HD("int13_f08\n");
6312 drive
= GET_ELDL ();
6313 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6317 if (hd_cylinders
<= 1024) {
6318 // hd_cylinders >>= 0;
6321 else if (hd_cylinders
<= 2048) {
6325 else if (hd_cylinders
<= 4096) {
6329 else if (hd_cylinders
<= 8192) {
6333 else { // hd_cylinders <= 16384
6338 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6340 SET_CH(max_cylinder
& 0xff);
6341 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6342 SET_DH(hd_heads
- 1);
6343 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6345 SET_DISK_RET_STATUS(0);
6346 CLEAR_CF(); /* successful */
6351 case 0x09: /* initialize drive parameters */
6352 BX_DEBUG_INT13_HD("int13_f09\n");
6354 SET_DISK_RET_STATUS(0);
6355 CLEAR_CF(); /* successful */
6359 case 0x0a: /* read disk sectors with ECC */
6360 BX_DEBUG_INT13_HD("int13_f0a\n");
6361 case 0x0b: /* write disk sectors with ECC */
6362 BX_DEBUG_INT13_HD("int13_f0b\n");
6363 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6367 case 0x0c: /* seek to specified cylinder */
6368 BX_DEBUG_INT13_HD("int13_f0c\n");
6369 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6371 SET_DISK_RET_STATUS(0);
6372 CLEAR_CF(); /* successful */
6376 case 0x0d: /* alternate disk reset */
6377 BX_DEBUG_INT13_HD("int13_f0d\n");
6379 SET_DISK_RET_STATUS(0);
6380 CLEAR_CF(); /* successful */
6384 case 0x10: /* check drive ready */
6385 BX_DEBUG_INT13_HD("int13_f10\n");
6387 //SET_DISK_RET_STATUS(0);
6388 //CLEAR_CF(); /* successful */
6392 // should look at 40:8E also???
6393 status
= inb(0x01f7);
6394 if ( (status
& 0xc0) == 0x40 ) {
6396 SET_DISK_RET_STATUS(0);
6397 CLEAR_CF(); // drive ready
6402 SET_DISK_RET_STATUS(0xAA);
6403 SET_CF(); // not ready
6408 case 0x11: /* recalibrate */
6409 BX_DEBUG_INT13_HD("int13_f11\n");
6411 SET_DISK_RET_STATUS(0);
6412 CLEAR_CF(); /* successful */
6416 case 0x14: /* controller internal diagnostic */
6417 BX_DEBUG_INT13_HD("int13_f14\n");
6419 SET_DISK_RET_STATUS(0);
6420 CLEAR_CF(); /* successful */
6425 case 0x15: /* read disk drive size */
6427 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6431 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6432 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6433 mul al
, ah
;; ax
= heads
* sectors
6434 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6435 dec bx
;; use (cylinders
- 1) ???
6436 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6437 ;; now we need to move the
32bit result dx
:ax to what the
6438 ;; BIOS wants which is cx
:dx
.
6439 ;; and then into CX
:DX on the stack
6440 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6441 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6444 SET_AH(3); // hard disk accessible
6445 SET_DISK_RET_STATUS(0); // ??? should this be 0
6446 CLEAR_CF(); // successful
6450 case 0x18: // set media type for format
6451 case 0x41: // IBM/MS
6452 case 0x42: // IBM/MS
6453 case 0x43: // IBM/MS
6454 case 0x44: // IBM/MS
6455 case 0x45: // IBM/MS lock/unlock drive
6456 case 0x46: // IBM/MS eject media
6457 case 0x47: // IBM/MS extended seek
6458 case 0x49: // IBM/MS extended media change
6459 case 0x50: // IBM/MS send packet command
6461 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6463 SET_AH(1); // code=invalid function in AH or invalid parameter
6464 SET_DISK_RET_STATUS(1);
6465 SET_CF(); /* unsuccessful */
6471 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6472 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6475 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6477 Bit16u
*hd_cylinders
;
6487 if (drive
== 0x80) {
6488 hd_type
= inb_cmos(0x12) & 0xf0;
6489 if (hd_type
!= 0xf0)
6490 BX_INFO(panic_msg_reg12h
,0);
6491 hd_type
= inb_cmos(0x19); // HD0: extended type
6493 BX_INFO(panic_msg_reg19h
,0,0x19);
6496 hd_type
= inb_cmos(0x12) & 0x0f;
6497 if (hd_type
!= 0x0f)
6498 BX_INFO(panic_msg_reg12h
,1);
6499 hd_type
= inb_cmos(0x1a); // HD0: extended type
6501 BX_INFO(panic_msg_reg19h
,0,0x1a);
6506 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6507 write_word(ss
, hd_cylinders
, cylinders
);
6510 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6512 // sectors per track
6513 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6516 #endif //else BX_USE_ATADRV
6519 //////////////////////
6520 // FLOPPY functions //
6521 //////////////////////
6523 void floppy_reset_controller()
6529 outb(0x03f2, val8
& ~0x04);
6530 outb(0x03f2, val8
| 0x04);
6532 // Wait for controller to come out of reset
6535 } while ( (val8
& 0xc0) != 0x80 );
6538 void floppy_prepare_controller(drive
)
6541 Bit8u val8
, dor
, prev_reset
;
6543 // set 40:3e bit 7 to 0
6544 val8
= read_byte(0x0040, 0x003e);
6546 write_byte(0x0040, 0x003e, val8
);
6548 // turn on motor of selected drive, DMA & int enabled, normal operation
6549 prev_reset
= inb(0x03f2) & 0x04;
6558 // reset the disk motor timeout value of INT 08
6559 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6561 // wait for drive readiness
6564 } while ( (val8
& 0xc0) != 0x80 );
6566 if (prev_reset
== 0) {
6567 // turn on interrupts
6571 // wait on 40:3e bit 7 to become 1
6573 val8
= read_byte(0x0040, 0x003e);
6574 } while ( (val8
& 0x80) == 0 );
6579 write_byte(0x0040, 0x003e, val8
);
6584 floppy_media_known(drive
)
6588 Bit16u media_state_offset
;
6590 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6597 media_state_offset
= 0x0090;
6599 media_state_offset
+= 1;
6601 val8
= read_byte(0x0040, media_state_offset
);
6602 val8
= (val8
>> 4) & 0x01;
6606 // check pass, return KNOWN
6611 floppy_media_sense(drive
)
6615 Bit16u media_state_offset
;
6616 Bit8u drive_type
, config_data
, media_state
;
6618 if (floppy_drive_recal(drive
) == 0) {
6622 // for now cheat and get drive type from CMOS,
6623 // assume media is same as drive type
6625 // ** config_data **
6626 // Bitfields for diskette media control:
6627 // Bit(s) Description (Table M0028)
6628 // 7-6 last data rate set by controller
6629 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6630 // 5-4 last diskette drive step rate selected
6631 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6632 // 3-2 {data rate at start of operation}
6635 // ** media_state **
6636 // Bitfields for diskette drive media state:
6637 // Bit(s) Description (Table M0030)
6639 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6640 // 5 double stepping required (e.g. 360kB in 1.2MB)
6641 // 4 media type established
6642 // 3 drive capable of supporting 4MB media
6643 // 2-0 on exit from BIOS, contains
6644 // 000 trying 360kB in 360kB
6645 // 001 trying 360kB in 1.2MB
6646 // 010 trying 1.2MB in 1.2MB
6647 // 011 360kB in 360kB established
6648 // 100 360kB in 1.2MB established
6649 // 101 1.2MB in 1.2MB established
6651 // 111 all other formats/drives
6653 drive_type
= inb_cmos(0x10);
6658 if ( drive_type
== 1 ) {
6660 config_data
= 0x00; // 0000 0000
6661 media_state
= 0x25; // 0010 0101
6664 else if ( drive_type
== 2 ) {
6665 // 1.2 MB 5.25" drive
6666 config_data
= 0x00; // 0000 0000
6667 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6670 else if ( drive_type
== 3 ) {
6672 config_data
= 0x00; // 0000 0000 ???
6673 media_state
= 0x17; // 0001 0111
6676 else if ( drive_type
== 4 ) {
6677 // 1.44 MB 3.5" drive
6678 config_data
= 0x00; // 0000 0000
6679 media_state
= 0x17; // 0001 0111
6682 else if ( drive_type
== 5 ) {
6683 // 2.88 MB 3.5" drive
6684 config_data
= 0xCC; // 1100 1100
6685 media_state
= 0xD7; // 1101 0111
6689 // Extended floppy size uses special cmos setting
6690 else if ( drive_type
== 6 ) {
6692 config_data
= 0x00; // 0000 0000
6693 media_state
= 0x27; // 0010 0111
6696 else if ( drive_type
== 7 ) {
6698 config_data
= 0x00; // 0000 0000
6699 media_state
= 0x27; // 0010 0111
6702 else if ( drive_type
== 8 ) {
6704 config_data
= 0x00; // 0000 0000
6705 media_state
= 0x27; // 0010 0111
6711 config_data
= 0x00; // 0000 0000
6712 media_state
= 0x00; // 0000 0000
6717 media_state_offset
= 0x90;
6719 media_state_offset
= 0x91;
6720 write_byte(0x0040, 0x008B, config_data
);
6721 write_byte(0x0040, media_state_offset
, media_state
);
6727 floppy_drive_recal(drive
)
6731 Bit16u curr_cyl_offset
;
6733 floppy_prepare_controller(drive
);
6735 // send Recalibrate command (2 bytes) to controller
6736 outb(0x03f5, 0x07); // 07: Recalibrate
6737 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6739 // turn on interrupts
6744 // wait on 40:3e bit 7 to become 1
6746 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6747 } while ( val8
== 0 );
6749 val8
= 0; // separate asm from while() loop
6750 // turn off interrupts
6755 // set 40:3e bit 7 to 0, and calibrated bit
6756 val8
= read_byte(0x0040, 0x003e);
6759 val8
|= 0x02; // Drive 1 calibrated
6760 curr_cyl_offset
= 0x0095;
6762 val8
|= 0x01; // Drive 0 calibrated
6763 curr_cyl_offset
= 0x0094;
6765 write_byte(0x0040, 0x003e, val8
);
6766 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6774 floppy_drive_exists(drive
)
6779 // check CMOS to see if drive exists
6780 drive_type
= inb_cmos(0x10);
6785 if ( drive_type
== 0 )
6791 #if BX_SUPPORT_FLOPPY
6793 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6794 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6796 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6797 Bit16u base_address
, base_count
, base_es
;
6798 Bit8u page
, mode_register
, val8
, dor
;
6799 Bit8u return_status
[7];
6800 Bit8u drive_type
, num_floppies
, ah
;
6801 Bit16u es
, last_addr
;
6803 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6808 case 0x00: // diskette controller reset
6809 BX_DEBUG_INT13_FL("floppy f00\n");
6812 SET_AH(1); // invalid param
6813 set_diskette_ret_status(1);
6817 drive_type
= inb_cmos(0x10);
6823 if (drive_type
== 0) {
6824 SET_AH(0x80); // drive not responding
6825 set_diskette_ret_status(0x80);
6830 set_diskette_ret_status(0);
6831 CLEAR_CF(); // successful
6832 set_diskette_current_cyl(drive
, 0); // current cylinder
6835 case 0x01: // Read Diskette Status
6837 val8
= read_byte(0x0000, 0x0441);
6844 case 0x02: // Read Diskette Sectors
6845 case 0x03: // Write Diskette Sectors
6846 case 0x04: // Verify Diskette Sectors
6847 num_sectors
= GET_AL();
6853 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
6854 (num_sectors
== 0) || (num_sectors
> 72)) {
6855 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
6857 set_diskette_ret_status(1);
6858 SET_AL(0); // no sectors read
6859 SET_CF(); // error occurred
6863 // see if drive exists
6864 if (floppy_drive_exists(drive
) == 0) {
6865 SET_AH(0x80); // not responding
6866 set_diskette_ret_status(0x80);
6867 SET_AL(0); // no sectors read
6868 SET_CF(); // error occurred
6872 // see if media in drive, and type is known
6873 if (floppy_media_known(drive
) == 0) {
6874 if (floppy_media_sense(drive
) == 0) {
6875 SET_AH(0x0C); // Media type not found
6876 set_diskette_ret_status(0x0C);
6877 SET_AL(0); // no sectors read
6878 SET_CF(); // error occurred
6884 // Read Diskette Sectors
6886 //-----------------------------------
6887 // set up DMA controller for transfer
6888 //-----------------------------------
6890 // es:bx = pointer to where to place information from diskette
6891 // port 04: DMA-1 base and current address, channel 2
6892 // port 05: DMA-1 base and current count, channel 2
6893 page
= (ES
>> 12); // upper 4 bits
6894 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6895 base_address
= base_es
+ BX
; // lower 16 bits of address
6896 // contributed by ES:BX
6897 if ( base_address
< base_es
) {
6898 // in case of carry, adjust page by 1
6901 base_count
= (num_sectors
* 512) - 1;
6903 // check for 64K boundary overrun
6904 last_addr
= base_address
+ base_count
;
6905 if (last_addr
< base_address
) {
6907 set_diskette_ret_status(0x09);
6908 SET_AL(0); // no sectors read
6909 SET_CF(); // error occurred
6913 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6916 BX_DEBUG_INT13_FL("clear flip-flop\n");
6917 outb(0x000c, 0x00); // clear flip-flop
6918 outb(0x0004, base_address
);
6919 outb(0x0004, base_address
>>8);
6920 BX_DEBUG_INT13_FL("clear flip-flop\n");
6921 outb(0x000c, 0x00); // clear flip-flop
6922 outb(0x0005, base_count
);
6923 outb(0x0005, base_count
>>8);
6925 // port 0b: DMA-1 Mode Register
6926 mode_register
= 0x46; // single mode, increment, autoinit disable,
6927 // transfer type=write, channel 2
6928 BX_DEBUG_INT13_FL("setting mode register\n");
6929 outb(0x000b, mode_register
);
6931 BX_DEBUG_INT13_FL("setting page register\n");
6932 // port 81: DMA-1 Page Register, channel 2
6935 BX_DEBUG_INT13_FL("unmask chan 2\n");
6936 outb(0x000a, 0x02); // unmask channel 2
6938 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6941 //--------------------------------------
6942 // set up floppy controller for transfer
6943 //--------------------------------------
6944 floppy_prepare_controller(drive
);
6946 // send read-normal-data command (9 bytes) to controller
6947 outb(0x03f5, 0xe6); // e6: read normal data
6948 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6949 outb(0x03f5, track
);
6951 outb(0x03f5, sector
);
6952 outb(0x03f5, 2); // 512 byte sector size
6953 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
6954 outb(0x03f5, 0); // Gap length
6955 outb(0x03f5, 0xff); // Gap length
6957 // turn on interrupts
6962 // wait on 40:3e bit 7 to become 1
6964 val8
= read_byte(0x0040, 0x0040);
6966 floppy_reset_controller();
6967 SET_AH(0x80); // drive not ready (timeout)
6968 set_diskette_ret_status(0x80);
6969 SET_AL(0); // no sectors read
6970 SET_CF(); // error occurred
6973 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6974 } while ( val8
== 0 );
6976 val8
= 0; // separate asm from while() loop
6977 // turn off interrupts
6982 // set 40:3e bit 7 to 0
6983 val8
= read_byte(0x0040, 0x003e);
6985 write_byte(0x0040, 0x003e, val8
);
6987 // check port 3f4 for accessibility to status bytes
6989 if ( (val8
& 0xc0) != 0xc0 )
6990 BX_PANIC("int13_diskette: ctrl not ready\n");
6992 // read 7 return status bytes from controller
6993 // using loop index broken, have to unroll...
6994 return_status
[0] = inb(0x3f5);
6995 return_status
[1] = inb(0x3f5);
6996 return_status
[2] = inb(0x3f5);
6997 return_status
[3] = inb(0x3f5);
6998 return_status
[4] = inb(0x3f5);
6999 return_status
[5] = inb(0x3f5);
7000 return_status
[6] = inb(0x3f5);
7001 // record in BIOS Data Area
7002 write_byte(0x0040, 0x0042, return_status
[0]);
7003 write_byte(0x0040, 0x0043, return_status
[1]);
7004 write_byte(0x0040, 0x0044, return_status
[2]);
7005 write_byte(0x0040, 0x0045, return_status
[3]);
7006 write_byte(0x0040, 0x0046, return_status
[4]);
7007 write_byte(0x0040, 0x0047, return_status
[5]);
7008 write_byte(0x0040, 0x0048, return_status
[6]);
7010 if ( (return_status
[0] & 0xc0) != 0 ) {
7012 set_diskette_ret_status(0x20);
7013 SET_AL(0); // no sectors read
7014 SET_CF(); // error occurred
7018 // ??? should track be new val from return_status[3] ?
7019 set_diskette_current_cyl(drive
, track
);
7020 // AL = number of sectors read (same value as passed)
7021 SET_AH(0x00); // success
7022 CLEAR_CF(); // success
7024 } else if (ah
== 0x03) {
7025 // Write Diskette Sectors
7027 //-----------------------------------
7028 // set up DMA controller for transfer
7029 //-----------------------------------
7031 // es:bx = pointer to where to place information from diskette
7032 // port 04: DMA-1 base and current address, channel 2
7033 // port 05: DMA-1 base and current count, channel 2
7034 page
= (ES
>> 12); // upper 4 bits
7035 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7036 base_address
= base_es
+ BX
; // lower 16 bits of address
7037 // contributed by ES:BX
7038 if ( base_address
< base_es
) {
7039 // in case of carry, adjust page by 1
7042 base_count
= (num_sectors
* 512) - 1;
7044 // check for 64K boundary overrun
7045 last_addr
= base_address
+ base_count
;
7046 if (last_addr
< base_address
) {
7048 set_diskette_ret_status(0x09);
7049 SET_AL(0); // no sectors read
7050 SET_CF(); // error occurred
7054 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7057 outb(0x000c, 0x00); // clear flip-flop
7058 outb(0x0004, base_address
);
7059 outb(0x0004, base_address
>>8);
7060 outb(0x000c, 0x00); // clear flip-flop
7061 outb(0x0005, base_count
);
7062 outb(0x0005, base_count
>>8);
7064 // port 0b: DMA-1 Mode Register
7065 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7066 // transfer type=read, channel 2
7067 outb(0x000b, mode_register
);
7069 // port 81: DMA-1 Page Register, channel 2
7072 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7075 //--------------------------------------
7076 // set up floppy controller for transfer
7077 //--------------------------------------
7078 floppy_prepare_controller(drive
);
7080 // send write-normal-data command (9 bytes) to controller
7081 outb(0x03f5, 0xc5); // c5: write normal data
7082 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7083 outb(0x03f5, track
);
7085 outb(0x03f5, sector
);
7086 outb(0x03f5, 2); // 512 byte sector size
7087 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7088 outb(0x03f5, 0); // Gap length
7089 outb(0x03f5, 0xff); // Gap length
7091 // turn on interrupts
7096 // wait on 40:3e bit 7 to become 1
7098 val8
= read_byte(0x0040, 0x0040);
7100 floppy_reset_controller();
7101 SET_AH(0x80); // drive not ready (timeout)
7102 set_diskette_ret_status(0x80);
7103 SET_AL(0); // no sectors written
7104 SET_CF(); // error occurred
7107 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7108 } while ( val8
== 0 );
7110 val8
= 0; // separate asm from while() loop
7111 // turn off interrupts
7116 // set 40:3e bit 7 to 0
7117 val8
= read_byte(0x0040, 0x003e);
7119 write_byte(0x0040, 0x003e, val8
);
7121 // check port 3f4 for accessibility to status bytes
7123 if ( (val8
& 0xc0) != 0xc0 )
7124 BX_PANIC("int13_diskette: ctrl not ready\n");
7126 // read 7 return status bytes from controller
7127 // using loop index broken, have to unroll...
7128 return_status
[0] = inb(0x3f5);
7129 return_status
[1] = inb(0x3f5);
7130 return_status
[2] = inb(0x3f5);
7131 return_status
[3] = inb(0x3f5);
7132 return_status
[4] = inb(0x3f5);
7133 return_status
[5] = inb(0x3f5);
7134 return_status
[6] = inb(0x3f5);
7135 // record in BIOS Data Area
7136 write_byte(0x0040, 0x0042, return_status
[0]);
7137 write_byte(0x0040, 0x0043, return_status
[1]);
7138 write_byte(0x0040, 0x0044, return_status
[2]);
7139 write_byte(0x0040, 0x0045, return_status
[3]);
7140 write_byte(0x0040, 0x0046, return_status
[4]);
7141 write_byte(0x0040, 0x0047, return_status
[5]);
7142 write_byte(0x0040, 0x0048, return_status
[6]);
7144 if ( (return_status
[0] & 0xc0) != 0 ) {
7145 if ( (return_status
[1] & 0x02) != 0 ) {
7146 // diskette not writable.
7147 // AH=status code=0x03 (tried to write on write-protected disk)
7148 // AL=number of sectors written=0
7153 BX_PANIC("int13_diskette_function: read error\n");
7157 // ??? should track be new val from return_status[3] ?
7158 set_diskette_current_cyl(drive
, track
);
7159 // AL = number of sectors read (same value as passed)
7160 SET_AH(0x00); // success
7161 CLEAR_CF(); // success
7163 } else { // if (ah == 0x04)
7164 // Verify Diskette Sectors
7166 // ??? should track be new val from return_status[3] ?
7167 set_diskette_current_cyl(drive
, track
);
7168 // AL = number of sectors verified (same value as passed)
7169 CLEAR_CF(); // success
7170 SET_AH(0x00); // success
7175 case 0x05: // format diskette track
7176 BX_DEBUG_INT13_FL("floppy f05\n");
7178 num_sectors
= GET_AL();
7183 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7184 (num_sectors
== 0) || (num_sectors
> 18)) {
7186 set_diskette_ret_status(1);
7187 SET_CF(); // error occurred
7190 // see if drive exists
7191 if (floppy_drive_exists(drive
) == 0) {
7192 SET_AH(0x80); // drive not responding
7193 set_diskette_ret_status(0x80);
7194 SET_CF(); // error occurred
7198 // see if media in drive, and type is known
7199 if (floppy_media_known(drive
) == 0) {
7200 if (floppy_media_sense(drive
) == 0) {
7201 SET_AH(0x0C); // Media type not found
7202 set_diskette_ret_status(0x0C);
7203 SET_AL(0); // no sectors read
7204 SET_CF(); // error occurred
7209 // set up DMA controller for transfer
7210 page
= (ES
>> 12); // upper 4 bits
7211 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7212 base_address
= base_es
+ BX
; // lower 16 bits of address
7213 // contributed by ES:BX
7214 if ( base_address
< base_es
) {
7215 // in case of carry, adjust page by 1
7218 base_count
= (num_sectors
* 4) - 1;
7220 // check for 64K boundary overrun
7221 last_addr
= base_address
+ base_count
;
7222 if (last_addr
< base_address
) {
7224 set_diskette_ret_status(0x09);
7225 SET_AL(0); // no sectors read
7226 SET_CF(); // error occurred
7231 outb(0x000c, 0x00); // clear flip-flop
7232 outb(0x0004, base_address
);
7233 outb(0x0004, base_address
>>8);
7234 outb(0x000c, 0x00); // clear flip-flop
7235 outb(0x0005, base_count
);
7236 outb(0x0005, base_count
>>8);
7237 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7238 // transfer type=read, channel 2
7239 outb(0x000b, mode_register
);
7240 // port 81: DMA-1 Page Register, channel 2
7244 // set up floppy controller for transfer
7245 floppy_prepare_controller(drive
);
7247 // send format-track command (6 bytes) to controller
7248 outb(0x03f5, 0x4d); // 4d: format track
7249 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7250 outb(0x03f5, 2); // 512 byte sector size
7251 outb(0x03f5, num_sectors
); // number of sectors per track
7252 outb(0x03f5, 0); // Gap length
7253 outb(0x03f5, 0xf6); // Fill byte
7254 // turn on interrupts
7259 // wait on 40:3e bit 7 to become 1
7261 val8
= read_byte(0x0040, 0x0040);
7263 floppy_reset_controller();
7264 SET_AH(0x80); // drive not ready (timeout)
7265 set_diskette_ret_status(0x80);
7266 SET_CF(); // error occurred
7269 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7270 } while ( val8
== 0 );
7272 val8
= 0; // separate asm from while() loop
7273 // turn off interrupts
7277 // set 40:3e bit 7 to 0
7278 val8
= read_byte(0x0040, 0x003e);
7280 write_byte(0x0040, 0x003e, val8
);
7281 // check port 3f4 for accessibility to status bytes
7283 if ( (val8
& 0xc0) != 0xc0 )
7284 BX_PANIC("int13_diskette: ctrl not ready\n");
7286 // read 7 return status bytes from controller
7287 // using loop index broken, have to unroll...
7288 return_status
[0] = inb(0x3f5);
7289 return_status
[1] = inb(0x3f5);
7290 return_status
[2] = inb(0x3f5);
7291 return_status
[3] = inb(0x3f5);
7292 return_status
[4] = inb(0x3f5);
7293 return_status
[5] = inb(0x3f5);
7294 return_status
[6] = inb(0x3f5);
7295 // record in BIOS Data Area
7296 write_byte(0x0040, 0x0042, return_status
[0]);
7297 write_byte(0x0040, 0x0043, return_status
[1]);
7298 write_byte(0x0040, 0x0044, return_status
[2]);
7299 write_byte(0x0040, 0x0045, return_status
[3]);
7300 write_byte(0x0040, 0x0046, return_status
[4]);
7301 write_byte(0x0040, 0x0047, return_status
[5]);
7302 write_byte(0x0040, 0x0048, return_status
[6]);
7304 if ( (return_status
[0] & 0xc0) != 0 ) {
7305 if ( (return_status
[1] & 0x02) != 0 ) {
7306 // diskette not writable.
7307 // AH=status code=0x03 (tried to write on write-protected disk)
7308 // AL=number of sectors written=0
7313 BX_PANIC("int13_diskette_function: write error\n");
7318 set_diskette_ret_status(0);
7319 set_diskette_current_cyl(drive
, 0);
7320 CLEAR_CF(); // successful
7324 case 0x08: // read diskette drive parameters
7325 BX_DEBUG_INT13_FL("floppy f08\n");
7335 SET_DL(num_floppies
);
7340 drive_type
= inb_cmos(0x10);
7342 if (drive_type
& 0xf0)
7344 if (drive_type
& 0x0f)
7356 SET_DL(num_floppies
);
7358 switch (drive_type
) {
7361 SET_DH(0); // max head #
7364 case 1: // 360KB, 5.25"
7365 CX
= 0x2709; // 40 tracks, 9 sectors
7366 SET_DH(1); // max head #
7369 case 2: // 1.2MB, 5.25"
7370 CX
= 0x4f0f; // 80 tracks, 15 sectors
7371 SET_DH(1); // max head #
7374 case 3: // 720KB, 3.5"
7375 CX
= 0x4f09; // 80 tracks, 9 sectors
7376 SET_DH(1); // max head #
7379 case 4: // 1.44MB, 3.5"
7380 CX
= 0x4f12; // 80 tracks, 18 sectors
7381 SET_DH(1); // max head #
7384 case 5: // 2.88MB, 3.5"
7385 CX
= 0x4f24; // 80 tracks, 36 sectors
7386 SET_DH(1); // max head #
7389 case 6: // 160k, 5.25"
7390 CX
= 0x2708; // 40 tracks, 8 sectors
7391 SET_DH(0); // max head #
7394 case 7: // 180k, 5.25"
7395 CX
= 0x2709; // 40 tracks, 9 sectors
7396 SET_DH(0); // max head #
7399 case 8: // 320k, 5.25"
7400 CX
= 0x2708; // 40 tracks, 8 sectors
7401 SET_DH(1); // max head #
7405 BX_PANIC("floppy: int13: bad floppy type\n");
7408 /* set es & di to point to 11 byte diskette param table in ROM */
7412 mov ax
, #diskette_param_table2
7413 mov _int13_diskette_function
.DI
+2[bp
], ax
7414 mov _int13_diskette_function
.ES
+2[bp
], cs
7417 CLEAR_CF(); // success
7418 /* disk status not changed upon success */
7422 case 0x15: // read diskette drive type
7423 BX_DEBUG_INT13_FL("floppy f15\n");
7426 SET_AH(0); // only 2 drives supported
7427 // set_diskette_ret_status here ???
7431 drive_type
= inb_cmos(0x10);
7437 CLEAR_CF(); // successful, not present
7438 if (drive_type
==0) {
7439 SET_AH(0); // drive not present
7442 SET_AH(1); // drive present, does not support change line
7447 case 0x16: // get diskette change line status
7448 BX_DEBUG_INT13_FL("floppy f16\n");
7451 SET_AH(0x01); // invalid drive
7452 set_diskette_ret_status(0x01);
7457 SET_AH(0x06); // change line not supported
7458 set_diskette_ret_status(0x06);
7462 case 0x17: // set diskette type for format(old)
7463 BX_DEBUG_INT13_FL("floppy f17\n");
7464 /* not used for 1.44M floppies */
7465 SET_AH(0x01); // not supported
7466 set_diskette_ret_status(1); /* not supported */
7470 case 0x18: // set diskette type for format(new)
7471 BX_DEBUG_INT13_FL("floppy f18\n");
7472 SET_AH(0x01); // do later
7473 set_diskette_ret_status(1);
7478 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7480 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7481 SET_AH(0x01); // ???
7482 set_diskette_ret_status(1);
7488 #else // #if BX_SUPPORT_FLOPPY
7490 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7491 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7495 switch ( GET_AH() ) {
7497 case 0x01: // Read Diskette Status
7499 val8
= read_byte(0x0000, 0x0441);
7508 write_byte(0x0000, 0x0441, 0x01);
7512 #endif // #if BX_SUPPORT_FLOPPY
7515 set_diskette_ret_status(value
)
7518 write_byte(0x0040, 0x0041, value
);
7522 set_diskette_current_cyl(drive
, cyl
)
7527 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7528 write_byte(0x0040, 0x0094+drive
, cyl
);
7532 determine_floppy_media(drive
)
7536 Bit8u val8
, DOR
, ctrl_info
;
7538 ctrl_info
= read_byte(0x0040, 0x008F);
7546 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7549 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7553 if ( (ctrl_info
& 0x04) != 0x04 ) {
7554 // Drive not determined means no drive exists, done.
7559 // check Main Status Register for readiness
7560 val8
= inb(0x03f4) & 0x80; // Main Status Register
7562 BX_PANIC("d_f_m: MRQ bit not set\n");
7566 // existing BDA values
7568 // turn on drive motor
7569 outb(0x03f2, DOR
); // Digital Output Register
7572 BX_PANIC("d_f_m: OK so far\n");
7577 int17_function(regs
, ds
, iret_addr
)
7578 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7579 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7580 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7582 Bit16u addr
,timeout
;
7589 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7590 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7591 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7592 if (regs
.u
.r8
.ah
== 0) {
7593 outb(addr
, regs
.u
.r8
.al
);
7595 outb(addr
+2, val8
| 0x01); // send strobe
7599 outb(addr
+2, val8
& ~0x01);
7600 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7604 if (regs
.u
.r8
.ah
== 1) {
7606 outb(addr
+2, val8
& ~0x04); // send init
7610 outb(addr
+2, val8
| 0x04);
7613 regs
.u
.r8
.ah
= (val8
^ 0x48);
7614 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7615 ClearCF(iret_addr
.flags
);
7617 SetCF(iret_addr
.flags
); // Unsupported
7622 int19_function(seq_nr
)
7625 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7635 // if BX_ELTORITO_BOOT is not defined, old behavior
7636 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7637 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7638 // 0: system boot sequence, first drive C: then A:
7639 // 1: system boot sequence, first drive A: then C:
7640 // else BX_ELTORITO_BOOT is defined
7641 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7642 // CMOS reg 0x3D & 0x0f : 1st boot device
7643 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7644 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7645 // boot device codes:
7646 // 0x00 : not defined
7647 // 0x01 : first floppy
7648 // 0x02 : first harddrive
7649 // 0x03 : first cdrom
7650 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7651 // else : boot failure
7653 // Get the boot sequence
7654 #if BX_ELTORITO_BOOT
7655 bootdev
= inb_cmos(0x3d);
7656 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
7657 bootdev
>>= 4 * seq_nr
;
7659 if (bootdev
== 0) BX_PANIC("No bootable device.\n");
7661 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7664 if (seq_nr
==2) BX_PANIC("No more boot devices.");
7665 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
7666 /* Boot from floppy if the bit is set or it's the second boot */
7672 /* Read the boot device from the IPL table */
7673 if (get_boot_vector(bootdev
, &e
) == 0) {
7674 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
7678 /* Do the loading, and set up vector as a far pointer to the boot
7679 * address, and bootdrv as the boot drive */
7680 print_boot_device(e
.type
);
7683 case 0x01: /* FDD */
7684 case 0x02: /* HDD */
7686 bootdrv
= (e
.type
== 0x02) ? 0x80 : 0x00;
7698 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7699 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7700 mov es
, ax
;; segment
7701 xor bx
, bx
;; offset
7702 mov ah
, #0x02 ;; function 2, read diskette sector
7703 mov al
, #0x01 ;; read 1 sector
7704 mov ch
, #0x00 ;; track 0
7705 mov cl
, #0x01 ;; sector 1
7706 mov dh
, #0x00 ;; head 0
7707 int #0x13 ;; read sector
7710 mov _int19_function
.status
+ 2[bp
], ax
7721 print_boot_failure(e
.type
, 1);
7725 /* Always check the signature on a HDD boot sector; on FDD, only do
7726 * the check if the CMOS doesn't tell us to skip it */
7727 if ((e
.type
!= 0x01) || !((inb_cmos(0x38) & 0x01))) {
7728 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7729 print_boot_failure(e
.type
, 0);
7734 /* Canonicalize bootseg:bootip */
7735 bootip
= (bootseg
& 0x0fff) << 4;
7739 #if BX_ELTORITO_BOOT
7740 case 0x03: /* CD-ROM */
7741 status
= cdrom_boot();
7744 if ( (status
& 0x00ff) !=0 ) {
7745 print_cdromboot_failure(status
);
7746 print_boot_failure(e
.type
, 1);
7750 bootdrv
= (Bit8u
)(status
>>8);
7751 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7752 /* Canonicalize bootseg:bootip */
7753 bootip
= (bootseg
& 0x0fff) << 4;
7758 case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7759 bootseg
= e
.vector
>> 16;
7760 bootip
= e
.vector
& 0xffff;
7766 /* Debugging info */
7767 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
7769 /* Jump to the boot vector */
7772 ;; Build an iret stack frame that will take us to the boot vector
.
7773 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
7775 mov ax
, _int19_function
.bootseg
+ 0[bp
]
7777 mov ax
, _int19_function
.bootip
+ 0[bp
]
7779 ;; Set the magic number in ax
and the boot drive in dl
.
7781 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
7782 ;; Zero some of the other registers
.
7793 int1a_function(regs
, ds
, iret_addr
)
7794 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7795 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7796 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7800 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
);
7806 switch (regs
.u
.r8
.ah
) {
7807 case 0: // get current clock count
7811 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7812 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7813 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7814 BiosData
->midnight_flag
= 0; // reset flag
7819 ClearCF(iret_addr
.flags
); // OK
7822 case 1: // Set Current Clock Count
7826 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7827 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7828 BiosData
->midnight_flag
= 0; // reset flag
7833 ClearCF(iret_addr
.flags
); // OK
7837 case 2: // Read CMOS Time
7838 if (rtc_updating()) {
7839 SetCF(iret_addr
.flags
);
7843 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7844 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7845 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7846 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7848 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7849 ClearCF(iret_addr
.flags
); // OK
7852 case 3: // Set CMOS Time
7853 // Using a debugger, I notice the following masking/setting
7854 // of bits in Status Register B, by setting Reg B to
7855 // a few values and getting its value after INT 1A was called.
7857 // try#1 try#2 try#3
7858 // before 1111 1101 0111 1101 0000 0000
7859 // after 0110 0010 0110 0010 0000 0010
7861 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7862 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7863 if (rtc_updating()) {
7865 // fall through as if an update were not in progress
7867 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7868 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7869 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7870 // Set Daylight Savings time enabled bit to requested value
7871 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7872 // (reg B already selected)
7873 outb_cmos(0x0b, val8
);
7875 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7876 ClearCF(iret_addr
.flags
); // OK
7879 case 4: // Read CMOS Date
7881 if (rtc_updating()) {
7882 SetCF(iret_addr
.flags
);
7885 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
7886 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
7887 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
7888 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
7889 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7890 ClearCF(iret_addr
.flags
); // OK
7893 case 5: // Set CMOS Date
7894 // Using a debugger, I notice the following masking/setting
7895 // of bits in Status Register B, by setting Reg B to
7896 // a few values and getting its value after INT 1A was called.
7898 // try#1 try#2 try#3 try#4
7899 // before 1111 1101 0111 1101 0000 0010 0000 0000
7900 // after 0110 1101 0111 1101 0000 0010 0000 0000
7902 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7903 // My assumption: RegB = (RegB & 01111111b)
7904 if (rtc_updating()) {
7906 SetCF(iret_addr
.flags
);
7909 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
7910 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
7911 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
7912 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
7913 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7914 outb_cmos(0x0b, val8
);
7916 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
7917 ClearCF(iret_addr
.flags
); // OK
7920 case 6: // Set Alarm Time in CMOS
7921 // Using a debugger, I notice the following masking/setting
7922 // of bits in Status Register B, by setting Reg B to
7923 // a few values and getting its value after INT 1A was called.
7925 // try#1 try#2 try#3
7926 // before 1101 1111 0101 1111 0000 0000
7927 // after 0110 1111 0111 1111 0010 0000
7929 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7930 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7931 val8
= inb_cmos(0x0b); // Get Status Reg B
7934 // Alarm interrupt enabled already
7935 SetCF(iret_addr
.flags
); // Error: alarm in use
7938 if (rtc_updating()) {
7940 // fall through as if an update were not in progress
7942 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
7943 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
7944 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
7945 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7946 // enable Status Reg B alarm bit, clear halt clock bit
7947 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
7948 ClearCF(iret_addr
.flags
); // OK
7951 case 7: // Turn off Alarm
7952 // Using a debugger, I notice the following masking/setting
7953 // of bits in Status Register B, by setting Reg B to
7954 // a few values and getting its value after INT 1A was called.
7956 // try#1 try#2 try#3 try#4
7957 // before 1111 1101 0111 1101 0010 0000 0010 0010
7958 // after 0100 0101 0101 0101 0000 0000 0000 0010
7960 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7961 // My assumption: RegB = (RegB & 01010111b)
7962 val8
= inb_cmos(0x0b); // Get Status Reg B
7963 // clear clock-halt bit, disable alarm bit
7964 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
7966 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7967 ClearCF(iret_addr
.flags
); // OK
7971 // real mode PCI BIOS functions now handled in assembler code
7972 // this C code handles the error code for information only
7973 if (regs
.u
.r8
.bl
== 0xff) {
7974 BX_INFO("PCI BIOS: PCI not present\n");
7975 } else if (regs
.u
.r8
.bl
== 0x81) {
7976 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
7977 } else if (regs
.u
.r8
.bl
== 0x83) {
7978 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
7979 } else if (regs
.u
.r8
.bl
== 0x86) {
7980 if (regs
.u
.r8
.al
== 0x02) {
7981 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
7983 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
);
7986 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
7987 SetCF(iret_addr
.flags
);
7992 SetCF(iret_addr
.flags
); // Unsupported
7997 int70_function(regs
, ds
, iret_addr
)
7998 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7999 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8000 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8002 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8003 Bit8u registerB
= 0, registerC
= 0;
8005 // Check which modes are enabled and have occurred.
8006 registerB
= inb_cmos( 0xB );
8007 registerC
= inb_cmos( 0xC );
8009 if( ( registerB
& 0x60 ) != 0 ) {
8010 if( ( registerC
& 0x20 ) != 0 ) {
8011 // Handle Alarm Interrupt.
8018 if( ( registerC
& 0x40 ) != 0 ) {
8019 // Handle Periodic Interrupt.
8021 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8022 // Wait Interval (Int 15, AH=83) active.
8023 Bit32u time
, toggle
;
8025 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8026 if( time
< 0x3D1 ) {
8028 Bit16u segment
, offset
;
8030 segment
= read_word( 0x40, 0x98 );
8031 offset
= read_word( 0x40, 0x9A );
8032 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8033 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8034 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8036 // Continue waiting.
8038 write_dword( 0x40, 0x9C, time
);
8051 ;------------------------------------------
8052 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8053 ;------------------------------------------
8058 push
#0x00 ;; placeholder for status
8059 push
#0x00 ;; placeholder for X
8060 push
#0x00 ;; placeholder for Y
8061 push
#0x00 ;; placeholder for Z
8062 push
#0x00 ;; placeholder for make_far_call boolean
8063 call _int74_function
8064 pop cx
;; remove make_far_call from stack
8067 ;; make far call to EBDA
:0022
8070 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8072 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8077 add sp
, #8 ;; pop status, x, y, z
8079 pop ds
;; restore DS
8084 ;; This will perform an IRET
, but will retain value of current CF
8085 ;; by altering flags on stack
. Better than RETF
#02.
8090 and BYTE
[bp
+ 0x06], #0xfe
8096 or BYTE
[bp
+ 0x06], #0x01
8101 ;----------------------
8102 ;- INT13h (relocated
) -
8103 ;----------------------
8105 ; int13_relocated is a little bit messed up since I played with it
8106 ; I have to rewrite it
:
8107 ; - call a function that detect which function to call
8108 ; - make all called C function get the same parameters list
8112 #if BX_ELTORITO_BOOT
8113 ;; check
for an eltorito function
8115 jb int13_not_eltorito
8117 ja int13_not_eltorito
8126 jmp _int13_eltorito
;; ELDX
not used
8134 ;; check
if emulation active
8135 call _cdemu_isactive
8137 je int13_cdemu_inactive
8139 ;; check
if access to the emulated drive
8140 call _cdemu_emulated_drive
8143 cmp al
,dl
;; int13 on emulated drive
8158 jmp _int13_cdemu
;; ELDX
not used
8161 and dl
,#0xE0 ;; mask to get device class, including cdroms
8162 cmp al
,dl
;; al is
0x00 or 0x80
8163 jne int13_cdemu_inactive
;; inactive
for device
class
8175 dec dl
;; real drive is dl
- 1
8178 int13_cdemu_inactive
:
8184 #endif // BX_ELTORITO_BOOT
8195 push dx
;; push eltorito value of dx instead of sp
8206 ;; now the
16-bit registers can be restored with
:
8207 ;; pop ds
; pop es
; popa
; iret
8208 ;; arguments passed to functions should be
8209 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8215 jmp _int13_diskette_function
8224 // ebx is modified: BSD 5.2.1 boot loader problem
8225 // someone should figure out which 32 bit register that actually are used
8242 ;; int13_harddisk modifies high word of EAX
8245 call _int13_harddisk
8258 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8266 ;; Get the boot sequence number out of the IPL memory
8268 mov ds
, bx
;; Set segment
8269 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8271 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8272 mov ds
, ax
;; and reset the segment to zero
.
8274 ;; Carry on in the INT
19h handler
, using the
new sequence number
8282 int19_relocated
: ;; Boot function
, relocated
8284 ;; int19 was beginning to be really
complex, so now it
8285 ;; just calls a C function that does the work
8296 ;; Start from the first boot
device (0, in AX
)
8298 mov ds
, bx
;; Set segment to write to the IPL memory
8299 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8300 mov ds
, ax
;; and reset the segment
.
8306 ;; Call the C code
for the next boot device
8307 call _int19_function
8309 ;; Boot failed
: invoke the boot recovery function
8315 int1c_handler
: ;; User Timer Tick
8319 ;----------------------
8320 ;- POST
: Floppy Drive
-
8321 ;----------------------
8327 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8329 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8331 mov
0x0440, al
;; diskette motor timeout counter
: not active
8332 mov
0x0441, al
;; diskette controller status
return code
8334 mov
0x0442, al
;; disk
& diskette controller status
register 0
8335 mov
0x0443, al
;; diskette controller status
register 1
8336 mov
0x0444, al
;; diskette controller status
register 2
8337 mov
0x0445, al
;; diskette controller cylinder number
8338 mov
0x0446, al
;; diskette controller head number
8339 mov
0x0447, al
;; diskette controller sector number
8340 mov
0x0448, al
;; diskette controller bytes written
8342 mov
0x048b, al
;; diskette configuration data
8344 ;; -----------------------------------------------------------------
8345 ;; (048F
) diskette controller information
8347 mov al
, #0x10 ;; get CMOS diskette drive type
8350 mov ah
, al
;; save byte to AH
8353 shr al
, #4 ;; look at top 4 bits for drive 0
8354 jz f0_missing
;; jump
if no drive0
8355 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8358 mov bl
, #0x00 ;; no drive0
8361 mov al
, ah
;; restore from AH
8362 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8363 jz f1_missing
;; jump
if no drive1
8364 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8366 ;; leave high bits in BL zerod
8367 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8368 ;; -----------------------------------------------------------------
8371 mov
0x0490, al
;; diskette
0 media state
8372 mov
0x0491, al
;; diskette
1 media state
8374 ;; diskette
0,1 operational starting state
8375 ;; drive type has
not been determined
,
8376 ;; has no changed detection line
8380 mov
0x0494, al
;; diskette
0 current cylinder
8381 mov
0x0495, al
;; diskette
1 current cylinder
8384 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8386 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8387 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8388 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8393 ;--------------------
8394 ;- POST
: HARD DRIVE
-
8395 ;--------------------
8396 ; relocated here because the primary POST area isnt big enough
.
8399 // INT 76h calls INT 15h function ax=9100
8401 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8407 mov
0x0474, al
/* hard disk status of last operation */
8408 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8409 mov
0x048c, al
/* hard disk status register */
8410 mov
0x048d, al
/* hard disk error register */
8411 mov
0x048e, al
/* hard disk task complete flag */
8413 mov
0x0475, al
/* hard disk number attached */
8415 mov
0x0476, al
/* hard disk control byte */
8416 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8417 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8418 ;; INT
41h
: hard disk
0 configuration pointer
8419 ;; INT
46h
: hard disk
1 configuration pointer
8420 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8421 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8423 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8435 cmp al
, #47 ;; decimal 47 - user definable
8439 ;; CMOS purpose param table offset
8440 ;; 1b cylinders low
0
8441 ;; 1c cylinders high
1
8443 ;; 1e write pre
-comp low
5
8444 ;; 1f write pre
-comp high
6
8445 ;; 20 retries
/bad map
/heads
>8 8
8446 ;; 21 landing zone low C
8447 ;; 22 landing zone high D
8448 ;; 23 sectors
/track E
8453 ;;; Filling EBDA table
for hard disk
0.
8461 mov (0x003d + 0x05), ax
;; write precomp word
8466 mov (0x003d + 0x08), al
;; drive control byte
8475 mov (0x003d + 0x0C), ax
;; landing zone word
8477 mov al
, #0x1c ;; get cylinders word in AX
8479 in al
, #0x71 ;; high byte
8483 in al
, #0x71 ;; low byte
8484 mov bx
, ax
;; BX
= cylinders
8489 mov cl
, al
;; CL
= heads
8494 mov dl
, al
;; DL
= sectors
8497 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8499 hd0_post_physical_chs
:
8500 ;; no logical CHS mapping used
, just physical CHS
8501 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8502 mov (0x003d + 0x00), bx
;; number of physical cylinders
8503 mov (0x003d + 0x02), cl
;; number of physical heads
8504 mov (0x003d + 0x0E), dl
;; number of physical sectors
8507 hd0_post_logical_chs
:
8508 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8509 mov (0x003d + 0x09), bx
;; number of physical cylinders
8510 mov (0x003d + 0x0b), cl
;; number of physical heads
8511 mov (0x003d + 0x04), dl
;; number of physical sectors
8512 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8514 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8517 jnbe hd0_post_above_2048
8518 ;; 1024 < c
<= 2048 cylinders
8521 jmp hd0_post_store_logical
8523 hd0_post_above_2048
:
8525 jnbe hd0_post_above_4096
8526 ;; 2048 < c
<= 4096 cylinders
8529 jmp hd0_post_store_logical
8531 hd0_post_above_4096
:
8533 jnbe hd0_post_above_8192
8534 ;; 4096 < c
<= 8192 cylinders
8537 jmp hd0_post_store_logical
8539 hd0_post_above_8192
:
8540 ;; 8192 < c
<= 16384 cylinders
8544 hd0_post_store_logical
:
8545 mov (0x003d + 0x00), bx
;; number of physical cylinders
8546 mov (0x003d + 0x02), cl
;; number of physical heads
8548 mov cl
, #0x0f ;; repeat count
8549 mov si
, #0x003d ;; offset to disk0 FDPT
8550 mov al
, #0x00 ;; sum
8551 hd0_post_checksum_loop
:
8555 jnz hd0_post_checksum_loop
8556 not al
;; now take
2s complement
8559 ;;; Done filling EBDA table
for hard disk
0.
8563 ;; is there really a second hard disk
? if not, return now
8571 ;; check that the hd type is really
0x0f.
8576 ;; check that the extended type is
47 - user definable
8580 cmp al
, #47 ;; decimal 47 - user definable
8585 ;; CMOS purpose param table offset
8586 ;; 0x24 cylinders low
0
8587 ;; 0x25 cylinders high
1
8589 ;; 0x27 write pre
-comp low
5
8590 ;; 0x28 write pre
-comp high
6
8592 ;; 0x2a landing zone low C
8593 ;; 0x2b landing zone high D
8594 ;; 0x2c sectors
/track E
8595 ;;; Fill EBDA table
for hard disk
1.
8605 mov (0x004d + 0x05), ax
;; write precomp word
8610 mov (0x004d + 0x08), al
;; drive control byte
8619 mov (0x004d + 0x0C), ax
;; landing zone word
8621 mov al
, #0x25 ;; get cylinders word in AX
8623 in al
, #0x71 ;; high byte
8627 in al
, #0x71 ;; low byte
8628 mov bx
, ax
;; BX
= cylinders
8633 mov cl
, al
;; CL
= heads
8638 mov dl
, al
;; DL
= sectors
8641 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8643 hd1_post_physical_chs
:
8644 ;; no logical CHS mapping used
, just physical CHS
8645 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8646 mov (0x004d + 0x00), bx
;; number of physical cylinders
8647 mov (0x004d + 0x02), cl
;; number of physical heads
8648 mov (0x004d + 0x0E), dl
;; number of physical sectors
8651 hd1_post_logical_chs
:
8652 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8653 mov (0x004d + 0x09), bx
;; number of physical cylinders
8654 mov (0x004d + 0x0b), cl
;; number of physical heads
8655 mov (0x004d + 0x04), dl
;; number of physical sectors
8656 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8658 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8661 jnbe hd1_post_above_2048
8662 ;; 1024 < c
<= 2048 cylinders
8665 jmp hd1_post_store_logical
8667 hd1_post_above_2048
:
8669 jnbe hd1_post_above_4096
8670 ;; 2048 < c
<= 4096 cylinders
8673 jmp hd1_post_store_logical
8675 hd1_post_above_4096
:
8677 jnbe hd1_post_above_8192
8678 ;; 4096 < c
<= 8192 cylinders
8681 jmp hd1_post_store_logical
8683 hd1_post_above_8192
:
8684 ;; 8192 < c
<= 16384 cylinders
8688 hd1_post_store_logical
:
8689 mov (0x004d + 0x00), bx
;; number of physical cylinders
8690 mov (0x004d + 0x02), cl
;; number of physical heads
8692 mov cl
, #0x0f ;; repeat count
8693 mov si
, #0x004d ;; offset to disk0 FDPT
8694 mov al
, #0x00 ;; sum
8695 hd1_post_checksum_loop
:
8699 jnz hd1_post_checksum_loop
8700 not al
;; now take
2s complement
8703 ;;; Done filling EBDA table
for hard disk
1.
8707 ;--------------------
8708 ;- POST
: EBDA segment
8709 ;--------------------
8710 ; relocated here because the primary POST area isnt big enough
.
8715 mov byte ptr
[0x0], #EBDA_SIZE
8717 xor ax
, ax
; mov EBDA seg into
40E
8719 mov word ptr
[0x40E], #EBDA_SEG
8722 ;--------------------
8723 ;- POST
: EOI
+ jmp via
[0x40:67)
8724 ;--------------------
8725 ; relocated here because the primary POST area isnt big enough
.
8735 ;--------------------
8738 out
#0xA0, al ;; slave PIC EOI
8741 out
#0x20, al ;; master PIC EOI
8744 ;--------------------
8746 ;; in
: AL in BCD format
8747 ;; out
: AL in binary format
, AH will always be
0
8750 and bl
, #0x0f ;; bl has low digit
8751 shr al
, #4 ;; al has high digit
8753 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8754 add al
, bl
;; then add low digit
8757 ;--------------------
8759 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8760 ;; Timer Ticks Roller
Flag (0x470:byte
)
8761 ;; The Timer Ticks Count needs to be set according to
8762 ;; the current CMOS time
, as
if ticks have been occurring
8763 ;; at
18.2hz since midnight up to
this point
. Calculating
8764 ;; this is a little complicated
. Here are the factors I gather
8765 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8766 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8767 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8768 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8769 ;; the timer
. With a maximum
16bit timer count
, this is again
8770 ;; divided down by
65536 to
18.2hz
.
8772 ;; 14,318,180 Hz clock
8773 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8774 ;; /4 = 1,193,181 Hz fed to timer
8775 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8776 ;; 1 second
= 18.20650736 ticks
8777 ;; 1 minute
= 1092.390442 ticks
8778 ;; 1 hour
= 65543.42651 ticks
8780 ;; Given the values in the CMOS clock
, one could calculate
8781 ;; the number of ticks by the following
:
8782 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8783 ;; (BcdToBin(minutes
) * 1092.3904)
8784 ;; (BcdToBin(hours
) * 65543.427)
8785 ;; To get a little more accuracy
, since Im
using integer
8786 ;; arithmatic
, I use
:
8787 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8788 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8789 ;; (BcdToBin(hours
) * 65543427) / 1000
8794 xor eax
, eax
;; clear EAX
8797 in al
, #0x71 ;; AL has CMOS seconds in BCD
8798 call BcdToBin
;; EAX now has seconds in binary
8804 mov ecx
, eax
;; ECX will accumulate total ticks
8807 xor eax
, eax
;; clear EAX
8810 in al
, #0x71 ;; AL has CMOS minutes in BCD
8811 call BcdToBin
;; EAX now has minutes in binary
8817 add ecx
, eax
;; add to total ticks
8820 xor eax
, eax
;; clear EAX
8823 in al
, #0x71 ;; AL has CMOS hours in BCD
8824 call BcdToBin
;; EAX now has hours in binary
8830 add ecx
, eax
;; add to total ticks
8832 mov
0x46C, ecx
;; Timer Ticks Count
8834 mov
0x470, al
;; Timer Ticks Rollover Flag
8837 ;--------------------
8839 ;; record completion in BIOS task complete flag
8851 ;--------------------
8856 #include "apmbios.S"
8860 #include "apmbios.S"
8863 #include "apmbios.S"
8867 ;--------------------
8872 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8873 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8874 db
0 ;; revision level
8875 ;; length in paragraphs
and checksum stored in a word to prevent errors
8876 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8877 & 0xff) << 8) + 0x01
8878 db
0,0,0,0,0 ;; reserved
8883 cmp eax
, #0x49435024 ;; "$PCI"
8885 mov eax
, #0x80000000
8890 #ifdef PCI_FIXED_HOST_BRIDGE
8891 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8894 ;; say ok
if a device is present
8895 cmp eax
, #0xffffffff
8898 mov ebx
, #0x000f0000
8900 mov edx
, #pcibios_protected
8907 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
8918 cmp al
, #0x01 ;; installation check
8922 mov edx
, #0x20494350 ;; "PCI "
8925 pci_pro_f02
: ;; find pci device
8933 call pci_pro_select_reg
8947 pci_pro_f03
: ;; find
class code
8953 call pci_pro_select_reg
8958 jne pci_pro_nextdev2
8965 jne pci_pro_devloop2
8968 pci_pro_f08
: ;; read configuration byte
8971 call pci_pro_select_reg
8980 pci_pro_f09
: ;; read configuration word
8983 call pci_pro_select_reg
8992 pci_pro_f0a
: ;; read configuration dword
8995 call pci_pro_select_reg
9002 pci_pro_f0b
: ;; write configuration byte
9005 call pci_pro_select_reg
9014 pci_pro_f0c
: ;; write configuration word
9017 call pci_pro_select_reg
9026 pci_pro_f0d
: ;; write configuration dword
9029 call pci_pro_select_reg
9042 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9052 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9076 mov eax
, #0x80000000
9081 #ifdef PCI_FIXED_HOST_BRIDGE
9082 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9085 ;; say ok
if a device is present
9086 cmp eax
, #0xffffffff
9097 cmp al
, #0x01 ;; installation check
9102 mov edx
, #0x20494350 ;; "PCI "
9104 mov di
, #pcibios_protected
9107 pci_real_f02
: ;; find pci device
9117 call pci_real_select_reg
9121 jne pci_real_nextdev
9128 jne pci_real_devloop
9133 pci_real_f03
: ;; find
class code
9139 call pci_real_select_reg
9144 jne pci_real_nextdev2
9151 jne pci_real_devloop2
9156 pci_real_f08
: ;; read configuration byte
9159 call pci_real_select_reg
9168 pci_real_f09
: ;; read configuration word
9171 call pci_real_select_reg
9180 pci_real_f0a
: ;; read configuration dword
9183 call pci_real_select_reg
9190 pci_real_f0b
: ;; write configuration byte
9193 call pci_real_select_reg
9202 pci_real_f0c
: ;; write configuration word
9205 call pci_real_select_reg
9214 pci_real_f0d
: ;; write configuration dword
9217 call pci_real_select_reg
9224 pci_real_f0e
: ;; get irq routing options
9226 jne pci_real_unknown
9228 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9229 jb pci_real_too_small
9231 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9239 mov si
, #pci_routing_table_structure_start
9247 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9256 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9260 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9278 pci_real_select_reg
:
9292 pci_routing_table_structure
:
9293 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9295 dw
32 + (6 * 16) ;; table size
9296 db
0 ;; PCI interrupt router bus
9297 db
0x08 ;; PCI interrupt router DevFunc
9298 dw
0x0000 ;; PCI exclusive IRQs
9299 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9300 dw
0x7000 ;; compatible PCI interrupt router device ID
9301 dw
0,0 ;; Miniport data
9302 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9304 pci_routing_table_structure_start
:
9305 ;; first slot entry PCI
-to
-ISA (embedded
)
9306 db
0 ;; pci bus number
9307 db
0x08 ;; pci device
number (bit
7-3)
9308 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9309 dw
0xdef8 ;; IRQ bitmap INTA
#
9310 db
0x61 ;; link value INTB
#
9311 dw
0xdef8 ;; IRQ bitmap INTB
#
9312 db
0x62 ;; link value INTC
#
9313 dw
0xdef8 ;; IRQ bitmap INTC
#
9314 db
0x63 ;; link value INTD
#
9315 dw
0xdef8 ;; IRQ bitmap INTD
#
9316 db
0 ;; physical
slot (0 = embedded
)
9318 ;; second slot entry
: 1st PCI slot
9319 db
0 ;; pci bus number
9320 db
0x10 ;; pci device
number (bit
7-3)
9321 db
0x61 ;; link value INTA
#
9322 dw
0xdef8 ;; IRQ bitmap INTA
#
9323 db
0x62 ;; link value INTB
#
9324 dw
0xdef8 ;; IRQ bitmap INTB
#
9325 db
0x63 ;; link value INTC
#
9326 dw
0xdef8 ;; IRQ bitmap INTC
#
9327 db
0x60 ;; link value INTD
#
9328 dw
0xdef8 ;; IRQ bitmap INTD
#
9329 db
1 ;; physical
slot (0 = embedded
)
9331 ;; third slot entry
: 2nd PCI slot
9332 db
0 ;; pci bus number
9333 db
0x18 ;; pci device
number (bit
7-3)
9334 db
0x62 ;; link value INTA
#
9335 dw
0xdef8 ;; IRQ bitmap INTA
#
9336 db
0x63 ;; link value INTB
#
9337 dw
0xdef8 ;; IRQ bitmap INTB
#
9338 db
0x60 ;; link value INTC
#
9339 dw
0xdef8 ;; IRQ bitmap INTC
#
9340 db
0x61 ;; link value INTD
#
9341 dw
0xdef8 ;; IRQ bitmap INTD
#
9342 db
2 ;; physical
slot (0 = embedded
)
9344 ;; 4th slot entry
: 3rd PCI slot
9345 db
0 ;; pci bus number
9346 db
0x20 ;; pci device
number (bit
7-3)
9347 db
0x63 ;; link value INTA
#
9348 dw
0xdef8 ;; IRQ bitmap INTA
#
9349 db
0x60 ;; link value INTB
#
9350 dw
0xdef8 ;; IRQ bitmap INTB
#
9351 db
0x61 ;; link value INTC
#
9352 dw
0xdef8 ;; IRQ bitmap INTC
#
9353 db
0x62 ;; link value INTD
#
9354 dw
0xdef8 ;; IRQ bitmap INTD
#
9355 db
3 ;; physical
slot (0 = embedded
)
9357 ;; 5th slot entry
: 4rd PCI slot
9358 db
0 ;; pci bus number
9359 db
0x28 ;; pci device
number (bit
7-3)
9360 db
0x60 ;; link value INTA
#
9361 dw
0xdef8 ;; IRQ bitmap INTA
#
9362 db
0x61 ;; link value INTB
#
9363 dw
0xdef8 ;; IRQ bitmap INTB
#
9364 db
0x62 ;; link value INTC
#
9365 dw
0xdef8 ;; IRQ bitmap INTC
#
9366 db
0x63 ;; link value INTD
#
9367 dw
0xdef8 ;; IRQ bitmap INTD
#
9368 db
4 ;; physical
slot (0 = embedded
)
9370 ;; 6th slot entry
: 5rd PCI slot
9371 db
0 ;; pci bus number
9372 db
0x30 ;; pci device
number (bit
7-3)
9373 db
0x61 ;; link value INTA
#
9374 dw
0xdef8 ;; IRQ bitmap INTA
#
9375 db
0x62 ;; link value INTB
#
9376 dw
0xdef8 ;; IRQ bitmap INTB
#
9377 db
0x63 ;; link value INTC
#
9378 dw
0xdef8 ;; IRQ bitmap INTC
#
9379 db
0x60 ;; link value INTD
#
9380 dw
0xdef8 ;; IRQ bitmap INTD
#
9381 db
5 ;; physical
slot (0 = embedded
)
9383 pci_routing_table_structure_end
:
9389 pcibios_init_sel_reg
:
9401 pcibios_init_iomem_bases
:
9404 mov eax
, #0xe0000000 ;; base for memory init
9406 mov ax
, #0xc000 ;; base for i/o init
9408 mov ax
, #0x0010 ;; start at base address #0
9413 call pcibios_init_sel_reg
9418 mov dl
, #0x04 ;; disable i/o and memory space access
9419 call pcibios_init_sel_reg
9426 call pcibios_init_sel_reg
9432 mov eax
, #0xffffffff
9437 xor eax
, #0xffffffff
9441 add eax
, ecx
;; calculate next free mem base
9442 add eax
, #0x01000000
9443 and eax
, #0xff000000
9457 add ax
, cx
;; calculate next free i
/o base
9465 je enable_iomem_space
9466 mov byte ptr
[bp
-8], al
9467 jmp pci_init_io_loop2
9469 mov dl
, #0x04 ;; enable i/o and memory space access if available
9470 call pcibios_init_sel_reg
9476 mov byte ptr
[bp
-8], #0x10
9479 jne pci_init_io_loop1
9484 pcibios_init_set_elcr
:
9508 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9513 mov si
, #pci_routing_table_structure
9517 call pcibios_init_sel_reg
9520 cmp eax
, [si
+12] ;; check irq router
9523 call pcibios_init_sel_reg
9524 push bx
;; save irq router bus
+ devfunc
9527 out dx
, ax
;; reset PIRQ route control
9535 add si
, #0x20 ;; set pointer to 1st entry
9537 mov ax
, #pci_irq_list
9546 call pcibios_init_sel_reg
9550 jnz pci_test_int_pin
9556 call pcibios_init_sel_reg
9561 dec al
;; determine pirq reg
9570 call pcibios_init_sel_reg
9577 mov bx
, [bp
-2] ;; pci irq list pointer
9582 call pcibios_init_set_elcr
9586 add bl
, [bp
-3] ;; pci function number
9588 call pcibios_init_sel_reg
9595 jnz pci_init_irq_loop2
9598 mov byte ptr
[bp
-3], #0x00
9599 loop pci_init_irq_loop1
9606 #endif // BX_ROMBIOS32
9607 #endif // BX_PCIBIOS
9611 ;; save a20
and enable it
9617 ;; save SS
:SP to the BDA
9624 lidt
[pmode_IDT_info
]
9626 lgdt
[rombios32_gdt_48
]
9627 ;; set PE bit in CR0
9631 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
9634 dw
0x000f ;; high
16 bit address
9639 ;; init data segments
9649 ;; copy rombios32 code to
ram (ram offset
= 1MB
)
9650 mov esi
, #0xfffe0000
9651 mov edi
, #0x00040000
9652 mov ecx
, #0x10000 / 4
9656 ;; init the stack pointer
9657 mov esp
, #0x00080000
9659 ;; call rombios32 code
9660 mov eax
, #0x00040000
9663 ;; reset the
memory (some boot loaders such as syslinux suppose
9664 ;; that the memory is set to zero
)
9665 mov edi
, #0x00040000
9666 mov ecx
, #0x40000 / 4
9671 ;; reset the
memory (some boot loaders such as syslinux suppose
9672 ;; that the memory is set to zero
)
9673 mov edi
, #0x00040000
9674 mov ecx
, #0x40000 / 4
9679 ;; return to
16 bit
protected mode first
9686 ;; restore data segment limits to
0xffff
9694 ;; reset PE bit in CR0
9699 ;; far jump to flush CPU queue after transition to real mode
9700 JMP_AP(0xf000, rombios32_real_mode
)
9702 rombios32_real_mode
:
9703 ;; restore IDT to normal real
-mode defaults
9705 lidt
[rmode_IDT_info
]
9713 ;; restore SS
:SP from the BDA
9730 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
9731 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
9732 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
9733 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
9737 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9742 and al
, #0xdf ; clear input mode
9752 mov
[bx
+0x408], dx
; Parallel I
/O address
9754 mov
[bx
+0x478], cl
; Parallel printer timeout
9759 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9778 mov
[bx
+0x400], dx
; Serial I
/O address
9780 mov
[bx
+0x47c], cl
; Serial timeout
9807 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
9808 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
9816 ;; Scan
for existence of valid expansion ROMS
.
9817 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9818 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9819 ;; System ROM
: only
0xE0000
9825 ;; 2 ROM length in
512-byte blocks
9826 ;; 3 ROM initialization entry
point (FAR CALL
)
9831 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9832 cmp
[0], #0xAA55 ;; look for signature
9833 jne rom_scan_increment
9835 jnz rom_scan_increment
9836 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9838 ;; We want our increment in
512-byte quantities
, rounded to
9839 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9841 jz block_count_rounded
9842 and al
, #0xfc ;; needs rounding up
9844 block_count_rounded
:
9846 xor bx
, bx
;; Restore DS back to
0000:
9850 ;; Push addr of ROM entry point
9852 push
#0x0003 ;; Push offset
9854 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
9855 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
9860 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9861 db
0xff ;; call_far ss
:[bp
+0]
9864 cli
;; In
case expansion ROM BIOS turns IF on
9865 add sp
, #2 ;; Pop offset value
9866 pop cx
;; Pop seg
value (restore CX
)
9868 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
9869 ;; to init all the ROMs
and then go back
and build an IPL table of
9870 ;; all the bootable devices
, but we can get away with one pass
.
9871 mov ds
, cx
;; ROM base
9872 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
9873 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
9874 cmp ax
, #0x5024 ;; we look for signature "$PnP"
9879 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
9880 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
9883 ;; Found a device that thinks it can boot the system
. Record its BEV
.
9884 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
9886 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
9887 cmp bx
, #IPL_TABLE_ENTRIES
9888 je no_bev
;; Get out
if the table is full
9889 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
9890 mov
0[bx
], #0x80 ;; This entry is a BEV device
9891 mov
6[bx
], cx
;; Build a far pointer from the segment
...
9892 mov
4[bx
], ax
;; and the offset
9893 shr bx
, #0x4 ;; Turn the offset back into a count
9894 inc bx
;; We have one more entry now
9895 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
9898 pop di
;; Restore DI
9899 pop ax
;; Restore AX
9901 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
9902 ;; because the segment selector is shifted left
4 bits
.
9907 xor ax
, ax
;; Restore DS back to
0000:
9911 ;; for 'C' strings
and other data
, insert them here with
9912 ;; a the following hack
:
9913 ;; DATA_SEG_DEFS_HERE
9916 ;; the following area can be used to write dynamically generated tables
9918 bios_table_area_start
:
9920 dd bios_table_area_end
- bios_table_area_start
- 8;
9925 .org
0xe05b ; POST Entry Point
9926 bios_table_area_end
:
9931 ;; first reset the DMA controllers
9935 ;; then initialize the DMA controllers
9937 out
0xD6, al
; cascade mode of channel
4 enabled
9939 out
0xD4, al
; unmask channel
4
9941 ;; Examine CMOS shutdown status
.
9949 ;; Reset CMOS shutdown status
.
9951 out
0x70, AL
; select CMOS
register Fh
9953 out
0x71, AL
; set shutdown action to normal
9955 ;; Examine CMOS shutdown status
.
9958 ;; 0x00, 0x09, 0x0D+ = normal startup
9966 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
9970 ;; Examine CMOS shutdown status
.
9971 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
9973 call _shutdown_status_panic
9979 ; 0xb0, 0x20, /* mov al, #0x20 */
9980 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9990 ; case 0: normal startup
9999 ;; zero out BIOS data
area (40:00..40:ff
)
10001 mov cx
, #0x0080 ;; 128 words
10007 call _log_bios_start
10009 ;; set all interrupts to
default handler
10010 xor bx
, bx
;; offset index
10011 mov cx
, #0x0100 ;; counter (256 interrupts)
10012 mov ax
, #dummy_iret_handler
10022 loop post_default_ints
10024 ;; set vector
0x79 to zero
10025 ;; this is used by
'gardian angel' protection system
10026 SET_INT_VECTOR(0x79, #0, #0)
10028 ;; base memory in K
40:13 (word
)
10029 mov ax
, #BASE_MEM_IN_K
10033 ;; Manufacturing Test
40:12
10036 ;; Warm Boot Flag
0040:0072
10037 ;; value of
1234h
= skip memory checks
10041 ;; Printer Services vector
10042 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10044 ;; Bootstrap failure vector
10045 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10047 ;; Bootstrap Loader vector
10048 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10050 ;; User Timer Tick vector
10051 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10053 ;; Memory Size Check vector
10054 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10056 ;; Equipment Configuration Check vector
10057 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10060 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10066 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10067 ;; int 1C already points at
dummy_iret_handler (above
)
10068 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10070 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10075 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10076 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10080 mov
0x0417, al
/* keyboard shift flags, set 1 */
10081 mov
0x0418, al
/* keyboard shift flags, set 2 */
10082 mov
0x0419, al
/* keyboard alt-numpad work area */
10083 mov
0x0471, al
/* keyboard ctrl-break flag */
10084 mov
0x0497, al
/* keyboard status flags 4 */
10086 mov
0x0496, al
/* keyboard status flags 3 */
10089 /* keyboard head of buffer pointer */
10093 /* keyboard end of buffer pointer */
10096 /* keyboard pointer to start of buffer */
10100 /* keyboard pointer to end of buffer */
10104 /* init the keyboard */
10105 call _keyboard_init
10107 ;; mov CMOS Equipment Byte to BDA Equipment Word
10116 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10120 mov cl
, #0x14 ; timeout value
10121 mov dx
, #0x378 ; Parallel I/O address, port 1
10122 call detect_parport
10123 mov dx
, #0x278 ; Parallel I/O address, port 2
10124 call detect_parport
10126 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10128 or ax
, bx
; set number of parallel ports
10132 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10133 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10135 mov cl
, #0x0a ; timeout value
10136 mov dx
, #0x03f8 ; Serial I/O address, port 1
10138 mov dx
, #0x02f8 ; Serial I/O address, port 2
10140 mov dx
, #0x03e8 ; Serial I/O address, port 3
10142 mov dx
, #0x02e8 ; Serial I/O address, port 4
10145 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10147 or ax
, bx
; set number of serial port
10151 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10152 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10153 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10154 ;; BIOS DATA AREA
0x4CE ???
10155 call timer_tick_post
10157 ;; PS
/2 mouse setup
10158 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10160 ;; IRQ13 (FPU exception
) setup
10161 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10164 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10167 mov al
, #0x11 ; send initialisation commands
10182 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10183 #if BX_USE_PS2_MOUSE
10188 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10191 call rombios32_init
10193 call pcibios_init_iomem_bases
10194 call pcibios_init_irqs
10197 call _init_boot_vectors
10201 call _print_bios_banner
10206 call floppy_drive_post
10211 ;; Hard Drive setup
10213 call hard_drive_post
10216 ;; ATA
/ATAPI driver setup
10221 #else // BX_USE_ATADRV
10224 ;; Hard Drive setup
10226 call hard_drive_post
10228 #endif // BX_USE_ATADRV
10230 #if BX_ELTORITO_BOOT
10232 ;; eltorito floppy
/harddisk emulation from cd
10236 #endif // BX_ELTORITO_BOOT
10238 sti
;; enable interrupts
10242 .org
0xe2c3 ; NMI Handler Entry Point
10244 ;; FIXME the NMI handler should
not panic
10245 ;; but iret when called from
int75 (fpu exception
)
10246 call _nmi_handler_msg
10250 out
0xf0, al
// clear irq13
10251 call eoi_both_pics
// clear interrupt
10252 int 2 // legacy nmi call
10255 ;-------------------------------------------
10256 ;- INT
13h Fixed Disk Services Entry Point
-
10257 ;-------------------------------------------
10258 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10260 //JMPL(int13_relocated)
10261 jmp int13_relocated
10263 .org
0xe401 ; Fixed Disk Parameter Table
10268 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10271 jmp int19_relocated
10272 ;-------------------------------------------
10273 ;- System BIOS Configuration Data Table
10274 ;-------------------------------------------
10275 .org BIOS_CONFIG_TABLE
10276 db
0x08 ; Table
size (bytes
) -Lo
10277 db
0x00 ; Table
size (bytes
) -Hi
10282 ; b7
: 1=DMA channel
3 used by hard disk
10283 ; b6
: 1=2 interrupt controllers present
10284 ; b5
: 1=RTC present
10285 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10286 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10287 ; b2
: 1=extended BIOS data area used
10288 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10289 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10293 (BX_CALL_INT15_4F
<< 4) | \
10295 (BX_USE_EBDA
<< 2) | \
10299 ; b7
: 1=32-bit DMA supported
10300 ; b6
: 1=int16h
, function
9 supported
10301 ; b5
: 1=int15h
/C6h (get POS data
) supported
10302 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10303 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10304 ; b2
: 1=non
-8042 kb controller
10305 ; b1
: 1=data streaming supported
10319 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10320 ; b3
: SCSI on system board
10321 ; b2
: info panel installed
10322 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10323 ; b0
: SCSI supported in IML
10327 ; b6
: EEPROM present
10328 ; b5
-3: ABIOS
presence (011 = not supported
)
10330 ; b1
: memory split above
16Mb supported
10331 ; b0
: POSTEXT directly supported by POST
10333 ; Feature byte
5 (IBM
)
10334 ; b1
: enhanced mouse
10340 .org
0xe729 ; Baud Rate Generator Table
10345 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10351 call _int14_function
10357 ;----------------------------------------
10358 ;- INT
16h Keyboard Service Entry Point
-
10359 ;----------------------------------------
10375 call _int16_function
10385 and BYTE
[bp
+ 0x06], #0xbf
10393 or BYTE
[bp
+ 0x06], #0x40
10401 int16_wait_for_key
:
10405 jne int16_key_found
10409 /* no key yet, call int 15h, function AX=9002 */
10410 0x50, /* push AX */
10411 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10412 0xcd, 0x15, /* int 15h */
10414 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10416 jmp int16_wait_for_key
10421 call _int16_function
10426 /* notify int16 complete w/ int 15h, function AX=9102 */
10427 0x50, /* push AX */
10428 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10429 0xcd, 0x15, /* int 15h */
10436 ;-------------------------------------------------
10437 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10438 ;-------------------------------------------------
10444 mov al
, #0xAD ;;disable keyboard
10453 in al
, #0x60 ;;read key from keyboard controller
10457 #ifdef BX_CALL_INT15_4F
10458 mov ah
, #0x4f ;; allow for keyboard intercept
10464 ;; check
for extended key
10466 jne int09_check_pause
10469 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10471 mov BYTE
[0x496], al
10474 int09_check_pause
: ;; check
for pause key
10476 jne int09_process_key
10479 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10481 mov BYTE
[0x496], al
10487 call _int09_function
10493 call eoi_master_pic
10496 mov al
, #0xAE ;;enable keyboard
10502 ;----------------------------------------
10503 ;- INT
13h Diskette Service Entry Point
-
10504 ;----------------------------------------
10507 jmp int13_noeltorito
10509 ;---------------------------------------------
10510 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10511 ;---------------------------------------------
10512 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10522 mov al
, #0x08 ; sense interrupt status
10540 xor ax
, ax
;; segment
0000
10542 call eoi_master_pic
10544 or al
, #0x80 ;; diskette interrupt has occurred
10552 .org
0xefc7 ; Diskette Controller Parameter Table
10553 diskette_param_table
:
10554 ;; Since no provisions are made
for multiple drive types
, most
10555 ;; values in
this table are ignored
. I set parameters
for 1.44M
10558 db
0x02 ;; head load time
0000001, DMA used
10570 ;----------------------------------------
10571 ;- INT17h
: Printer Service Entry Point
-
10572 ;----------------------------------------
10579 call _int17_function
10584 diskette_param_table2
:
10585 ;; New diskette parameter table adding
3 parameters from IBM
10586 ;; Since no provisions are made
for multiple drive types
, most
10587 ;; values in
this table are ignored
. I set parameters
for 1.44M
10590 db
0x02 ;; head load time
0000001, DMA used
10600 db
79 ;; maximum track
10601 db
0 ;; data transfer rate
10602 db
4 ;; drive type in cmos
10604 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10611 .org
0xf065 ; INT
10h Video Support Service Entry Point
10613 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10616 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10621 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10622 ; ??? different
for Pentium (machine check
)?
10634 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10646 .org
0xf859 ; INT
15h System Services Entry Point
10660 #if BX_USE_PS2_MOUSE
10662 je int15_handler_mouse
10664 call _int15_function
10665 int15_handler_mouse_ret
:
10667 int15_handler32_ret
:
10677 #if BX_USE_PS2_MOUSE
10678 int15_handler_mouse
:
10679 call _int15_function_mouse
10680 jmp int15_handler_mouse_ret
10685 call _int15_function32
10687 jmp int15_handler32_ret
10689 ;; Protected mode IDT descriptor
10691 ;; I just make the limit
0, so the machine will shutdown
10692 ;; if an exception occurs during
protected mode memory
10695 ;; Set base to f0000 to correspond to beginning of BIOS
,
10696 ;; in
case I actually define an IDT later
10700 dw
0x0000 ;; limit
15:00
10701 dw
0x0000 ;; base
15:00
10702 db
0x0f ;; base
23:16
10704 ;; Real mode IDT descriptor
10706 ;; Set to typical real
-mode values
.
10711 dw
0x03ff ;; limit
15:00
10712 dw
0x0000 ;; base
15:00
10713 db
0x00 ;; base
23:16
10719 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10732 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10733 mov ds
, ax
; on
16bit
protected mode
.
10734 jmp int1a_callfunction
10741 int1a_callfunction
:
10742 call _int1a_function
10748 ;; int70h
: IRQ8
- CMOS RTC
10755 call _int70_function
10763 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10771 ;; time to turn off
drive(s
)?
10774 jz int08_floppy_off
10777 jnz int08_floppy_off
10778 ;; turn
motor(s
) off
10787 mov eax
, 0x046c ;; get ticks dword
10790 ;; compare eax to one days worth of timer ticks at
18.2 hz
10791 cmp eax
, #0x001800B0
10792 jb int08_store_ticks
10793 ;; there has been a midnight rollover at
this point
10794 xor eax
, eax
;; zero out counter
10795 inc BYTE
0x0470 ;; increment rollover flag
10798 mov
0x046c, eax
;; store
new ticks dword
10799 ;; chain to user timer tick INT
#0x1c
10801 //;; call_ep [ds:loc]
10802 //CALL_EP( 0x1c << 2 )
10805 call eoi_master_pic
10810 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10814 .ascii BIOS_COPYRIGHT_STRING
10816 ;------------------------------------------------
10817 ;- IRET Instruction
for Dummy Interrupt Handler
-
10818 ;------------------------------------------------
10819 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10820 dummy_iret_handler
:
10823 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10827 .org
0xfff0 ; Power
-up Entry Point
10830 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10831 .ascii BIOS_BUILD_DATE
10833 .org
0xfffe ; System Model ID
10837 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10840 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10841 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10842 * This font is public domain
10844 static Bit8u vgafont8
[128*8]=
10846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10847 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10848 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10849 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10850 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10851 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10852 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10853 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10854 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10855 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10856 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10857 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10858 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10859 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10860 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10861 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10862 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10863 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10864 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10865 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10866 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10867 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10868 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10869 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10870 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10871 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10872 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10873 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10874 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10875 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10876 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10877 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10878 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10879 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10880 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10881 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10882 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10883 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10884 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10885 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10886 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10887 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10888 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10889 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10890 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10891 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10892 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10893 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10894 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10895 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10896 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10897 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10898 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10899 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10900 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10901 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10902 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10903 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10904 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10905 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10906 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10907 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10908 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10909 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10910 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10911 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10912 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10913 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10914 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10915 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10916 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10917 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10918 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10919 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10920 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10921 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10922 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10923 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10924 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10925 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10926 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10927 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10928 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10929 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10930 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10931 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10932 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10933 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10934 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10935 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10936 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10937 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10938 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10939 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10940 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10941 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10942 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10943 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10944 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10945 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10946 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10947 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10948 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10949 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10950 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10951 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10952 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10953 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10954 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10955 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10956 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10957 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10958 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10959 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10960 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10961 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10962 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10963 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10964 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10965 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10966 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10967 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10968 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10969 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10970 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10971 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10972 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10973 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10978 // bcc-generated data will be placed here