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 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
173 #define IPL_SEG 0x9ff0
174 #define IPL_TABLE_OFFSET 0x0000
175 #define IPL_TABLE_ENTRIES 8
176 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
177 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
178 #define IPL_SIZE 0xff
179 #define IPL_TYPE_FLOPPY 0x01
180 #define IPL_TYPE_HARDDISK 0x02
181 #define IPL_TYPE_CDROM 0x03
182 #define IPL_TYPE_BEV 0x80
185 #if BX_USE_ATADRV && BX_CPU<3
186 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
188 #if BX_USE_ATADRV && !BX_USE_EBDA
189 # error ATA/ATAPI Driver can only be used if EBDA is available
191 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
192 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
194 #if BX_PCIBIOS && BX_CPU<3
195 # error PCI BIOS can only be used with 386+ cpu
197 #if BX_APM && BX_CPU<3
198 # error APM BIOS can only be used with 386+ cpu
201 // define this if you want to make PCIBIOS working on a specific bridge only
202 // undef enables PCIBIOS when at least one PCI device is found
203 // i440FX is emulated by Bochs and QEMU
204 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
207 // #$20 is hex 20 = 32
208 // #0x20 is hex 20 = 32
215 // all hex literals should be prefixed with '0x'
216 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
217 // no mov SEG-REG, #value, must mov register into seg-reg
218 // grep -i "mov[ ]*.s" rombios.c
220 // This is for compiling with gcc2 and gcc3
221 #define ASM_START #asm
222 #define ASM_END #endasm
236 ;; the HALT macro is called with the line number of the HALT call
.
237 ;; The line number is then sent to the PANIC_PORT
, causing Bochs
/Plex
238 ;; to print a BX_PANIC message
. This will normally halt the simulation
239 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
240 ;; However
, users can choose to make panics non
-fatal
and continue.
267 typedef unsigned char Bit8u
;
268 typedef unsigned short Bit16u
;
269 typedef unsigned short bx_bool
;
270 typedef unsigned long Bit32u
;
273 void memsetb(seg
,offset
,value
,count
);
274 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
275 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
277 // memset of count bytes
279 memsetb(seg
,offset
,value
,count
)
294 mov cx
, 10[bp
] ; count
297 mov ax
, 4[bp
] ; segment
299 mov ax
, 6[bp
] ; offset
301 mov al
, 8[bp
] ; value
316 // memcpy of count bytes
318 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
336 mov cx
, 12[bp
] ; count
339 mov ax
, 4[bp
] ; dsegment
341 mov ax
, 6[bp
] ; doffset
343 mov ax
, 8[bp
] ; ssegment
345 mov ax
, 10[bp
] ; soffset
363 // memcpy of count dword
365 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
383 mov cx
, 12[bp
] ; count
386 mov ax
, 4[bp
] ; dsegment
388 mov ax
, 6[bp
] ; doffset
390 mov ax
, 8[bp
] ; ssegment
392 mov ax
, 10[bp
] ; soffset
410 // read_dword and write_dword functions
411 static Bit32u
read_dword();
412 static void write_dword();
415 read_dword(seg
, offset
)
425 mov ax
, 4[bp
] ; segment
427 mov bx
, 6[bp
] ; offset
431 ;; ax
= return value (word
)
432 ;; dx
= return value (word
)
441 write_dword(seg
, offset
, data
)
453 mov ax
, 4[bp
] ; segment
455 mov bx
, 6[bp
] ; offset
456 mov ax
, 8[bp
] ; data word
457 mov
[bx
], ax
; write data word
459 mov ax
, 10[bp
] ; data word
460 mov
[bx
], ax
; write data word
469 // Bit32u (unsigned long) and long helper functions
498 cmp eax
, dword ptr
[di
]
517 mul eax
, dword ptr
[di
]
613 // for access to RAM area which is used by interrupt vectors
614 // and BIOS Data Area
617 unsigned char filler1
[0x400];
618 unsigned char filler2
[0x6c];
624 #define BiosData ((bios_data_t *) 0)
628 Bit16u heads
; // # heads
629 Bit16u cylinders
; // # cylinders
630 Bit16u spt
; // # sectors / track
650 Bit8u iface
; // ISA or PCI
651 Bit16u iobase1
; // IO Base 1
652 Bit16u iobase2
; // IO Base 2
657 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
658 Bit8u device
; // Detected type of attached devices (hd/cd/none)
659 Bit8u removable
; // Removable device flag
660 Bit8u lock
; // Locks for removable devices
661 Bit8u mode
; // transfer 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)
851 static Bit8u
inb_cmos();
853 static void outb_cmos();
856 static void init_rtc();
857 static bx_bool
rtc_updating();
859 static Bit8u
read_byte();
860 static Bit16u
read_word();
861 static void write_byte();
862 static void write_word();
863 static void bios_printf();
865 static Bit8u
inhibit_mouse_int_and_events();
866 static void enable_mouse_int_and_events();
867 static Bit8u
send_to_mouse_ctrl();
868 static Bit8u
get_mouse_data();
869 static void set_kbd_command_byte();
871 static void int09_function();
872 static void int13_harddisk();
873 static void int13_cdrom();
874 static void int13_cdemu();
875 static void int13_eltorito();
876 static void int13_diskette_function();
877 static void int14_function();
878 static void int15_function();
879 static void int16_function();
880 static void int17_function();
881 static void int19_function();
882 static void int1a_function();
883 static void int70_function();
884 static void int74_function();
885 static Bit16u
get_CS();
886 static Bit16u
get_SS();
887 static unsigned int enqueue_key();
888 static unsigned int dequeue_key();
889 static void get_hd_geometry();
890 static void set_diskette_ret_status();
891 static void set_diskette_current_cyl();
892 static void determine_floppy_media();
893 static bx_bool
floppy_drive_exists();
894 static bx_bool
floppy_drive_recal();
895 static bx_bool
floppy_media_known();
896 static bx_bool
floppy_media_sense();
897 static bx_bool
set_enable_a20();
898 static void debugger_on();
899 static void debugger_off();
900 static void keyboard_init();
901 static void keyboard_panic();
902 static void shutdown_status_panic();
903 static void nmi_handler_msg();
905 static void print_bios_banner();
906 static void print_boot_device();
907 static void print_boot_failure();
908 static void print_cdromboot_failure();
912 // ATA / ATAPI driver
917 Bit16u
ata_cmd_non_data();
918 Bit16u
ata_cmd_data_in();
919 Bit16u
ata_cmd_data_out();
920 Bit16u
ata_cmd_packet();
922 Bit16u
atapi_get_sense();
923 Bit16u
atapi_is_ready();
924 Bit16u
atapi_is_cdrom();
926 #endif // BX_USE_ATADRV
931 Bit8u
cdemu_isactive();
932 Bit8u
cdemu_emulated_drive();
936 #endif // BX_ELTORITO_BOOT
938 static char bios_cvs_version_string
[] = "$Revision: 1.182 $ $Date: 2007/08/01 17:09:51 $";
940 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
943 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
945 # define BX_DEBUG_ATA(a...)
948 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
950 # define BX_DEBUG_INT13_HD(a...)
953 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
955 # define BX_DEBUG_INT13_CD(a...)
958 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
960 # define BX_DEBUG_INT13_ET(a...)
963 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
965 # define BX_DEBUG_INT13_FL(a...)
968 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
970 # define BX_DEBUG_INT15(a...)
973 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
975 # define BX_DEBUG_INT16(a...)
978 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
980 # define BX_DEBUG_INT1A(a...)
983 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
985 # define BX_DEBUG_INT74(a...)
988 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
989 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
990 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
991 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
992 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
993 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
994 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
995 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
997 #define GET_AL() ( AX & 0x00ff )
998 #define GET_BL() ( BX & 0x00ff )
999 #define GET_CL() ( CX & 0x00ff )
1000 #define GET_DL() ( DX & 0x00ff )
1001 #define GET_AH() ( AX >> 8 )
1002 #define GET_BH() ( BX >> 8 )
1003 #define GET_CH() ( CX >> 8 )
1004 #define GET_DH() ( DX >> 8 )
1006 #define GET_ELDL() ( ELDX & 0x00ff )
1007 #define GET_ELDH() ( ELDX >> 8 )
1009 #define SET_CF() FLAGS |= 0x0001
1010 #define CLEAR_CF() FLAGS &= 0xfffe
1011 #define GET_CF() (FLAGS & 0x0001)
1013 #define SET_ZF() FLAGS |= 0x0040
1014 #define CLEAR_ZF() FLAGS &= 0xffbf
1015 #define GET_ZF() (FLAGS & 0x0040)
1017 #define UNSUPPORTED_FUNCTION 0x86
1020 #define MAX_SCAN_CODE 0x58
1028 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1029 { none
, none
, none
, none
, none
},
1030 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1031 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1032 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1033 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1034 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1035 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1036 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1037 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1038 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1039 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1040 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1041 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1042 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1043 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1044 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1045 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1046 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1047 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1048 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1049 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1050 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1051 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1052 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1053 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1054 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1055 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1056 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1057 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1058 { none
, none
, none
, none
, none
}, /* L Ctrl */
1059 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1060 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1061 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1062 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1063 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1064 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1065 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1066 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1067 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1068 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1069 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1070 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1071 { none
, none
, none
, none
, none
}, /* L shift */
1072 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1073 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1074 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1075 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1076 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1077 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1078 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1079 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1080 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1081 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1082 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1083 { none
, none
, none
, none
, none
}, /* R Shift */
1084 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1085 { none
, none
, none
, none
, none
}, /* L Alt */
1086 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1087 { none
, none
, none
, none
, none
}, /* caps lock */
1088 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1089 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1090 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1091 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1092 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1093 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1094 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1095 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1096 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1097 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1098 { none
, none
, none
, none
, none
}, /* Num Lock */
1099 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1100 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1101 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1102 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1103 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1104 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1105 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1106 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1107 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1108 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1109 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1110 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1111 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1112 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1113 { none
, none
, none
, none
, none
},
1114 { none
, none
, none
, none
, none
},
1115 { 0x565c, 0x567c, none
, none
, none
}, /* \| */
1116 { 0x5700, 0x5700, none
, none
, none
}, /* F11 */
1117 { 0x5800, 0x5800, none
, none
, none
} /* F12 */
1201 outb_cmos(cmos_reg
, val
)
1209 mov al
, 4[bp
] ;; cmos_reg
1211 mov al
, 6[bp
] ;; val
1226 mov al
, 4[bp
] ;; cmos_reg
1237 outb_cmos(0x0a, 0x26);
1238 outb_cmos(0x0b, 0x02);
1246 // This function checks to see if the update-in-progress bit
1247 // is set in CMOS Status Register A. If not, it returns 0.
1248 // If it is set, it tries to wait until there is a transition
1249 // to 0, and will return 0 if such a transition occurs. A 1
1250 // is returned only after timing out. The maximum period
1251 // that this bit should be set is constrained to 244useconds.
1252 // The count I use below guarantees coverage or more than
1253 // this time, with any reasonable IPS setting.
1258 while (--count
!= 0) {
1259 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1262 return(1); // update-in-progress never transitioned to 0
1267 read_byte(seg
, offset
)
1277 mov ax
, 4[bp
] ; segment
1279 mov bx
, 6[bp
] ; offset
1281 ;; al
= return value (byte
)
1290 read_word(seg
, offset
)
1300 mov ax
, 4[bp
] ; segment
1302 mov bx
, 6[bp
] ; offset
1304 ;; ax
= return value (word
)
1313 write_byte(seg
, offset
, data
)
1325 mov ax
, 4[bp
] ; segment
1327 mov bx
, 6[bp
] ; offset
1328 mov al
, 8[bp
] ; data byte
1329 mov
[bx
], al
; write data byte
1339 write_word(seg
, offset
, data
)
1351 mov ax
, 4[bp
] ; segment
1353 mov bx
, 6[bp
] ; offset
1354 mov ax
, 8[bp
] ; data word
1355 mov
[bx
], ax
; write data word
1381 /* serial debug port*/
1382 #define BX_DEBUG_PORT 0x03f8
1385 #define UART_RBR 0x00
1386 #define UART_THR 0x00
1389 #define UART_IER 0x01
1390 #define UART_IIR 0x02
1391 #define UART_FCR 0x02
1392 #define UART_LCR 0x03
1393 #define UART_MCR 0x04
1394 #define UART_DLL 0x00
1395 #define UART_DLM 0x01
1398 #define UART_LSR 0x05
1399 #define UART_MSR 0x06
1400 #define UART_SCR 0x07
1402 int uart_can_tx_byte(base_port
)
1405 return inb(base_port
+ UART_LSR
) & 0x20;
1408 void uart_wait_to_tx_byte(base_port
)
1411 while (!uart_can_tx_byte(base_port
));
1414 void uart_wait_until_sent(base_port
)
1417 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1420 void uart_tx_byte(base_port
, data
)
1424 uart_wait_to_tx_byte(base_port
);
1425 outb(base_port
+ UART_THR
, data
);
1426 uart_wait_until_sent(base_port
);
1455 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1456 uart_tx_byte(BX_DEBUG_PORT
, c
);
1458 #if BX_VIRTUAL_PORTS
1459 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1460 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1462 if (action
& BIOS_PRINTF_SCREEN
) {
1463 if (c
== '\n') wrch('\r');
1469 put_int(action
, val
, width
, neg
)
1474 short nval
= val
/ 10;
1476 put_int(action
, nval
, width
- 1, neg
);
1478 while (--width
> 0) send(action
, ' ');
1479 if (neg
) send(action
, '-');
1481 send(action
, val
- (nval
* 10) + '0');
1485 put_uint(action
, val
, width
, neg
)
1491 unsigned short nval
= val
/ 10;
1493 put_uint(action
, nval
, width
- 1, neg
);
1495 while (--width
> 0) send(action
, ' ');
1496 if (neg
) send(action
, '-');
1498 send(action
, val
- (nval
* 10) + '0');
1502 put_luint(action
, val
, width
, neg
)
1508 unsigned long nval
= val
/ 10;
1510 put_luint(action
, nval
, width
- 1, neg
);
1512 while (--width
> 0) send(action
, ' ');
1513 if (neg
) send(action
, '-');
1515 send(action
, val
- (nval
* 10) + '0');
1518 void put_str(action
, s
)
1526 while (c
= read_byte(get_CS(), s
)) {
1532 //--------------------------------------------------------------------------
1534 // A compact variable argument printf function.
1536 // Supports %[format_width][length]format
1537 // where format can be x,X,u,d,s,c
1538 // and the optional length modifier is l (ell)
1539 //--------------------------------------------------------------------------
1541 bios_printf(action
, s
)
1545 Bit8u c
, format_char
;
1549 Bit16u arg_seg
, arg
, nibble
, hibyte
, shift_count
, format_width
, hexadd
;
1557 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1558 #if BX_VIRTUAL_PORTS
1559 outb(PANIC_PORT2
, 0x00);
1561 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1564 while (c
= read_byte(get_CS(), s
)) {
1569 else if (in_format
) {
1570 if ( (c
>='0') && (c
<='9') ) {
1571 format_width
= (format_width
* 10) + (c
- '0');
1574 arg_ptr
++; // increment to next arg
1575 arg
= read_word(arg_seg
, arg_ptr
);
1576 if (c
== 'x' || c
== 'X') {
1577 if (format_width
== 0)
1583 for (i
=format_width
-1; i
>=0; i
--) {
1584 nibble
= (arg
>> (4 * i
)) & 0x000f;
1585 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1588 else if (c
== 'u') {
1589 put_uint(action
, arg
, format_width
, 0);
1591 else if (c
== 'l') {
1593 c
= read_byte(get_CS(), s
); /* is it ld,lx,lu? */
1594 arg_ptr
++; /* increment to next arg */
1595 hibyte
= read_word(arg_seg
, arg_ptr
);
1597 if (hibyte
& 0x8000)
1598 put_luint(action
, 0L-(((Bit32u
) hibyte
<< 16) | arg
), format_width
-1, 1);
1600 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1602 else if (c
== 'u') {
1603 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1605 else if (c
== 'x' || c
== 'X')
1607 if (format_width
== 0)
1613 for (i
=format_width
-1; i
>=0; i
--) {
1614 nibble
= ((((Bit32u
) hibyte
<<16) | arg
) >> (4 * i
)) & 0x000f;
1615 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1619 else if (c
== 'd') {
1621 put_int(action
, -arg
, format_width
- 1, 1);
1623 put_int(action
, arg
, format_width
, 0);
1625 else if (c
== 's') {
1626 put_str(action
, arg
);
1628 else if (c
== 'c') {
1632 BX_PANIC("bios_printf: unknown format\n");
1642 if (action
& BIOS_PRINTF_HALT
) {
1643 // freeze in a busy loop.
1653 //--------------------------------------------------------------------------
1655 //--------------------------------------------------------------------------
1656 // this file is based on LinuxBIOS implementation of keyboard.c
1657 // could convert to #asm to gain space
1663 /* ------------------- Flush buffers ------------------------*/
1664 /* Wait until buffer is empty */
1666 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1668 /* flush incoming keys */
1672 if (inb(0x64) & 0x01) {
1678 // Due to timer issues, and if the IPS setting is > 15000000,
1679 // the incoming keys might not be flushed here. That will
1680 // cause a panic a few lines below. See sourceforge bug report :
1681 // [ 642031 ] FATAL: Keyboard RESET error:993
1683 /* ------------------- controller side ----------------------*/
1684 /* send cmd = 0xAA, self test 8042 */
1687 /* Wait until buffer is empty */
1689 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1690 if (max
==0x0) keyboard_panic(00);
1694 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1695 if (max
==0x0) keyboard_panic(01);
1697 /* read self-test result, 0x55 should be returned from 0x60 */
1698 if ((inb(0x60) != 0x55)){
1699 keyboard_panic(991);
1702 /* send cmd = 0xAB, keyboard interface test */
1705 /* Wait until buffer is empty */
1707 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1708 if (max
==0x0) keyboard_panic(10);
1712 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1713 if (max
==0x0) keyboard_panic(11);
1715 /* read keyboard interface test result, */
1716 /* 0x00 should be returned form 0x60 */
1717 if ((inb(0x60) != 0x00)) {
1718 keyboard_panic(992);
1721 /* Enable Keyboard clock */
1725 /* ------------------- keyboard side ------------------------*/
1726 /* reset kerboard and self test (keyboard side) */
1729 /* Wait until buffer is empty */
1731 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1732 if (max
==0x0) keyboard_panic(20);
1736 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1737 if (max
==0x0) keyboard_panic(21);
1739 /* keyboard should return ACK */
1740 if ((inb(0x60) != 0xfa)) {
1741 keyboard_panic(993);
1746 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1747 if (max
==0x0) keyboard_panic(31);
1749 if ((inb(0x60) != 0xaa)) {
1750 keyboard_panic(994);
1753 /* Disable keyboard */
1756 /* Wait until buffer is empty */
1758 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1759 if (max
==0x0) keyboard_panic(40);
1763 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1764 if (max
==0x0) keyboard_panic(41);
1766 /* keyboard should return ACK */
1767 if ((inb(0x60) != 0xfa)) {
1768 keyboard_panic(995);
1771 /* Write Keyboard Mode */
1774 /* Wait until buffer is empty */
1776 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1777 if (max
==0x0) keyboard_panic(50);
1779 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1782 /* Wait until buffer is empty */
1784 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1785 if (max
==0x0) keyboard_panic(60);
1787 /* Enable keyboard */
1790 /* Wait until buffer is empty */
1792 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1793 if (max
==0x0) keyboard_panic(70);
1797 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1798 if (max
==0x0) keyboard_panic(70);
1800 /* keyboard should return ACK */
1801 if ((inb(0x60) != 0xfa)) {
1802 keyboard_panic(996);
1808 //--------------------------------------------------------------------------
1810 //--------------------------------------------------------------------------
1812 keyboard_panic(status
)
1815 // If you're getting a 993 keyboard panic here,
1816 // please see the comment in keyboard_init
1818 BX_PANIC("Keyboard error:%u\n",status
);
1821 //--------------------------------------------------------------------------
1822 // shutdown_status_panic
1823 // called when the shutdown statsu is not implemented, displays the status
1824 //--------------------------------------------------------------------------
1826 shutdown_status_panic(status
)
1829 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1832 //--------------------------------------------------------------------------
1833 // print_bios_banner
1834 // displays a the bios version
1835 //--------------------------------------------------------------------------
1839 printf(BX_APPNAME
" BIOS - build: %s\n%s\nOptions: ",
1840 BIOS_BUILD_DATE
, bios_cvs_version_string
);
1848 #if BX_ELTORITO_BOOT
1857 //--------------------------------------------------------------------------
1858 // BIOS Boot Specification 1.0.1 compatibility
1860 // Very basic support for the BIOS Boot Specification, which allows expansion
1861 // ROMs to register themselves as boot devices, instead of just stealing the
1862 // INT 19h boot vector.
1864 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1865 // one; we just lie to the option ROMs to make them behave correctly.
1866 // We also don't support letting option ROMs register as bootable disk
1867 // drives (BCVs), only as bootable devices (BEVs).
1869 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1870 //--------------------------------------------------------------------------
1878 Bit16u ss
= get_SS();
1880 /* Clear out the IPL table. */
1881 memsetb(IPL_SEG
, IPL_TABLE_OFFSET
, 0, IPL_SIZE
);
1884 e
.type
= IPL_TYPE_FLOPPY
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1885 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1889 e
.type
= IPL_TYPE_HARDDISK
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1890 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1893 #if BX_ELTORITO_BOOT
1895 e
.type
= IPL_TYPE_CDROM
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1896 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1900 /* Remember how many devices we have */
1901 write_word(IPL_SEG
, IPL_COUNT_OFFSET
, count
);
1902 /* Not tried booting anything yet */
1903 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xffff);
1907 get_boot_vector(i
, e
)
1908 Bit16u i
; ipl_entry_t
*e
;
1911 Bit16u ss
= get_SS();
1912 /* Get the count of boot devices, and refuse to overrun the array */
1913 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
1914 if (i
>= count
) return 0;
1915 /* OK to read this device */
1916 memcpyb(ss
, e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (*e
), sizeof (*e
));
1921 //--------------------------------------------------------------------------
1922 // print_boot_device
1923 // displays the boot device
1924 //--------------------------------------------------------------------------
1926 static char drivetypes
[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1929 print_boot_device(type
)
1932 /* NIC appears as type 0x80 */
1933 if (type
== IPL_TYPE_BEV
) type
= 0x4;
1934 if (type
== 0 || type
> 0x4) BX_PANIC("Bad drive type\n");
1935 printf("Booting from %s...\n", drivetypes
[type
]);
1938 //--------------------------------------------------------------------------
1939 // print_boot_failure
1940 // displays the reason why boot failed
1941 //--------------------------------------------------------------------------
1943 print_boot_failure(type
, reason
)
1944 Bit16u type
; Bit8u reason
;
1946 if (type
== 0 || type
> 0x3) BX_PANIC("Bad drive type\n");
1948 printf("Boot from %s failed", drivetypes
[type
]);
1950 /* Report the reason too */
1952 printf(": not a bootable disk");
1954 printf(": could not read the boot disk");
1959 //--------------------------------------------------------------------------
1960 // print_cdromboot_failure
1961 // displays the reason why boot failed
1962 //--------------------------------------------------------------------------
1964 print_cdromboot_failure( code
)
1967 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1975 BX_PANIC("NMI Handler called\n");
1981 BX_PANIC("INT18: BOOT FAILURE\n");
1988 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
1990 BX_INFO("%s\n", bios_cvs_version_string
);
1999 // Use PS2 System Control port A to set A20 enable
2001 // get current setting first
2004 // change A20 status
2006 outb(0x92, oldval
| 0x02);
2008 outb(0x92, oldval
& 0xfd);
2010 return((oldval
& 0x02) != 0);
2027 // ---------------------------------------------------------------------------
2028 // Start of ATA/ATAPI Driver
2029 // ---------------------------------------------------------------------------
2031 // Global defines -- ATA register and register bits.
2032 // command block & control block regs
2033 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2034 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2035 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2036 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2037 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2038 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2039 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2040 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2041 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2042 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2043 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2044 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2045 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2047 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2048 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2049 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2050 #define ATA_CB_ER_MC 0x20 // ATA media change
2051 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2052 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2053 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2054 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2055 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2057 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2058 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2059 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2060 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2061 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2063 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2064 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2065 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2066 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2067 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2069 // bits 7-4 of the device/head (CB_DH) reg
2070 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2071 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2072 #define ATA_CB_DH_LBA 0x40 // use LBA
2074 // status reg (CB_STAT and CB_ASTAT) bits
2075 #define ATA_CB_STAT_BSY 0x80 // busy
2076 #define ATA_CB_STAT_RDY 0x40 // ready
2077 #define ATA_CB_STAT_DF 0x20 // device fault
2078 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2079 #define ATA_CB_STAT_SKC 0x10 // seek complete
2080 #define ATA_CB_STAT_SERV 0x10 // service
2081 #define ATA_CB_STAT_DRQ 0x08 // data request
2082 #define ATA_CB_STAT_CORR 0x04 // corrected
2083 #define ATA_CB_STAT_IDX 0x02 // index
2084 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2085 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2087 // device control reg (CB_DC) bits
2088 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2089 #define ATA_CB_DC_SRST 0x04 // soft reset
2090 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2092 // Most mandtory and optional ATA commands (from ATA-3),
2093 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2094 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2095 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2096 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2097 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2098 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2099 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2100 #define ATA_CMD_DEVICE_RESET 0x08
2101 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2102 #define ATA_CMD_FLUSH_CACHE 0xE7
2103 #define ATA_CMD_FORMAT_TRACK 0x50
2104 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2105 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2106 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2107 #define ATA_CMD_IDLE1 0xE3
2108 #define ATA_CMD_IDLE2 0x97
2109 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2110 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2111 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2112 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2113 #define ATA_CMD_NOP 0x00
2114 #define ATA_CMD_PACKET 0xA0
2115 #define ATA_CMD_READ_BUFFER 0xE4
2116 #define ATA_CMD_READ_DMA 0xC8
2117 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2118 #define ATA_CMD_READ_MULTIPLE 0xC4
2119 #define ATA_CMD_READ_SECTORS 0x20
2120 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2121 #define ATA_CMD_RECALIBRATE 0x10
2122 #define ATA_CMD_REQUEST_SENSE 0x03
2123 #define ATA_CMD_SEEK 0x70
2124 #define ATA_CMD_SET_FEATURES 0xEF
2125 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2126 #define ATA_CMD_SLEEP1 0xE6
2127 #define ATA_CMD_SLEEP2 0x99
2128 #define ATA_CMD_STANDBY1 0xE2
2129 #define ATA_CMD_STANDBY2 0x96
2130 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2131 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2132 #define ATA_CMD_WRITE_BUFFER 0xE8
2133 #define ATA_CMD_WRITE_DMA 0xCA
2134 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2135 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2136 #define ATA_CMD_WRITE_SECTORS 0x30
2137 #define ATA_CMD_WRITE_VERIFY 0x3C
2139 #define ATA_IFACE_NONE 0x00
2140 #define ATA_IFACE_ISA 0x00
2141 #define ATA_IFACE_PCI 0x01
2143 #define ATA_TYPE_NONE 0x00
2144 #define ATA_TYPE_UNKNOWN 0x01
2145 #define ATA_TYPE_ATA 0x02
2146 #define ATA_TYPE_ATAPI 0x03
2148 #define ATA_DEVICE_NONE 0x00
2149 #define ATA_DEVICE_HD 0xFF
2150 #define ATA_DEVICE_CDROM 0x05
2152 #define ATA_MODE_NONE 0x00
2153 #define ATA_MODE_PIO16 0x00
2154 #define ATA_MODE_PIO32 0x01
2155 #define ATA_MODE_ISADMA 0x02
2156 #define ATA_MODE_PCIDMA 0x03
2157 #define ATA_MODE_USEIRQ 0x10
2159 #define ATA_TRANSLATION_NONE 0
2160 #define ATA_TRANSLATION_LBA 1
2161 #define ATA_TRANSLATION_LARGE 2
2162 #define ATA_TRANSLATION_RECHS 3
2164 #define ATA_DATA_NO 0x00
2165 #define ATA_DATA_IN 0x01
2166 #define ATA_DATA_OUT 0x02
2168 // ---------------------------------------------------------------------------
2169 // ATA/ATAPI driver : initialization
2170 // ---------------------------------------------------------------------------
2173 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2174 Bit8u channel
, device
;
2176 // Channels info init.
2177 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2178 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2179 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2180 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2181 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2184 // Devices info init.
2185 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2186 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2187 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2188 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2189 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2190 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2191 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2192 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2193 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2194 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2195 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2196 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2197 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2198 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2200 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2203 // hdidmap and cdidmap init.
2204 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2205 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2206 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2209 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2210 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2216 #define NOT_BSY_DRQ 3
2217 #define NOT_BSY_NOT_DRQ 4
2218 #define NOT_BSY_RDY 5
2220 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
2223 static int await_ide(when_done
,base
,timeout
)
2228 Bit32u time
=0,last
=0;
2231 status
= inb(base
+ ATA_CB_STAT
); // for the times you're supposed to throw one away
2233 status
= inb(base
+ATA_CB_STAT
);
2235 if (when_done
== BSY
)
2236 result
= status
& ATA_CB_STAT_BSY
;
2237 else if (when_done
== NOT_BSY
)
2238 result
= !(status
& ATA_CB_STAT_BSY
);
2239 else if (when_done
== NOT_BSY_DRQ
)
2240 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_DRQ
);
2241 else if (when_done
== NOT_BSY_NOT_DRQ
)
2242 result
= !(status
& ATA_CB_STAT_BSY
) && !(status
& ATA_CB_STAT_DRQ
);
2243 else if (when_done
== NOT_BSY_RDY
)
2244 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_RDY
);
2245 else if (when_done
== TIMEOUT
)
2248 if (result
) return 0;
2249 if (time
>>16 != last
) // mod 2048 each 16 ms
2252 BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done
,time
>>11, timeout
);
2254 if (status
& ATA_CB_STAT_ERR
)
2256 BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done
,time
>>11, timeout
);
2259 if ((timeout
== 0) || ((time
>>11) > timeout
)) break;
2261 BX_INFO("IDE time out\n");
2265 // ---------------------------------------------------------------------------
2266 // ATA/ATAPI driver : device detection
2267 // ---------------------------------------------------------------------------
2271 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2272 Bit8u hdcount
, cdcount
, device
, type
;
2273 Bit8u buffer
[0x0200];
2275 #if BX_MAX_ATA_INTERFACES > 0
2276 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2277 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2278 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2279 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2281 #if BX_MAX_ATA_INTERFACES > 1
2282 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2283 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2284 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2285 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2287 #if BX_MAX_ATA_INTERFACES > 2
2288 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2289 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2290 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2291 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2293 #if BX_MAX_ATA_INTERFACES > 3
2294 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2295 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2296 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2297 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2299 #if BX_MAX_ATA_INTERFACES > 4
2300 #error Please fill the ATA interface informations
2306 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2307 Bit16u iobase1
, iobase2
;
2308 Bit8u channel
, slave
, shift
;
2309 Bit8u sc
, sn
, cl
, ch
, st
;
2311 channel
= device
/ 2;
2314 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2315 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2317 // Disable interrupts
2318 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2321 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2322 outb(iobase1
+ATA_CB_SC
, 0x55);
2323 outb(iobase1
+ATA_CB_SN
, 0xaa);
2324 outb(iobase1
+ATA_CB_SC
, 0xaa);
2325 outb(iobase1
+ATA_CB_SN
, 0x55);
2326 outb(iobase1
+ATA_CB_SC
, 0x55);
2327 outb(iobase1
+ATA_CB_SN
, 0xaa);
2329 // If we found something
2330 sc
= inb(iobase1
+ATA_CB_SC
);
2331 sn
= inb(iobase1
+ATA_CB_SN
);
2333 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2334 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2336 // reset the channel
2339 // check for ATA or ATAPI
2340 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2341 sc
= inb(iobase1
+ATA_CB_SC
);
2342 sn
= inb(iobase1
+ATA_CB_SN
);
2343 if ((sc
==0x01) && (sn
==0x01)) {
2344 cl
= inb(iobase1
+ATA_CB_CL
);
2345 ch
= inb(iobase1
+ATA_CB_CH
);
2346 st
= inb(iobase1
+ATA_CB_STAT
);
2348 if ((cl
==0x14) && (ch
==0xeb)) {
2349 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2350 } else if ((cl
==0x00) && (ch
==0x00) && (st
!=0x00)) {
2351 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2352 } else if ((cl
==0xff) && (ch
==0xff)) {
2353 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2358 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2360 // Now we send a IDENTIFY command to ATA device
2361 if(type
== ATA_TYPE_ATA
) {
2363 Bit16u cylinders
, heads
, spt
, blksize
;
2364 Bit8u translation
, removable
, mode
;
2366 //Temporary values to do the transfer
2367 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2368 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2370 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2371 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2373 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2374 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2375 blksize
= read_word(get_SS(),buffer
+10);
2377 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2378 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2379 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2381 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2383 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2384 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2385 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2386 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2387 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2388 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2389 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2390 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2391 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2393 translation
= inb_cmos(0x39 + channel
/2);
2394 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2395 translation
&= 0x03;
2397 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2399 switch (translation
) {
2400 case ATA_TRANSLATION_NONE
:
2403 case ATA_TRANSLATION_LBA
:
2406 case ATA_TRANSLATION_LARGE
:
2409 case ATA_TRANSLATION_RECHS
:
2413 switch (translation
) {
2414 case ATA_TRANSLATION_NONE
:
2416 case ATA_TRANSLATION_LBA
:
2419 heads
= sectors
/ 1024;
2420 if (heads
>128) heads
= 255;
2421 else if (heads
>64) heads
= 128;
2422 else if (heads
>32) heads
= 64;
2423 else if (heads
>16) heads
= 32;
2425 cylinders
= sectors
/ heads
;
2427 case ATA_TRANSLATION_RECHS
:
2428 // Take care not to overflow
2430 if(cylinders
>61439) cylinders
=61439;
2432 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2434 // then go through the large bitshift process
2435 case ATA_TRANSLATION_LARGE
:
2436 while(cylinders
> 1024) {
2440 // If we max out the head count
2441 if (heads
> 127) break;
2445 // clip to 1024 cylinders in lchs
2446 if (cylinders
> 1024) cylinders
=1024;
2447 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2449 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2450 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2451 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2454 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2458 // Now we send a IDENTIFY command to ATAPI device
2459 if(type
== ATA_TYPE_ATAPI
) {
2461 Bit8u type
, removable
, mode
;
2464 //Temporary values to do the transfer
2465 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2466 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2468 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2469 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2471 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2472 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2473 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2476 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2477 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2478 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2479 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2482 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2489 Bit8u c
, i
, version
, model
[41];
2493 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2495 case ATA_TYPE_ATAPI
:
2496 // Read ATA/ATAPI version
2497 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2498 for(version
=15;version
>0;version
--) {
2499 if((ataversion
&(1<<version
))!=0)
2505 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2506 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2510 write_byte(get_SS(),model
+40,0x00);
2512 if(read_byte(get_SS(),model
+i
)==0x20)
2513 write_byte(get_SS(),model
+i
,0x00);
2521 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2522 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2523 if (sizeinmb
< (1UL<<16))
2524 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version
, (Bit16u
)sizeinmb
);
2526 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version
, (Bit16u
)(sizeinmb
>>10));
2528 case ATA_TYPE_ATAPI
:
2529 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2530 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2531 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2532 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2534 printf(" ATAPI-%d Device\n",version
);
2536 case ATA_TYPE_UNKNOWN
:
2537 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2543 // Store the devices counts
2544 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2545 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2546 write_byte(0x40,0x75, hdcount
);
2550 // FIXME : should use bios=cmos|auto|disable bits
2551 // FIXME : should know about translation bits
2552 // FIXME : move hard_drive_post here
2556 // ---------------------------------------------------------------------------
2557 // ATA/ATAPI driver : software reset
2558 // ---------------------------------------------------------------------------
2560 // 8.2.1 Software reset - Device 0
2562 void ata_reset(device
)
2565 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2566 Bit16u iobase1
, iobase2
;
2567 Bit8u channel
, slave
, sn
, sc
;
2571 channel
= device
/ 2;
2574 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2575 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2579 // 8.2.1 (a) -- set SRST in DC
2580 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2582 // 8.2.1 (b) -- wait for BSY
2583 await_ide(BSY
, iobase1
, 20);
2585 // 8.2.1 (f) -- clear SRST
2586 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2588 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2589 if (type
!= ATA_TYPE_NONE
) {
2591 // 8.2.1 (g) -- check for sc==sn==0x01
2593 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2594 sc
= inb(iobase1
+ATA_CB_SC
);
2595 sn
= inb(iobase1
+ATA_CB_SN
);
2597 if ( (sc
==0x01) && (sn
==0x01) ) {
2598 if (type
== ATA_TYPE_ATA
) //ATA
2599 await_ide(NOT_BSY_RDY
, iobase1
, IDE_TIMEOUT
);
2601 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2604 // 8.2.1 (h) -- wait for not BSY
2605 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2608 // Enable interrupts
2609 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2612 // ---------------------------------------------------------------------------
2613 // ATA/ATAPI driver : execute a non data command
2614 // ---------------------------------------------------------------------------
2616 Bit16u
ata_cmd_non_data()
2619 // ---------------------------------------------------------------------------
2620 // ATA/ATAPI driver : execute a data-in command
2621 // ---------------------------------------------------------------------------
2626 // 3 : expected DRQ=1
2627 // 4 : no sectors left to read/verify
2628 // 5 : more sectors to read/verify
2629 // 6 : no sectors left to write
2630 // 7 : more sectors to write
2631 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2632 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2635 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2636 Bit16u iobase1
, iobase2
, blksize
;
2637 Bit8u channel
, slave
;
2638 Bit8u status
, current
, mode
;
2640 channel
= device
/ 2;
2643 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2644 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2645 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2646 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2647 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2650 // Reset count of transferred data
2651 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2652 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2655 status
= inb(iobase1
+ ATA_CB_STAT
);
2656 if (status
& ATA_CB_STAT_BSY
) return 1;
2658 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2660 // sector will be 0 only on lba access. Convert to lba-chs
2662 if ((count
>= 1 << 8) || (lba
+ count
>= 1UL << 28)) {
2663 outb(iobase1
+ ATA_CB_FR
, 0x00);
2664 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2665 outb(iobase1
+ ATA_CB_SN
, lba
>> 24);
2666 outb(iobase1
+ ATA_CB_CL
, 0);
2667 outb(iobase1
+ ATA_CB_CH
, 0);
2669 count
&= (1UL << 8) - 1;
2670 lba
&= (1UL << 24) - 1;
2672 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2673 cylinder
= (Bit16u
) ((lba
>>8) & 0x0000ffffL
);
2674 head
= ((Bit16u
) ((lba
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2677 outb(iobase1
+ ATA_CB_FR
, 0x00);
2678 outb(iobase1
+ ATA_CB_SC
, count
);
2679 outb(iobase1
+ ATA_CB_SN
, sector
);
2680 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2681 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2682 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2683 outb(iobase1
+ ATA_CB_CMD
, command
);
2685 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2686 status
= inb(iobase1
+ ATA_CB_STAT
);
2688 if (status
& ATA_CB_STAT_ERR
) {
2689 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2691 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2692 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2696 // FIXME : move seg/off translation here
2699 sti
;; enable higher priority interrupts
2707 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2708 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2709 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2711 ;; adjust
if there will be an overrun
. 2K max sector size
2713 jbe ata_in_no_adjust
2716 sub di
, #0x0800 ;; sub 2 kbytes from offset
2717 add ax
, #0x0080 ;; add 2 Kbytes to segment
2720 mov es
, ax
;; segment in es
2722 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2724 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2725 cmp ah
, #ATA_MODE_PIO32
2730 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2735 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2738 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2739 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2744 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2746 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2747 status
= inb(iobase1
+ ATA_CB_STAT
);
2749 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2750 != ATA_CB_STAT_RDY
) {
2751 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2757 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2758 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2759 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2765 // Enable interrupts
2766 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2770 // ---------------------------------------------------------------------------
2771 // ATA/ATAPI driver : execute a data-out command
2772 // ---------------------------------------------------------------------------
2777 // 3 : expected DRQ=1
2778 // 4 : no sectors left to read/verify
2779 // 5 : more sectors to read/verify
2780 // 6 : no sectors left to write
2781 // 7 : more sectors to write
2782 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2783 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2786 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2787 Bit16u iobase1
, iobase2
, blksize
;
2788 Bit8u channel
, slave
;
2789 Bit8u status
, current
, mode
;
2791 channel
= device
/ 2;
2794 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2795 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2796 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2797 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2798 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2801 // Reset count of transferred data
2802 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2803 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2806 status
= inb(iobase1
+ ATA_CB_STAT
);
2807 if (status
& ATA_CB_STAT_BSY
) return 1;
2809 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2811 // sector will be 0 only on lba access. Convert to lba-chs
2813 if ((count
>= 1 << 8) || (lba
+ count
>= 1UL << 28)) {
2814 outb(iobase1
+ ATA_CB_FR
, 0x00);
2815 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2816 outb(iobase1
+ ATA_CB_SN
, lba
>> 24);
2817 outb(iobase1
+ ATA_CB_CL
, 0);
2818 outb(iobase1
+ ATA_CB_CH
, 0);
2820 count
&= (1UL << 8) - 1;
2821 lba
&= (1UL << 24) - 1;
2823 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2824 cylinder
= (Bit16u
) ((lba
>>8) & 0x0000ffffL
);
2825 head
= ((Bit16u
) ((lba
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2828 outb(iobase1
+ ATA_CB_FR
, 0x00);
2829 outb(iobase1
+ ATA_CB_SC
, count
);
2830 outb(iobase1
+ ATA_CB_SN
, sector
);
2831 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2832 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2833 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2834 outb(iobase1
+ ATA_CB_CMD
, command
);
2836 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2837 status
= inb(iobase1
+ ATA_CB_STAT
);
2839 if (status
& ATA_CB_STAT_ERR
) {
2840 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2842 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2843 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2847 // FIXME : move seg/off translation here
2850 sti
;; enable higher priority interrupts
2858 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2859 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2860 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2862 ;; adjust
if there will be an overrun
. 2K max sector size
2864 jbe ata_out_no_adjust
2867 sub si
, #0x0800 ;; sub 2 kbytes from offset
2868 add ax
, #0x0080 ;; add 2 Kbytes to segment
2871 mov es
, ax
;; segment in es
2873 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2875 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2876 cmp ah
, #ATA_MODE_PIO32
2882 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2888 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2891 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2892 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2897 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2899 status
= inb(iobase1
+ ATA_CB_STAT
);
2901 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2902 != ATA_CB_STAT_RDY
) {
2903 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2909 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2910 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2911 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2917 // Enable interrupts
2918 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2922 // ---------------------------------------------------------------------------
2923 // ATA/ATAPI driver : execute a packet command
2924 // ---------------------------------------------------------------------------
2927 // 1 : error in parameters
2931 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2933 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2937 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2938 Bit16u iobase1
, iobase2
;
2939 Bit16u lcount
, lbefore
, lafter
, count
;
2940 Bit8u channel
, slave
;
2941 Bit8u status
, mode
, lmode
;
2942 Bit32u total
, transfer
;
2944 channel
= device
/ 2;
2947 // Data out is not supported yet
2948 if (inout
== ATA_DATA_OUT
) {
2949 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2953 // The header length must be even
2955 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2959 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2960 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2961 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2964 if (cmdlen
< 12) cmdlen
=12;
2965 if (cmdlen
> 12) cmdlen
=16;
2968 // Reset count of transferred data
2969 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2970 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2972 status
= inb(iobase1
+ ATA_CB_STAT
);
2973 if (status
& ATA_CB_STAT_BSY
) return 2;
2975 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2976 outb(iobase1
+ ATA_CB_FR
, 0x00);
2977 outb(iobase1
+ ATA_CB_SC
, 0x00);
2978 outb(iobase1
+ ATA_CB_SN
, 0x00);
2979 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2980 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2981 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2982 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2984 // Device should ok to receive command
2985 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2986 status
= inb(iobase1
+ ATA_CB_STAT
);
2988 if (status
& ATA_CB_STAT_ERR
) {
2989 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2991 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2992 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2996 // Normalize address
2997 cmdseg
+= (cmdoff
/ 16);
3000 // Send command to device
3002 sti
;; enable higher priority interrupts
3007 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
3008 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
3009 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
3010 mov es
, ax
;; segment in es
3012 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
3016 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
3021 if (inout
== ATA_DATA_NO
) {
3022 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3023 status
= inb(iobase1
+ ATA_CB_STAT
);
3030 if (loops
== 0) {//first time through
3031 status
= inb(iobase2
+ ATA_CB_ASTAT
);
3032 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3035 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3038 status
= inb(iobase1
+ ATA_CB_STAT
);
3039 sc
= inb(iobase1
+ ATA_CB_SC
);
3041 // Check if command completed
3042 if(((inb(iobase1
+ ATA_CB_SC
)&0x7)==0x3) &&
3043 ((status
& (ATA_CB_STAT_RDY
| ATA_CB_STAT_ERR
)) == ATA_CB_STAT_RDY
)) break;
3045 if (status
& ATA_CB_STAT_ERR
) {
3046 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
3050 // Normalize address
3051 bufseg
+= (bufoff
/ 16);
3054 // Get the byte count
3055 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
3057 // adjust to read what we want
3070 lafter
=lcount
-length
;
3082 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
3083 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
3085 // If counts not dividable by 4, use 16bits mode
3087 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
3088 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
3089 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
3091 // adds an extra byte if count are odd. before is always even
3092 if (lcount
& 0x01) {
3094 if ((lafter
> 0) && (lafter
& 0x01)) {
3099 if (lmode
== ATA_MODE_PIO32
) {
3100 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
3103 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
3112 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
3114 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
3115 jcxz ata_packet_no_before
3117 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3118 cmp ah
, #ATA_MODE_PIO32
3119 je ata_packet_in_before_32
3121 ata_packet_in_before_16
:
3123 loop ata_packet_in_before_16
3124 jmp ata_packet_no_before
3126 ata_packet_in_before_32
:
3128 ata_packet_in_before_32_loop
:
3130 loop ata_packet_in_before_32_loop
3133 ata_packet_no_before
:
3134 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3135 jcxz ata_packet_after
3137 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3138 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3141 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3142 cmp ah
, #ATA_MODE_PIO32
3147 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3148 jmp ata_packet_after
3152 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3155 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3156 jcxz ata_packet_done
3158 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3159 cmp ah
, #ATA_MODE_PIO32
3160 je ata_packet_in_after_32
3162 ata_packet_in_after_16
:
3164 loop ata_packet_in_after_16
3167 ata_packet_in_after_32
:
3169 ata_packet_in_after_32_loop
:
3171 loop ata_packet_in_after_32_loop
3178 // Compute new buffer address
3181 // Save transferred bytes count
3183 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3187 // Final check, device must be ready
3188 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3189 != ATA_CB_STAT_RDY
) {
3190 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3194 // Enable interrupts
3195 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3199 // ---------------------------------------------------------------------------
3200 // End of ATA/ATAPI Driver
3201 // ---------------------------------------------------------------------------
3203 // ---------------------------------------------------------------------------
3204 // Start of ATA/ATAPI generic functions
3205 // ---------------------------------------------------------------------------
3208 atapi_get_sense(device
, seg
, asc
, ascq
)
3215 memsetb(get_SS(),atacmd
,0,12);
3218 atacmd
[0]=ATA_CMD_REQUEST_SENSE
;
3219 atacmd
[4]=sizeof(buffer
);
3220 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 18L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3223 write_byte(seg
,asc
,buffer
[12]);
3224 write_byte(seg
,ascq
,buffer
[13]);
3230 atapi_is_ready(device
)
3237 Bit32u timeout
; //measured in ms
3241 Bit16u ebda_seg
= read_word(0x0040,0x000E);
3242 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
) {
3243 printf("not implemented for non-ATAPI device\n");
3247 BX_DEBUG_ATA("ata_detect_medium: begin\n");
3248 memsetb(get_SS(),packet
, 0, sizeof packet
);
3249 packet
[0] = 0x25; /* READ CAPACITY */
3251 /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
3252 * is reported by the device. If the device reports "IN PROGRESS",
3253 * 30 seconds is added. */
3257 while (time
< timeout
) {
3258 if (ata_cmd_packet(device
, sizeof(packet
), get_SS(), packet
, 0, 8L, ATA_DATA_IN
, get_SS(), buf
) == 0)
3261 if (atapi_get_sense(device
, get_SS(), &asc
, &ascq
) == 0) {
3262 if (asc
== 0x3a) { /* MEDIUM NOT PRESENT */
3263 BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
3267 if (asc
== 0x04 && ascq
== 0x01 && !in_progress
) {
3268 /* IN PROGRESS OF BECOMING READY */
3269 printf("Waiting for device to detect medium... ");
3270 /* Allow 30 seconds more */
3277 BX_DEBUG_ATA("read capacity failed\n");
3281 block_len
= (Bit32u
) buf
[4] << 24
3282 | (Bit32u
) buf
[5] << 16
3283 | (Bit32u
) buf
[6] << 8
3284 | (Bit32u
) buf
[7] << 0;
3285 BX_DEBUG_ATA("block_len=%u\n", block_len
);
3287 if (block_len
!= 2048 && block_len
!= 512)
3289 printf("Unsupported sector size %u\n", block_len
);
3292 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, block_len
);
3294 sectors
= (Bit32u
) buf
[0] << 24
3295 | (Bit32u
) buf
[1] << 16
3296 | (Bit32u
) buf
[2] << 8
3297 | (Bit32u
) buf
[3] << 0;
3299 BX_DEBUG_ATA("sectors=%u\n", sectors
);
3300 if (block_len
== 2048)
3301 sectors
<<= 2; /* # of sectors in 512-byte "soft" sector */
3302 if (sectors
!= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
))
3303 printf("%dMB medium detected\n", sectors
>>(20-9));
3304 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
3309 atapi_is_cdrom(device
)
3312 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3314 if (device
>= BX_MAX_ATA_DEVICES
)
3317 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3320 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3326 // ---------------------------------------------------------------------------
3327 // End of ATA/ATAPI generic functions
3328 // ---------------------------------------------------------------------------
3330 #endif // BX_USE_ATADRV
3332 #if BX_ELTORITO_BOOT
3334 // ---------------------------------------------------------------------------
3335 // Start of El-Torito boot functions
3336 // ---------------------------------------------------------------------------
3341 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3343 // the only important data is this one for now
3344 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3350 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3352 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3356 cdemu_emulated_drive()
3358 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3360 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3363 static char isotag
[6]="CD001";
3364 static char eltorito
[24]="EL TORITO SPECIFICATION";
3366 // Returns ah: emulated drive, al: error code
3371 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3372 Bit8u atacmd
[12], buffer
[2048];
3374 Bit16u boot_segment
, nbsectors
, i
, error
;
3377 // Find out the first cdrom
3378 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3379 if (atapi_is_cdrom(device
)) break;
3383 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3385 // Read the Boot Record Volume Descriptor
3386 memsetb(get_SS(),atacmd
,0,12);
3387 atacmd
[0]=0x28; // READ command
3388 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3389 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3390 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3391 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3392 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3393 atacmd
[5]=(0x11 & 0x000000ff);
3394 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3398 if(buffer
[0]!=0)return 4;
3400 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3403 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3405 // ok, now we calculate the Boot catalog address
3406 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3408 // And we read the Boot Catalog
3409 memsetb(get_SS(),atacmd
,0,12);
3410 atacmd
[0]=0x28; // READ command
3411 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3412 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3413 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3414 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3415 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3416 atacmd
[5]=(lba
& 0x000000ff);
3417 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3421 if(buffer
[0x00]!=0x01)return 8; // Header
3422 if(buffer
[0x01]!=0x00)return 9; // Platform
3423 if(buffer
[0x1E]!=0x55)return 10; // key 1
3424 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3426 // Initial/Default Entry
3427 if(buffer
[0x20]!=0x88)return 11; // Bootable
3429 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3430 if(buffer
[0x21]==0){
3431 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3432 // Win2000 cd boot needs to know it booted from cd
3433 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3435 else if(buffer
[0x21]<4)
3436 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3438 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3440 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3441 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3443 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3444 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3446 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3447 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3449 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3450 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3452 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3453 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3455 // And we read the image in memory
3456 memsetb(get_SS(),atacmd
,0,12);
3457 atacmd
[0]=0x28; // READ command
3458 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3459 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3460 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3461 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3462 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3463 atacmd
[5]=(lba
& 0x000000ff);
3464 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3467 // Remember the media type
3468 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3469 case 0x01: // 1.2M floppy
3470 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3471 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3472 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3474 case 0x02: // 1.44M floppy
3475 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3476 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3477 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3479 case 0x03: // 2.88M floppy
3480 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3481 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3482 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3484 case 0x04: // Harddrive
3485 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3486 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3487 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3488 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3492 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3493 // Increase bios installed hardware number of devices
3494 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3495 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3497 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3501 // everything is ok, so from now on, the emulation is active
3502 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3503 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3505 // return the boot drive + no error
3506 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3509 // ---------------------------------------------------------------------------
3510 // End of El-Torito boot functions
3511 // ---------------------------------------------------------------------------
3512 #endif // BX_ELTORITO_BOOT
3515 int14_function(regs
, ds
, iret_addr
)
3516 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3517 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3518 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3520 Bit16u addr
,timer
,val16
;
3527 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3528 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3529 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3530 switch (regs
.u
.r8
.ah
) {
3532 outb(addr
+3, inb(addr
+3) | 0x80);
3533 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3537 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3538 outb(addr
, val16
& 0xFF);
3539 outb(addr
+1, val16
>> 8);
3541 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3542 regs
.u
.r8
.ah
= inb(addr
+5);
3543 regs
.u
.r8
.al
= inb(addr
+6);
3544 ClearCF(iret_addr
.flags
);
3547 timer
= read_word(0x0040, 0x006C);
3548 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3549 val16
= read_word(0x0040, 0x006C);
3550 if (val16
!= timer
) {
3555 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3556 regs
.u
.r8
.ah
= inb(addr
+5);
3557 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3558 ClearCF(iret_addr
.flags
);
3561 timer
= read_word(0x0040, 0x006C);
3562 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3563 val16
= read_word(0x0040, 0x006C);
3564 if (val16
!= timer
) {
3571 regs
.u
.r8
.al
= inb(addr
);
3573 regs
.u
.r8
.ah
= inb(addr
+5);
3575 ClearCF(iret_addr
.flags
);
3578 regs
.u
.r8
.ah
= inb(addr
+5);
3579 regs
.u
.r8
.al
= inb(addr
+6);
3580 ClearCF(iret_addr
.flags
);
3583 SetCF(iret_addr
.flags
); // Unsupported
3586 SetCF(iret_addr
.flags
); // Unsupported
3591 int15_function(regs
, ES
, DS
, FLAGS
)
3592 pusha_regs_t regs
; // REGS pushed via pusha
3593 Bit16u ES
, DS
, FLAGS
;
3595 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3596 bx_bool prev_a20_enable
;
3605 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3607 switch (regs
.u
.r8
.ah
) {
3608 case 0x24: /* A20 Control */
3609 switch (regs
.u
.r8
.al
) {
3621 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3631 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3633 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3639 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3643 /* keyboard intercept */
3645 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3652 case 0x52: // removable media eject
3654 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3658 if( regs
.u
.r8
.al
== 0 ) {
3659 // Set Interval requested.
3660 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3661 // Interval not already set.
3662 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3663 write_word( 0x40, 0x98, ES
); // Byte location, segment
3664 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3665 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3666 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3668 irqDisable
= inb( 0xA1 );
3669 outb( 0xA1, irqDisable
& 0xFE );
3670 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3671 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3673 // Interval already set.
3674 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3676 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3678 } else if( regs
.u
.r8
.al
== 1 ) {
3679 // Clear Interval requested
3680 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3682 bRegister
= inb_cmos( 0xB );
3683 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3685 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3687 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3696 # error "Int15 function 87h not supported on < 80386"
3698 // +++ should probably have descriptor checks
3699 // +++ should have exception handlers
3701 // turn off interrupts
3706 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3708 // 128K max of transfer on 386+ ???
3709 // source == destination ???
3711 // ES:SI points to descriptor table
3712 // offset use initially comments
3713 // ==============================================
3714 // 00..07 Unused zeros Null descriptor
3715 // 08..0f GDT zeros filled in by BIOS
3716 // 10..17 source ssssssss source of data
3717 // 18..1f dest dddddddd destination of data
3718 // 20..27 CS zeros filled in by BIOS
3719 // 28..2f SS zeros filled in by BIOS
3726 // check for access rights of source & dest here
3728 // Initialize GDT descriptor
3729 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3730 base23_16
= ES
>> 12;
3731 if (base15_00
< (ES
<<4))
3733 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3734 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3735 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3736 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3737 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3739 // Initialize CS descriptor
3740 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3741 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3742 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3743 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3744 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3746 // Initialize SS descriptor
3748 base15_00
= ss
<< 4;
3749 base23_16
= ss
>> 12;
3750 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3751 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3752 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3753 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3754 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3758 // Compile generates locals offset info relative to SP.
3759 // Get CX (word count) from stack.
3762 mov cx
, _int15_function
.CX
[bx
]
3764 // since we need to set SS:SP, save them to the BDA
3765 // for future restore
3775 lidt
[pmode_IDT_info
]
3776 ;; perhaps
do something with IDT here
3778 ;; set PE bit in CR0
3782 ;; far jump to flush CPU queue after transition to
protected mode
3783 JMP_AP(0x0020, protected_mode
)
3786 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3787 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3789 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3791 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3797 movsw
;; move CX words from DS
:SI to ES
:DI
3799 ;; make sure DS
and ES limits are
64KB
3804 ;; reset PG bit in CR0
???
3809 ;; far jump to flush CPU queue after transition to real mode
3810 JMP_AP(0xf000, real_mode
)
3813 ;; restore IDT to normal real
-mode defaults
3815 lidt
[rmode_IDT_info
]
3817 // restore SS:SP from the BDA
3825 set_enable_a20(prev_a20_enable
);
3827 // turn back on interrupts
3838 // Get the amount of extended memory (above 1M)
3840 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3843 regs
.u
.r8
.al
= inb_cmos(0x30);
3844 regs
.u
.r8
.ah
= inb_cmos(0x31);
3846 // According to Ralf Brown's interrupt the limit should be 15M,
3847 // but real machines mostly return max. 63M.
3848 if(regs
.u
.r16
.ax
> 0xffc0)
3849 regs
.u
.r16
.ax
= 0xffc0;
3856 /* Device busy interrupt. Called by Int 16h when no key available */
3860 /* Interrupt complete. Called by Int 16h when key becomes available */
3864 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3866 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3872 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3877 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3887 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3889 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3893 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3894 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3896 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3901 #if BX_USE_PS2_MOUSE
3903 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3904 pusha_regs_t regs
; // REGS pushed via pusha
3905 Bit16u ES
, DS
, FLAGS
;
3907 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3908 Bit8u mouse_flags_1
, mouse_flags_2
;
3909 Bit16u mouse_driver_seg
;
3910 Bit16u mouse_driver_offset
;
3911 Bit8u comm_byte
, prev_command_byte
;
3912 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3914 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3916 switch (regs
.u
.r8
.ah
) {
3918 // Return Codes status in AH
3919 // =========================
3921 // 01: invalid subfunction (AL > 7)
3922 // 02: invalid input value (out of allowable range)
3923 // 03: interface error
3924 // 04: resend command received from mouse controller,
3925 // device driver should attempt command again
3926 // 05: cannot enable mouse, since no far call has been installed
3927 // 80/86: mouse service not implemented
3929 switch (regs
.u
.r8
.al
) {
3930 case 0: // Disable/Enable Mouse
3931 BX_DEBUG_INT15("case 0:\n");
3932 switch (regs
.u
.r8
.bh
) {
3933 case 0: // Disable Mouse
3934 BX_DEBUG_INT15("case 0: disable mouse\n");
3935 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3936 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3938 ret
= get_mouse_data(&mouse_data1
);
3939 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3952 case 1: // Enable Mouse
3953 BX_DEBUG_INT15("case 1: enable mouse\n");
3954 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3955 if ( (mouse_flags_2
& 0x80) == 0 ) {
3956 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3958 regs
.u
.r8
.ah
= 5; // no far call installed
3961 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3962 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3964 ret
= get_mouse_data(&mouse_data1
);
3965 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3966 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3976 default: // invalid subfunction
3977 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3979 regs
.u
.r8
.ah
= 1; // invalid subfunction
3984 case 1: // Reset Mouse
3985 case 5: // Initialize Mouse
3986 BX_DEBUG_INT15("case 1 or 5:\n");
3987 if (regs
.u
.r8
.al
== 5) {
3988 if (regs
.u
.r8
.bh
!= 3) {
3990 regs
.u
.r8
.ah
= 0x02; // invalid input
3993 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3994 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3995 mouse_flags_1
= 0x00;
3996 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3997 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4000 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4001 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
4003 ret
= get_mouse_data(&mouse_data3
);
4004 // if no mouse attached, it will return RESEND
4005 if (mouse_data3
== 0xfe) {
4009 if (mouse_data3
!= 0xfa)
4010 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
4012 ret
= get_mouse_data(&mouse_data1
);
4014 ret
= get_mouse_data(&mouse_data2
);
4016 // turn IRQ12 and packet generation on
4017 enable_mouse_int_and_events();
4020 regs
.u
.r8
.bl
= mouse_data1
;
4021 regs
.u
.r8
.bh
= mouse_data2
;
4033 case 2: // Set Sample Rate
4034 BX_DEBUG_INT15("case 2:\n");
4035 switch (regs
.u
.r8
.bh
) {
4036 case 0: mouse_data1
= 10; break; // 10 reports/sec
4037 case 1: mouse_data1
= 20; break; // 20 reports/sec
4038 case 2: mouse_data1
= 40; break; // 40 reports/sec
4039 case 3: mouse_data1
= 60; break; // 60 reports/sec
4040 case 4: mouse_data1
= 80; break; // 80 reports/sec
4041 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
4042 case 6: mouse_data1
= 200; break; // 200 reports/sec
4043 default: mouse_data1
= 0;
4045 if (mouse_data1
> 0) {
4046 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
4048 ret
= get_mouse_data(&mouse_data2
);
4049 ret
= send_to_mouse_ctrl(mouse_data1
);
4050 ret
= get_mouse_data(&mouse_data2
);
4056 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4061 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4065 case 3: // Set Resolution
4066 BX_DEBUG_INT15("case 3:\n");
4068 // 0 = 25 dpi, 1 count per millimeter
4069 // 1 = 50 dpi, 2 counts per millimeter
4070 // 2 = 100 dpi, 4 counts per millimeter
4071 // 3 = 200 dpi, 8 counts per millimeter
4072 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4073 if (regs
.u
.r8
.bh
< 4) {
4074 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
4076 ret
= get_mouse_data(&mouse_data1
);
4077 if (mouse_data1
!= 0xfa)
4078 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4079 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
4080 ret
= get_mouse_data(&mouse_data1
);
4081 if (mouse_data1
!= 0xfa)
4082 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4088 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4093 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4095 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4098 case 4: // Get Device ID
4099 BX_DEBUG_INT15("case 4:\n");
4100 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4101 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
4103 ret
= get_mouse_data(&mouse_data1
);
4104 ret
= get_mouse_data(&mouse_data2
);
4107 regs
.u
.r8
.bh
= mouse_data2
;
4111 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4115 case 6: // Return Status & Set Scaling Factor...
4116 BX_DEBUG_INT15("case 6:\n");
4117 switch (regs
.u
.r8
.bh
) {
4118 case 0: // Return Status
4119 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4120 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4122 ret
= get_mouse_data(&mouse_data1
);
4123 if (mouse_data1
!= 0xfa)
4124 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4126 ret
= get_mouse_data(&mouse_data1
);
4128 ret
= get_mouse_data(&mouse_data2
);
4130 ret
= get_mouse_data(&mouse_data3
);
4134 regs
.u
.r8
.bl
= mouse_data1
;
4135 regs
.u
.r8
.cl
= mouse_data2
;
4136 regs
.u
.r8
.dl
= mouse_data3
;
4137 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4148 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4151 case 1: // Set Scaling Factor to 1:1
4152 case 2: // Set Scaling Factor to 2:1
4153 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4154 if (regs
.u
.r8
.bh
== 1) {
4155 ret
= send_to_mouse_ctrl(0xE6);
4157 ret
= send_to_mouse_ctrl(0xE7);
4160 get_mouse_data(&mouse_data1
);
4161 ret
= (mouse_data1
!= 0xFA);
4169 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4171 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4175 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4179 case 7: // Set Mouse Handler Address
4180 BX_DEBUG_INT15("case 7:\n");
4181 mouse_driver_seg
= ES
;
4182 mouse_driver_offset
= regs
.u
.r16
.bx
;
4183 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4184 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4185 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4186 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4187 /* remove handler */
4188 if ( (mouse_flags_2
& 0x80) != 0 ) {
4189 mouse_flags_2
&= ~0x80;
4190 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4194 /* install handler */
4195 mouse_flags_2
|= 0x80;
4197 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4203 BX_DEBUG_INT15("case default:\n");
4204 regs
.u
.r8
.ah
= 1; // invalid function
4210 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4211 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4213 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4220 void set_e820_range(ES
, DI
, start
, end
, extra_start
, extra_end
, type
)
4229 write_word(ES
, DI
, start
);
4230 write_word(ES
, DI
+2, start
>> 16);
4231 write_word(ES
, DI
+4, extra_start
);
4232 write_word(ES
, DI
+6, 0x00);
4235 extra_end
-= extra_start
;
4236 write_word(ES
, DI
+8, end
);
4237 write_word(ES
, DI
+10, end
>> 16);
4238 write_word(ES
, DI
+12, extra_end
);
4239 write_word(ES
, DI
+14, 0x0000);
4241 write_word(ES
, DI
+16, type
);
4242 write_word(ES
, DI
+18, 0x0);
4246 int15_function32(regs
, ES
, DS
, FLAGS
)
4247 pushad_regs_t regs
; // REGS pushed via pushad
4248 Bit16u ES
, DS
, FLAGS
;
4250 Bit32u extended_memory_size
=0; // 64bits long
4251 Bit32u extra_lowbits_memory_size
=0;
4253 Bit8u extra_highbits_memory_size
=0;
4255 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4257 switch (regs
.u
.r8
.ah
) {
4259 // Wait for CX:DX microseconds. currently using the
4260 // refresh request port 0x61 bit4, toggling every 15usec
4268 ;; Get the count in eax
4271 mov ax
, _int15_function32
.CX
[bx
]
4274 mov ax
, _int15_function32
.DX
[bx
]
4276 ;; convert to numbers of
15usec ticks
4282 ;; wait
for ecx number of refresh requests
4303 switch(regs
.u
.r8
.al
)
4305 case 0x20: // coded by osmaker aka K.J.
4306 if(regs
.u
.r32
.edx
== 0x534D4150)
4308 extended_memory_size
= inb_cmos(0x35);
4309 extended_memory_size
<<= 8;
4310 extended_memory_size
|= inb_cmos(0x34);
4311 extended_memory_size
*= 64;
4312 // greater than EFF00000???
4313 if(extended_memory_size
> 0x3bc000) {
4314 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4316 extended_memory_size
*= 1024;
4317 extended_memory_size
+= (16L * 1024 * 1024);
4319 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4320 extended_memory_size
= inb_cmos(0x31);
4321 extended_memory_size
<<= 8;
4322 extended_memory_size
|= inb_cmos(0x30);
4323 extended_memory_size
*= 1024;
4326 extra_lowbits_memory_size
= inb_cmos(0x5c);
4327 extra_lowbits_memory_size
<<= 8;
4328 extra_lowbits_memory_size
|= inb_cmos(0x5b);
4329 extra_lowbits_memory_size
*= 64;
4330 extra_lowbits_memory_size
*= 1024;
4331 extra_highbits_memory_size
= inb_cmos(0x5d);
4333 switch(regs
.u
.r16
.bx
)
4336 set_e820_range(ES
, regs
.u
.r16
.di
,
4337 0x0000000L
, 0x0009fc00L
, 0, 0, 1);
4339 regs
.u
.r32
.eax
= 0x534D4150;
4340 regs
.u
.r32
.ecx
= 0x14;
4345 set_e820_range(ES
, regs
.u
.r16
.di
,
4346 0x0009fc00L
, 0x000a0000L
, 0, 0, 2);
4348 regs
.u
.r32
.eax
= 0x534D4150;
4349 regs
.u
.r32
.ecx
= 0x14;
4354 set_e820_range(ES
, regs
.u
.r16
.di
,
4355 0x000e8000L
, 0x00100000L
, 0, 0, 2);
4357 regs
.u
.r32
.eax
= 0x534D4150;
4358 regs
.u
.r32
.ecx
= 0x14;
4363 set_e820_range(ES
, regs
.u
.r16
.di
,
4365 extended_memory_size
- ACPI_DATA_SIZE
,0, 0, 1);
4367 regs
.u
.r32
.eax
= 0x534D4150;
4368 regs
.u
.r32
.ecx
= 0x14;
4373 set_e820_range(ES
, regs
.u
.r16
.di
,
4374 extended_memory_size
- ACPI_DATA_SIZE
,
4375 extended_memory_size
,0, 0, 3); // ACPI RAM
4377 regs
.u
.r32
.eax
= 0x534D4150;
4378 regs
.u
.r32
.ecx
= 0x14;
4383 /* 3 pages before the bios, we map the vmx tss pages */
4384 set_e820_range(ES
, regs
.u
.r16
.di
, 0xfffbd000L
,
4385 0xfffc0000L
, 0, 0, 2);
4387 regs
.u
.r32
.eax
= 0x534D4150;
4388 regs
.u
.r32
.ecx
= 0x14;
4392 /* 256KB BIOS area at the end of 4 GB */
4393 set_e820_range(ES
, regs
.u
.r16
.di
,
4394 0xfffc0000L
, 0x00000000L
,0, 0, 2);
4395 if (extra_highbits_memory_size
|| extra_lowbits_memory_size
)
4399 regs
.u
.r32
.eax
= 0x534D4150;
4400 regs
.u
.r32
.ecx
= 0x14;
4404 /* Maping of memory above 4 GB */
4405 set_e820_range(ES
, regs
.u
.r16
.di
, 0x00000000L
,
4406 extra_lowbits_memory_size
, 1, extra_highbits_memory_size
4409 regs
.u
.r32
.eax
= 0x534D4150;
4410 regs
.u
.r32
.ecx
= 0x14;
4413 default: /* AX=E820, DX=534D4150, BX unrecognized */
4414 goto int15_unimplemented
;
4418 // if DX != 0x534D4150)
4419 goto int15_unimplemented
;
4424 // do we have any reason to fail here ?
4427 // my real system sets ax and bx to 0
4428 // this is confirmed by Ralph Brown list
4429 // but syslinux v1.48 is known to behave
4430 // strangely if ax is set to 0
4431 // regs.u.r16.ax = 0;
4432 // regs.u.r16.bx = 0;
4434 // Get the amount of extended memory (above 1M)
4435 regs
.u
.r8
.cl
= inb_cmos(0x30);
4436 regs
.u
.r8
.ch
= inb_cmos(0x31);
4439 if(regs
.u
.r16
.cx
> 0x3c00)
4441 regs
.u
.r16
.cx
= 0x3c00;
4444 // Get the amount of extended memory above 16M in 64k blocs
4445 regs
.u
.r8
.dl
= inb_cmos(0x34);
4446 regs
.u
.r8
.dh
= inb_cmos(0x35);
4448 // Set configured memory equal to extended memory
4449 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4450 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4452 default: /* AH=0xE8?? but not implemented */
4453 goto int15_unimplemented
;
4456 int15_unimplemented
:
4457 // fall into the default
4459 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4460 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4462 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4468 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4469 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4471 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4472 Bit16u kbd_code
, max
;
4474 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4476 shift_flags
= read_byte(0x0040, 0x17);
4477 led_flags
= read_byte(0x0040, 0x97);
4478 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4483 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4484 if ((inb(0x60) == 0xfa)) {
4486 led_flags
|= ((shift_flags
>> 4) & 0x07);
4487 outb(0x60, led_flags
& 0x07);
4488 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4490 write_byte(0x0040, 0x97, led_flags
);
4498 case 0x00: /* read keyboard input */
4500 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4501 BX_PANIC("KBD: int16h: out of keyboard input\n");
4503 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4504 else if (ascii_code
== 0xE0) ascii_code
= 0;
4505 AX
= (scan_code
<< 8) | ascii_code
;
4508 case 0x01: /* check keyboard status */
4509 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4513 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4514 else if (ascii_code
== 0xE0) ascii_code
= 0;
4515 AX
= (scan_code
<< 8) | ascii_code
;
4519 case 0x02: /* get shift flag status */
4520 shift_flags
= read_byte(0x0040, 0x17);
4521 SET_AL(shift_flags
);
4524 case 0x05: /* store key-stroke into buffer */
4525 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4533 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4534 // bit Bochs Description
4536 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4537 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4538 // 4 1 INT 16/AH=0Ah supported
4539 // 3 0 INT 16/AX=0306h supported
4540 // 2 0 INT 16/AX=0305h supported
4541 // 1 0 INT 16/AX=0304h supported
4542 // 0 0 INT 16/AX=0300h supported
4547 case 0x0A: /* GET KEYBOARD ID */
4553 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4555 if ((inb(0x60) == 0xfa)) {
4558 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4561 kbd_code
|= (inb(0x60) << 8);
4563 } while (--count
>0);
4569 case 0x10: /* read MF-II keyboard input */
4571 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4572 BX_PANIC("KBD: int16h: out of keyboard input\n");
4574 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4575 AX
= (scan_code
<< 8) | ascii_code
;
4578 case 0x11: /* check MF-II keyboard status */
4579 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4583 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4584 AX
= (scan_code
<< 8) | ascii_code
;
4588 case 0x12: /* get extended keyboard status */
4589 shift_flags
= read_byte(0x0040, 0x17);
4590 SET_AL(shift_flags
);
4591 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4592 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4593 SET_AH(shift_flags
);
4594 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4597 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4598 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4601 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4602 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4606 if (GET_AL() == 0x08)
4607 SET_AH(0x02); // unsupported, aka normal keyboard
4610 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4615 dequeue_key(scan_code
, ascii_code
, incr
)
4620 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4625 buffer_start
= 0x001E;
4626 buffer_end
= 0x003E;
4628 buffer_start
= read_word(0x0040, 0x0080);
4629 buffer_end
= read_word(0x0040, 0x0082);
4632 buffer_head
= read_word(0x0040, 0x001a);
4633 buffer_tail
= read_word(0x0040, 0x001c);
4635 if (buffer_head
!= buffer_tail
) {
4637 acode
= read_byte(0x0040, buffer_head
);
4638 scode
= read_byte(0x0040, buffer_head
+1);
4639 write_byte(ss
, ascii_code
, acode
);
4640 write_byte(ss
, scan_code
, scode
);
4644 if (buffer_head
>= buffer_end
)
4645 buffer_head
= buffer_start
;
4646 write_word(0x0040, 0x001a, buffer_head
);
4655 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4658 inhibit_mouse_int_and_events()
4660 Bit8u command_byte
, prev_command_byte
;
4662 // Turn off IRQ generation and aux data line
4663 if ( inb(0x64) & 0x02 )
4664 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4665 outb(0x64, 0x20); // get command byte
4666 while ( (inb(0x64) & 0x01) != 0x01 );
4667 prev_command_byte
= inb(0x60);
4668 command_byte
= prev_command_byte
;
4669 //while ( (inb(0x64) & 0x02) );
4670 if ( inb(0x64) & 0x02 )
4671 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4672 command_byte
&= 0xfd; // turn off IRQ 12 generation
4673 command_byte
|= 0x20; // disable mouse serial clock line
4674 outb(0x64, 0x60); // write command byte
4675 outb(0x60, command_byte
);
4676 return(prev_command_byte
);
4680 enable_mouse_int_and_events()
4684 // Turn on IRQ generation and aux data line
4685 if ( inb(0x64) & 0x02 )
4686 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4687 outb(0x64, 0x20); // get command byte
4688 while ( (inb(0x64) & 0x01) != 0x01 );
4689 command_byte
= inb(0x60);
4690 //while ( (inb(0x64) & 0x02) );
4691 if ( inb(0x64) & 0x02 )
4692 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4693 command_byte
|= 0x02; // turn on IRQ 12 generation
4694 command_byte
&= 0xdf; // enable mouse serial clock line
4695 outb(0x64, 0x60); // write command byte
4696 outb(0x60, command_byte
);
4700 send_to_mouse_ctrl(sendbyte
)
4705 // wait for chance to write to ctrl
4706 if ( inb(0x64) & 0x02 )
4707 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4709 outb(0x60, sendbyte
);
4715 get_mouse_data(data
)
4721 while ( (inb(0x64) & 0x21) != 0x21 ) {
4724 response
= inb(0x60);
4727 write_byte(ss
, data
, response
);
4732 set_kbd_command_byte(command_byte
)
4735 if ( inb(0x64) & 0x02 )
4736 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4739 outb(0x64, 0x60); // write command byte
4740 outb(0x60, command_byte
);
4744 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4745 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4747 Bit8u scancode
, asciicode
, shift_flags
;
4748 Bit8u mf2_flags
, mf2_state
;
4751 // DS has been set to F000 before call
4755 scancode
= GET_AL();
4757 if (scancode
== 0) {
4758 BX_INFO("KBD: int09 handler: AL=0\n");
4763 shift_flags
= read_byte(0x0040, 0x17);
4764 mf2_flags
= read_byte(0x0040, 0x18);
4765 mf2_state
= read_byte(0x0040, 0x96);
4769 case 0x3a: /* Caps Lock press */
4770 shift_flags
^= 0x40;
4771 write_byte(0x0040, 0x17, shift_flags
);
4773 write_byte(0x0040, 0x18, mf2_flags
);
4775 case 0xba: /* Caps Lock release */
4777 write_byte(0x0040, 0x18, mf2_flags
);
4780 case 0x2a: /* L Shift press */
4781 shift_flags
|= 0x02;
4782 write_byte(0x0040, 0x17, shift_flags
);
4784 case 0xaa: /* L Shift release */
4785 shift_flags
&= ~0x02;
4786 write_byte(0x0040, 0x17, shift_flags
);
4789 case 0x36: /* R Shift press */
4790 shift_flags
|= 0x01;
4791 write_byte(0x0040, 0x17, shift_flags
);
4793 case 0xb6: /* R Shift release */
4794 shift_flags
&= ~0x01;
4795 write_byte(0x0040, 0x17, shift_flags
);
4798 case 0x1d: /* Ctrl press */
4799 if ((mf2_state
& 0x01) == 0) {
4800 shift_flags
|= 0x04;
4801 write_byte(0x0040, 0x17, shift_flags
);
4802 if (mf2_state
& 0x02) {
4804 write_byte(0x0040, 0x96, mf2_state
);
4807 write_byte(0x0040, 0x18, mf2_flags
);
4811 case 0x9d: /* Ctrl release */
4812 if ((mf2_state
& 0x01) == 0) {
4813 shift_flags
&= ~0x04;
4814 write_byte(0x0040, 0x17, shift_flags
);
4815 if (mf2_state
& 0x02) {
4817 write_byte(0x0040, 0x96, mf2_state
);
4820 write_byte(0x0040, 0x18, mf2_flags
);
4825 case 0x38: /* Alt press */
4826 shift_flags
|= 0x08;
4827 write_byte(0x0040, 0x17, shift_flags
);
4828 if (mf2_state
& 0x02) {
4830 write_byte(0x0040, 0x96, mf2_state
);
4833 write_byte(0x0040, 0x18, mf2_flags
);
4836 case 0xb8: /* Alt release */
4837 shift_flags
&= ~0x08;
4838 write_byte(0x0040, 0x17, shift_flags
);
4839 if (mf2_state
& 0x02) {
4841 write_byte(0x0040, 0x96, mf2_state
);
4844 write_byte(0x0040, 0x18, mf2_flags
);
4848 case 0x45: /* Num Lock press */
4849 if ((mf2_state
& 0x03) == 0) {
4851 write_byte(0x0040, 0x18, mf2_flags
);
4852 shift_flags
^= 0x20;
4853 write_byte(0x0040, 0x17, shift_flags
);
4856 case 0xc5: /* Num Lock release */
4857 if ((mf2_state
& 0x03) == 0) {
4859 write_byte(0x0040, 0x18, mf2_flags
);
4863 case 0x46: /* Scroll Lock press */
4865 write_byte(0x0040, 0x18, mf2_flags
);
4866 shift_flags
^= 0x10;
4867 write_byte(0x0040, 0x17, shift_flags
);
4870 case 0xc6: /* Scroll Lock release */
4872 write_byte(0x0040, 0x18, mf2_flags
);
4876 if (scancode
& 0x80) {
4877 break; /* toss key releases ... */
4879 if (scancode
> MAX_SCAN_CODE
) {
4880 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4883 if (shift_flags
& 0x08) { /* ALT */
4884 asciicode
= scan_to_scanascii
[scancode
].alt
;
4885 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4886 } else if (shift_flags
& 0x04) { /* CONTROL */
4887 asciicode
= scan_to_scanascii
[scancode
].control
;
4888 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4889 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
4890 /* extended keys handling */
4892 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4893 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4894 /* check if lock state should be ignored
4895 * because a SHIFT key are pressed */
4897 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4898 asciicode
= scan_to_scanascii
[scancode
].normal
;
4899 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4901 asciicode
= scan_to_scanascii
[scancode
].shift
;
4902 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4905 /* check if lock is on */
4906 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4907 asciicode
= scan_to_scanascii
[scancode
].shift
;
4908 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4910 asciicode
= scan_to_scanascii
[scancode
].normal
;
4911 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4914 if (scancode
==0 && asciicode
==0) {
4915 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4917 enqueue_key(scancode
, asciicode
);
4920 if ((scancode
& 0x7f) != 0x1d) {
4924 write_byte(0x0040, 0x96, mf2_state
);
4928 enqueue_key(scan_code
, ascii_code
)
4929 Bit8u scan_code
, ascii_code
;
4931 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4934 buffer_start
= 0x001E;
4935 buffer_end
= 0x003E;
4937 buffer_start
= read_word(0x0040, 0x0080);
4938 buffer_end
= read_word(0x0040, 0x0082);
4941 buffer_head
= read_word(0x0040, 0x001A);
4942 buffer_tail
= read_word(0x0040, 0x001C);
4944 temp_tail
= buffer_tail
;
4946 if (buffer_tail
>= buffer_end
)
4947 buffer_tail
= buffer_start
;
4949 if (buffer_tail
== buffer_head
) {
4953 write_byte(0x0040, temp_tail
, ascii_code
);
4954 write_byte(0x0040, temp_tail
+1, scan_code
);
4955 write_word(0x0040, 0x001C, buffer_tail
);
4961 int74_function(make_farcall
, Z
, Y
, X
, status
)
4962 Bit16u make_farcall
, Z
, Y
, X
, status
;
4964 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4965 Bit8u in_byte
, index
, package_count
;
4966 Bit8u mouse_flags_1
, mouse_flags_2
;
4968 BX_DEBUG_INT74("entering int74_function\n");
4971 in_byte
= inb(0x64);
4972 if ( (in_byte
& 0x21) != 0x21 ) {
4975 in_byte
= inb(0x60);
4976 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4978 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4979 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4981 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4985 package_count
= mouse_flags_2
& 0x07;
4986 index
= mouse_flags_1
& 0x07;
4987 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4989 if ( (index
+1) >= package_count
) {
4990 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4991 status
= read_byte(ebda_seg
, 0x0028 + 0);
4992 X
= read_byte(ebda_seg
, 0x0028 + 1);
4993 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4996 // check if far call handler installed
4997 if (mouse_flags_2
& 0x80)
5003 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
5006 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5011 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5012 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5015 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5016 Bit16u cylinder
, head
, sector
;
5017 Bit16u segment
, offset
;
5018 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
5020 Bit8u device
, status
;
5022 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5024 write_byte(0x0040, 0x008e, 0); // clear completion flag
5026 // basic check : device has to be defined
5027 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
5028 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5032 // Get the ata channel
5033 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
5035 // basic check : device has to be valid
5036 if (device
>= BX_MAX_ATA_DEVICES
) {
5037 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5043 case 0x00: /* disk controller reset */
5048 case 0x01: /* read disk status */
5049 status
= read_byte(0x0040, 0x0074);
5051 SET_DISK_RET_STATUS(0);
5052 /* set CF if error status read */
5053 if (status
) goto int13_fail_nostatus
;
5054 else goto int13_success_noah
;
5057 case 0x02: // read disk sectors
5058 case 0x03: // write disk sectors
5059 case 0x04: // verify disk sectors
5062 cylinder
= GET_CH();
5063 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5064 sector
= (GET_CL() & 0x3f);
5070 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
5071 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5075 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5076 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5077 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5079 // sanity check on cyl heads, sec
5080 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
5081 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
5086 if ( GET_AH() == 0x04 ) goto int13_success
;
5088 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5089 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5091 // if needed, translate lchs to lba, and execute command
5092 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
5093 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
5094 sector
= 0; // this forces the command to be lba
5097 if ( GET_AH() == 0x02 )
5098 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5100 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5102 // Set nb of sector transferred
5103 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
5106 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5108 goto int13_fail_noah
;
5114 case 0x05: /* format disk track */
5115 BX_INFO("format disk track called\n");
5120 case 0x08: /* read disk drive parameters */
5122 // Get logical geometry from table
5123 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5124 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5125 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5126 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5128 nlc
= nlc
- 2; /* 0 based , last sector not used */
5131 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5133 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5135 // FIXME should set ES & DI
5140 case 0x10: /* check drive ready */
5141 // should look at 40:8E also???
5143 // Read the status from controller
5144 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5145 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5150 goto int13_fail_noah
;
5154 case 0x15: /* read disk drive size */
5156 // Get logical geometry from table
5157 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5158 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5159 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5161 // Compute sector count seen by int13
5162 lba
= (Bit32u
)(nlc
- 1) * (Bit32u
)nlh
* (Bit32u
)nlspt
;
5166 SET_AH(3); // hard disk accessible
5167 goto int13_success_noah
;
5170 case 0x41: // IBM/MS installation check
5171 BX
=0xaa55; // install check
5172 SET_AH(0x30); // EDD 3.0
5173 CX
=0x0007; // ext disk access and edd, removable supported
5174 goto int13_success_noah
;
5177 case 0x42: // IBM/MS extended read
5178 case 0x43: // IBM/MS extended write
5179 case 0x44: // IBM/MS verify
5180 case 0x47: // IBM/MS extended seek
5182 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5183 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5184 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5186 // Can't use 64 bits lba
5187 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5189 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5193 // Get 32 bits lba and check
5194 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5195 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
5196 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5200 // If verify or seek
5201 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5204 // Execute the command
5205 if ( GET_AH() == 0x42 )
5206 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5208 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5210 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5211 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5214 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5216 goto int13_fail_noah
;
5222 case 0x45: // IBM/MS lock/unlock drive
5223 case 0x49: // IBM/MS extended media change
5224 goto int13_success
; // Always success for HD
5227 case 0x46: // IBM/MS eject media
5228 SET_AH(0xb2); // Volume Not Removable
5229 goto int13_fail_noah
; // Always fail for HD
5232 case 0x48: // IBM/MS get drive parameters
5233 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5235 // Buffer is too small
5243 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5244 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5245 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5246 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
5247 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5249 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5250 if ((lba
/npspt
)/nph
> 0x3fff)
5252 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x00); // geometry is invalid
5253 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0x3fff);
5257 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5258 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5260 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5261 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5262 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
5263 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
5264 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5269 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5270 Bit16u iobase1
, iobase2
, options
;
5272 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5274 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5275 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5278 channel
= device
/ 2;
5279 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5280 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5281 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5282 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5283 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5285 options
= (translation
==ATA_TRANSLATION_NONE
?0:1)<<3; // chs translation
5286 options
|= (1<<4); // lba translation
5287 options
|= (mode
==ATA_MODE_PIO32
?1:0)<<7;
5288 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0)<<9;
5289 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0)<<9;
5291 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5292 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5293 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5294 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5295 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5296 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5297 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5298 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5299 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5300 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5302 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5304 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x10);
5307 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5308 checksum
= ~checksum
;
5309 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5314 Bit8u channel
, iface
, checksum
, i
;
5317 channel
= device
/ 2;
5318 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5319 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5321 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5322 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5323 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5324 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5325 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5327 if (iface
==ATA_IFACE_ISA
) {
5328 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5329 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5330 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5331 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5336 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5337 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5338 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5339 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5341 if (iface
==ATA_IFACE_ISA
) {
5342 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5343 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5344 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5349 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5350 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5351 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5352 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5355 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5356 checksum
= ~checksum
;
5357 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5363 case 0x4e: // // IBM/MS set hardware configuration
5364 // DMA, prefetch, PIO maximum not supported
5377 case 0x09: /* initialize drive parameters */
5378 case 0x0c: /* seek to specified cylinder */
5379 case 0x0d: /* alternate disk reset */
5380 case 0x11: /* recalibrate */
5381 case 0x14: /* controller internal diagnostic */
5382 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5386 case 0x0a: /* read disk sectors with ECC */
5387 case 0x0b: /* write disk sectors with ECC */
5388 case 0x18: // set media type for format
5389 case 0x50: // IBM/MS send packet command
5391 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5397 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5399 SET_DISK_RET_STATUS(GET_AH());
5400 int13_fail_nostatus
:
5401 SET_CF(); // error occurred
5405 SET_AH(0x00); // no error
5407 SET_DISK_RET_STATUS(0x00);
5408 CLEAR_CF(); // no error
5412 // ---------------------------------------------------------------------------
5413 // Start of int13 for cdrom
5414 // ---------------------------------------------------------------------------
5417 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5418 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5420 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5421 Bit8u device
, status
, locks
;
5424 Bit16u count
, segment
, offset
, i
, size
;
5426 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5428 SET_DISK_RET_STATUS(0x00);
5430 /* basic check : device should be 0xE0+ */
5431 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5432 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5436 // Get the ata channel
5437 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5439 /* basic check : device has to be valid */
5440 if (device
>= BX_MAX_ATA_DEVICES
) {
5441 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5447 // all those functions return SUCCESS
5448 case 0x00: /* disk controller reset */
5449 case 0x09: /* initialize drive parameters */
5450 case 0x0c: /* seek to specified cylinder */
5451 case 0x0d: /* alternate disk reset */
5452 case 0x10: /* check drive ready */
5453 case 0x11: /* recalibrate */
5454 case 0x14: /* controller internal diagnostic */
5455 case 0x16: /* detect disk change */
5459 // all those functions return disk write-protected
5460 case 0x03: /* write disk sectors */
5461 case 0x05: /* format disk track */
5462 case 0x43: // IBM/MS extended write
5464 goto int13_fail_noah
;
5467 case 0x01: /* read disk status */
5468 status
= read_byte(0x0040, 0x0074);
5470 SET_DISK_RET_STATUS(0);
5472 /* set CF if error status read */
5473 if (status
) goto int13_fail_nostatus
;
5474 else goto int13_success_noah
;
5477 case 0x15: /* read disk drive size */
5479 goto int13_fail_noah
;
5482 case 0x41: // IBM/MS installation check
5483 BX
=0xaa55; // install check
5484 SET_AH(0x30); // EDD 2.1
5485 CX
=0x0007; // ext disk access, removable and edd
5486 goto int13_success_noah
;
5489 case 0x42: // IBM/MS extended read
5490 case 0x44: // IBM/MS verify sectors
5491 case 0x47: // IBM/MS extended seek
5493 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5494 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5495 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5497 // Can't use 64 bits lba
5498 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5500 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5505 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5507 // If verify or seek
5508 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5511 memsetb(get_SS(),atacmd
,0,12);
5512 atacmd
[0]=0x28; // READ command
5513 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5514 atacmd
[8]=(count
& 0x00ff); // Sectors
5515 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5516 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5517 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5518 atacmd
[5]=(lba
& 0x000000ff);
5519 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5521 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5522 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5525 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5527 goto int13_fail_noah
;
5533 case 0x45: // IBM/MS lock/unlock drive
5534 if (GET_AL() > 2) goto int13_fail
;
5536 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5540 if (locks
== 0xff) {
5543 goto int13_fail_noah
;
5545 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5549 if (locks
== 0x00) {
5552 goto int13_fail_noah
;
5554 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5555 SET_AL(locks
==0?0:1);
5558 SET_AL(locks
==0?0:1);
5564 case 0x46: // IBM/MS eject media
5565 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5568 SET_AH(0xb1); // media locked
5569 goto int13_fail_noah
;
5571 // FIXME should handle 0x31 no media in device
5572 // FIXME should handle 0xb5 valid request failed
5574 // Call removable media eject
5581 mov _int13_cdrom
.status
+ 2[bp
], ah
5582 jnc int13_cdrom_rme_end
5583 mov _int13_cdrom
.status
, #1
5584 int13_cdrom_rme_end
:
5589 SET_AH(0xb1); // media locked
5590 goto int13_fail_noah
;
5596 case 0x48: // IBM/MS get drive parameters
5597 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5599 // Buffer is too small
5605 Bit16u cylinders
, heads
, spt
, blksize
;
5607 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5609 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5610 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5611 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5612 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5613 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5614 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5615 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5616 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5621 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5622 Bit16u iobase1
, iobase2
, options
;
5624 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5626 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5627 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5630 channel
= device
/ 2;
5631 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5632 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5633 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5634 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5636 // FIXME atapi device
5637 options
= (1<<4); // lba translation
5638 options
|= (1<<5); // removable device
5639 options
|= (1<<6); // atapi device
5640 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5642 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5643 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5644 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5645 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5646 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5647 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5648 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5649 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5650 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5651 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5652 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5655 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5656 checksum
= ~checksum
;
5657 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5662 Bit8u channel
, iface
, checksum
, i
;
5665 channel
= device
/ 2;
5666 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5667 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5669 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5670 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5671 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5672 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5673 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5675 if (iface
==ATA_IFACE_ISA
) {
5676 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5677 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5678 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5679 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5684 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5685 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5686 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5687 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5689 if (iface
==ATA_IFACE_ISA
) {
5690 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5691 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5692 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5697 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5698 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5699 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5700 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5703 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5704 checksum
= ~checksum
;
5705 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5711 case 0x49: // IBM/MS extended media change
5712 // always send changed ??
5714 goto int13_fail_nostatus
;
5717 case 0x4e: // // IBM/MS set hardware configuration
5718 // DMA, prefetch, PIO maximum not supported
5731 // all those functions return unimplemented
5732 case 0x02: /* read sectors */
5733 case 0x04: /* verify sectors */
5734 case 0x08: /* read disk drive parameters */
5735 case 0x0a: /* read disk sectors with ECC */
5736 case 0x0b: /* write disk sectors with ECC */
5737 case 0x18: /* set media type for format */
5738 case 0x50: // ? - send packet command
5740 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5746 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5748 SET_DISK_RET_STATUS(GET_AH());
5749 int13_fail_nostatus
:
5750 SET_CF(); // error occurred
5754 SET_AH(0x00); // no error
5756 SET_DISK_RET_STATUS(0x00);
5757 CLEAR_CF(); // no error
5761 // ---------------------------------------------------------------------------
5762 // End of int13 for cdrom
5763 // ---------------------------------------------------------------------------
5765 #if BX_ELTORITO_BOOT
5766 // ---------------------------------------------------------------------------
5767 // Start of int13 for eltorito functions
5768 // ---------------------------------------------------------------------------
5771 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5772 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5774 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5776 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5777 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5781 // FIXME ElTorito Various. Should be implemented
5782 case 0x4a: // ElTorito - Initiate disk emu
5783 case 0x4c: // ElTorito - Initiate disk emu and boot
5784 case 0x4d: // ElTorito - Return Boot catalog
5785 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5789 case 0x4b: // ElTorito - Terminate disk emu
5790 // FIXME ElTorito Hardcoded
5791 write_byte(DS
,SI
+0x00,0x13);
5792 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5793 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5794 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5795 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5796 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5797 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5798 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5799 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5800 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5801 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5802 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5804 // If we have to terminate emulation
5805 if(GET_AL() == 0x00) {
5806 // FIXME ElTorito Various. Should be handled accordingly to spec
5807 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5814 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5820 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5821 SET_DISK_RET_STATUS(GET_AH());
5822 SET_CF(); // error occurred
5826 SET_AH(0x00); // no error
5827 SET_DISK_RET_STATUS(0x00);
5828 CLEAR_CF(); // no error
5832 // ---------------------------------------------------------------------------
5833 // End of int13 for eltorito functions
5834 // ---------------------------------------------------------------------------
5836 // ---------------------------------------------------------------------------
5837 // Start of int13 when emulating a device from the cd
5838 // ---------------------------------------------------------------------------
5841 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5842 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5844 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5845 Bit8u device
, status
;
5846 Bit16u vheads
, vspt
, vcylinders
;
5847 Bit16u head
, sector
, cylinder
, nbsectors
;
5848 Bit32u vlba
, ilba
, slba
, elba
;
5849 Bit16u before
, segment
, offset
;
5852 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5854 /* at this point, we are emulating a floppy/harddisk */
5856 // Recompute the device number
5857 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5858 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5860 SET_DISK_RET_STATUS(0x00);
5862 /* basic checks : emulation should be active, dl should equal the emulated drive */
5863 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5864 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5865 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5871 // all those functions return SUCCESS
5872 case 0x00: /* disk controller reset */
5873 case 0x09: /* initialize drive parameters */
5874 case 0x0c: /* seek to specified cylinder */
5875 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5876 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5877 case 0x11: /* recalibrate */
5878 case 0x14: /* controller internal diagnostic */
5879 case 0x16: /* detect disk change */
5883 // all those functions return disk write-protected
5884 case 0x03: /* write disk sectors */
5885 case 0x05: /* format disk track */
5887 goto int13_fail_noah
;
5890 case 0x01: /* read disk status */
5891 status
=read_byte(0x0040, 0x0074);
5893 SET_DISK_RET_STATUS(0);
5895 /* set CF if error status read */
5896 if (status
) goto int13_fail_nostatus
;
5897 else goto int13_success_noah
;
5900 case 0x02: // read disk sectors
5901 case 0x04: // verify disk sectors
5902 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5903 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5904 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5906 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5908 sector
= GET_CL() & 0x003f;
5909 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5911 nbsectors
= GET_AL();
5915 // no sector to read ?
5916 if(nbsectors
==0) goto int13_success
;
5918 // sanity checks sco openserver needs this!
5920 || (cylinder
>= vcylinders
)
5921 || (head
>= vheads
)) {
5925 // After controls, verify do nothing
5926 if (GET_AH() == 0x04) goto int13_success
;
5928 segment
= ES
+(BX
/ 16);
5931 // calculate the virtual lba inside the image
5932 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5934 // In advance so we don't loose the count
5938 slba
= (Bit32u
)vlba
/4;
5939 before
= (Bit16u
)vlba
%4;
5942 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5944 memsetb(get_SS(),atacmd
,0,12);
5945 atacmd
[0]=0x28; // READ command
5946 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5947 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5948 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5949 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5950 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5951 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5952 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5953 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5956 goto int13_fail_noah
;
5962 case 0x08: /* read disk drive parameters */
5963 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5964 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5965 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5969 SET_CH( vcylinders
& 0xff );
5970 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5972 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5973 // FIXME ElTorito Harddisk. should send the HD count
5975 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5976 case 0x01: SET_BL( 0x02 ); break;
5977 case 0x02: SET_BL( 0x04 ); break;
5978 case 0x03: SET_BL( 0x06 ); break;
5984 mov ax
, #diskette_param_table2
5985 mov _int13_cdemu
.DI
+2[bp
], ax
5986 mov _int13_cdemu
.ES
+2[bp
], cs
5992 case 0x15: /* read disk drive size */
5993 // FIXME ElTorito Harddisk. What geometry to send ?
5995 goto int13_success_noah
;
5998 // all those functions return unimplemented
5999 case 0x0a: /* read disk sectors with ECC */
6000 case 0x0b: /* write disk sectors with ECC */
6001 case 0x18: /* set media type for format */
6002 case 0x41: // IBM/MS installation check
6003 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6004 case 0x42: // IBM/MS extended read
6005 case 0x43: // IBM/MS extended write
6006 case 0x44: // IBM/MS verify sectors
6007 case 0x45: // IBM/MS lock/unlock drive
6008 case 0x46: // IBM/MS eject media
6009 case 0x47: // IBM/MS extended seek
6010 case 0x48: // IBM/MS get drive parameters
6011 case 0x49: // IBM/MS extended media change
6012 case 0x4e: // ? - set hardware configuration
6013 case 0x50: // ? - send packet command
6015 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6021 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6023 SET_DISK_RET_STATUS(GET_AH());
6024 int13_fail_nostatus
:
6025 SET_CF(); // error occurred
6029 SET_AH(0x00); // no error
6031 SET_DISK_RET_STATUS(0x00);
6032 CLEAR_CF(); // no error
6036 // ---------------------------------------------------------------------------
6037 // End of int13 when emulating a device from the cd
6038 // ---------------------------------------------------------------------------
6040 #endif // BX_ELTORITO_BOOT
6042 #else //BX_USE_ATADRV
6045 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
6060 mov ax
,4[bp
] // cylinder
6062 mov bl
,6[bp
] // hd_heads
6065 mov bl
,8[bp
] // head
6067 mov bl
,10[bp
] // hd_sectors
6069 mov bl
,12[bp
] // sector
6098 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6099 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6101 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
6105 Bit16u max_cylinder
, cylinder
, total_sectors
;
6106 Bit16u hd_cylinders
;
6107 Bit8u hd_heads
, hd_sectors
;
6114 Bit16u count
, segment
, offset
;
6118 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6120 write_byte(0x0040, 0x008e, 0); // clear completion flag
6122 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6124 /* check how many disks first (cmos reg 0x12), return an error if
6125 drive not present */
6126 drive_map
= inb_cmos(0x12);
6127 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6128 (((drive_map
& 0x0f)==0) ? 0 : 2);
6129 n_drives
= (drive_map
==0) ? 0 :
6130 ((drive_map
==3) ? 2 : 1);
6132 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6134 SET_DISK_RET_STATUS(0x01);
6135 SET_CF(); /* error occurred */
6141 case 0x00: /* disk controller reset */
6142 BX_DEBUG_INT13_HD("int13_f00\n");
6145 SET_DISK_RET_STATUS(0);
6146 set_diskette_ret_status(0);
6147 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6148 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6149 CLEAR_CF(); /* successful */
6153 case 0x01: /* read disk status */
6154 BX_DEBUG_INT13_HD("int13_f01\n");
6155 status
= read_byte(0x0040, 0x0074);
6157 SET_DISK_RET_STATUS(0);
6158 /* set CF if error status read */
6159 if (status
) SET_CF();
6164 case 0x04: // verify disk sectors
6165 case 0x02: // read disk sectors
6167 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6169 num_sectors
= GET_AL();
6170 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6171 sector
= (GET_CL() & 0x3f);
6175 if (hd_cylinders
> 1024) {
6176 if (hd_cylinders
<= 2048) {
6179 else if (hd_cylinders
<= 4096) {
6182 else if (hd_cylinders
<= 8192) {
6185 else { // hd_cylinders <= 16384
6189 ax
= head
/ hd_heads
;
6190 cyl_mod
= ax
& 0xff;
6192 cylinder
|= cyl_mod
;
6195 if ( (cylinder
>= hd_cylinders
) ||
6196 (sector
> hd_sectors
) ||
6197 (head
>= hd_heads
) ) {
6199 SET_DISK_RET_STATUS(1);
6200 SET_CF(); /* error occurred */
6204 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6205 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6208 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6210 if ( GET_AH() == 0x04 ) {
6212 SET_DISK_RET_STATUS(0);
6217 status
= inb(0x1f7);
6218 if (status
& 0x80) {
6219 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6221 outb(0x01f2, num_sectors
);
6222 /* activate LBA? (tomv) */
6223 if (hd_heads
> 16) {
6224 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6225 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6228 outb(0x01f3, sector
);
6229 outb(0x01f4, cylinder
& 0x00ff);
6230 outb(0x01f5, cylinder
>> 8);
6231 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6236 status
= inb(0x1f7);
6237 if ( !(status
& 0x80) ) break;
6240 if (status
& 0x01) {
6241 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6242 } else if ( !(status
& 0x08) ) {
6243 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6244 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6251 sti
;; enable higher priority interrupts
6256 ;; store temp bx in real DI
register
6259 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6262 ;; adjust
if there will be an overrun
6264 jbe i13_f02_no_adjust
6266 sub di
, #0x0200 ; sub 512 bytes from offset
6268 add ax
, #0x0020 ; add 512 to segment
6272 mov cx
, #0x0100 ;; counter (256 words = 512b)
6273 mov dx
, #0x01f0 ;; AT data read port
6276 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6279 ;; store real DI
register back to temp bx
6282 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6288 if (num_sectors
== 0) {
6289 status
= inb(0x1f7);
6290 if ( (status
& 0xc9) != 0x40 )
6291 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6295 status
= inb(0x1f7);
6296 if ( (status
& 0xc9) != 0x48 )
6297 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6303 SET_DISK_RET_STATUS(0);
6304 SET_AL(sector_count
);
6305 CLEAR_CF(); /* successful */
6310 case 0x03: /* write disk sectors */
6311 BX_DEBUG_INT13_HD("int13_f03\n");
6312 drive
= GET_ELDL ();
6313 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6315 num_sectors
= GET_AL();
6316 cylinder
= GET_CH();
6317 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6318 sector
= (GET_CL() & 0x3f);
6321 if (hd_cylinders
> 1024) {
6322 if (hd_cylinders
<= 2048) {
6325 else if (hd_cylinders
<= 4096) {
6328 else if (hd_cylinders
<= 8192) {
6331 else { // hd_cylinders <= 16384
6335 ax
= head
/ hd_heads
;
6336 cyl_mod
= ax
& 0xff;
6338 cylinder
|= cyl_mod
;
6341 if ( (cylinder
>= hd_cylinders
) ||
6342 (sector
> hd_sectors
) ||
6343 (head
>= hd_heads
) ) {
6345 SET_DISK_RET_STATUS(1);
6346 SET_CF(); /* error occurred */
6350 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6351 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6354 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6356 status
= inb(0x1f7);
6357 if (status
& 0x80) {
6358 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6360 // should check for Drive Ready Bit also in status reg
6361 outb(0x01f2, num_sectors
);
6363 /* activate LBA? (tomv) */
6364 if (hd_heads
> 16) {
6365 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6366 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6369 outb(0x01f3, sector
);
6370 outb(0x01f4, cylinder
& 0x00ff);
6371 outb(0x01f5, cylinder
>> 8);
6372 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6376 // wait for busy bit to turn off after seeking
6378 status
= inb(0x1f7);
6379 if ( !(status
& 0x80) ) break;
6382 if ( !(status
& 0x08) ) {
6383 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6384 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6391 sti
;; enable higher priority interrupts
6396 ;; store temp bx in real SI
register
6399 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6402 ;; adjust
if there will be an overrun
6404 jbe i13_f03_no_adjust
6406 sub si
, #0x0200 ; sub 512 bytes from offset
6408 add ax
, #0x0020 ; add 512 to segment
6412 mov cx
, #0x0100 ;; counter (256 words = 512b)
6413 mov dx
, #0x01f0 ;; AT data read port
6417 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6419 ;; store real SI
register back to temp bx
6422 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6428 if (num_sectors
== 0) {
6429 status
= inb(0x1f7);
6430 if ( (status
& 0xe9) != 0x40 )
6431 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6435 status
= inb(0x1f7);
6436 if ( (status
& 0xc9) != 0x48 )
6437 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6443 SET_DISK_RET_STATUS(0);
6444 SET_AL(sector_count
);
6445 CLEAR_CF(); /* successful */
6449 case 0x05: /* format disk track */
6450 BX_DEBUG_INT13_HD("int13_f05\n");
6451 BX_PANIC("format disk track called\n");
6454 SET_DISK_RET_STATUS(0);
6455 CLEAR_CF(); /* successful */
6459 case 0x08: /* read disk drive parameters */
6460 BX_DEBUG_INT13_HD("int13_f08\n");
6462 drive
= GET_ELDL ();
6463 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6467 if (hd_cylinders
<= 1024) {
6468 // hd_cylinders >>= 0;
6471 else if (hd_cylinders
<= 2048) {
6475 else if (hd_cylinders
<= 4096) {
6479 else if (hd_cylinders
<= 8192) {
6483 else { // hd_cylinders <= 16384
6488 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6490 SET_CH(max_cylinder
& 0xff);
6491 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6492 SET_DH(hd_heads
- 1);
6493 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6495 SET_DISK_RET_STATUS(0);
6496 CLEAR_CF(); /* successful */
6501 case 0x09: /* initialize drive parameters */
6502 BX_DEBUG_INT13_HD("int13_f09\n");
6504 SET_DISK_RET_STATUS(0);
6505 CLEAR_CF(); /* successful */
6509 case 0x0a: /* read disk sectors with ECC */
6510 BX_DEBUG_INT13_HD("int13_f0a\n");
6511 case 0x0b: /* write disk sectors with ECC */
6512 BX_DEBUG_INT13_HD("int13_f0b\n");
6513 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6517 case 0x0c: /* seek to specified cylinder */
6518 BX_DEBUG_INT13_HD("int13_f0c\n");
6519 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6521 SET_DISK_RET_STATUS(0);
6522 CLEAR_CF(); /* successful */
6526 case 0x0d: /* alternate disk reset */
6527 BX_DEBUG_INT13_HD("int13_f0d\n");
6529 SET_DISK_RET_STATUS(0);
6530 CLEAR_CF(); /* successful */
6534 case 0x10: /* check drive ready */
6535 BX_DEBUG_INT13_HD("int13_f10\n");
6537 //SET_DISK_RET_STATUS(0);
6538 //CLEAR_CF(); /* successful */
6542 // should look at 40:8E also???
6543 status
= inb(0x01f7);
6544 if ( (status
& 0xc0) == 0x40 ) {
6546 SET_DISK_RET_STATUS(0);
6547 CLEAR_CF(); // drive ready
6552 SET_DISK_RET_STATUS(0xAA);
6553 SET_CF(); // not ready
6558 case 0x11: /* recalibrate */
6559 BX_DEBUG_INT13_HD("int13_f11\n");
6561 SET_DISK_RET_STATUS(0);
6562 CLEAR_CF(); /* successful */
6566 case 0x14: /* controller internal diagnostic */
6567 BX_DEBUG_INT13_HD("int13_f14\n");
6569 SET_DISK_RET_STATUS(0);
6570 CLEAR_CF(); /* successful */
6575 case 0x15: /* read disk drive size */
6577 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6581 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6582 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6583 mul al
, ah
;; ax
= heads
* sectors
6584 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6585 dec bx
;; use (cylinders
- 1) ???
6586 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6587 ;; now we need to move the
32bit result dx
:ax to what the
6588 ;; BIOS wants which is cx
:dx
.
6589 ;; and then into CX
:DX on the stack
6590 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6591 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6594 SET_AH(3); // hard disk accessible
6595 SET_DISK_RET_STATUS(0); // ??? should this be 0
6596 CLEAR_CF(); // successful
6600 case 0x18: // set media type for format
6601 case 0x41: // IBM/MS
6602 case 0x42: // IBM/MS
6603 case 0x43: // IBM/MS
6604 case 0x44: // IBM/MS
6605 case 0x45: // IBM/MS lock/unlock drive
6606 case 0x46: // IBM/MS eject media
6607 case 0x47: // IBM/MS extended seek
6608 case 0x49: // IBM/MS extended media change
6609 case 0x50: // IBM/MS send packet command
6611 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6613 SET_AH(1); // code=invalid function in AH or invalid parameter
6614 SET_DISK_RET_STATUS(1);
6615 SET_CF(); /* unsuccessful */
6621 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6622 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6625 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6627 Bit16u
*hd_cylinders
;
6637 if (drive
== 0x80) {
6638 hd_type
= inb_cmos(0x12) & 0xf0;
6639 if (hd_type
!= 0xf0)
6640 BX_INFO(panic_msg_reg12h
,0);
6641 hd_type
= inb_cmos(0x19); // HD0: extended type
6643 BX_INFO(panic_msg_reg19h
,0,0x19);
6646 hd_type
= inb_cmos(0x12) & 0x0f;
6647 if (hd_type
!= 0x0f)
6648 BX_INFO(panic_msg_reg12h
,1);
6649 hd_type
= inb_cmos(0x1a); // HD1: extended type
6651 BX_INFO(panic_msg_reg19h
,0,0x1a);
6656 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6657 write_word(ss
, hd_cylinders
, cylinders
);
6660 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6662 // sectors per track
6663 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6666 #endif //else BX_USE_ATADRV
6668 #if BX_SUPPORT_FLOPPY
6670 //////////////////////
6671 // FLOPPY functions //
6672 //////////////////////
6674 void floppy_reset_controller()
6680 outb(0x03f2, val8
& ~0x04);
6681 outb(0x03f2, val8
| 0x04);
6683 // Wait for controller to come out of reset
6686 } while ( (val8
& 0xc0) != 0x80 );
6689 void floppy_prepare_controller(drive
)
6692 Bit8u val8
, dor
, prev_reset
;
6694 // set 40:3e bit 7 to 0
6695 val8
= read_byte(0x0040, 0x003e);
6697 write_byte(0x0040, 0x003e, val8
);
6699 // turn on motor of selected drive, DMA & int enabled, normal operation
6700 prev_reset
= inb(0x03f2) & 0x04;
6709 // reset the disk motor timeout value of INT 08
6710 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6712 // wait for drive readiness
6715 } while ( (val8
& 0xc0) != 0x80 );
6717 if (prev_reset
== 0) {
6718 // turn on interrupts
6722 // wait on 40:3e bit 7 to become 1
6724 val8
= read_byte(0x0040, 0x003e);
6725 } while ( (val8
& 0x80) == 0 );
6730 write_byte(0x0040, 0x003e, val8
);
6735 floppy_media_known(drive
)
6739 Bit16u media_state_offset
;
6741 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6748 media_state_offset
= 0x0090;
6750 media_state_offset
+= 1;
6752 val8
= read_byte(0x0040, media_state_offset
);
6753 val8
= (val8
>> 4) & 0x01;
6757 // check pass, return KNOWN
6762 floppy_media_sense(drive
)
6766 Bit16u media_state_offset
;
6767 Bit8u drive_type
, config_data
, media_state
;
6769 if (floppy_drive_recal(drive
) == 0) {
6773 // for now cheat and get drive type from CMOS,
6774 // assume media is same as drive type
6776 // ** config_data **
6777 // Bitfields for diskette media control:
6778 // Bit(s) Description (Table M0028)
6779 // 7-6 last data rate set by controller
6780 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6781 // 5-4 last diskette drive step rate selected
6782 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6783 // 3-2 {data rate at start of operation}
6786 // ** media_state **
6787 // Bitfields for diskette drive media state:
6788 // Bit(s) Description (Table M0030)
6790 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6791 // 5 double stepping required (e.g. 360kB in 1.2MB)
6792 // 4 media type established
6793 // 3 drive capable of supporting 4MB media
6794 // 2-0 on exit from BIOS, contains
6795 // 000 trying 360kB in 360kB
6796 // 001 trying 360kB in 1.2MB
6797 // 010 trying 1.2MB in 1.2MB
6798 // 011 360kB in 360kB established
6799 // 100 360kB in 1.2MB established
6800 // 101 1.2MB in 1.2MB established
6802 // 111 all other formats/drives
6804 drive_type
= inb_cmos(0x10);
6809 if ( drive_type
== 1 ) {
6811 config_data
= 0x00; // 0000 0000
6812 media_state
= 0x25; // 0010 0101
6815 else if ( drive_type
== 2 ) {
6816 // 1.2 MB 5.25" drive
6817 config_data
= 0x00; // 0000 0000
6818 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6821 else if ( drive_type
== 3 ) {
6823 config_data
= 0x00; // 0000 0000 ???
6824 media_state
= 0x17; // 0001 0111
6827 else if ( drive_type
== 4 ) {
6828 // 1.44 MB 3.5" drive
6829 config_data
= 0x00; // 0000 0000
6830 media_state
= 0x17; // 0001 0111
6833 else if ( drive_type
== 5 ) {
6834 // 2.88 MB 3.5" drive
6835 config_data
= 0xCC; // 1100 1100
6836 media_state
= 0xD7; // 1101 0111
6840 // Extended floppy size uses special cmos setting
6841 else if ( drive_type
== 6 ) {
6843 config_data
= 0x00; // 0000 0000
6844 media_state
= 0x27; // 0010 0111
6847 else if ( drive_type
== 7 ) {
6849 config_data
= 0x00; // 0000 0000
6850 media_state
= 0x27; // 0010 0111
6853 else if ( drive_type
== 8 ) {
6855 config_data
= 0x00; // 0000 0000
6856 media_state
= 0x27; // 0010 0111
6862 config_data
= 0x00; // 0000 0000
6863 media_state
= 0x00; // 0000 0000
6868 media_state_offset
= 0x90;
6870 media_state_offset
= 0x91;
6871 write_byte(0x0040, 0x008B, config_data
);
6872 write_byte(0x0040, media_state_offset
, media_state
);
6878 floppy_drive_recal(drive
)
6882 Bit16u curr_cyl_offset
;
6884 floppy_prepare_controller(drive
);
6886 // send Recalibrate command (2 bytes) to controller
6887 outb(0x03f5, 0x07); // 07: Recalibrate
6888 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6890 // turn on interrupts
6895 // wait on 40:3e bit 7 to become 1
6897 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6898 } while ( val8
== 0 );
6900 val8
= 0; // separate asm from while() loop
6901 // turn off interrupts
6906 // set 40:3e bit 7 to 0, and calibrated bit
6907 val8
= read_byte(0x0040, 0x003e);
6910 val8
|= 0x02; // Drive 1 calibrated
6911 curr_cyl_offset
= 0x0095;
6913 val8
|= 0x01; // Drive 0 calibrated
6914 curr_cyl_offset
= 0x0094;
6916 write_byte(0x0040, 0x003e, val8
);
6917 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6925 floppy_drive_exists(drive
)
6930 // check CMOS to see if drive exists
6931 drive_type
= inb_cmos(0x10);
6936 if ( drive_type
== 0 )
6943 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6944 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6946 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6947 Bit16u base_address
, base_count
, base_es
;
6948 Bit8u page
, mode_register
, val8
, dor
;
6949 Bit8u return_status
[7];
6950 Bit8u drive_type
, num_floppies
, ah
;
6951 Bit16u es
, last_addr
;
6953 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6958 case 0x00: // diskette controller reset
6959 BX_DEBUG_INT13_FL("floppy f00\n");
6962 SET_AH(1); // invalid param
6963 set_diskette_ret_status(1);
6967 drive_type
= inb_cmos(0x10);
6973 if (drive_type
== 0) {
6974 SET_AH(0x80); // drive not responding
6975 set_diskette_ret_status(0x80);
6980 set_diskette_ret_status(0);
6981 CLEAR_CF(); // successful
6982 set_diskette_current_cyl(drive
, 0); // current cylinder
6985 case 0x01: // Read Diskette Status
6987 val8
= read_byte(0x0000, 0x0441);
6994 case 0x02: // Read Diskette Sectors
6995 case 0x03: // Write Diskette Sectors
6996 case 0x04: // Verify Diskette Sectors
6997 num_sectors
= GET_AL();
7003 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
7004 (num_sectors
== 0) || (num_sectors
> 72)) {
7005 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
7007 set_diskette_ret_status(1);
7008 SET_AL(0); // no sectors read
7009 SET_CF(); // error occurred
7013 // see if drive exists
7014 if (floppy_drive_exists(drive
) == 0) {
7015 SET_AH(0x80); // not responding
7016 set_diskette_ret_status(0x80);
7017 SET_AL(0); // no sectors read
7018 SET_CF(); // error occurred
7022 // see if media in drive, and type is known
7023 if (floppy_media_known(drive
) == 0) {
7024 if (floppy_media_sense(drive
) == 0) {
7025 SET_AH(0x0C); // Media type not found
7026 set_diskette_ret_status(0x0C);
7027 SET_AL(0); // no sectors read
7028 SET_CF(); // error occurred
7034 // Read Diskette Sectors
7036 //-----------------------------------
7037 // set up DMA controller for transfer
7038 //-----------------------------------
7040 // es:bx = pointer to where to place information from diskette
7041 // port 04: DMA-1 base and current address, channel 2
7042 // port 05: DMA-1 base and current count, channel 2
7043 page
= (ES
>> 12); // upper 4 bits
7044 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7045 base_address
= base_es
+ BX
; // lower 16 bits of address
7046 // contributed by ES:BX
7047 if ( base_address
< base_es
) {
7048 // in case of carry, adjust page by 1
7051 base_count
= (num_sectors
* 512) - 1;
7053 // check for 64K boundary overrun
7054 last_addr
= base_address
+ base_count
;
7055 if (last_addr
< base_address
) {
7057 set_diskette_ret_status(0x09);
7058 SET_AL(0); // no sectors read
7059 SET_CF(); // error occurred
7063 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7066 BX_DEBUG_INT13_FL("clear flip-flop\n");
7067 outb(0x000c, 0x00); // clear flip-flop
7068 outb(0x0004, base_address
);
7069 outb(0x0004, base_address
>>8);
7070 BX_DEBUG_INT13_FL("clear flip-flop\n");
7071 outb(0x000c, 0x00); // clear flip-flop
7072 outb(0x0005, base_count
);
7073 outb(0x0005, base_count
>>8);
7075 // port 0b: DMA-1 Mode Register
7076 mode_register
= 0x46; // single mode, increment, autoinit disable,
7077 // transfer type=write, channel 2
7078 BX_DEBUG_INT13_FL("setting mode register\n");
7079 outb(0x000b, mode_register
);
7081 BX_DEBUG_INT13_FL("setting page register\n");
7082 // port 81: DMA-1 Page Register, channel 2
7085 BX_DEBUG_INT13_FL("unmask chan 2\n");
7086 outb(0x000a, 0x02); // unmask channel 2
7088 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7091 //--------------------------------------
7092 // set up floppy controller for transfer
7093 //--------------------------------------
7094 floppy_prepare_controller(drive
);
7096 // send read-normal-data command (9 bytes) to controller
7097 outb(0x03f5, 0xe6); // e6: read normal data
7098 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7099 outb(0x03f5, track
);
7101 outb(0x03f5, sector
);
7102 outb(0x03f5, 2); // 512 byte sector size
7103 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
7104 outb(0x03f5, 0); // Gap length
7105 outb(0x03f5, 0xff); // Gap length
7107 // turn on interrupts
7112 // wait on 40:3e bit 7 to become 1
7114 val8
= read_byte(0x0040, 0x0040);
7116 floppy_reset_controller();
7117 SET_AH(0x80); // drive not ready (timeout)
7118 set_diskette_ret_status(0x80);
7119 SET_AL(0); // no sectors read
7120 SET_CF(); // error occurred
7123 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7124 } while ( val8
== 0 );
7126 val8
= 0; // separate asm from while() loop
7127 // turn off interrupts
7132 // set 40:3e bit 7 to 0
7133 val8
= read_byte(0x0040, 0x003e);
7135 write_byte(0x0040, 0x003e, val8
);
7137 // check port 3f4 for accessibility to status bytes
7139 if ( (val8
& 0xc0) != 0xc0 )
7140 BX_PANIC("int13_diskette: ctrl not ready\n");
7142 // read 7 return status bytes from controller
7143 // using loop index broken, have to unroll...
7144 return_status
[0] = inb(0x3f5);
7145 return_status
[1] = inb(0x3f5);
7146 return_status
[2] = inb(0x3f5);
7147 return_status
[3] = inb(0x3f5);
7148 return_status
[4] = inb(0x3f5);
7149 return_status
[5] = inb(0x3f5);
7150 return_status
[6] = inb(0x3f5);
7151 // record in BIOS Data Area
7152 write_byte(0x0040, 0x0042, return_status
[0]);
7153 write_byte(0x0040, 0x0043, return_status
[1]);
7154 write_byte(0x0040, 0x0044, return_status
[2]);
7155 write_byte(0x0040, 0x0045, return_status
[3]);
7156 write_byte(0x0040, 0x0046, return_status
[4]);
7157 write_byte(0x0040, 0x0047, return_status
[5]);
7158 write_byte(0x0040, 0x0048, return_status
[6]);
7160 if ( (return_status
[0] & 0xc0) != 0 ) {
7162 set_diskette_ret_status(0x20);
7163 SET_AL(0); // no sectors read
7164 SET_CF(); // error occurred
7168 // ??? should track be new val from return_status[3] ?
7169 set_diskette_current_cyl(drive
, track
);
7170 // AL = number of sectors read (same value as passed)
7171 SET_AH(0x00); // success
7172 CLEAR_CF(); // success
7174 } else if (ah
== 0x03) {
7175 // Write Diskette Sectors
7177 //-----------------------------------
7178 // set up DMA controller for transfer
7179 //-----------------------------------
7181 // es:bx = pointer to where to place information from diskette
7182 // port 04: DMA-1 base and current address, channel 2
7183 // port 05: DMA-1 base and current count, channel 2
7184 page
= (ES
>> 12); // upper 4 bits
7185 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7186 base_address
= base_es
+ BX
; // lower 16 bits of address
7187 // contributed by ES:BX
7188 if ( base_address
< base_es
) {
7189 // in case of carry, adjust page by 1
7192 base_count
= (num_sectors
* 512) - 1;
7194 // check for 64K boundary overrun
7195 last_addr
= base_address
+ base_count
;
7196 if (last_addr
< base_address
) {
7198 set_diskette_ret_status(0x09);
7199 SET_AL(0); // no sectors read
7200 SET_CF(); // error occurred
7204 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7207 outb(0x000c, 0x00); // clear flip-flop
7208 outb(0x0004, base_address
);
7209 outb(0x0004, base_address
>>8);
7210 outb(0x000c, 0x00); // clear flip-flop
7211 outb(0x0005, base_count
);
7212 outb(0x0005, base_count
>>8);
7214 // port 0b: DMA-1 Mode Register
7215 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7216 // transfer type=read, channel 2
7217 outb(0x000b, mode_register
);
7219 // port 81: DMA-1 Page Register, channel 2
7222 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7225 //--------------------------------------
7226 // set up floppy controller for transfer
7227 //--------------------------------------
7228 floppy_prepare_controller(drive
);
7230 // send write-normal-data command (9 bytes) to controller
7231 outb(0x03f5, 0xc5); // c5: write normal data
7232 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7233 outb(0x03f5, track
);
7235 outb(0x03f5, sector
);
7236 outb(0x03f5, 2); // 512 byte sector size
7237 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7238 outb(0x03f5, 0); // Gap length
7239 outb(0x03f5, 0xff); // Gap length
7241 // turn on interrupts
7246 // wait on 40:3e bit 7 to become 1
7248 val8
= read_byte(0x0040, 0x0040);
7250 floppy_reset_controller();
7251 SET_AH(0x80); // drive not ready (timeout)
7252 set_diskette_ret_status(0x80);
7253 SET_AL(0); // no sectors written
7254 SET_CF(); // error occurred
7257 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7258 } while ( val8
== 0 );
7260 val8
= 0; // separate asm from while() loop
7261 // turn off interrupts
7266 // set 40:3e bit 7 to 0
7267 val8
= read_byte(0x0040, 0x003e);
7269 write_byte(0x0040, 0x003e, val8
);
7271 // check port 3f4 for accessibility to status bytes
7273 if ( (val8
& 0xc0) != 0xc0 )
7274 BX_PANIC("int13_diskette: ctrl not ready\n");
7276 // read 7 return status bytes from controller
7277 // using loop index broken, have to unroll...
7278 return_status
[0] = inb(0x3f5);
7279 return_status
[1] = inb(0x3f5);
7280 return_status
[2] = inb(0x3f5);
7281 return_status
[3] = inb(0x3f5);
7282 return_status
[4] = inb(0x3f5);
7283 return_status
[5] = inb(0x3f5);
7284 return_status
[6] = inb(0x3f5);
7285 // record in BIOS Data Area
7286 write_byte(0x0040, 0x0042, return_status
[0]);
7287 write_byte(0x0040, 0x0043, return_status
[1]);
7288 write_byte(0x0040, 0x0044, return_status
[2]);
7289 write_byte(0x0040, 0x0045, return_status
[3]);
7290 write_byte(0x0040, 0x0046, return_status
[4]);
7291 write_byte(0x0040, 0x0047, return_status
[5]);
7292 write_byte(0x0040, 0x0048, return_status
[6]);
7294 if ( (return_status
[0] & 0xc0) != 0 ) {
7295 if ( (return_status
[1] & 0x02) != 0 ) {
7296 // diskette not writable.
7297 // AH=status code=0x03 (tried to write on write-protected disk)
7298 // AL=number of sectors written=0
7303 BX_PANIC("int13_diskette_function: read error\n");
7307 // ??? should track be new val from return_status[3] ?
7308 set_diskette_current_cyl(drive
, track
);
7309 // AL = number of sectors read (same value as passed)
7310 SET_AH(0x00); // success
7311 CLEAR_CF(); // success
7313 } else { // if (ah == 0x04)
7314 // Verify Diskette Sectors
7316 // ??? should track be new val from return_status[3] ?
7317 set_diskette_current_cyl(drive
, track
);
7318 // AL = number of sectors verified (same value as passed)
7319 CLEAR_CF(); // success
7320 SET_AH(0x00); // success
7325 case 0x05: // format diskette track
7326 BX_DEBUG_INT13_FL("floppy f05\n");
7328 num_sectors
= GET_AL();
7333 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7334 (num_sectors
== 0) || (num_sectors
> 18)) {
7336 set_diskette_ret_status(1);
7337 SET_CF(); // error occurred
7340 // see if drive exists
7341 if (floppy_drive_exists(drive
) == 0) {
7342 SET_AH(0x80); // drive not responding
7343 set_diskette_ret_status(0x80);
7344 SET_CF(); // error occurred
7348 // see if media in drive, and type is known
7349 if (floppy_media_known(drive
) == 0) {
7350 if (floppy_media_sense(drive
) == 0) {
7351 SET_AH(0x0C); // Media type not found
7352 set_diskette_ret_status(0x0C);
7353 SET_AL(0); // no sectors read
7354 SET_CF(); // error occurred
7359 // set up DMA controller for transfer
7360 page
= (ES
>> 12); // upper 4 bits
7361 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7362 base_address
= base_es
+ BX
; // lower 16 bits of address
7363 // contributed by ES:BX
7364 if ( base_address
< base_es
) {
7365 // in case of carry, adjust page by 1
7368 base_count
= (num_sectors
* 4) - 1;
7370 // check for 64K boundary overrun
7371 last_addr
= base_address
+ base_count
;
7372 if (last_addr
< base_address
) {
7374 set_diskette_ret_status(0x09);
7375 SET_AL(0); // no sectors read
7376 SET_CF(); // error occurred
7381 outb(0x000c, 0x00); // clear flip-flop
7382 outb(0x0004, base_address
);
7383 outb(0x0004, base_address
>>8);
7384 outb(0x000c, 0x00); // clear flip-flop
7385 outb(0x0005, base_count
);
7386 outb(0x0005, base_count
>>8);
7387 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7388 // transfer type=read, channel 2
7389 outb(0x000b, mode_register
);
7390 // port 81: DMA-1 Page Register, channel 2
7394 // set up floppy controller for transfer
7395 floppy_prepare_controller(drive
);
7397 // send format-track command (6 bytes) to controller
7398 outb(0x03f5, 0x4d); // 4d: format track
7399 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7400 outb(0x03f5, 2); // 512 byte sector size
7401 outb(0x03f5, num_sectors
); // number of sectors per track
7402 outb(0x03f5, 0); // Gap length
7403 outb(0x03f5, 0xf6); // Fill byte
7404 // turn on interrupts
7409 // wait on 40:3e bit 7 to become 1
7411 val8
= read_byte(0x0040, 0x0040);
7413 floppy_reset_controller();
7414 SET_AH(0x80); // drive not ready (timeout)
7415 set_diskette_ret_status(0x80);
7416 SET_CF(); // error occurred
7419 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7420 } while ( val8
== 0 );
7422 val8
= 0; // separate asm from while() loop
7423 // turn off interrupts
7427 // set 40:3e bit 7 to 0
7428 val8
= read_byte(0x0040, 0x003e);
7430 write_byte(0x0040, 0x003e, val8
);
7431 // check port 3f4 for accessibility to status bytes
7433 if ( (val8
& 0xc0) != 0xc0 )
7434 BX_PANIC("int13_diskette: ctrl not ready\n");
7436 // read 7 return status bytes from controller
7437 // using loop index broken, have to unroll...
7438 return_status
[0] = inb(0x3f5);
7439 return_status
[1] = inb(0x3f5);
7440 return_status
[2] = inb(0x3f5);
7441 return_status
[3] = inb(0x3f5);
7442 return_status
[4] = inb(0x3f5);
7443 return_status
[5] = inb(0x3f5);
7444 return_status
[6] = inb(0x3f5);
7445 // record in BIOS Data Area
7446 write_byte(0x0040, 0x0042, return_status
[0]);
7447 write_byte(0x0040, 0x0043, return_status
[1]);
7448 write_byte(0x0040, 0x0044, return_status
[2]);
7449 write_byte(0x0040, 0x0045, return_status
[3]);
7450 write_byte(0x0040, 0x0046, return_status
[4]);
7451 write_byte(0x0040, 0x0047, return_status
[5]);
7452 write_byte(0x0040, 0x0048, return_status
[6]);
7454 if ( (return_status
[0] & 0xc0) != 0 ) {
7455 if ( (return_status
[1] & 0x02) != 0 ) {
7456 // diskette not writable.
7457 // AH=status code=0x03 (tried to write on write-protected disk)
7458 // AL=number of sectors written=0
7463 BX_PANIC("int13_diskette_function: write error\n");
7468 set_diskette_ret_status(0);
7469 set_diskette_current_cyl(drive
, 0);
7470 CLEAR_CF(); // successful
7474 case 0x08: // read diskette drive parameters
7475 BX_DEBUG_INT13_FL("floppy f08\n");
7485 SET_DL(num_floppies
);
7490 drive_type
= inb_cmos(0x10);
7492 if (drive_type
& 0xf0)
7494 if (drive_type
& 0x0f)
7506 SET_DL(num_floppies
);
7508 switch (drive_type
) {
7511 SET_DH(0); // max head #
7514 case 1: // 360KB, 5.25"
7515 CX
= 0x2709; // 40 tracks, 9 sectors
7516 SET_DH(1); // max head #
7519 case 2: // 1.2MB, 5.25"
7520 CX
= 0x4f0f; // 80 tracks, 15 sectors
7521 SET_DH(1); // max head #
7524 case 3: // 720KB, 3.5"
7525 CX
= 0x4f09; // 80 tracks, 9 sectors
7526 SET_DH(1); // max head #
7529 case 4: // 1.44MB, 3.5"
7530 CX
= 0x4f12; // 80 tracks, 18 sectors
7531 SET_DH(1); // max head #
7534 case 5: // 2.88MB, 3.5"
7535 CX
= 0x4f24; // 80 tracks, 36 sectors
7536 SET_DH(1); // max head #
7539 case 6: // 160k, 5.25"
7540 CX
= 0x2708; // 40 tracks, 8 sectors
7541 SET_DH(0); // max head #
7544 case 7: // 180k, 5.25"
7545 CX
= 0x2709; // 40 tracks, 9 sectors
7546 SET_DH(0); // max head #
7549 case 8: // 320k, 5.25"
7550 CX
= 0x2708; // 40 tracks, 8 sectors
7551 SET_DH(1); // max head #
7555 BX_PANIC("floppy: int13: bad floppy type\n");
7558 /* set es & di to point to 11 byte diskette param table in ROM */
7562 mov ax
, #diskette_param_table2
7563 mov _int13_diskette_function
.DI
+2[bp
], ax
7564 mov _int13_diskette_function
.ES
+2[bp
], cs
7567 CLEAR_CF(); // success
7568 /* disk status not changed upon success */
7572 case 0x15: // read diskette drive type
7573 BX_DEBUG_INT13_FL("floppy f15\n");
7576 SET_AH(0); // only 2 drives supported
7577 // set_diskette_ret_status here ???
7581 drive_type
= inb_cmos(0x10);
7587 CLEAR_CF(); // successful, not present
7588 if (drive_type
==0) {
7589 SET_AH(0); // drive not present
7592 SET_AH(1); // drive present, does not support change line
7597 case 0x16: // get diskette change line status
7598 BX_DEBUG_INT13_FL("floppy f16\n");
7601 SET_AH(0x01); // invalid drive
7602 set_diskette_ret_status(0x01);
7607 SET_AH(0x06); // change line not supported
7608 set_diskette_ret_status(0x06);
7612 case 0x17: // set diskette type for format(old)
7613 BX_DEBUG_INT13_FL("floppy f17\n");
7614 /* not used for 1.44M floppies */
7615 SET_AH(0x01); // not supported
7616 set_diskette_ret_status(1); /* not supported */
7620 case 0x18: // set diskette type for format(new)
7621 BX_DEBUG_INT13_FL("floppy f18\n");
7622 SET_AH(0x01); // do later
7623 set_diskette_ret_status(1);
7628 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7630 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7631 SET_AH(0x01); // ???
7632 set_diskette_ret_status(1);
7638 #else // #if BX_SUPPORT_FLOPPY
7640 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7641 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7645 switch ( GET_AH() ) {
7647 case 0x01: // Read Diskette Status
7649 val8
= read_byte(0x0000, 0x0441);
7658 write_byte(0x0000, 0x0441, 0x01);
7662 #endif // #if BX_SUPPORT_FLOPPY
7665 set_diskette_ret_status(value
)
7668 write_byte(0x0040, 0x0041, value
);
7672 set_diskette_current_cyl(drive
, cyl
)
7677 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7678 write_byte(0x0040, 0x0094+drive
, cyl
);
7682 determine_floppy_media(drive
)
7686 Bit8u val8
, DOR
, ctrl_info
;
7688 ctrl_info
= read_byte(0x0040, 0x008F);
7696 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7699 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7703 if ( (ctrl_info
& 0x04) != 0x04 ) {
7704 // Drive not determined means no drive exists, done.
7709 // check Main Status Register for readiness
7710 val8
= inb(0x03f4) & 0x80; // Main Status Register
7712 BX_PANIC("d_f_m: MRQ bit not set\n");
7716 // existing BDA values
7718 // turn on drive motor
7719 outb(0x03f2, DOR
); // Digital Output Register
7722 BX_PANIC("d_f_m: OK so far\n");
7727 int17_function(regs
, ds
, iret_addr
)
7728 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7729 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7730 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7732 Bit16u addr
,timeout
;
7739 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7740 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7741 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7742 if (regs
.u
.r8
.ah
== 0) {
7743 outb(addr
, regs
.u
.r8
.al
);
7745 outb(addr
+2, val8
| 0x01); // send strobe
7749 outb(addr
+2, val8
& ~0x01);
7750 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7754 if (regs
.u
.r8
.ah
== 1) {
7756 outb(addr
+2, val8
& ~0x04); // send init
7760 outb(addr
+2, val8
| 0x04);
7763 regs
.u
.r8
.ah
= (val8
^ 0x48);
7764 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7765 ClearCF(iret_addr
.flags
);
7767 SetCF(iret_addr
.flags
); // Unsupported
7772 int19_function(seq_nr
)
7775 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7785 // if BX_ELTORITO_BOOT is not defined, old behavior
7786 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7787 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7788 // 0: system boot sequence, first drive C: then A:
7789 // 1: system boot sequence, first drive A: then C:
7790 // else BX_ELTORITO_BOOT is defined
7791 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7792 // CMOS reg 0x3D & 0x0f : 1st boot device
7793 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7794 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7795 // boot device codes:
7796 // 0x00 : not defined
7797 // 0x01 : first floppy
7798 // 0x02 : first harddrive
7799 // 0x03 : first cdrom
7800 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7801 // else : boot failure
7803 // Get the boot sequence
7804 #if BX_ELTORITO_BOOT
7805 bootdev
= inb_cmos(0x3d);
7806 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
7807 bootdev
>>= 4 * seq_nr
;
7809 if (bootdev
== 0) BX_PANIC("No bootable device.\n");
7811 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7814 if (seq_nr
==2) BX_PANIC("No more boot devices.");
7815 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
7816 /* Boot from floppy if the bit is set or it's the second boot */
7822 /* Read the boot device from the IPL table */
7823 if (get_boot_vector(bootdev
, &e
) == 0) {
7824 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
7828 /* Do the loading, and set up vector as a far pointer to the boot
7829 * address, and bootdrv as the boot drive */
7830 print_boot_device(e
.type
);
7833 case IPL_TYPE_FLOPPY
: /* FDD */
7834 case IPL_TYPE_HARDDISK
: /* HDD */
7836 bootdrv
= (e
.type
== IPL_TYPE_HARDDISK
) ? 0x80 : 0x00;
7848 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7849 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7850 mov es
, ax
;; segment
7851 xor bx
, bx
;; offset
7852 mov ah
, #0x02 ;; function 2, read diskette sector
7853 mov al
, #0x01 ;; read 1 sector
7854 mov ch
, #0x00 ;; track 0
7855 mov cl
, #0x01 ;; sector 1
7856 mov dh
, #0x00 ;; head 0
7857 int #0x13 ;; read sector
7860 mov _int19_function
.status
+ 2[bp
], ax
7871 print_boot_failure(e
.type
, 1);
7875 /* Always check the signature on a HDD boot sector; on FDD, only do
7876 * the check if the CMOS doesn't tell us to skip it */
7877 if ((e
.type
!= IPL_TYPE_FLOPPY
) || !((inb_cmos(0x38) & 0x01))) {
7878 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7879 print_boot_failure(e
.type
, 0);
7884 /* Canonicalize bootseg:bootip */
7885 bootip
= (bootseg
& 0x0fff) << 4;
7889 #if BX_ELTORITO_BOOT
7890 case IPL_TYPE_CDROM
: /* CD-ROM */
7891 status
= cdrom_boot();
7894 if ( (status
& 0x00ff) !=0 ) {
7895 print_cdromboot_failure(status
);
7896 print_boot_failure(e
.type
, 1);
7900 bootdrv
= (Bit8u
)(status
>>8);
7901 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7902 /* Canonicalize bootseg:bootip */
7903 bootip
= (bootseg
& 0x0fff) << 4;
7908 case IPL_TYPE_BEV
: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7909 bootseg
= e
.vector
>> 16;
7910 bootip
= e
.vector
& 0xffff;
7916 /* Debugging info */
7917 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
7919 /* Jump to the boot vector */
7922 ;; Build an iret stack frame that will take us to the boot vector
.
7923 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
7925 mov ax
, _int19_function
.bootseg
+ 0[bp
]
7927 mov ax
, _int19_function
.bootip
+ 0[bp
]
7929 ;; Set the magic number in ax
and the boot drive in dl
.
7931 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
7932 ;; Zero some of the other registers
.
7943 int1a_function(regs
, ds
, iret_addr
)
7944 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7945 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7946 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7950 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
);
7956 switch (regs
.u
.r8
.ah
) {
7957 case 0: // get current clock count
7961 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7962 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7963 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7964 BiosData
->midnight_flag
= 0; // reset flag
7969 ClearCF(iret_addr
.flags
); // OK
7972 case 1: // Set Current Clock Count
7976 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7977 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7978 BiosData
->midnight_flag
= 0; // reset flag
7983 ClearCF(iret_addr
.flags
); // OK
7987 case 2: // Read CMOS Time
7988 if (rtc_updating()) {
7989 SetCF(iret_addr
.flags
);
7993 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7994 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7995 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7996 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7998 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7999 ClearCF(iret_addr
.flags
); // OK
8002 case 3: // Set CMOS Time
8003 // Using a debugger, I notice the following masking/setting
8004 // of bits in Status Register B, by setting Reg B to
8005 // a few values and getting its value after INT 1A was called.
8007 // try#1 try#2 try#3
8008 // before 1111 1101 0111 1101 0000 0000
8009 // after 0110 0010 0110 0010 0000 0010
8011 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8012 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8013 if (rtc_updating()) {
8015 // fall through as if an update were not in progress
8017 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
8018 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
8019 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
8020 // Set Daylight Savings time enabled bit to requested value
8021 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
8022 // (reg B already selected)
8023 outb_cmos(0x0b, val8
);
8025 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8026 ClearCF(iret_addr
.flags
); // OK
8029 case 4: // Read CMOS Date
8031 if (rtc_updating()) {
8032 SetCF(iret_addr
.flags
);
8035 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
8036 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
8037 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
8038 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
8039 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8040 ClearCF(iret_addr
.flags
); // OK
8043 case 5: // Set CMOS Date
8044 // Using a debugger, I notice the following masking/setting
8045 // of bits in Status Register B, by setting Reg B to
8046 // a few values and getting its value after INT 1A was called.
8048 // try#1 try#2 try#3 try#4
8049 // before 1111 1101 0111 1101 0000 0010 0000 0000
8050 // after 0110 1101 0111 1101 0000 0010 0000 0000
8052 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8053 // My assumption: RegB = (RegB & 01111111b)
8054 if (rtc_updating()) {
8056 SetCF(iret_addr
.flags
);
8059 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
8060 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
8061 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
8062 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
8063 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8064 outb_cmos(0x0b, val8
);
8066 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
8067 ClearCF(iret_addr
.flags
); // OK
8070 case 6: // Set Alarm Time in CMOS
8071 // Using a debugger, I notice the following masking/setting
8072 // of bits in Status Register B, by setting Reg B to
8073 // a few values and getting its value after INT 1A was called.
8075 // try#1 try#2 try#3
8076 // before 1101 1111 0101 1111 0000 0000
8077 // after 0110 1111 0111 1111 0010 0000
8079 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8080 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8081 val8
= inb_cmos(0x0b); // Get Status Reg B
8084 // Alarm interrupt enabled already
8085 SetCF(iret_addr
.flags
); // Error: alarm in use
8088 if (rtc_updating()) {
8090 // fall through as if an update were not in progress
8092 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
8093 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
8094 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
8095 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8096 // enable Status Reg B alarm bit, clear halt clock bit
8097 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
8098 ClearCF(iret_addr
.flags
); // OK
8101 case 7: // Turn off Alarm
8102 // Using a debugger, I notice the following masking/setting
8103 // of bits in Status Register B, by setting Reg B to
8104 // a few values and getting its value after INT 1A was called.
8106 // try#1 try#2 try#3 try#4
8107 // before 1111 1101 0111 1101 0010 0000 0010 0010
8108 // after 0100 0101 0101 0101 0000 0000 0000 0010
8110 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8111 // My assumption: RegB = (RegB & 01010111b)
8112 val8
= inb_cmos(0x0b); // Get Status Reg B
8113 // clear clock-halt bit, disable alarm bit
8114 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
8116 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8117 ClearCF(iret_addr
.flags
); // OK
8121 // real mode PCI BIOS functions now handled in assembler code
8122 // this C code handles the error code for information only
8123 if (regs
.u
.r8
.bl
== 0xff) {
8124 BX_INFO("PCI BIOS: PCI not present\n");
8125 } else if (regs
.u
.r8
.bl
== 0x81) {
8126 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8127 } else if (regs
.u
.r8
.bl
== 0x83) {
8128 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8129 } else if (regs
.u
.r8
.bl
== 0x86) {
8130 if (regs
.u
.r8
.al
== 0x02) {
8131 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8133 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
);
8136 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8137 SetCF(iret_addr
.flags
);
8142 SetCF(iret_addr
.flags
); // Unsupported
8147 int70_function(regs
, ds
, iret_addr
)
8148 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8149 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8150 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8152 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8153 Bit8u registerB
= 0, registerC
= 0;
8155 // Check which modes are enabled and have occurred.
8156 registerB
= inb_cmos( 0xB );
8157 registerC
= inb_cmos( 0xC );
8159 if( ( registerB
& 0x60 ) != 0 ) {
8160 if( ( registerC
& 0x20 ) != 0 ) {
8161 // Handle Alarm Interrupt.
8168 if( ( registerC
& 0x40 ) != 0 ) {
8169 // Handle Periodic Interrupt.
8171 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8172 // Wait Interval (Int 15, AH=83) active.
8173 Bit32u time
, toggle
;
8175 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8176 if( time
< 0x3D1 ) {
8178 Bit16u segment
, offset
;
8180 segment
= read_word( 0x40, 0x98 );
8181 offset
= read_word( 0x40, 0x9A );
8182 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8183 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8184 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8186 // Continue waiting.
8188 write_dword( 0x40, 0x9C, time
);
8201 ;------------------------------------------
8202 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8203 ;------------------------------------------
8208 push
#0x00 ;; placeholder for status
8209 push
#0x00 ;; placeholder for X
8210 push
#0x00 ;; placeholder for Y
8211 push
#0x00 ;; placeholder for Z
8212 push
#0x00 ;; placeholder for make_far_call boolean
8213 call _int74_function
8214 pop cx
;; remove make_far_call from stack
8217 ;; make far call to EBDA
:0022
8220 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8222 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8227 add sp
, #8 ;; pop status, x, y, z
8229 pop ds
;; restore DS
8234 ;; This will perform an IRET
, but will retain value of current CF
8235 ;; by altering flags on stack
. Better than RETF
#02.
8240 and BYTE
[bp
+ 0x06], #0xfe
8246 or BYTE
[bp
+ 0x06], #0x01
8251 ;----------------------
8252 ;- INT13h (relocated
) -
8253 ;----------------------
8255 ; int13_relocated is a little bit messed up since I played with it
8256 ; I have to rewrite it
:
8257 ; - call a function that detect which function to call
8258 ; - make all called C function get the same parameters list
8262 #if BX_ELTORITO_BOOT
8263 ;; check
for an eltorito function
8265 jb int13_not_eltorito
8267 ja int13_not_eltorito
8276 jmp _int13_eltorito
;; ELDX
not used
8284 ;; check
if emulation active
8285 call _cdemu_isactive
8287 je int13_cdemu_inactive
8289 ;; check
if access to the emulated drive
8290 call _cdemu_emulated_drive
8293 cmp al
,dl
;; int13 on emulated drive
8308 jmp _int13_cdemu
;; ELDX
not used
8311 and dl
,#0xE0 ;; mask to get device class, including cdroms
8312 cmp al
,dl
;; al is
0x00 or 0x80
8313 jne int13_cdemu_inactive
;; inactive
for device
class
8325 dec dl
;; real drive is dl
- 1
8328 int13_cdemu_inactive
:
8334 #endif // BX_ELTORITO_BOOT
8345 push dx
;; push eltorito value of dx instead of sp
8356 ;; now the
16-bit registers can be restored with
:
8357 ;; pop ds
; pop es
; popa
; iret
8358 ;; arguments passed to functions should be
8359 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8365 jmp _int13_diskette_function
8374 // ebx is modified: BSD 5.2.1 boot loader problem
8375 // someone should figure out which 32 bit register that actually are used
8392 ;; int13_harddisk modifies high word of EAX
8395 call _int13_harddisk
8408 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8416 ;; Get the boot sequence number out of the IPL memory
8418 mov ds
, bx
;; Set segment
8419 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8421 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8422 mov ds
, ax
;; and reset the segment to zero
.
8424 ;; Carry on in the INT
19h handler
, using the
new sequence number
8432 int19_relocated
: ;; Boot function
, relocated
8434 ;; int19 was beginning to be really
complex, so now it
8435 ;; just calls a C function that does the work
8446 ;; Start from the first boot
device (0, in AX
)
8448 mov ds
, bx
;; Set segment to write to the IPL memory
8449 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8450 mov ds
, ax
;; and reset the segment
.
8456 ;; Call the C code
for the next boot device
8457 call _int19_function
8459 ;; Boot failed
: invoke the boot recovery function
8465 int1c_handler
: ;; User Timer Tick
8469 ;----------------------
8470 ;- POST
: Floppy Drive
-
8471 ;----------------------
8477 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8479 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8481 mov
0x0440, al
;; diskette motor timeout counter
: not active
8482 mov
0x0441, al
;; diskette controller status
return code
8484 mov
0x0442, al
;; disk
& diskette controller status
register 0
8485 mov
0x0443, al
;; diskette controller status
register 1
8486 mov
0x0444, al
;; diskette controller status
register 2
8487 mov
0x0445, al
;; diskette controller cylinder number
8488 mov
0x0446, al
;; diskette controller head number
8489 mov
0x0447, al
;; diskette controller sector number
8490 mov
0x0448, al
;; diskette controller bytes written
8492 mov
0x048b, al
;; diskette configuration data
8494 ;; -----------------------------------------------------------------
8495 ;; (048F
) diskette controller information
8497 mov al
, #0x10 ;; get CMOS diskette drive type
8500 mov ah
, al
;; save byte to AH
8503 shr al
, #4 ;; look at top 4 bits for drive 0
8504 jz f0_missing
;; jump
if no drive0
8505 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8508 mov bl
, #0x00 ;; no drive0
8511 mov al
, ah
;; restore from AH
8512 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8513 jz f1_missing
;; jump
if no drive1
8514 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8516 ;; leave high bits in BL zerod
8517 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8518 ;; -----------------------------------------------------------------
8521 mov
0x0490, al
;; diskette
0 media state
8522 mov
0x0491, al
;; diskette
1 media state
8524 ;; diskette
0,1 operational starting state
8525 ;; drive type has
not been determined
,
8526 ;; has no changed detection line
8530 mov
0x0494, al
;; diskette
0 current cylinder
8531 mov
0x0495, al
;; diskette
1 current cylinder
8534 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8536 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8537 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8538 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8543 ;--------------------
8544 ;- POST
: HARD DRIVE
-
8545 ;--------------------
8546 ; relocated here because the primary POST area isnt big enough
.
8549 // INT 76h calls INT 15h function ax=9100
8551 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8557 mov
0x0474, al
/* hard disk status of last operation */
8558 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8559 mov
0x048c, al
/* hard disk status register */
8560 mov
0x048d, al
/* hard disk error register */
8561 mov
0x048e, al
/* hard disk task complete flag */
8563 mov
0x0475, al
/* hard disk number attached */
8565 mov
0x0476, al
/* hard disk control byte */
8566 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8567 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8568 ;; INT
41h
: hard disk
0 configuration pointer
8569 ;; INT
46h
: hard disk
1 configuration pointer
8570 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8571 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8573 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8585 cmp al
, #47 ;; decimal 47 - user definable
8589 ;; CMOS purpose param table offset
8590 ;; 1b cylinders low
0
8591 ;; 1c cylinders high
1
8593 ;; 1e write pre
-comp low
5
8594 ;; 1f write pre
-comp high
6
8595 ;; 20 retries
/bad map
/heads
>8 8
8596 ;; 21 landing zone low C
8597 ;; 22 landing zone high D
8598 ;; 23 sectors
/track E
8603 ;;; Filling EBDA table
for hard disk
0.
8611 mov (0x003d + 0x05), ax
;; write precomp word
8616 mov (0x003d + 0x08), al
;; drive control byte
8625 mov (0x003d + 0x0C), ax
;; landing zone word
8627 mov al
, #0x1c ;; get cylinders word in AX
8629 in al
, #0x71 ;; high byte
8633 in al
, #0x71 ;; low byte
8634 mov bx
, ax
;; BX
= cylinders
8639 mov cl
, al
;; CL
= heads
8644 mov dl
, al
;; DL
= sectors
8647 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8649 hd0_post_physical_chs
:
8650 ;; no logical CHS mapping used
, just physical CHS
8651 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8652 mov (0x003d + 0x00), bx
;; number of physical cylinders
8653 mov (0x003d + 0x02), cl
;; number of physical heads
8654 mov (0x003d + 0x0E), dl
;; number of physical sectors
8657 hd0_post_logical_chs
:
8658 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8659 mov (0x003d + 0x09), bx
;; number of physical cylinders
8660 mov (0x003d + 0x0b), cl
;; number of physical heads
8661 mov (0x003d + 0x04), dl
;; number of physical sectors
8662 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8664 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8667 jnbe hd0_post_above_2048
8668 ;; 1024 < c
<= 2048 cylinders
8671 jmp hd0_post_store_logical
8673 hd0_post_above_2048
:
8675 jnbe hd0_post_above_4096
8676 ;; 2048 < c
<= 4096 cylinders
8679 jmp hd0_post_store_logical
8681 hd0_post_above_4096
:
8683 jnbe hd0_post_above_8192
8684 ;; 4096 < c
<= 8192 cylinders
8687 jmp hd0_post_store_logical
8689 hd0_post_above_8192
:
8690 ;; 8192 < c
<= 16384 cylinders
8694 hd0_post_store_logical
:
8695 mov (0x003d + 0x00), bx
;; number of physical cylinders
8696 mov (0x003d + 0x02), cl
;; number of physical heads
8698 mov cl
, #0x0f ;; repeat count
8699 mov si
, #0x003d ;; offset to disk0 FDPT
8700 mov al
, #0x00 ;; sum
8701 hd0_post_checksum_loop
:
8705 jnz hd0_post_checksum_loop
8706 not al
;; now take
2s complement
8709 ;;; Done filling EBDA table
for hard disk
0.
8713 ;; is there really a second hard disk
? if not, return now
8721 ;; check that the hd type is really
0x0f.
8726 ;; check that the extended type is
47 - user definable
8730 cmp al
, #47 ;; decimal 47 - user definable
8735 ;; CMOS purpose param table offset
8736 ;; 0x24 cylinders low
0
8737 ;; 0x25 cylinders high
1
8739 ;; 0x27 write pre
-comp low
5
8740 ;; 0x28 write pre
-comp high
6
8742 ;; 0x2a landing zone low C
8743 ;; 0x2b landing zone high D
8744 ;; 0x2c sectors
/track E
8745 ;;; Fill EBDA table
for hard disk
1.
8755 mov (0x004d + 0x05), ax
;; write precomp word
8760 mov (0x004d + 0x08), al
;; drive control byte
8769 mov (0x004d + 0x0C), ax
;; landing zone word
8771 mov al
, #0x25 ;; get cylinders word in AX
8773 in al
, #0x71 ;; high byte
8777 in al
, #0x71 ;; low byte
8778 mov bx
, ax
;; BX
= cylinders
8783 mov cl
, al
;; CL
= heads
8788 mov dl
, al
;; DL
= sectors
8791 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8793 hd1_post_physical_chs
:
8794 ;; no logical CHS mapping used
, just physical CHS
8795 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8796 mov (0x004d + 0x00), bx
;; number of physical cylinders
8797 mov (0x004d + 0x02), cl
;; number of physical heads
8798 mov (0x004d + 0x0E), dl
;; number of physical sectors
8801 hd1_post_logical_chs
:
8802 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8803 mov (0x004d + 0x09), bx
;; number of physical cylinders
8804 mov (0x004d + 0x0b), cl
;; number of physical heads
8805 mov (0x004d + 0x04), dl
;; number of physical sectors
8806 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8808 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8811 jnbe hd1_post_above_2048
8812 ;; 1024 < c
<= 2048 cylinders
8815 jmp hd1_post_store_logical
8817 hd1_post_above_2048
:
8819 jnbe hd1_post_above_4096
8820 ;; 2048 < c
<= 4096 cylinders
8823 jmp hd1_post_store_logical
8825 hd1_post_above_4096
:
8827 jnbe hd1_post_above_8192
8828 ;; 4096 < c
<= 8192 cylinders
8831 jmp hd1_post_store_logical
8833 hd1_post_above_8192
:
8834 ;; 8192 < c
<= 16384 cylinders
8838 hd1_post_store_logical
:
8839 mov (0x004d + 0x00), bx
;; number of physical cylinders
8840 mov (0x004d + 0x02), cl
;; number of physical heads
8842 mov cl
, #0x0f ;; repeat count
8843 mov si
, #0x004d ;; offset to disk0 FDPT
8844 mov al
, #0x00 ;; sum
8845 hd1_post_checksum_loop
:
8849 jnz hd1_post_checksum_loop
8850 not al
;; now take
2s complement
8853 ;;; Done filling EBDA table
for hard disk
1.
8857 ;--------------------
8858 ;- POST
: EBDA segment
8859 ;--------------------
8860 ; relocated here because the primary POST area isnt big enough
.
8865 mov byte ptr
[0x0], #EBDA_SIZE
8867 xor ax
, ax
; mov EBDA seg into
40E
8869 mov word ptr
[0x40E], #EBDA_SEG
8872 ;--------------------
8873 ;- POST
: EOI
+ jmp via
[0x40:67)
8874 ;--------------------
8875 ; relocated here because the primary POST area isnt big enough
.
8885 ;--------------------
8888 out
#0xA0, al ;; slave PIC EOI
8891 out
#0x20, al ;; master PIC EOI
8894 ;--------------------
8896 ;; in
: AL in BCD format
8897 ;; out
: AL in binary format
, AH will always be
0
8900 and bl
, #0x0f ;; bl has low digit
8901 shr al
, #4 ;; al has high digit
8903 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8904 add al
, bl
;; then add low digit
8907 ;--------------------
8909 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8910 ;; Timer Ticks Roller
Flag (0x470:byte
)
8911 ;; The Timer Ticks Count needs to be set according to
8912 ;; the current CMOS time
, as
if ticks have been occurring
8913 ;; at
18.2hz since midnight up to
this point
. Calculating
8914 ;; this is a little complicated
. Here are the factors I gather
8915 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8916 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8917 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8918 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8919 ;; the timer
. With a maximum
16bit timer count
, this is again
8920 ;; divided down by
65536 to
18.2hz
.
8922 ;; 14,318,180 Hz clock
8923 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8924 ;; /4 = 1,193,181 Hz fed to timer
8925 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8926 ;; 1 second
= 18.20650736 ticks
8927 ;; 1 minute
= 1092.390442 ticks
8928 ;; 1 hour
= 65543.42651 ticks
8930 ;; Given the values in the CMOS clock
, one could calculate
8931 ;; the number of ticks by the following
:
8932 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8933 ;; (BcdToBin(minutes
) * 1092.3904)
8934 ;; (BcdToBin(hours
) * 65543.427)
8935 ;; To get a little more accuracy
, since Im
using integer
8936 ;; arithmatic
, I use
:
8937 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8938 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8939 ;; (BcdToBin(hours
) * 65543427) / 1000
8944 xor eax
, eax
;; clear EAX
8947 in al
, #0x71 ;; AL has CMOS seconds in BCD
8948 call BcdToBin
;; EAX now has seconds in binary
8954 mov ecx
, eax
;; ECX will accumulate total ticks
8957 xor eax
, eax
;; clear EAX
8960 in al
, #0x71 ;; AL has CMOS minutes in BCD
8961 call BcdToBin
;; EAX now has minutes in binary
8967 add ecx
, eax
;; add to total ticks
8970 xor eax
, eax
;; clear EAX
8973 in al
, #0x71 ;; AL has CMOS hours in BCD
8974 call BcdToBin
;; EAX now has hours in binary
8980 add ecx
, eax
;; add to total ticks
8982 mov
0x46C, ecx
;; Timer Ticks Count
8984 mov
0x470, al
;; Timer Ticks Rollover Flag
8987 ;--------------------
8989 ;; record completion in BIOS task complete flag
9001 ;--------------------
9006 #include "apmbios.S"
9010 #include "apmbios.S"
9013 #include "apmbios.S"
9017 ;--------------------
9022 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9023 dw bios32_entry_point
, 0xf ;; 32 bit physical address
9024 db
0 ;; revision level
9025 ;; length in paragraphs
and checksum stored in a word to prevent errors
9026 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
9027 & 0xff) << 8) + 0x01
9028 db
0,0,0,0,0 ;; reserved
9033 cmp eax
, #0x49435024 ;; "$PCI"
9035 mov eax
, #0x80000000
9040 #ifdef PCI_FIXED_HOST_BRIDGE
9041 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9044 ;; say ok
if a device is present
9045 cmp eax
, #0xffffffff
9048 mov ebx
, #0x000f0000
9050 mov edx
, #pcibios_protected
9057 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9068 cmp al
, #0x01 ;; installation check
9072 mov edx
, #0x20494350 ;; "PCI "
9075 pci_pro_f02
: ;; find pci device
9083 call pci_pro_select_reg
9097 pci_pro_f03
: ;; find
class code
9103 call pci_pro_select_reg
9108 jne pci_pro_nextdev2
9115 jne pci_pro_devloop2
9118 pci_pro_f08
: ;; read configuration byte
9121 call pci_pro_select_reg
9130 pci_pro_f09
: ;; read configuration word
9133 call pci_pro_select_reg
9142 pci_pro_f0a
: ;; read configuration dword
9145 call pci_pro_select_reg
9152 pci_pro_f0b
: ;; write configuration byte
9155 call pci_pro_select_reg
9164 pci_pro_f0c
: ;; write configuration word
9167 call pci_pro_select_reg
9176 pci_pro_f0d
: ;; write configuration dword
9179 call pci_pro_select_reg
9192 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9202 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9226 mov eax
, #0x80000000
9231 #ifdef PCI_FIXED_HOST_BRIDGE
9232 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9235 ;; say ok
if a device is present
9236 cmp eax
, #0xffffffff
9247 cmp al
, #0x01 ;; installation check
9252 mov edx
, #0x20494350 ;; "PCI "
9254 mov di
, #pcibios_protected
9257 pci_real_f02
: ;; find pci device
9267 call pci_real_select_reg
9271 jne pci_real_nextdev
9278 jne pci_real_devloop
9283 pci_real_f03
: ;; find
class code
9289 call pci_real_select_reg
9294 jne pci_real_nextdev2
9301 jne pci_real_devloop2
9306 pci_real_f08
: ;; read configuration byte
9309 call pci_real_select_reg
9318 pci_real_f09
: ;; read configuration word
9321 call pci_real_select_reg
9330 pci_real_f0a
: ;; read configuration dword
9333 call pci_real_select_reg
9340 pci_real_f0b
: ;; write configuration byte
9343 call pci_real_select_reg
9352 pci_real_f0c
: ;; write configuration word
9355 call pci_real_select_reg
9364 pci_real_f0d
: ;; write configuration dword
9367 call pci_real_select_reg
9374 pci_real_f0e
: ;; get irq routing options
9376 jne pci_real_unknown
9378 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9379 jb pci_real_too_small
9381 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9389 mov si
, #pci_routing_table_structure_start
9397 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9406 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9410 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9428 pci_real_select_reg
:
9442 pci_routing_table_structure
:
9443 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9445 dw
32 + (6 * 16) ;; table size
9446 db
0 ;; PCI interrupt router bus
9447 db
0x08 ;; PCI interrupt router DevFunc
9448 dw
0x0000 ;; PCI exclusive IRQs
9449 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9450 dw
0x7000 ;; compatible PCI interrupt router device ID
9451 dw
0,0 ;; Miniport data
9452 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9454 pci_routing_table_structure_start
:
9455 ;; first slot entry PCI
-to
-ISA (embedded
)
9456 db
0 ;; pci bus number
9457 db
0x08 ;; pci device
number (bit
7-3)
9458 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9459 dw
0xdef8 ;; IRQ bitmap INTA
#
9460 db
0x61 ;; link value INTB
#
9461 dw
0xdef8 ;; IRQ bitmap INTB
#
9462 db
0x62 ;; link value INTC
#
9463 dw
0xdef8 ;; IRQ bitmap INTC
#
9464 db
0x63 ;; link value INTD
#
9465 dw
0xdef8 ;; IRQ bitmap INTD
#
9466 db
0 ;; physical
slot (0 = embedded
)
9468 ;; second slot entry
: 1st PCI slot
9469 db
0 ;; pci bus number
9470 db
0x10 ;; pci device
number (bit
7-3)
9471 db
0x61 ;; link value INTA
#
9472 dw
0xdef8 ;; IRQ bitmap INTA
#
9473 db
0x62 ;; link value INTB
#
9474 dw
0xdef8 ;; IRQ bitmap INTB
#
9475 db
0x63 ;; link value INTC
#
9476 dw
0xdef8 ;; IRQ bitmap INTC
#
9477 db
0x60 ;; link value INTD
#
9478 dw
0xdef8 ;; IRQ bitmap INTD
#
9479 db
1 ;; physical
slot (0 = embedded
)
9481 ;; third slot entry
: 2nd PCI slot
9482 db
0 ;; pci bus number
9483 db
0x18 ;; pci device
number (bit
7-3)
9484 db
0x62 ;; link value INTA
#
9485 dw
0xdef8 ;; IRQ bitmap INTA
#
9486 db
0x63 ;; link value INTB
#
9487 dw
0xdef8 ;; IRQ bitmap INTB
#
9488 db
0x60 ;; link value INTC
#
9489 dw
0xdef8 ;; IRQ bitmap INTC
#
9490 db
0x61 ;; link value INTD
#
9491 dw
0xdef8 ;; IRQ bitmap INTD
#
9492 db
2 ;; physical
slot (0 = embedded
)
9494 ;; 4th slot entry
: 3rd PCI slot
9495 db
0 ;; pci bus number
9496 db
0x20 ;; pci device
number (bit
7-3)
9497 db
0x63 ;; link value INTA
#
9498 dw
0xdef8 ;; IRQ bitmap INTA
#
9499 db
0x60 ;; link value INTB
#
9500 dw
0xdef8 ;; IRQ bitmap INTB
#
9501 db
0x61 ;; link value INTC
#
9502 dw
0xdef8 ;; IRQ bitmap INTC
#
9503 db
0x62 ;; link value INTD
#
9504 dw
0xdef8 ;; IRQ bitmap INTD
#
9505 db
3 ;; physical
slot (0 = embedded
)
9507 ;; 5th slot entry
: 4rd PCI slot
9508 db
0 ;; pci bus number
9509 db
0x28 ;; pci device
number (bit
7-3)
9510 db
0x60 ;; link value INTA
#
9511 dw
0xdef8 ;; IRQ bitmap INTA
#
9512 db
0x61 ;; link value INTB
#
9513 dw
0xdef8 ;; IRQ bitmap INTB
#
9514 db
0x62 ;; link value INTC
#
9515 dw
0xdef8 ;; IRQ bitmap INTC
#
9516 db
0x63 ;; link value INTD
#
9517 dw
0xdef8 ;; IRQ bitmap INTD
#
9518 db
4 ;; physical
slot (0 = embedded
)
9520 ;; 6th slot entry
: 5rd PCI slot
9521 db
0 ;; pci bus number
9522 db
0x30 ;; pci device
number (bit
7-3)
9523 db
0x61 ;; link value INTA
#
9524 dw
0xdef8 ;; IRQ bitmap INTA
#
9525 db
0x62 ;; link value INTB
#
9526 dw
0xdef8 ;; IRQ bitmap INTB
#
9527 db
0x63 ;; link value INTC
#
9528 dw
0xdef8 ;; IRQ bitmap INTC
#
9529 db
0x60 ;; link value INTD
#
9530 dw
0xdef8 ;; IRQ bitmap INTD
#
9531 db
5 ;; physical
slot (0 = embedded
)
9533 pci_routing_table_structure_end
:
9539 pcibios_init_sel_reg
:
9551 pcibios_init_iomem_bases
:
9554 mov eax
, #0xe0000000 ;; base for memory init
9556 mov ax
, #0xc000 ;; base for i/o init
9558 mov ax
, #0x0010 ;; start at base address #0
9563 call pcibios_init_sel_reg
9568 mov dl
, #0x04 ;; disable i/o and memory space access
9569 call pcibios_init_sel_reg
9576 call pcibios_init_sel_reg
9582 mov eax
, #0xffffffff
9587 xor eax
, #0xffffffff
9591 add eax
, ecx
;; calculate next free mem base
9592 add eax
, #0x01000000
9593 and eax
, #0xff000000
9607 add ax
, cx
;; calculate next free i
/o base
9615 je enable_iomem_space
9616 mov byte ptr
[bp
-8], al
9617 jmp pci_init_io_loop2
9619 mov dl
, #0x04 ;; enable i/o and memory space access if available
9620 call pcibios_init_sel_reg
9626 mov byte ptr
[bp
-8], #0x10
9629 jne pci_init_io_loop1
9634 pcibios_init_set_elcr
:
9658 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9663 mov si
, #pci_routing_table_structure
9667 call pcibios_init_sel_reg
9670 cmp eax
, [si
+12] ;; check irq router
9673 call pcibios_init_sel_reg
9674 push bx
;; save irq router bus
+ devfunc
9677 out dx
, ax
;; reset PIRQ route control
9684 add si
, #0x20 ;; set pointer to 1st entry
9686 mov ax
, #pci_irq_list
9695 call pcibios_init_sel_reg
9699 jnz pci_test_int_pin
9705 call pcibios_init_sel_reg
9710 dec al
;; determine pirq reg
9719 call pcibios_init_sel_reg
9726 mov bx
, [bp
-2] ;; pci irq list pointer
9731 call pcibios_init_set_elcr
9735 add bl
, [bp
-3] ;; pci function number
9737 call pcibios_init_sel_reg
9744 jnz pci_init_irq_loop2
9747 mov byte ptr
[bp
-3], #0x00
9748 loop pci_init_irq_loop1
9755 #endif // BX_ROMBIOS32
9756 #endif // BX_PCIBIOS
9760 ;; save a20
and enable it
9766 ;; save SS
:SP to the BDA
9773 lidt
[pmode_IDT_info
]
9775 lgdt
[rombios32_gdt_48
]
9776 ;; set PE bit in CR0
9780 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
9783 dw
0x000f ;; high
16 bit address
9788 ;; init data segments
9798 ;; copy rombios32 code to
ram (ram offset
= 1MB
)
9799 mov esi
, #0xfffe0000
9800 mov edi
, #0x00040000
9801 mov ecx
, #0x10000 / 4
9805 ;; init the stack pointer
9806 mov esp
, #0x00080000
9808 ;; call rombios32 code
9809 mov eax
, #0x00040000
9812 ;; reset the
memory (some boot loaders such as syslinux suppose
9813 ;; that the memory is set to zero
)
9814 mov edi
, #0x00040000
9815 mov ecx
, #0x40000 / 4
9820 ;; return to
16 bit
protected mode first
9827 ;; restore data segment limits to
0xffff
9835 ;; reset PE bit in CR0
9840 ;; far jump to flush CPU queue after transition to real mode
9841 JMP_AP(0xf000, rombios32_real_mode
)
9843 rombios32_real_mode
:
9844 ;; restore IDT to normal real
-mode defaults
9846 lidt
[rmode_IDT_info
]
9854 ;; restore SS
:SP from the BDA
9871 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
9872 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
9873 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
9874 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
9878 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9883 and al
, #0xdf ; clear input mode
9893 mov
[bx
+0x408], dx
; Parallel I
/O address
9895 mov
[bx
+0x478], cl
; Parallel printer timeout
9900 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9919 mov
[bx
+0x400], dx
; Serial I
/O address
9921 mov
[bx
+0x47c], cl
; Serial timeout
9948 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
9949 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
9957 ;; Scan
for existence of valid expansion ROMS
.
9958 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9959 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9960 ;; System ROM
: only
0xE0000
9966 ;; 2 ROM length in
512-byte blocks
9967 ;; 3 ROM initialization entry
point (FAR CALL
)
9972 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9973 cmp
[0], #0xAA55 ;; look for signature
9974 jne rom_scan_increment
9976 jnz rom_scan_increment
9977 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9979 ;; We want our increment in
512-byte quantities
, rounded to
9980 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9982 jz block_count_rounded
9983 and al
, #0xfc ;; needs rounding up
9985 block_count_rounded
:
9987 xor bx
, bx
;; Restore DS back to
0000:
9991 ;; Push addr of ROM entry point
9993 push
#0x0003 ;; Push offset
9995 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
9996 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
10001 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
10002 db
0xff ;; call_far ss
:[bp
+0]
10005 cli
;; In
case expansion ROM BIOS turns IF on
10006 add sp
, #2 ;; Pop offset value
10007 pop cx
;; Pop seg
value (restore CX
)
10009 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
10010 ;; to init all the ROMs
and then go back
and build an IPL table of
10011 ;; all the bootable devices
, but we can get away with one pass
.
10012 mov ds
, cx
;; ROM base
10013 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
10014 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
10015 cmp ax
, #0x5024 ;; we look for signature "$PnP"
10020 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
10021 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
10024 ;; Found a device that thinks it can boot the system
. Record its BEV
and product name string
.
10025 mov di
, 0x10[bx
] ;; Pointer to the product name string
or zero
if none
10026 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
10028 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
10029 cmp bx
, #IPL_TABLE_ENTRIES
10030 je no_bev
;; Get out
if the table is full
10031 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
10032 mov
0[bx
], #IPL_TYPE_BEV ;; This entry is a BEV device
10033 mov
6[bx
], cx
;; Build a far pointer from the segment
...
10034 mov
4[bx
], ax
;; and the offset
10037 mov
0xA[bx
], cx
;; Build a far pointer from the segment
...
10038 mov
8[bx
], di
;; and the offset
10040 shr bx
, #0x4 ;; Turn the offset back into a count
10041 inc bx
;; We have one more entry now
10042 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
10045 pop di
;; Restore DI
10046 pop ax
;; Restore AX
10047 rom_scan_increment
:
10048 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
10049 ;; because the segment selector is shifted left
4 bits
.
10051 pop ax
;; Restore AX
10055 xor ax
, ax
;; Restore DS back to
0000:
10059 ;; for 'C' strings
and other data
, insert them here with
10060 ;; a the following hack
:
10061 ;; DATA_SEG_DEFS_HERE
10064 ;; the following area can be used to write dynamically generated tables
10066 bios_table_area_start
:
10068 dd bios_table_area_end
- bios_table_area_start
- 8;
10073 .org
0xe05b ; POST Entry Point
10077 and eax
, #0x9fffffff
10082 ;; first reset the DMA controllers
10086 ;; then initialize the DMA controllers
10088 out
0xD6, al
; cascade mode of channel
4 enabled
10090 out
0xD4, al
; unmask channel
4
10092 ;; Examine CMOS shutdown status
.
10100 ;; Reset CMOS shutdown status
.
10102 out
0x70, AL
; select CMOS
register Fh
10104 out
0x71, AL
; set shutdown action to normal
10106 ;; Examine CMOS shutdown status
.
10109 ;; 0x00, 0x09, 0x0D+ = normal startup
10117 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
10121 ;; Examine CMOS shutdown status
.
10122 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
10124 call _shutdown_status_panic
10130 ; 0xb0, 0x20, /* mov al, #0x20 */
10131 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10141 ; case 0: normal startup
10150 ;; zero out BIOS data
area (40:00..40:ff
)
10152 mov cx
, #0x0080 ;; 128 words
10158 call _log_bios_start
10160 ;; set all interrupts to
default handler
10161 xor bx
, bx
;; offset index
10162 mov cx
, #0x0100 ;; counter (256 interrupts)
10163 mov ax
, #dummy_iret_handler
10171 loop post_default_ints
10173 ;; set vector
0x79 to zero
10174 ;; this is used by
'gardian angel' protection system
10175 SET_INT_VECTOR(0x79, #0, #0)
10177 ;; base memory in K
40:13 (word
)
10178 mov ax
, #BASE_MEM_IN_K
10182 ;; Manufacturing Test
40:12
10185 ;; Warm Boot Flag
0040:0072
10186 ;; value of
1234h
= skip memory checks
10190 ;; Printer Services vector
10191 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10193 ;; Bootstrap failure vector
10194 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10196 ;; Bootstrap Loader vector
10197 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10199 ;; User Timer Tick vector
10200 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10202 ;; Memory Size Check vector
10203 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10205 ;; Equipment Configuration Check vector
10206 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10209 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10215 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10216 ;; int 1C already points at
dummy_iret_handler (above
)
10217 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10219 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10224 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10225 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10229 mov
0x0417, al
/* keyboard shift flags, set 1 */
10230 mov
0x0418, al
/* keyboard shift flags, set 2 */
10231 mov
0x0419, al
/* keyboard alt-numpad work area */
10232 mov
0x0471, al
/* keyboard ctrl-break flag */
10233 mov
0x0497, al
/* keyboard status flags 4 */
10235 mov
0x0496, al
/* keyboard status flags 3 */
10238 /* keyboard head of buffer pointer */
10242 /* keyboard end of buffer pointer */
10245 /* keyboard pointer to start of buffer */
10249 /* keyboard pointer to end of buffer */
10253 /* init the keyboard */
10254 call _keyboard_init
10256 ;; mov CMOS Equipment Byte to BDA Equipment Word
10265 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10269 mov cl
, #0x14 ; timeout value
10270 mov dx
, #0x378 ; Parallel I/O address, port 1
10271 call detect_parport
10272 mov dx
, #0x278 ; Parallel I/O address, port 2
10273 call detect_parport
10275 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10277 or ax
, bx
; set number of parallel ports
10281 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10282 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10284 mov cl
, #0x0a ; timeout value
10285 mov dx
, #0x03f8 ; Serial I/O address, port 1
10287 mov dx
, #0x02f8 ; Serial I/O address, port 2
10289 mov dx
, #0x03e8 ; Serial I/O address, port 3
10291 mov dx
, #0x02e8 ; Serial I/O address, port 4
10294 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10296 or ax
, bx
; set number of serial port
10300 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10301 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10302 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10303 ;; BIOS DATA AREA
0x4CE ???
10304 call timer_tick_post
10306 ;; PS
/2 mouse setup
10307 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10309 ;; IRQ13 (FPU exception
) setup
10310 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10313 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10316 mov al
, #0x11 ; send initialisation commands
10331 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10332 #if BX_USE_PS2_MOUSE
10337 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10339 mov cx
, #0xc000 ;; init vga bios
10343 call _print_bios_banner
10346 call rombios32_init
10349 call pcibios_init_iomem_bases
10350 call pcibios_init_irqs
10351 #endif //BX_PCIBIOS
10357 call floppy_drive_post
10362 ;; Hard Drive setup
10364 call hard_drive_post
10367 ;; ATA
/ATAPI driver setup
10372 #else // BX_USE_ATADRV
10375 ;; Hard Drive setup
10377 call hard_drive_post
10379 #endif // BX_USE_ATADRV
10381 #if BX_ELTORITO_BOOT
10383 ;; eltorito floppy
/harddisk emulation from cd
10387 #endif // BX_ELTORITO_BOOT
10389 call _init_boot_vectors
10391 mov cx
, #0xc800 ;; init option roms
10395 sti
;; enable interrupts
10398 .org
0xe2c3 ; NMI Handler Entry Point
10400 ;; FIXME the NMI handler should
not panic
10401 ;; but iret when called from
int75 (fpu exception
)
10402 call _nmi_handler_msg
10406 out
0xf0, al
// clear irq13
10407 call eoi_both_pics
// clear interrupt
10408 int 2 // legacy nmi call
10411 ;-------------------------------------------
10412 ;- INT
13h Fixed Disk Services Entry Point
-
10413 ;-------------------------------------------
10414 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10416 //JMPL(int13_relocated)
10417 jmp int13_relocated
10419 .org
0xe401 ; Fixed Disk Parameter Table
10424 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10427 jmp int19_relocated
10428 ;-------------------------------------------
10429 ;- System BIOS Configuration Data Table
10430 ;-------------------------------------------
10431 .org BIOS_CONFIG_TABLE
10432 db
0x08 ; Table
size (bytes
) -Lo
10433 db
0x00 ; Table
size (bytes
) -Hi
10438 ; b7
: 1=DMA channel
3 used by hard disk
10439 ; b6
: 1=2 interrupt controllers present
10440 ; b5
: 1=RTC present
10441 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10442 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10443 ; b2
: 1=extended BIOS data area used
10444 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10445 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10449 (BX_CALL_INT15_4F
<< 4) | \
10451 (BX_USE_EBDA
<< 2) | \
10455 ; b7
: 1=32-bit DMA supported
10456 ; b6
: 1=int16h
, function
9 supported
10457 ; b5
: 1=int15h
/C6h (get POS data
) supported
10458 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10459 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10460 ; b2
: 1=non
-8042 kb controller
10461 ; b1
: 1=data streaming supported
10475 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10476 ; b3
: SCSI on system board
10477 ; b2
: info panel installed
10478 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10479 ; b0
: SCSI supported in IML
10483 ; b6
: EEPROM present
10484 ; b5
-3: ABIOS
presence (011 = not supported
)
10486 ; b1
: memory split above
16Mb supported
10487 ; b0
: POSTEXT directly supported by POST
10489 ; Feature byte
5 (IBM
)
10490 ; b1
: enhanced mouse
10496 .org
0xe729 ; Baud Rate Generator Table
10501 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10507 call _int14_function
10513 ;----------------------------------------
10514 ;- INT
16h Keyboard Service Entry Point
-
10515 ;----------------------------------------
10531 call _int16_function
10541 and BYTE
[bp
+ 0x06], #0xbf
10549 or BYTE
[bp
+ 0x06], #0x40
10557 int16_wait_for_key
:
10561 jne int16_key_found
10565 /* no key yet, call int 15h, function AX=9002 */
10566 0x50, /* push AX */
10567 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10568 0xcd, 0x15, /* int 15h */
10570 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10572 jmp int16_wait_for_key
10577 call _int16_function
10582 /* notify int16 complete w/ int 15h, function AX=9102 */
10583 0x50, /* push AX */
10584 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10585 0xcd, 0x15, /* int 15h */
10592 ;-------------------------------------------------
10593 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10594 ;-------------------------------------------------
10600 mov al
, #0xAD ;;disable keyboard
10609 in al
, #0x60 ;;read key from keyboard controller
10613 #ifdef BX_CALL_INT15_4F
10614 mov ah
, #0x4f ;; allow for keyboard intercept
10620 ;; check
for extended key
10622 jne int09_check_pause
10625 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10627 mov BYTE
[0x496], al
10630 int09_check_pause
: ;; check
for pause key
10632 jne int09_process_key
10635 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10637 mov BYTE
[0x496], al
10643 call _int09_function
10649 call eoi_master_pic
10652 mov al
, #0xAE ;;enable keyboard
10658 ;----------------------------------------
10659 ;- INT
13h Diskette Service Entry Point
-
10660 ;----------------------------------------
10663 jmp int13_noeltorito
10665 ;---------------------------------------------
10666 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10667 ;---------------------------------------------
10668 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10678 mov al
, #0x08 ; sense interrupt status
10696 xor ax
, ax
;; segment
0000
10698 call eoi_master_pic
10700 or al
, #0x80 ;; diskette interrupt has occurred
10708 .org
0xefc7 ; Diskette Controller Parameter Table
10709 diskette_param_table
:
10710 ;; Since no provisions are made
for multiple drive types
, most
10711 ;; values in
this table are ignored
. I set parameters
for 1.44M
10714 db
0x02 ;; head load time
0000001, DMA used
10726 ;----------------------------------------
10727 ;- INT17h
: Printer Service Entry Point
-
10728 ;----------------------------------------
10735 call _int17_function
10740 diskette_param_table2
:
10741 ;; New diskette parameter table adding
3 parameters from IBM
10742 ;; Since no provisions are made
for multiple drive types
, most
10743 ;; values in
this table are ignored
. I set parameters
for 1.44M
10746 db
0x02 ;; head load time
0000001, DMA used
10756 db
79 ;; maximum track
10757 db
0 ;; data transfer rate
10758 db
4 ;; drive type in cmos
10760 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10767 .org
0xf065 ; INT
10h Video Support Service Entry Point
10769 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10772 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10777 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10778 ; ??? different
for Pentium (machine check
)?
10790 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10802 .org
0xf859 ; INT
15h System Services Entry Point
10816 #if BX_USE_PS2_MOUSE
10818 je int15_handler_mouse
10820 call _int15_function
10821 int15_handler_mouse_ret
:
10823 int15_handler32_ret
:
10833 #if BX_USE_PS2_MOUSE
10834 int15_handler_mouse
:
10835 call _int15_function_mouse
10836 jmp int15_handler_mouse_ret
10841 call _int15_function32
10843 jmp int15_handler32_ret
10845 ;; Protected mode IDT descriptor
10847 ;; I just make the limit
0, so the machine will shutdown
10848 ;; if an exception occurs during
protected mode memory
10851 ;; Set base to f0000 to correspond to beginning of BIOS
,
10852 ;; in
case I actually define an IDT later
10856 dw
0x0000 ;; limit
15:00
10857 dw
0x0000 ;; base
15:00
10858 db
0x0f ;; base
23:16
10860 ;; Real mode IDT descriptor
10862 ;; Set to typical real
-mode values
.
10867 dw
0x03ff ;; limit
15:00
10868 dw
0x0000 ;; base
15:00
10869 db
0x00 ;; base
23:16
10875 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10888 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10889 mov ds
, ax
; on
16bit
protected mode
.
10890 jmp int1a_callfunction
10897 int1a_callfunction
:
10898 call _int1a_function
10904 ;; int70h
: IRQ8
- CMOS RTC
10911 call _int70_function
10919 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10927 ;; time to turn off
drive(s
)?
10930 jz int08_floppy_off
10933 jnz int08_floppy_off
10934 ;; turn
motor(s
) off
10943 mov eax
, 0x046c ;; get ticks dword
10946 ;; compare eax to one days worth of timer ticks at
18.2 hz
10947 cmp eax
, #0x001800B0
10948 jb int08_store_ticks
10949 ;; there has been a midnight rollover at
this point
10950 xor eax
, eax
;; zero out counter
10951 inc BYTE
0x0470 ;; increment rollover flag
10954 mov
0x046c, eax
;; store
new ticks dword
10955 ;; chain to user timer tick INT
#0x1c
10957 //;; call_ep [ds:loc]
10958 //CALL_EP( 0x1c << 2 )
10961 call eoi_master_pic
10966 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10970 .ascii BIOS_COPYRIGHT_STRING
10972 ;------------------------------------------------
10973 ;- IRET Instruction
for Dummy Interrupt Handler
-
10974 ;------------------------------------------------
10975 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10976 dummy_iret_handler
:
10979 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10983 .org
0xfff0 ; Power
-up Entry Point
10986 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10987 .ascii BIOS_BUILD_DATE
10989 .org
0xfffe ; System Model ID
10993 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10996 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10997 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10998 * This font is public domain
11000 static Bit8u vgafont8
[128*8]=
11002 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11003 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
11004 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
11005 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11006 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11007 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
11008 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
11009 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
11010 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
11011 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
11012 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
11013 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
11014 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
11015 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
11016 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
11017 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
11018 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
11019 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
11020 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
11021 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
11022 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
11023 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
11024 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11025 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11026 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11027 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11028 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11029 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11030 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11031 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11032 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11033 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11034 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11035 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11036 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11037 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11038 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11039 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11040 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11041 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11042 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11043 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11044 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11045 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11046 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11047 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11048 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11049 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11050 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11051 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11052 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11053 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11054 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11055 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11056 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11057 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11058 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11059 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11060 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11061 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11062 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11063 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11064 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11065 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11066 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11067 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11068 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11069 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11070 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11071 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11072 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11073 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11074 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11075 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11076 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11077 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11078 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11079 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11080 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11081 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11082 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11083 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11084 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11085 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11086 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11087 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11088 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11089 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11090 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11091 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11092 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11093 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11094 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11095 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11096 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11098 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11099 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11100 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11101 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11102 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11103 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11104 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11105 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11106 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11107 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11108 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11109 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11110 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11111 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11112 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11113 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11114 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11115 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11116 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11117 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11118 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11119 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11120 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11121 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11122 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11123 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11124 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11125 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11126 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11127 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11128 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11129 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11134 bios_table_area_end
:
11135 // bcc-generated data will be placed here