1 /////////////////////////////////////////////////////////////////////////
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
128 #define DEBUG_INT13_HD 0
129 #define DEBUG_INT13_CD 0
130 #define DEBUG_INT13_ET 0
131 #define DEBUG_INT13_FL 0
132 #define DEBUG_INT15 0
133 #define DEBUG_INT16 0
134 #define DEBUG_INT1A 0
135 #define DEBUG_INT74 0
139 #define BX_USE_PS2_MOUSE 1
140 #define BX_CALL_INT15_4F 1
141 #define BX_USE_EBDA 1
142 #define BX_SUPPORT_FLOPPY 1
143 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
147 #define BX_USE_ATADRV 1
148 #define BX_ELTORITO_BOOT 1
150 #define BX_MAX_ATA_INTERFACES 4
151 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
153 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
154 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
156 /* model byte 0xFC = AT */
157 #define SYS_MODEL_ID 0xFC
158 #define SYS_SUBMODEL_ID 0x00
159 #define BIOS_REVISION 1
160 #define BIOS_CONFIG_TABLE 0xe6f5
162 #ifndef BIOS_BUILD_DATE
163 # define BIOS_BUILD_DATE "06/23/99"
166 // 1K of base memory used for Extended Bios Data Area (EBDA)
167 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
168 #define EBDA_SEG 0x9FC0
169 #define EBDA_SIZE 1 // In KiB
170 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
172 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
173 #define IPL_SEG 0x9ff0
174 #define IPL_TABLE_OFFSET 0x0000
175 #define IPL_TABLE_ENTRIES 8
176 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
177 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
178 #define IPL_SIZE 0xff
179 #define IPL_TYPE_FLOPPY 0x01
180 #define IPL_TYPE_HARDDISK 0x02
181 #define IPL_TYPE_CDROM 0x03
182 #define IPL_TYPE_BEV 0x80
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$ $Date$";
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;
3382 if(error
= atapi_is_ready(device
) != 0)
3383 BX_INFO("ata_is_ready returned %d\n",error
);
3386 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3388 // Read the Boot Record Volume Descriptor
3389 memsetb(get_SS(),atacmd
,0,12);
3390 atacmd
[0]=0x28; // READ command
3391 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3392 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3393 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3394 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3395 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3396 atacmd
[5]=(0x11 & 0x000000ff);
3397 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3401 if(buffer
[0]!=0)return 4;
3403 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3406 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3408 // ok, now we calculate the Boot catalog address
3409 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3411 // And we read the Boot Catalog
3412 memsetb(get_SS(),atacmd
,0,12);
3413 atacmd
[0]=0x28; // READ command
3414 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3415 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3416 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3417 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3418 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3419 atacmd
[5]=(lba
& 0x000000ff);
3420 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3424 if(buffer
[0x00]!=0x01)return 8; // Header
3425 if(buffer
[0x01]!=0x00)return 9; // Platform
3426 if(buffer
[0x1E]!=0x55)return 10; // key 1
3427 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3429 // Initial/Default Entry
3430 if(buffer
[0x20]!=0x88)return 11; // Bootable
3432 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3433 if(buffer
[0x21]==0){
3434 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3435 // Win2000 cd boot needs to know it booted from cd
3436 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3438 else if(buffer
[0x21]<4)
3439 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3441 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3443 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3444 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3446 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3447 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3449 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3450 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3452 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3453 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3455 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3456 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3458 // And we read the image in memory
3459 memsetb(get_SS(),atacmd
,0,12);
3460 atacmd
[0]=0x28; // READ command
3461 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3462 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3463 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3464 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3465 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3466 atacmd
[5]=(lba
& 0x000000ff);
3467 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3470 // Remember the media type
3471 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3472 case 0x01: // 1.2M floppy
3473 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3474 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3475 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3477 case 0x02: // 1.44M floppy
3478 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3479 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3480 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3482 case 0x03: // 2.88M floppy
3483 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3484 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3485 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3487 case 0x04: // Harddrive
3488 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3489 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3490 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3491 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3495 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3496 // Increase bios installed hardware number of devices
3497 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3498 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3500 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3504 // everything is ok, so from now on, the emulation is active
3505 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3506 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3508 // return the boot drive + no error
3509 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3512 // ---------------------------------------------------------------------------
3513 // End of El-Torito boot functions
3514 // ---------------------------------------------------------------------------
3515 #endif // BX_ELTORITO_BOOT
3518 int14_function(regs
, ds
, iret_addr
)
3519 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3520 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3521 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3523 Bit16u addr
,timer
,val16
;
3530 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3531 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3532 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3533 switch (regs
.u
.r8
.ah
) {
3535 outb(addr
+3, inb(addr
+3) | 0x80);
3536 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3540 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3541 outb(addr
, val16
& 0xFF);
3542 outb(addr
+1, val16
>> 8);
3544 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3545 regs
.u
.r8
.ah
= inb(addr
+5);
3546 regs
.u
.r8
.al
= inb(addr
+6);
3547 ClearCF(iret_addr
.flags
);
3550 timer
= read_word(0x0040, 0x006C);
3551 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3552 val16
= read_word(0x0040, 0x006C);
3553 if (val16
!= timer
) {
3558 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3559 regs
.u
.r8
.ah
= inb(addr
+5);
3560 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3561 ClearCF(iret_addr
.flags
);
3564 timer
= read_word(0x0040, 0x006C);
3565 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3566 val16
= read_word(0x0040, 0x006C);
3567 if (val16
!= timer
) {
3574 regs
.u
.r8
.al
= inb(addr
);
3576 regs
.u
.r8
.ah
= inb(addr
+5);
3578 ClearCF(iret_addr
.flags
);
3581 regs
.u
.r8
.ah
= inb(addr
+5);
3582 regs
.u
.r8
.al
= inb(addr
+6);
3583 ClearCF(iret_addr
.flags
);
3586 SetCF(iret_addr
.flags
); // Unsupported
3589 SetCF(iret_addr
.flags
); // Unsupported
3594 int15_function(regs
, ES
, DS
, FLAGS
)
3595 pusha_regs_t regs
; // REGS pushed via pusha
3596 Bit16u ES
, DS
, FLAGS
;
3598 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3599 bx_bool prev_a20_enable
;
3608 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3610 switch (regs
.u
.r8
.ah
) {
3611 case 0x24: /* A20 Control */
3612 switch (regs
.u
.r8
.al
) {
3624 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3634 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3636 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3642 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3646 /* keyboard intercept */
3648 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3655 case 0x52: // removable media eject
3657 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3661 if( regs
.u
.r8
.al
== 0 ) {
3662 // Set Interval requested.
3663 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3664 // Interval not already set.
3665 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3666 write_word( 0x40, 0x98, ES
); // Byte location, segment
3667 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3668 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3669 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3671 irqDisable
= inb( 0xA1 );
3672 outb( 0xA1, irqDisable
& 0xFE );
3673 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3674 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3676 // Interval already set.
3677 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3679 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3681 } else if( regs
.u
.r8
.al
== 1 ) {
3682 // Clear Interval requested
3683 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3685 bRegister
= inb_cmos( 0xB );
3686 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3688 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3690 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3699 # error "Int15 function 87h not supported on < 80386"
3701 // +++ should probably have descriptor checks
3702 // +++ should have exception handlers
3704 // turn off interrupts
3709 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3711 // 128K max of transfer on 386+ ???
3712 // source == destination ???
3714 // ES:SI points to descriptor table
3715 // offset use initially comments
3716 // ==============================================
3717 // 00..07 Unused zeros Null descriptor
3718 // 08..0f GDT zeros filled in by BIOS
3719 // 10..17 source ssssssss source of data
3720 // 18..1f dest dddddddd destination of data
3721 // 20..27 CS zeros filled in by BIOS
3722 // 28..2f SS zeros filled in by BIOS
3729 // check for access rights of source & dest here
3731 // Initialize GDT descriptor
3732 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3733 base23_16
= ES
>> 12;
3734 if (base15_00
< (ES
<<4))
3736 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3737 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3738 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3739 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3740 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3742 // Initialize CS descriptor
3743 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3744 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3745 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3746 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3747 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3749 // Initialize SS descriptor
3751 base15_00
= ss
<< 4;
3752 base23_16
= ss
>> 12;
3753 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3754 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3755 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3756 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3757 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3761 // Compile generates locals offset info relative to SP.
3762 // Get CX (word count) from stack.
3765 mov cx
, _int15_function
.CX
[bx
]
3767 // since we need to set SS:SP, save them to the BDA
3768 // for future restore
3778 lidt
[pmode_IDT_info
]
3779 ;; perhaps
do something with IDT here
3781 ;; set PE bit in CR0
3785 ;; far jump to flush CPU queue after transition to
protected mode
3786 JMP_AP(0x0020, protected_mode
)
3789 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3790 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3792 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3794 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3800 movsw
;; move CX words from DS
:SI to ES
:DI
3802 ;; make sure DS
and ES limits are
64KB
3807 ;; reset PG bit in CR0
???
3812 ;; far jump to flush CPU queue after transition to real mode
3813 JMP_AP(0xf000, real_mode
)
3816 ;; restore IDT to normal real
-mode defaults
3818 lidt
[rmode_IDT_info
]
3820 // restore SS:SP from the BDA
3828 set_enable_a20(prev_a20_enable
);
3830 // turn back on interrupts
3841 // Get the amount of extended memory (above 1M)
3843 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3846 regs
.u
.r8
.al
= inb_cmos(0x30);
3847 regs
.u
.r8
.ah
= inb_cmos(0x31);
3849 // According to Ralf Brown's interrupt the limit should be 15M,
3850 // but real machines mostly return max. 63M.
3851 if(regs
.u
.r16
.ax
> 0xffc0)
3852 regs
.u
.r16
.ax
= 0xffc0;
3859 /* Device busy interrupt. Called by Int 16h when no key available */
3863 /* Interrupt complete. Called by Int 16h when key becomes available */
3867 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3869 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3875 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3880 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3890 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3892 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3896 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3897 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3899 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3904 #if BX_USE_PS2_MOUSE
3906 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3907 pusha_regs_t regs
; // REGS pushed via pusha
3908 Bit16u ES
, DS
, FLAGS
;
3910 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3911 Bit8u mouse_flags_1
, mouse_flags_2
;
3912 Bit16u mouse_driver_seg
;
3913 Bit16u mouse_driver_offset
;
3914 Bit8u comm_byte
, prev_command_byte
;
3915 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3917 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3919 switch (regs
.u
.r8
.ah
) {
3921 // Return Codes status in AH
3922 // =========================
3924 // 01: invalid subfunction (AL > 7)
3925 // 02: invalid input value (out of allowable range)
3926 // 03: interface error
3927 // 04: resend command received from mouse controller,
3928 // device driver should attempt command again
3929 // 05: cannot enable mouse, since no far call has been installed
3930 // 80/86: mouse service not implemented
3932 switch (regs
.u
.r8
.al
) {
3933 case 0: // Disable/Enable Mouse
3934 BX_DEBUG_INT15("case 0:\n");
3935 switch (regs
.u
.r8
.bh
) {
3936 case 0: // Disable Mouse
3937 BX_DEBUG_INT15("case 0: disable mouse\n");
3938 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3939 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3941 ret
= get_mouse_data(&mouse_data1
);
3942 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3955 case 1: // Enable Mouse
3956 BX_DEBUG_INT15("case 1: enable mouse\n");
3957 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3958 if ( (mouse_flags_2
& 0x80) == 0 ) {
3959 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3961 regs
.u
.r8
.ah
= 5; // no far call installed
3964 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3965 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3967 ret
= get_mouse_data(&mouse_data1
);
3968 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3969 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3979 default: // invalid subfunction
3980 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3982 regs
.u
.r8
.ah
= 1; // invalid subfunction
3987 case 1: // Reset Mouse
3988 case 5: // Initialize Mouse
3989 BX_DEBUG_INT15("case 1 or 5:\n");
3990 if (regs
.u
.r8
.al
== 5) {
3991 if (regs
.u
.r8
.bh
!= 3) {
3993 regs
.u
.r8
.ah
= 0x02; // invalid input
3996 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3997 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3998 mouse_flags_1
= 0x00;
3999 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4000 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4003 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4004 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
4006 ret
= get_mouse_data(&mouse_data3
);
4007 // if no mouse attached, it will return RESEND
4008 if (mouse_data3
== 0xfe) {
4012 if (mouse_data3
!= 0xfa)
4013 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
4015 ret
= get_mouse_data(&mouse_data1
);
4017 ret
= get_mouse_data(&mouse_data2
);
4019 // turn IRQ12 and packet generation on
4020 enable_mouse_int_and_events();
4023 regs
.u
.r8
.bl
= mouse_data1
;
4024 regs
.u
.r8
.bh
= mouse_data2
;
4036 case 2: // Set Sample Rate
4037 BX_DEBUG_INT15("case 2:\n");
4038 switch (regs
.u
.r8
.bh
) {
4039 case 0: mouse_data1
= 10; break; // 10 reports/sec
4040 case 1: mouse_data1
= 20; break; // 20 reports/sec
4041 case 2: mouse_data1
= 40; break; // 40 reports/sec
4042 case 3: mouse_data1
= 60; break; // 60 reports/sec
4043 case 4: mouse_data1
= 80; break; // 80 reports/sec
4044 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
4045 case 6: mouse_data1
= 200; break; // 200 reports/sec
4046 default: mouse_data1
= 0;
4048 if (mouse_data1
> 0) {
4049 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
4051 ret
= get_mouse_data(&mouse_data2
);
4052 ret
= send_to_mouse_ctrl(mouse_data1
);
4053 ret
= get_mouse_data(&mouse_data2
);
4059 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4064 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4068 case 3: // Set Resolution
4069 BX_DEBUG_INT15("case 3:\n");
4071 // 0 = 25 dpi, 1 count per millimeter
4072 // 1 = 50 dpi, 2 counts per millimeter
4073 // 2 = 100 dpi, 4 counts per millimeter
4074 // 3 = 200 dpi, 8 counts per millimeter
4075 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4076 if (regs
.u
.r8
.bh
< 4) {
4077 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
4079 ret
= get_mouse_data(&mouse_data1
);
4080 if (mouse_data1
!= 0xfa)
4081 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4082 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
4083 ret
= get_mouse_data(&mouse_data1
);
4084 if (mouse_data1
!= 0xfa)
4085 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4091 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4096 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4098 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4101 case 4: // Get Device ID
4102 BX_DEBUG_INT15("case 4:\n");
4103 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4104 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
4106 ret
= get_mouse_data(&mouse_data1
);
4107 ret
= get_mouse_data(&mouse_data2
);
4110 regs
.u
.r8
.bh
= mouse_data2
;
4114 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4118 case 6: // Return Status & Set Scaling Factor...
4119 BX_DEBUG_INT15("case 6:\n");
4120 switch (regs
.u
.r8
.bh
) {
4121 case 0: // Return Status
4122 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4123 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4125 ret
= get_mouse_data(&mouse_data1
);
4126 if (mouse_data1
!= 0xfa)
4127 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4129 ret
= get_mouse_data(&mouse_data1
);
4131 ret
= get_mouse_data(&mouse_data2
);
4133 ret
= get_mouse_data(&mouse_data3
);
4137 regs
.u
.r8
.bl
= mouse_data1
;
4138 regs
.u
.r8
.cl
= mouse_data2
;
4139 regs
.u
.r8
.dl
= mouse_data3
;
4140 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4151 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4154 case 1: // Set Scaling Factor to 1:1
4155 case 2: // Set Scaling Factor to 2:1
4156 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4157 if (regs
.u
.r8
.bh
== 1) {
4158 ret
= send_to_mouse_ctrl(0xE6);
4160 ret
= send_to_mouse_ctrl(0xE7);
4163 get_mouse_data(&mouse_data1
);
4164 ret
= (mouse_data1
!= 0xFA);
4172 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4174 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4178 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4182 case 7: // Set Mouse Handler Address
4183 BX_DEBUG_INT15("case 7:\n");
4184 mouse_driver_seg
= ES
;
4185 mouse_driver_offset
= regs
.u
.r16
.bx
;
4186 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4187 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4188 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4189 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4190 /* remove handler */
4191 if ( (mouse_flags_2
& 0x80) != 0 ) {
4192 mouse_flags_2
&= ~0x80;
4193 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4197 /* install handler */
4198 mouse_flags_2
|= 0x80;
4200 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4206 BX_DEBUG_INT15("case default:\n");
4207 regs
.u
.r8
.ah
= 1; // invalid function
4213 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4214 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4216 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4223 void set_e820_range(ES
, DI
, start
, end
, type
)
4230 write_word(ES
, DI
, start
);
4231 write_word(ES
, DI
+2, start
>> 16);
4232 write_word(ES
, DI
+4, 0x00);
4233 write_word(ES
, DI
+6, 0x00);
4236 write_word(ES
, DI
+8, end
);
4237 write_word(ES
, DI
+10, end
>> 16);
4238 write_word(ES
, DI
+12, 0x0000);
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
4253 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4255 switch (regs
.u
.r8
.ah
) {
4257 // Wait for CX:DX microseconds. currently using the
4258 // refresh request port 0x61 bit4, toggling every 15usec
4266 ;; Get the count in eax
4269 mov ax
, _int15_function32
.CX
[bx
]
4272 mov ax
, _int15_function32
.DX
[bx
]
4274 ;; convert to numbers of
15usec ticks
4280 ;; wait
for ecx number of refresh requests
4301 switch(regs
.u
.r8
.al
)
4303 case 0x20: // coded by osmaker aka K.J.
4304 if(regs
.u
.r32
.edx
== 0x534D4150)
4306 extended_memory_size
= inb_cmos(0x35);
4307 extended_memory_size
<<= 8;
4308 extended_memory_size
|= inb_cmos(0x34);
4309 extended_memory_size
*= 64;
4310 // greater than EFF00000???
4311 if(extended_memory_size
> 0x3bc000) {
4312 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4314 extended_memory_size
*= 1024;
4315 extended_memory_size
+= (16L * 1024 * 1024);
4317 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4318 extended_memory_size
= inb_cmos(0x31);
4319 extended_memory_size
<<= 8;
4320 extended_memory_size
|= inb_cmos(0x30);
4321 extended_memory_size
*= 1024;
4324 switch(regs
.u
.r16
.bx
)
4327 set_e820_range(ES
, regs
.u
.r16
.di
,
4328 0x0000000L
, 0x0009fc00L
, 1);
4330 regs
.u
.r32
.eax
= 0x534D4150;
4331 regs
.u
.r32
.ecx
= 0x14;
4336 set_e820_range(ES
, regs
.u
.r16
.di
,
4337 0x0009fc00L
, 0x000a0000L
, 2);
4339 regs
.u
.r32
.eax
= 0x534D4150;
4340 regs
.u
.r32
.ecx
= 0x14;
4345 set_e820_range(ES
, regs
.u
.r16
.di
,
4346 0x000e8000L
, 0x00100000L
, 2);
4348 regs
.u
.r32
.eax
= 0x534D4150;
4349 regs
.u
.r32
.ecx
= 0x14;
4354 set_e820_range(ES
, regs
.u
.r16
.di
,
4356 extended_memory_size
- ACPI_DATA_SIZE
, 1);
4358 regs
.u
.r32
.eax
= 0x534D4150;
4359 regs
.u
.r32
.ecx
= 0x14;
4364 set_e820_range(ES
, regs
.u
.r16
.di
,
4365 extended_memory_size
- ACPI_DATA_SIZE
,
4366 extended_memory_size
, 3); // ACPI RAM
4368 regs
.u
.r32
.eax
= 0x534D4150;
4369 regs
.u
.r32
.ecx
= 0x14;
4374 /* 256KB BIOS area at the end of 4 GB */
4375 set_e820_range(ES
, regs
.u
.r16
.di
,
4376 0xfffc0000L
, 0x00000000L
, 2);
4378 regs
.u
.r32
.eax
= 0x534D4150;
4379 regs
.u
.r32
.ecx
= 0x14;
4382 default: /* AX=E820, DX=534D4150, BX unrecognized */
4383 goto int15_unimplemented
;
4387 // if DX != 0x534D4150)
4388 goto int15_unimplemented
;
4393 // do we have any reason to fail here ?
4396 // my real system sets ax and bx to 0
4397 // this is confirmed by Ralph Brown list
4398 // but syslinux v1.48 is known to behave
4399 // strangely if ax is set to 0
4400 // regs.u.r16.ax = 0;
4401 // regs.u.r16.bx = 0;
4403 // Get the amount of extended memory (above 1M)
4404 regs
.u
.r8
.cl
= inb_cmos(0x30);
4405 regs
.u
.r8
.ch
= inb_cmos(0x31);
4408 if(regs
.u
.r16
.cx
> 0x3c00)
4410 regs
.u
.r16
.cx
= 0x3c00;
4413 // Get the amount of extended memory above 16M in 64k blocs
4414 regs
.u
.r8
.dl
= inb_cmos(0x34);
4415 regs
.u
.r8
.dh
= inb_cmos(0x35);
4417 // Set configured memory equal to extended memory
4418 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4419 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4421 default: /* AH=0xE8?? but not implemented */
4422 goto int15_unimplemented
;
4425 int15_unimplemented
:
4426 // fall into the default
4428 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4429 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4431 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4437 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4438 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4440 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4441 Bit16u kbd_code
, max
;
4443 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4445 shift_flags
= read_byte(0x0040, 0x17);
4446 led_flags
= read_byte(0x0040, 0x97);
4447 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4452 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4453 if ((inb(0x60) == 0xfa)) {
4455 led_flags
|= ((shift_flags
>> 4) & 0x07);
4456 outb(0x60, led_flags
& 0x07);
4457 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4459 write_byte(0x0040, 0x97, led_flags
);
4467 case 0x00: /* read keyboard input */
4469 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4470 BX_PANIC("KBD: int16h: out of keyboard input\n");
4472 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4473 else if (ascii_code
== 0xE0) ascii_code
= 0;
4474 AX
= (scan_code
<< 8) | ascii_code
;
4477 case 0x01: /* check keyboard status */
4478 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4482 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4483 else if (ascii_code
== 0xE0) ascii_code
= 0;
4484 AX
= (scan_code
<< 8) | ascii_code
;
4488 case 0x02: /* get shift flag status */
4489 shift_flags
= read_byte(0x0040, 0x17);
4490 SET_AL(shift_flags
);
4493 case 0x05: /* store key-stroke into buffer */
4494 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4502 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4503 // bit Bochs Description
4505 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4506 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4507 // 4 1 INT 16/AH=0Ah supported
4508 // 3 0 INT 16/AX=0306h supported
4509 // 2 0 INT 16/AX=0305h supported
4510 // 1 0 INT 16/AX=0304h supported
4511 // 0 0 INT 16/AX=0300h supported
4516 case 0x0A: /* GET KEYBOARD ID */
4522 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4524 if ((inb(0x60) == 0xfa)) {
4527 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4530 kbd_code
|= (inb(0x60) << 8);
4532 } while (--count
>0);
4538 case 0x10: /* read MF-II keyboard input */
4540 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4541 BX_PANIC("KBD: int16h: out of keyboard input\n");
4543 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4544 AX
= (scan_code
<< 8) | ascii_code
;
4547 case 0x11: /* check MF-II keyboard status */
4548 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4552 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4553 AX
= (scan_code
<< 8) | ascii_code
;
4557 case 0x12: /* get extended keyboard status */
4558 shift_flags
= read_byte(0x0040, 0x17);
4559 SET_AL(shift_flags
);
4560 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4561 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4562 SET_AH(shift_flags
);
4563 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4566 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4567 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4570 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4571 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4575 if (GET_AL() == 0x08)
4576 SET_AH(0x02); // unsupported, aka normal keyboard
4579 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4584 dequeue_key(scan_code
, ascii_code
, incr
)
4589 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4594 buffer_start
= 0x001E;
4595 buffer_end
= 0x003E;
4597 buffer_start
= read_word(0x0040, 0x0080);
4598 buffer_end
= read_word(0x0040, 0x0082);
4601 buffer_head
= read_word(0x0040, 0x001a);
4602 buffer_tail
= read_word(0x0040, 0x001c);
4604 if (buffer_head
!= buffer_tail
) {
4606 acode
= read_byte(0x0040, buffer_head
);
4607 scode
= read_byte(0x0040, buffer_head
+1);
4608 write_byte(ss
, ascii_code
, acode
);
4609 write_byte(ss
, scan_code
, scode
);
4613 if (buffer_head
>= buffer_end
)
4614 buffer_head
= buffer_start
;
4615 write_word(0x0040, 0x001a, buffer_head
);
4624 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4627 inhibit_mouse_int_and_events()
4629 Bit8u command_byte
, prev_command_byte
;
4631 // Turn off IRQ generation and aux data line
4632 if ( inb(0x64) & 0x02 )
4633 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4634 outb(0x64, 0x20); // get command byte
4635 while ( (inb(0x64) & 0x01) != 0x01 );
4636 prev_command_byte
= inb(0x60);
4637 command_byte
= prev_command_byte
;
4638 //while ( (inb(0x64) & 0x02) );
4639 if ( inb(0x64) & 0x02 )
4640 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4641 command_byte
&= 0xfd; // turn off IRQ 12 generation
4642 command_byte
|= 0x20; // disable mouse serial clock line
4643 outb(0x64, 0x60); // write command byte
4644 outb(0x60, command_byte
);
4645 return(prev_command_byte
);
4649 enable_mouse_int_and_events()
4653 // Turn on IRQ generation and aux data line
4654 if ( inb(0x64) & 0x02 )
4655 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4656 outb(0x64, 0x20); // get command byte
4657 while ( (inb(0x64) & 0x01) != 0x01 );
4658 command_byte
= inb(0x60);
4659 //while ( (inb(0x64) & 0x02) );
4660 if ( inb(0x64) & 0x02 )
4661 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4662 command_byte
|= 0x02; // turn on IRQ 12 generation
4663 command_byte
&= 0xdf; // enable mouse serial clock line
4664 outb(0x64, 0x60); // write command byte
4665 outb(0x60, command_byte
);
4669 send_to_mouse_ctrl(sendbyte
)
4674 // wait for chance to write to ctrl
4675 if ( inb(0x64) & 0x02 )
4676 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4678 outb(0x60, sendbyte
);
4684 get_mouse_data(data
)
4690 while ( (inb(0x64) & 0x21) != 0x21 ) {
4693 response
= inb(0x60);
4696 write_byte(ss
, data
, response
);
4701 set_kbd_command_byte(command_byte
)
4704 if ( inb(0x64) & 0x02 )
4705 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4708 outb(0x64, 0x60); // write command byte
4709 outb(0x60, command_byte
);
4713 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4714 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4716 Bit8u scancode
, asciicode
, shift_flags
;
4717 Bit8u mf2_flags
, mf2_state
;
4720 // DS has been set to F000 before call
4724 scancode
= GET_AL();
4726 if (scancode
== 0) {
4727 BX_INFO("KBD: int09 handler: AL=0\n");
4732 shift_flags
= read_byte(0x0040, 0x17);
4733 mf2_flags
= read_byte(0x0040, 0x18);
4734 mf2_state
= read_byte(0x0040, 0x96);
4738 case 0x3a: /* Caps Lock press */
4739 shift_flags
^= 0x40;
4740 write_byte(0x0040, 0x17, shift_flags
);
4742 write_byte(0x0040, 0x18, mf2_flags
);
4744 case 0xba: /* Caps Lock release */
4746 write_byte(0x0040, 0x18, mf2_flags
);
4749 case 0x2a: /* L Shift press */
4750 shift_flags
|= 0x02;
4751 write_byte(0x0040, 0x17, shift_flags
);
4753 case 0xaa: /* L Shift release */
4754 shift_flags
&= ~0x02;
4755 write_byte(0x0040, 0x17, shift_flags
);
4758 case 0x36: /* R Shift press */
4759 shift_flags
|= 0x01;
4760 write_byte(0x0040, 0x17, shift_flags
);
4762 case 0xb6: /* R Shift release */
4763 shift_flags
&= ~0x01;
4764 write_byte(0x0040, 0x17, shift_flags
);
4767 case 0x1d: /* Ctrl press */
4768 if ((mf2_state
& 0x01) == 0) {
4769 shift_flags
|= 0x04;
4770 write_byte(0x0040, 0x17, shift_flags
);
4771 if (mf2_state
& 0x02) {
4773 write_byte(0x0040, 0x96, mf2_state
);
4776 write_byte(0x0040, 0x18, mf2_flags
);
4780 case 0x9d: /* Ctrl release */
4781 if ((mf2_state
& 0x01) == 0) {
4782 shift_flags
&= ~0x04;
4783 write_byte(0x0040, 0x17, shift_flags
);
4784 if (mf2_state
& 0x02) {
4786 write_byte(0x0040, 0x96, mf2_state
);
4789 write_byte(0x0040, 0x18, mf2_flags
);
4794 case 0x38: /* Alt press */
4795 shift_flags
|= 0x08;
4796 write_byte(0x0040, 0x17, shift_flags
);
4797 if (mf2_state
& 0x02) {
4799 write_byte(0x0040, 0x96, mf2_state
);
4802 write_byte(0x0040, 0x18, mf2_flags
);
4805 case 0xb8: /* Alt release */
4806 shift_flags
&= ~0x08;
4807 write_byte(0x0040, 0x17, shift_flags
);
4808 if (mf2_state
& 0x02) {
4810 write_byte(0x0040, 0x96, mf2_state
);
4813 write_byte(0x0040, 0x18, mf2_flags
);
4817 case 0x45: /* Num Lock press */
4818 if ((mf2_state
& 0x03) == 0) {
4820 write_byte(0x0040, 0x18, mf2_flags
);
4821 shift_flags
^= 0x20;
4822 write_byte(0x0040, 0x17, shift_flags
);
4825 case 0xc5: /* Num Lock release */
4826 if ((mf2_state
& 0x03) == 0) {
4828 write_byte(0x0040, 0x18, mf2_flags
);
4832 case 0x46: /* Scroll Lock press */
4834 write_byte(0x0040, 0x18, mf2_flags
);
4835 shift_flags
^= 0x10;
4836 write_byte(0x0040, 0x17, shift_flags
);
4839 case 0xc6: /* Scroll Lock release */
4841 write_byte(0x0040, 0x18, mf2_flags
);
4845 if (scancode
& 0x80) {
4846 break; /* toss key releases ... */
4848 if (scancode
> MAX_SCAN_CODE
) {
4849 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4852 if (shift_flags
& 0x08) { /* ALT */
4853 asciicode
= scan_to_scanascii
[scancode
].alt
;
4854 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4855 } else if (shift_flags
& 0x04) { /* CONTROL */
4856 asciicode
= scan_to_scanascii
[scancode
].control
;
4857 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4858 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
4859 /* extended keys handling */
4861 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4862 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4863 /* check if lock state should be ignored
4864 * because a SHIFT key are pressed */
4866 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4867 asciicode
= scan_to_scanascii
[scancode
].normal
;
4868 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4870 asciicode
= scan_to_scanascii
[scancode
].shift
;
4871 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4874 /* check if lock is on */
4875 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4876 asciicode
= scan_to_scanascii
[scancode
].shift
;
4877 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4879 asciicode
= scan_to_scanascii
[scancode
].normal
;
4880 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4883 if (scancode
==0 && asciicode
==0) {
4884 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4886 enqueue_key(scancode
, asciicode
);
4889 if ((scancode
& 0x7f) != 0x1d) {
4893 write_byte(0x0040, 0x96, mf2_state
);
4897 enqueue_key(scan_code
, ascii_code
)
4898 Bit8u scan_code
, ascii_code
;
4900 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4903 buffer_start
= 0x001E;
4904 buffer_end
= 0x003E;
4906 buffer_start
= read_word(0x0040, 0x0080);
4907 buffer_end
= read_word(0x0040, 0x0082);
4910 buffer_head
= read_word(0x0040, 0x001A);
4911 buffer_tail
= read_word(0x0040, 0x001C);
4913 temp_tail
= buffer_tail
;
4915 if (buffer_tail
>= buffer_end
)
4916 buffer_tail
= buffer_start
;
4918 if (buffer_tail
== buffer_head
) {
4922 write_byte(0x0040, temp_tail
, ascii_code
);
4923 write_byte(0x0040, temp_tail
+1, scan_code
);
4924 write_word(0x0040, 0x001C, buffer_tail
);
4930 int74_function(make_farcall
, Z
, Y
, X
, status
)
4931 Bit16u make_farcall
, Z
, Y
, X
, status
;
4933 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4934 Bit8u in_byte
, index
, package_count
;
4935 Bit8u mouse_flags_1
, mouse_flags_2
;
4937 BX_DEBUG_INT74("entering int74_function\n");
4940 in_byte
= inb(0x64);
4941 if ( (in_byte
& 0x21) != 0x21 ) {
4944 in_byte
= inb(0x60);
4945 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4947 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4948 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4950 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4954 package_count
= mouse_flags_2
& 0x07;
4955 index
= mouse_flags_1
& 0x07;
4956 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4958 if ( (index
+1) >= package_count
) {
4959 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4960 status
= read_byte(ebda_seg
, 0x0028 + 0);
4961 X
= read_byte(ebda_seg
, 0x0028 + 1);
4962 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4965 // check if far call handler installed
4966 if (mouse_flags_2
& 0x80)
4972 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4975 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4980 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4981 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4984 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4985 Bit16u cylinder
, head
, sector
;
4986 Bit16u segment
, offset
;
4987 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4989 Bit8u device
, status
;
4991 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4993 write_byte(0x0040, 0x008e, 0); // clear completion flag
4995 // basic check : device has to be defined
4996 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4997 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5001 // Get the ata channel
5002 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
5004 // basic check : device has to be valid
5005 if (device
>= BX_MAX_ATA_DEVICES
) {
5006 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5012 case 0x00: /* disk controller reset */
5017 case 0x01: /* read disk status */
5018 status
= read_byte(0x0040, 0x0074);
5020 SET_DISK_RET_STATUS(0);
5021 /* set CF if error status read */
5022 if (status
) goto int13_fail_nostatus
;
5023 else goto int13_success_noah
;
5026 case 0x02: // read disk sectors
5027 case 0x03: // write disk sectors
5028 case 0x04: // verify disk sectors
5031 cylinder
= GET_CH();
5032 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5033 sector
= (GET_CL() & 0x3f);
5039 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
5040 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5044 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5045 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5046 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5048 // sanity check on cyl heads, sec
5049 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
5050 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
5055 if ( GET_AH() == 0x04 ) goto int13_success
;
5057 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5058 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5060 // if needed, translate lchs to lba, and execute command
5061 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
5062 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
5063 sector
= 0; // this forces the command to be lba
5066 if ( GET_AH() == 0x02 )
5067 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5069 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5071 // Set nb of sector transferred
5072 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
5075 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5077 goto int13_fail_noah
;
5083 case 0x05: /* format disk track */
5084 BX_INFO("format disk track called\n");
5089 case 0x08: /* read disk drive parameters */
5091 // Get logical geometry from table
5092 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5093 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5094 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5095 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5097 nlc
= nlc
- 2; /* 0 based , last sector not used */
5100 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5102 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5104 // FIXME should set ES & DI
5109 case 0x10: /* check drive ready */
5110 // should look at 40:8E also???
5112 // Read the status from controller
5113 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5114 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5119 goto int13_fail_noah
;
5123 case 0x15: /* read disk drive size */
5125 // Get logical geometry from table
5126 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5127 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5128 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5130 // Compute sector count seen by int13
5131 lba
= (Bit32u
)(nlc
- 1) * (Bit32u
)nlh
* (Bit32u
)nlspt
;
5135 SET_AH(3); // hard disk accessible
5136 goto int13_success_noah
;
5139 case 0x41: // IBM/MS installation check
5140 BX
=0xaa55; // install check
5141 SET_AH(0x30); // EDD 3.0
5142 CX
=0x0007; // ext disk access and edd, removable supported
5143 goto int13_success_noah
;
5146 case 0x42: // IBM/MS extended read
5147 case 0x43: // IBM/MS extended write
5148 case 0x44: // IBM/MS verify
5149 case 0x47: // IBM/MS extended seek
5151 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5152 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5153 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5155 // Can't use 64 bits lba
5156 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5158 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5162 // Get 32 bits lba and check
5163 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5164 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
5165 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5169 // If verify or seek
5170 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5173 // Execute the command
5174 if ( GET_AH() == 0x42 )
5175 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5177 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5179 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5180 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5183 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5185 goto int13_fail_noah
;
5191 case 0x45: // IBM/MS lock/unlock drive
5192 case 0x49: // IBM/MS extended media change
5193 goto int13_success
; // Always success for HD
5196 case 0x46: // IBM/MS eject media
5197 SET_AH(0xb2); // Volume Not Removable
5198 goto int13_fail_noah
; // Always fail for HD
5201 case 0x48: // IBM/MS get drive parameters
5202 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5204 // Buffer is too small
5212 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5213 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5214 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5215 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
5216 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5218 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5219 if ((lba
/npspt
)/nph
> 0x3fff)
5221 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x00); // geometry is invalid
5222 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0x3fff);
5226 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5227 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5229 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5230 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5231 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
5232 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
5233 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5238 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5239 Bit16u iobase1
, iobase2
, options
;
5241 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5243 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5244 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5247 channel
= device
/ 2;
5248 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5249 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5250 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5251 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5252 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5254 options
= (translation
==ATA_TRANSLATION_NONE
?0:1)<<3; // chs translation
5255 options
|= (1<<4); // lba translation
5256 options
|= (mode
==ATA_MODE_PIO32
?1:0)<<7;
5257 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0)<<9;
5258 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0)<<9;
5260 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5261 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5262 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5263 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5264 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5265 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5266 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5267 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5268 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5269 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5271 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5273 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x10);
5276 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5277 checksum
= ~checksum
;
5278 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5283 Bit8u channel
, iface
, checksum
, i
;
5286 channel
= device
/ 2;
5287 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5288 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5290 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5291 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5292 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5293 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5294 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5296 if (iface
==ATA_IFACE_ISA
) {
5297 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5298 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5299 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5300 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5305 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5306 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5307 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5308 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5310 if (iface
==ATA_IFACE_ISA
) {
5311 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5312 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5313 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5318 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5319 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5320 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5321 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5324 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5325 checksum
= ~checksum
;
5326 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5332 case 0x4e: // // IBM/MS set hardware configuration
5333 // DMA, prefetch, PIO maximum not supported
5346 case 0x09: /* initialize drive parameters */
5347 case 0x0c: /* seek to specified cylinder */
5348 case 0x0d: /* alternate disk reset */
5349 case 0x11: /* recalibrate */
5350 case 0x14: /* controller internal diagnostic */
5351 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5355 case 0x0a: /* read disk sectors with ECC */
5356 case 0x0b: /* write disk sectors with ECC */
5357 case 0x18: // set media type for format
5358 case 0x50: // IBM/MS send packet command
5360 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5366 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5368 SET_DISK_RET_STATUS(GET_AH());
5369 int13_fail_nostatus
:
5370 SET_CF(); // error occurred
5374 SET_AH(0x00); // no error
5376 SET_DISK_RET_STATUS(0x00);
5377 CLEAR_CF(); // no error
5381 // ---------------------------------------------------------------------------
5382 // Start of int13 for cdrom
5383 // ---------------------------------------------------------------------------
5386 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5387 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5389 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5390 Bit8u device
, status
, locks
;
5393 Bit16u count
, segment
, offset
, i
, size
;
5395 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5397 SET_DISK_RET_STATUS(0x00);
5399 /* basic check : device should be 0xE0+ */
5400 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5401 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5405 // Get the ata channel
5406 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5408 /* basic check : device has to be valid */
5409 if (device
>= BX_MAX_ATA_DEVICES
) {
5410 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5416 // all those functions return SUCCESS
5417 case 0x00: /* disk controller reset */
5418 case 0x09: /* initialize drive parameters */
5419 case 0x0c: /* seek to specified cylinder */
5420 case 0x0d: /* alternate disk reset */
5421 case 0x10: /* check drive ready */
5422 case 0x11: /* recalibrate */
5423 case 0x14: /* controller internal diagnostic */
5424 case 0x16: /* detect disk change */
5428 // all those functions return disk write-protected
5429 case 0x03: /* write disk sectors */
5430 case 0x05: /* format disk track */
5431 case 0x43: // IBM/MS extended write
5433 goto int13_fail_noah
;
5436 case 0x01: /* read disk status */
5437 status
= read_byte(0x0040, 0x0074);
5439 SET_DISK_RET_STATUS(0);
5441 /* set CF if error status read */
5442 if (status
) goto int13_fail_nostatus
;
5443 else goto int13_success_noah
;
5446 case 0x15: /* read disk drive size */
5448 goto int13_fail_noah
;
5451 case 0x41: // IBM/MS installation check
5452 BX
=0xaa55; // install check
5453 SET_AH(0x30); // EDD 2.1
5454 CX
=0x0007; // ext disk access, removable and edd
5455 goto int13_success_noah
;
5458 case 0x42: // IBM/MS extended read
5459 case 0x44: // IBM/MS verify sectors
5460 case 0x47: // IBM/MS extended seek
5462 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5463 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5464 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5466 // Can't use 64 bits lba
5467 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5469 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5474 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5476 // If verify or seek
5477 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5480 memsetb(get_SS(),atacmd
,0,12);
5481 atacmd
[0]=0x28; // READ command
5482 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5483 atacmd
[8]=(count
& 0x00ff); // Sectors
5484 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5485 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5486 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5487 atacmd
[5]=(lba
& 0x000000ff);
5488 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5490 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5491 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5494 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5496 goto int13_fail_noah
;
5502 case 0x45: // IBM/MS lock/unlock drive
5503 if (GET_AL() > 2) goto int13_fail
;
5505 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5509 if (locks
== 0xff) {
5512 goto int13_fail_noah
;
5514 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5518 if (locks
== 0x00) {
5521 goto int13_fail_noah
;
5523 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5524 SET_AL(locks
==0?0:1);
5527 SET_AL(locks
==0?0:1);
5533 case 0x46: // IBM/MS eject media
5534 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5537 SET_AH(0xb1); // media locked
5538 goto int13_fail_noah
;
5540 // FIXME should handle 0x31 no media in device
5541 // FIXME should handle 0xb5 valid request failed
5543 // Call removable media eject
5550 mov _int13_cdrom
.status
+ 2[bp
], ah
5551 jnc int13_cdrom_rme_end
5552 mov _int13_cdrom
.status
, #1
5553 int13_cdrom_rme_end
:
5558 SET_AH(0xb1); // media locked
5559 goto int13_fail_noah
;
5565 case 0x48: // IBM/MS get drive parameters
5566 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5568 // Buffer is too small
5574 Bit16u cylinders
, heads
, spt
, blksize
;
5576 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5578 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5579 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5580 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5581 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5582 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5583 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5584 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5585 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5590 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5591 Bit16u iobase1
, iobase2
, options
;
5593 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5595 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5596 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5599 channel
= device
/ 2;
5600 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5601 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5602 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5603 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5605 // FIXME atapi device
5606 options
= (1<<4); // lba translation
5607 options
|= (1<<5); // removable device
5608 options
|= (1<<6); // atapi device
5609 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5611 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5612 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5613 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5614 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5615 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5616 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5617 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5618 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5619 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5620 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5621 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5624 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5625 checksum
= ~checksum
;
5626 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5631 Bit8u channel
, iface
, checksum
, i
;
5634 channel
= device
/ 2;
5635 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5636 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5638 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5639 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5640 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5641 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5642 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5644 if (iface
==ATA_IFACE_ISA
) {
5645 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5646 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5647 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5648 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5653 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5654 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5655 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5656 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5658 if (iface
==ATA_IFACE_ISA
) {
5659 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5660 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5661 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5666 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5667 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5668 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5669 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5672 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5673 checksum
= ~checksum
;
5674 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5680 case 0x49: // IBM/MS extended media change
5681 // always send changed ??
5683 goto int13_fail_nostatus
;
5686 case 0x4e: // // IBM/MS set hardware configuration
5687 // DMA, prefetch, PIO maximum not supported
5700 // all those functions return unimplemented
5701 case 0x02: /* read sectors */
5702 case 0x04: /* verify sectors */
5703 case 0x08: /* read disk drive parameters */
5704 case 0x0a: /* read disk sectors with ECC */
5705 case 0x0b: /* write disk sectors with ECC */
5706 case 0x18: /* set media type for format */
5707 case 0x50: // ? - send packet command
5709 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5715 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5717 SET_DISK_RET_STATUS(GET_AH());
5718 int13_fail_nostatus
:
5719 SET_CF(); // error occurred
5723 SET_AH(0x00); // no error
5725 SET_DISK_RET_STATUS(0x00);
5726 CLEAR_CF(); // no error
5730 // ---------------------------------------------------------------------------
5731 // End of int13 for cdrom
5732 // ---------------------------------------------------------------------------
5734 #if BX_ELTORITO_BOOT
5735 // ---------------------------------------------------------------------------
5736 // Start of int13 for eltorito functions
5737 // ---------------------------------------------------------------------------
5740 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5741 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5743 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5745 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5746 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5750 // FIXME ElTorito Various. Should be implemented
5751 case 0x4a: // ElTorito - Initiate disk emu
5752 case 0x4c: // ElTorito - Initiate disk emu and boot
5753 case 0x4d: // ElTorito - Return Boot catalog
5754 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5758 case 0x4b: // ElTorito - Terminate disk emu
5759 // FIXME ElTorito Hardcoded
5760 write_byte(DS
,SI
+0x00,0x13);
5761 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5762 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5763 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5764 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5765 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5766 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5767 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5768 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5769 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5770 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5771 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5773 // If we have to terminate emulation
5774 if(GET_AL() == 0x00) {
5775 // FIXME ElTorito Various. Should be handled accordingly to spec
5776 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5783 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5789 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5790 SET_DISK_RET_STATUS(GET_AH());
5791 SET_CF(); // error occurred
5795 SET_AH(0x00); // no error
5796 SET_DISK_RET_STATUS(0x00);
5797 CLEAR_CF(); // no error
5801 // ---------------------------------------------------------------------------
5802 // End of int13 for eltorito functions
5803 // ---------------------------------------------------------------------------
5805 // ---------------------------------------------------------------------------
5806 // Start of int13 when emulating a device from the cd
5807 // ---------------------------------------------------------------------------
5810 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5811 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5813 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5814 Bit8u device
, status
;
5815 Bit16u vheads
, vspt
, vcylinders
;
5816 Bit16u head
, sector
, cylinder
, nbsectors
;
5817 Bit32u vlba
, ilba
, slba
, elba
;
5818 Bit16u before
, segment
, offset
;
5821 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5823 /* at this point, we are emulating a floppy/harddisk */
5825 // Recompute the device number
5826 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5827 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5829 SET_DISK_RET_STATUS(0x00);
5831 /* basic checks : emulation should be active, dl should equal the emulated drive */
5832 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5833 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5834 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5840 // all those functions return SUCCESS
5841 case 0x00: /* disk controller reset */
5842 case 0x09: /* initialize drive parameters */
5843 case 0x0c: /* seek to specified cylinder */
5844 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5845 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5846 case 0x11: /* recalibrate */
5847 case 0x14: /* controller internal diagnostic */
5848 case 0x16: /* detect disk change */
5852 // all those functions return disk write-protected
5853 case 0x03: /* write disk sectors */
5854 case 0x05: /* format disk track */
5856 goto int13_fail_noah
;
5859 case 0x01: /* read disk status */
5860 status
=read_byte(0x0040, 0x0074);
5862 SET_DISK_RET_STATUS(0);
5864 /* set CF if error status read */
5865 if (status
) goto int13_fail_nostatus
;
5866 else goto int13_success_noah
;
5869 case 0x02: // read disk sectors
5870 case 0x04: // verify disk sectors
5871 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5872 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5873 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5875 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5877 sector
= GET_CL() & 0x003f;
5878 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5880 nbsectors
= GET_AL();
5884 // no sector to read ?
5885 if(nbsectors
==0) goto int13_success
;
5887 // sanity checks sco openserver needs this!
5889 || (cylinder
>= vcylinders
)
5890 || (head
>= vheads
)) {
5894 // After controls, verify do nothing
5895 if (GET_AH() == 0x04) goto int13_success
;
5897 segment
= ES
+(BX
/ 16);
5900 // calculate the virtual lba inside the image
5901 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5903 // In advance so we don't loose the count
5907 slba
= (Bit32u
)vlba
/4;
5908 before
= (Bit16u
)vlba
%4;
5911 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5913 memsetb(get_SS(),atacmd
,0,12);
5914 atacmd
[0]=0x28; // READ command
5915 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5916 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5917 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5918 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5919 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5920 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5921 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5922 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5925 goto int13_fail_noah
;
5931 case 0x08: /* read disk drive parameters */
5932 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5933 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5934 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5938 SET_CH( vcylinders
& 0xff );
5939 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5941 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5942 // FIXME ElTorito Harddisk. should send the HD count
5944 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5945 case 0x01: SET_BL( 0x02 ); break;
5946 case 0x02: SET_BL( 0x04 ); break;
5947 case 0x03: SET_BL( 0x06 ); break;
5953 mov ax
, #diskette_param_table2
5954 mov _int13_cdemu
.DI
+2[bp
], ax
5955 mov _int13_cdemu
.ES
+2[bp
], cs
5961 case 0x15: /* read disk drive size */
5962 // FIXME ElTorito Harddisk. What geometry to send ?
5964 goto int13_success_noah
;
5967 // all those functions return unimplemented
5968 case 0x0a: /* read disk sectors with ECC */
5969 case 0x0b: /* write disk sectors with ECC */
5970 case 0x18: /* set media type for format */
5971 case 0x41: // IBM/MS installation check
5972 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5973 case 0x42: // IBM/MS extended read
5974 case 0x43: // IBM/MS extended write
5975 case 0x44: // IBM/MS verify sectors
5976 case 0x45: // IBM/MS lock/unlock drive
5977 case 0x46: // IBM/MS eject media
5978 case 0x47: // IBM/MS extended seek
5979 case 0x48: // IBM/MS get drive parameters
5980 case 0x49: // IBM/MS extended media change
5981 case 0x4e: // ? - set hardware configuration
5982 case 0x50: // ? - send packet command
5984 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5990 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5992 SET_DISK_RET_STATUS(GET_AH());
5993 int13_fail_nostatus
:
5994 SET_CF(); // error occurred
5998 SET_AH(0x00); // no error
6000 SET_DISK_RET_STATUS(0x00);
6001 CLEAR_CF(); // no error
6005 // ---------------------------------------------------------------------------
6006 // End of int13 when emulating a device from the cd
6007 // ---------------------------------------------------------------------------
6009 #endif // BX_ELTORITO_BOOT
6011 #else //BX_USE_ATADRV
6014 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
6029 mov ax
,4[bp
] // cylinder
6031 mov bl
,6[bp
] // hd_heads
6034 mov bl
,8[bp
] // head
6036 mov bl
,10[bp
] // hd_sectors
6038 mov bl
,12[bp
] // sector
6067 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6068 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6070 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
6074 Bit16u max_cylinder
, cylinder
, total_sectors
;
6075 Bit16u hd_cylinders
;
6076 Bit8u hd_heads
, hd_sectors
;
6083 Bit16u count
, segment
, offset
;
6087 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6089 write_byte(0x0040, 0x008e, 0); // clear completion flag
6091 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6093 /* check how many disks first (cmos reg 0x12), return an error if
6094 drive not present */
6095 drive_map
= inb_cmos(0x12);
6096 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6097 (((drive_map
& 0x0f)==0) ? 0 : 2);
6098 n_drives
= (drive_map
==0) ? 0 :
6099 ((drive_map
==3) ? 2 : 1);
6101 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6103 SET_DISK_RET_STATUS(0x01);
6104 SET_CF(); /* error occurred */
6110 case 0x00: /* disk controller reset */
6111 BX_DEBUG_INT13_HD("int13_f00\n");
6114 SET_DISK_RET_STATUS(0);
6115 set_diskette_ret_status(0);
6116 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6117 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6118 CLEAR_CF(); /* successful */
6122 case 0x01: /* read disk status */
6123 BX_DEBUG_INT13_HD("int13_f01\n");
6124 status
= read_byte(0x0040, 0x0074);
6126 SET_DISK_RET_STATUS(0);
6127 /* set CF if error status read */
6128 if (status
) SET_CF();
6133 case 0x04: // verify disk sectors
6134 case 0x02: // read disk sectors
6136 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6138 num_sectors
= GET_AL();
6139 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6140 sector
= (GET_CL() & 0x3f);
6144 if (hd_cylinders
> 1024) {
6145 if (hd_cylinders
<= 2048) {
6148 else if (hd_cylinders
<= 4096) {
6151 else if (hd_cylinders
<= 8192) {
6154 else { // hd_cylinders <= 16384
6158 ax
= head
/ hd_heads
;
6159 cyl_mod
= ax
& 0xff;
6161 cylinder
|= cyl_mod
;
6164 if ( (cylinder
>= hd_cylinders
) ||
6165 (sector
> hd_sectors
) ||
6166 (head
>= hd_heads
) ) {
6168 SET_DISK_RET_STATUS(1);
6169 SET_CF(); /* error occurred */
6173 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6174 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6177 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6179 if ( GET_AH() == 0x04 ) {
6181 SET_DISK_RET_STATUS(0);
6186 status
= inb(0x1f7);
6187 if (status
& 0x80) {
6188 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6190 outb(0x01f2, num_sectors
);
6191 /* activate LBA? (tomv) */
6192 if (hd_heads
> 16) {
6193 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6194 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6197 outb(0x01f3, sector
);
6198 outb(0x01f4, cylinder
& 0x00ff);
6199 outb(0x01f5, cylinder
>> 8);
6200 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6205 status
= inb(0x1f7);
6206 if ( !(status
& 0x80) ) break;
6209 if (status
& 0x01) {
6210 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6211 } else if ( !(status
& 0x08) ) {
6212 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6213 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6220 sti
;; enable higher priority interrupts
6225 ;; store temp bx in real DI
register
6228 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6231 ;; adjust
if there will be an overrun
6233 jbe i13_f02_no_adjust
6235 sub di
, #0x0200 ; sub 512 bytes from offset
6237 add ax
, #0x0020 ; add 512 to segment
6241 mov cx
, #0x0100 ;; counter (256 words = 512b)
6242 mov dx
, #0x01f0 ;; AT data read port
6245 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6248 ;; store real DI
register back to temp bx
6251 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6257 if (num_sectors
== 0) {
6258 status
= inb(0x1f7);
6259 if ( (status
& 0xc9) != 0x40 )
6260 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6264 status
= inb(0x1f7);
6265 if ( (status
& 0xc9) != 0x48 )
6266 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6272 SET_DISK_RET_STATUS(0);
6273 SET_AL(sector_count
);
6274 CLEAR_CF(); /* successful */
6279 case 0x03: /* write disk sectors */
6280 BX_DEBUG_INT13_HD("int13_f03\n");
6281 drive
= GET_ELDL ();
6282 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6284 num_sectors
= GET_AL();
6285 cylinder
= GET_CH();
6286 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6287 sector
= (GET_CL() & 0x3f);
6290 if (hd_cylinders
> 1024) {
6291 if (hd_cylinders
<= 2048) {
6294 else if (hd_cylinders
<= 4096) {
6297 else if (hd_cylinders
<= 8192) {
6300 else { // hd_cylinders <= 16384
6304 ax
= head
/ hd_heads
;
6305 cyl_mod
= ax
& 0xff;
6307 cylinder
|= cyl_mod
;
6310 if ( (cylinder
>= hd_cylinders
) ||
6311 (sector
> hd_sectors
) ||
6312 (head
>= hd_heads
) ) {
6314 SET_DISK_RET_STATUS(1);
6315 SET_CF(); /* error occurred */
6319 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6320 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6323 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6325 status
= inb(0x1f7);
6326 if (status
& 0x80) {
6327 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6329 // should check for Drive Ready Bit also in status reg
6330 outb(0x01f2, num_sectors
);
6332 /* activate LBA? (tomv) */
6333 if (hd_heads
> 16) {
6334 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6335 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6338 outb(0x01f3, sector
);
6339 outb(0x01f4, cylinder
& 0x00ff);
6340 outb(0x01f5, cylinder
>> 8);
6341 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6345 // wait for busy bit to turn off after seeking
6347 status
= inb(0x1f7);
6348 if ( !(status
& 0x80) ) break;
6351 if ( !(status
& 0x08) ) {
6352 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6353 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6360 sti
;; enable higher priority interrupts
6365 ;; store temp bx in real SI
register
6368 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6371 ;; adjust
if there will be an overrun
6373 jbe i13_f03_no_adjust
6375 sub si
, #0x0200 ; sub 512 bytes from offset
6377 add ax
, #0x0020 ; add 512 to segment
6381 mov cx
, #0x0100 ;; counter (256 words = 512b)
6382 mov dx
, #0x01f0 ;; AT data read port
6386 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6388 ;; store real SI
register back to temp bx
6391 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6397 if (num_sectors
== 0) {
6398 status
= inb(0x1f7);
6399 if ( (status
& 0xe9) != 0x40 )
6400 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6404 status
= inb(0x1f7);
6405 if ( (status
& 0xc9) != 0x48 )
6406 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6412 SET_DISK_RET_STATUS(0);
6413 SET_AL(sector_count
);
6414 CLEAR_CF(); /* successful */
6418 case 0x05: /* format disk track */
6419 BX_DEBUG_INT13_HD("int13_f05\n");
6420 BX_PANIC("format disk track called\n");
6423 SET_DISK_RET_STATUS(0);
6424 CLEAR_CF(); /* successful */
6428 case 0x08: /* read disk drive parameters */
6429 BX_DEBUG_INT13_HD("int13_f08\n");
6431 drive
= GET_ELDL ();
6432 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6436 if (hd_cylinders
<= 1024) {
6437 // hd_cylinders >>= 0;
6440 else if (hd_cylinders
<= 2048) {
6444 else if (hd_cylinders
<= 4096) {
6448 else if (hd_cylinders
<= 8192) {
6452 else { // hd_cylinders <= 16384
6457 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6459 SET_CH(max_cylinder
& 0xff);
6460 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6461 SET_DH(hd_heads
- 1);
6462 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6464 SET_DISK_RET_STATUS(0);
6465 CLEAR_CF(); /* successful */
6470 case 0x09: /* initialize drive parameters */
6471 BX_DEBUG_INT13_HD("int13_f09\n");
6473 SET_DISK_RET_STATUS(0);
6474 CLEAR_CF(); /* successful */
6478 case 0x0a: /* read disk sectors with ECC */
6479 BX_DEBUG_INT13_HD("int13_f0a\n");
6480 case 0x0b: /* write disk sectors with ECC */
6481 BX_DEBUG_INT13_HD("int13_f0b\n");
6482 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6486 case 0x0c: /* seek to specified cylinder */
6487 BX_DEBUG_INT13_HD("int13_f0c\n");
6488 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6490 SET_DISK_RET_STATUS(0);
6491 CLEAR_CF(); /* successful */
6495 case 0x0d: /* alternate disk reset */
6496 BX_DEBUG_INT13_HD("int13_f0d\n");
6498 SET_DISK_RET_STATUS(0);
6499 CLEAR_CF(); /* successful */
6503 case 0x10: /* check drive ready */
6504 BX_DEBUG_INT13_HD("int13_f10\n");
6506 //SET_DISK_RET_STATUS(0);
6507 //CLEAR_CF(); /* successful */
6511 // should look at 40:8E also???
6512 status
= inb(0x01f7);
6513 if ( (status
& 0xc0) == 0x40 ) {
6515 SET_DISK_RET_STATUS(0);
6516 CLEAR_CF(); // drive ready
6521 SET_DISK_RET_STATUS(0xAA);
6522 SET_CF(); // not ready
6527 case 0x11: /* recalibrate */
6528 BX_DEBUG_INT13_HD("int13_f11\n");
6530 SET_DISK_RET_STATUS(0);
6531 CLEAR_CF(); /* successful */
6535 case 0x14: /* controller internal diagnostic */
6536 BX_DEBUG_INT13_HD("int13_f14\n");
6538 SET_DISK_RET_STATUS(0);
6539 CLEAR_CF(); /* successful */
6544 case 0x15: /* read disk drive size */
6546 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6550 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6551 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6552 mul al
, ah
;; ax
= heads
* sectors
6553 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6554 dec bx
;; use (cylinders
- 1) ???
6555 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6556 ;; now we need to move the
32bit result dx
:ax to what the
6557 ;; BIOS wants which is cx
:dx
.
6558 ;; and then into CX
:DX on the stack
6559 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6560 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6563 SET_AH(3); // hard disk accessible
6564 SET_DISK_RET_STATUS(0); // ??? should this be 0
6565 CLEAR_CF(); // successful
6569 case 0x18: // set media type for format
6570 case 0x41: // IBM/MS
6571 case 0x42: // IBM/MS
6572 case 0x43: // IBM/MS
6573 case 0x44: // IBM/MS
6574 case 0x45: // IBM/MS lock/unlock drive
6575 case 0x46: // IBM/MS eject media
6576 case 0x47: // IBM/MS extended seek
6577 case 0x49: // IBM/MS extended media change
6578 case 0x50: // IBM/MS send packet command
6580 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6582 SET_AH(1); // code=invalid function in AH or invalid parameter
6583 SET_DISK_RET_STATUS(1);
6584 SET_CF(); /* unsuccessful */
6590 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6591 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6594 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6596 Bit16u
*hd_cylinders
;
6606 if (drive
== 0x80) {
6607 hd_type
= inb_cmos(0x12) & 0xf0;
6608 if (hd_type
!= 0xf0)
6609 BX_INFO(panic_msg_reg12h
,0);
6610 hd_type
= inb_cmos(0x19); // HD0: extended type
6612 BX_INFO(panic_msg_reg19h
,0,0x19);
6615 hd_type
= inb_cmos(0x12) & 0x0f;
6616 if (hd_type
!= 0x0f)
6617 BX_INFO(panic_msg_reg12h
,1);
6618 hd_type
= inb_cmos(0x1a); // HD0: extended type
6620 BX_INFO(panic_msg_reg19h
,0,0x1a);
6625 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6626 write_word(ss
, hd_cylinders
, cylinders
);
6629 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6631 // sectors per track
6632 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6635 #endif //else BX_USE_ATADRV
6637 #if BX_SUPPORT_FLOPPY
6639 //////////////////////
6640 // FLOPPY functions //
6641 //////////////////////
6643 void floppy_reset_controller()
6649 outb(0x03f2, val8
& ~0x04);
6650 outb(0x03f2, val8
| 0x04);
6652 // Wait for controller to come out of reset
6655 } while ( (val8
& 0xc0) != 0x80 );
6658 void floppy_prepare_controller(drive
)
6661 Bit8u val8
, dor
, prev_reset
;
6663 // set 40:3e bit 7 to 0
6664 val8
= read_byte(0x0040, 0x003e);
6666 write_byte(0x0040, 0x003e, val8
);
6668 // turn on motor of selected drive, DMA & int enabled, normal operation
6669 prev_reset
= inb(0x03f2) & 0x04;
6678 // reset the disk motor timeout value of INT 08
6679 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6681 // wait for drive readiness
6684 } while ( (val8
& 0xc0) != 0x80 );
6686 if (prev_reset
== 0) {
6687 // turn on interrupts
6691 // wait on 40:3e bit 7 to become 1
6693 val8
= read_byte(0x0040, 0x003e);
6694 } while ( (val8
& 0x80) == 0 );
6699 write_byte(0x0040, 0x003e, val8
);
6704 floppy_media_known(drive
)
6708 Bit16u media_state_offset
;
6710 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6717 media_state_offset
= 0x0090;
6719 media_state_offset
+= 1;
6721 val8
= read_byte(0x0040, media_state_offset
);
6722 val8
= (val8
>> 4) & 0x01;
6726 // check pass, return KNOWN
6731 floppy_media_sense(drive
)
6735 Bit16u media_state_offset
;
6736 Bit8u drive_type
, config_data
, media_state
;
6738 if (floppy_drive_recal(drive
) == 0) {
6742 // for now cheat and get drive type from CMOS,
6743 // assume media is same as drive type
6745 // ** config_data **
6746 // Bitfields for diskette media control:
6747 // Bit(s) Description (Table M0028)
6748 // 7-6 last data rate set by controller
6749 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6750 // 5-4 last diskette drive step rate selected
6751 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6752 // 3-2 {data rate at start of operation}
6755 // ** media_state **
6756 // Bitfields for diskette drive media state:
6757 // Bit(s) Description (Table M0030)
6759 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6760 // 5 double stepping required (e.g. 360kB in 1.2MB)
6761 // 4 media type established
6762 // 3 drive capable of supporting 4MB media
6763 // 2-0 on exit from BIOS, contains
6764 // 000 trying 360kB in 360kB
6765 // 001 trying 360kB in 1.2MB
6766 // 010 trying 1.2MB in 1.2MB
6767 // 011 360kB in 360kB established
6768 // 100 360kB in 1.2MB established
6769 // 101 1.2MB in 1.2MB established
6771 // 111 all other formats/drives
6773 drive_type
= inb_cmos(0x10);
6778 if ( drive_type
== 1 ) {
6780 config_data
= 0x00; // 0000 0000
6781 media_state
= 0x25; // 0010 0101
6784 else if ( drive_type
== 2 ) {
6785 // 1.2 MB 5.25" drive
6786 config_data
= 0x00; // 0000 0000
6787 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6790 else if ( drive_type
== 3 ) {
6792 config_data
= 0x00; // 0000 0000 ???
6793 media_state
= 0x17; // 0001 0111
6796 else if ( drive_type
== 4 ) {
6797 // 1.44 MB 3.5" drive
6798 config_data
= 0x00; // 0000 0000
6799 media_state
= 0x17; // 0001 0111
6802 else if ( drive_type
== 5 ) {
6803 // 2.88 MB 3.5" drive
6804 config_data
= 0xCC; // 1100 1100
6805 media_state
= 0xD7; // 1101 0111
6809 // Extended floppy size uses special cmos setting
6810 else if ( drive_type
== 6 ) {
6812 config_data
= 0x00; // 0000 0000
6813 media_state
= 0x27; // 0010 0111
6816 else if ( drive_type
== 7 ) {
6818 config_data
= 0x00; // 0000 0000
6819 media_state
= 0x27; // 0010 0111
6822 else if ( drive_type
== 8 ) {
6824 config_data
= 0x00; // 0000 0000
6825 media_state
= 0x27; // 0010 0111
6831 config_data
= 0x00; // 0000 0000
6832 media_state
= 0x00; // 0000 0000
6837 media_state_offset
= 0x90;
6839 media_state_offset
= 0x91;
6840 write_byte(0x0040, 0x008B, config_data
);
6841 write_byte(0x0040, media_state_offset
, media_state
);
6847 floppy_drive_recal(drive
)
6851 Bit16u curr_cyl_offset
;
6853 floppy_prepare_controller(drive
);
6855 // send Recalibrate command (2 bytes) to controller
6856 outb(0x03f5, 0x07); // 07: Recalibrate
6857 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6859 // turn on interrupts
6864 // wait on 40:3e bit 7 to become 1
6866 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6867 } while ( val8
== 0 );
6869 val8
= 0; // separate asm from while() loop
6870 // turn off interrupts
6875 // set 40:3e bit 7 to 0, and calibrated bit
6876 val8
= read_byte(0x0040, 0x003e);
6879 val8
|= 0x02; // Drive 1 calibrated
6880 curr_cyl_offset
= 0x0095;
6882 val8
|= 0x01; // Drive 0 calibrated
6883 curr_cyl_offset
= 0x0094;
6885 write_byte(0x0040, 0x003e, val8
);
6886 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6894 floppy_drive_exists(drive
)
6899 // check CMOS to see if drive exists
6900 drive_type
= inb_cmos(0x10);
6905 if ( drive_type
== 0 )
6912 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6913 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6915 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6916 Bit16u base_address
, base_count
, base_es
;
6917 Bit8u page
, mode_register
, val8
, dor
;
6918 Bit8u return_status
[7];
6919 Bit8u drive_type
, num_floppies
, ah
;
6920 Bit16u es
, last_addr
;
6922 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6927 case 0x00: // diskette controller reset
6928 BX_DEBUG_INT13_FL("floppy f00\n");
6931 SET_AH(1); // invalid param
6932 set_diskette_ret_status(1);
6936 drive_type
= inb_cmos(0x10);
6942 if (drive_type
== 0) {
6943 SET_AH(0x80); // drive not responding
6944 set_diskette_ret_status(0x80);
6949 set_diskette_ret_status(0);
6950 CLEAR_CF(); // successful
6951 set_diskette_current_cyl(drive
, 0); // current cylinder
6954 case 0x01: // Read Diskette Status
6956 val8
= read_byte(0x0000, 0x0441);
6963 case 0x02: // Read Diskette Sectors
6964 case 0x03: // Write Diskette Sectors
6965 case 0x04: // Verify Diskette Sectors
6966 num_sectors
= GET_AL();
6972 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
6973 (num_sectors
== 0) || (num_sectors
> 72)) {
6974 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
6976 set_diskette_ret_status(1);
6977 SET_AL(0); // no sectors read
6978 SET_CF(); // error occurred
6982 // see if drive exists
6983 if (floppy_drive_exists(drive
) == 0) {
6984 SET_AH(0x80); // not responding
6985 set_diskette_ret_status(0x80);
6986 SET_AL(0); // no sectors read
6987 SET_CF(); // error occurred
6991 // see if media in drive, and type is known
6992 if (floppy_media_known(drive
) == 0) {
6993 if (floppy_media_sense(drive
) == 0) {
6994 SET_AH(0x0C); // Media type not found
6995 set_diskette_ret_status(0x0C);
6996 SET_AL(0); // no sectors read
6997 SET_CF(); // error occurred
7003 // Read Diskette Sectors
7005 //-----------------------------------
7006 // set up DMA controller for transfer
7007 //-----------------------------------
7009 // es:bx = pointer to where to place information from diskette
7010 // port 04: DMA-1 base and current address, channel 2
7011 // port 05: DMA-1 base and current count, channel 2
7012 page
= (ES
>> 12); // upper 4 bits
7013 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7014 base_address
= base_es
+ BX
; // lower 16 bits of address
7015 // contributed by ES:BX
7016 if ( base_address
< base_es
) {
7017 // in case of carry, adjust page by 1
7020 base_count
= (num_sectors
* 512) - 1;
7022 // check for 64K boundary overrun
7023 last_addr
= base_address
+ base_count
;
7024 if (last_addr
< base_address
) {
7026 set_diskette_ret_status(0x09);
7027 SET_AL(0); // no sectors read
7028 SET_CF(); // error occurred
7032 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7035 BX_DEBUG_INT13_FL("clear flip-flop\n");
7036 outb(0x000c, 0x00); // clear flip-flop
7037 outb(0x0004, base_address
);
7038 outb(0x0004, base_address
>>8);
7039 BX_DEBUG_INT13_FL("clear flip-flop\n");
7040 outb(0x000c, 0x00); // clear flip-flop
7041 outb(0x0005, base_count
);
7042 outb(0x0005, base_count
>>8);
7044 // port 0b: DMA-1 Mode Register
7045 mode_register
= 0x46; // single mode, increment, autoinit disable,
7046 // transfer type=write, channel 2
7047 BX_DEBUG_INT13_FL("setting mode register\n");
7048 outb(0x000b, mode_register
);
7050 BX_DEBUG_INT13_FL("setting page register\n");
7051 // port 81: DMA-1 Page Register, channel 2
7054 BX_DEBUG_INT13_FL("unmask chan 2\n");
7055 outb(0x000a, 0x02); // unmask channel 2
7057 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7060 //--------------------------------------
7061 // set up floppy controller for transfer
7062 //--------------------------------------
7063 floppy_prepare_controller(drive
);
7065 // send read-normal-data command (9 bytes) to controller
7066 outb(0x03f5, 0xe6); // e6: read normal data
7067 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7068 outb(0x03f5, track
);
7070 outb(0x03f5, sector
);
7071 outb(0x03f5, 2); // 512 byte sector size
7072 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
7073 outb(0x03f5, 0); // Gap length
7074 outb(0x03f5, 0xff); // Gap length
7076 // turn on interrupts
7081 // wait on 40:3e bit 7 to become 1
7083 val8
= read_byte(0x0040, 0x0040);
7085 floppy_reset_controller();
7086 SET_AH(0x80); // drive not ready (timeout)
7087 set_diskette_ret_status(0x80);
7088 SET_AL(0); // no sectors read
7089 SET_CF(); // error occurred
7092 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7093 } while ( val8
== 0 );
7095 val8
= 0; // separate asm from while() loop
7096 // turn off interrupts
7101 // set 40:3e bit 7 to 0
7102 val8
= read_byte(0x0040, 0x003e);
7104 write_byte(0x0040, 0x003e, val8
);
7106 // check port 3f4 for accessibility to status bytes
7108 if ( (val8
& 0xc0) != 0xc0 )
7109 BX_PANIC("int13_diskette: ctrl not ready\n");
7111 // read 7 return status bytes from controller
7112 // using loop index broken, have to unroll...
7113 return_status
[0] = inb(0x3f5);
7114 return_status
[1] = inb(0x3f5);
7115 return_status
[2] = inb(0x3f5);
7116 return_status
[3] = inb(0x3f5);
7117 return_status
[4] = inb(0x3f5);
7118 return_status
[5] = inb(0x3f5);
7119 return_status
[6] = inb(0x3f5);
7120 // record in BIOS Data Area
7121 write_byte(0x0040, 0x0042, return_status
[0]);
7122 write_byte(0x0040, 0x0043, return_status
[1]);
7123 write_byte(0x0040, 0x0044, return_status
[2]);
7124 write_byte(0x0040, 0x0045, return_status
[3]);
7125 write_byte(0x0040, 0x0046, return_status
[4]);
7126 write_byte(0x0040, 0x0047, return_status
[5]);
7127 write_byte(0x0040, 0x0048, return_status
[6]);
7129 if ( (return_status
[0] & 0xc0) != 0 ) {
7131 set_diskette_ret_status(0x20);
7132 SET_AL(0); // no sectors read
7133 SET_CF(); // error occurred
7137 // ??? should track be new val from return_status[3] ?
7138 set_diskette_current_cyl(drive
, track
);
7139 // AL = number of sectors read (same value as passed)
7140 SET_AH(0x00); // success
7141 CLEAR_CF(); // success
7143 } else if (ah
== 0x03) {
7144 // Write Diskette Sectors
7146 //-----------------------------------
7147 // set up DMA controller for transfer
7148 //-----------------------------------
7150 // es:bx = pointer to where to place information from diskette
7151 // port 04: DMA-1 base and current address, channel 2
7152 // port 05: DMA-1 base and current count, channel 2
7153 page
= (ES
>> 12); // upper 4 bits
7154 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7155 base_address
= base_es
+ BX
; // lower 16 bits of address
7156 // contributed by ES:BX
7157 if ( base_address
< base_es
) {
7158 // in case of carry, adjust page by 1
7161 base_count
= (num_sectors
* 512) - 1;
7163 // check for 64K boundary overrun
7164 last_addr
= base_address
+ base_count
;
7165 if (last_addr
< base_address
) {
7167 set_diskette_ret_status(0x09);
7168 SET_AL(0); // no sectors read
7169 SET_CF(); // error occurred
7173 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7176 outb(0x000c, 0x00); // clear flip-flop
7177 outb(0x0004, base_address
);
7178 outb(0x0004, base_address
>>8);
7179 outb(0x000c, 0x00); // clear flip-flop
7180 outb(0x0005, base_count
);
7181 outb(0x0005, base_count
>>8);
7183 // port 0b: DMA-1 Mode Register
7184 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7185 // transfer type=read, channel 2
7186 outb(0x000b, mode_register
);
7188 // port 81: DMA-1 Page Register, channel 2
7191 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7194 //--------------------------------------
7195 // set up floppy controller for transfer
7196 //--------------------------------------
7197 floppy_prepare_controller(drive
);
7199 // send write-normal-data command (9 bytes) to controller
7200 outb(0x03f5, 0xc5); // c5: write normal data
7201 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7202 outb(0x03f5, track
);
7204 outb(0x03f5, sector
);
7205 outb(0x03f5, 2); // 512 byte sector size
7206 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7207 outb(0x03f5, 0); // Gap length
7208 outb(0x03f5, 0xff); // Gap length
7210 // turn on interrupts
7215 // wait on 40:3e bit 7 to become 1
7217 val8
= read_byte(0x0040, 0x0040);
7219 floppy_reset_controller();
7220 SET_AH(0x80); // drive not ready (timeout)
7221 set_diskette_ret_status(0x80);
7222 SET_AL(0); // no sectors written
7223 SET_CF(); // error occurred
7226 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7227 } while ( val8
== 0 );
7229 val8
= 0; // separate asm from while() loop
7230 // turn off interrupts
7235 // set 40:3e bit 7 to 0
7236 val8
= read_byte(0x0040, 0x003e);
7238 write_byte(0x0040, 0x003e, val8
);
7240 // check port 3f4 for accessibility to status bytes
7242 if ( (val8
& 0xc0) != 0xc0 )
7243 BX_PANIC("int13_diskette: ctrl not ready\n");
7245 // read 7 return status bytes from controller
7246 // using loop index broken, have to unroll...
7247 return_status
[0] = inb(0x3f5);
7248 return_status
[1] = inb(0x3f5);
7249 return_status
[2] = inb(0x3f5);
7250 return_status
[3] = inb(0x3f5);
7251 return_status
[4] = inb(0x3f5);
7252 return_status
[5] = inb(0x3f5);
7253 return_status
[6] = inb(0x3f5);
7254 // record in BIOS Data Area
7255 write_byte(0x0040, 0x0042, return_status
[0]);
7256 write_byte(0x0040, 0x0043, return_status
[1]);
7257 write_byte(0x0040, 0x0044, return_status
[2]);
7258 write_byte(0x0040, 0x0045, return_status
[3]);
7259 write_byte(0x0040, 0x0046, return_status
[4]);
7260 write_byte(0x0040, 0x0047, return_status
[5]);
7261 write_byte(0x0040, 0x0048, return_status
[6]);
7263 if ( (return_status
[0] & 0xc0) != 0 ) {
7264 if ( (return_status
[1] & 0x02) != 0 ) {
7265 // diskette not writable.
7266 // AH=status code=0x03 (tried to write on write-protected disk)
7267 // AL=number of sectors written=0
7272 BX_PANIC("int13_diskette_function: read error\n");
7276 // ??? should track be new val from return_status[3] ?
7277 set_diskette_current_cyl(drive
, track
);
7278 // AL = number of sectors read (same value as passed)
7279 SET_AH(0x00); // success
7280 CLEAR_CF(); // success
7282 } else { // if (ah == 0x04)
7283 // Verify Diskette Sectors
7285 // ??? should track be new val from return_status[3] ?
7286 set_diskette_current_cyl(drive
, track
);
7287 // AL = number of sectors verified (same value as passed)
7288 CLEAR_CF(); // success
7289 SET_AH(0x00); // success
7294 case 0x05: // format diskette track
7295 BX_DEBUG_INT13_FL("floppy f05\n");
7297 num_sectors
= GET_AL();
7302 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7303 (num_sectors
== 0) || (num_sectors
> 18)) {
7305 set_diskette_ret_status(1);
7306 SET_CF(); // error occurred
7309 // see if drive exists
7310 if (floppy_drive_exists(drive
) == 0) {
7311 SET_AH(0x80); // drive not responding
7312 set_diskette_ret_status(0x80);
7313 SET_CF(); // error occurred
7317 // see if media in drive, and type is known
7318 if (floppy_media_known(drive
) == 0) {
7319 if (floppy_media_sense(drive
) == 0) {
7320 SET_AH(0x0C); // Media type not found
7321 set_diskette_ret_status(0x0C);
7322 SET_AL(0); // no sectors read
7323 SET_CF(); // error occurred
7328 // set up DMA controller for transfer
7329 page
= (ES
>> 12); // upper 4 bits
7330 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7331 base_address
= base_es
+ BX
; // lower 16 bits of address
7332 // contributed by ES:BX
7333 if ( base_address
< base_es
) {
7334 // in case of carry, adjust page by 1
7337 base_count
= (num_sectors
* 4) - 1;
7339 // check for 64K boundary overrun
7340 last_addr
= base_address
+ base_count
;
7341 if (last_addr
< base_address
) {
7343 set_diskette_ret_status(0x09);
7344 SET_AL(0); // no sectors read
7345 SET_CF(); // error occurred
7350 outb(0x000c, 0x00); // clear flip-flop
7351 outb(0x0004, base_address
);
7352 outb(0x0004, base_address
>>8);
7353 outb(0x000c, 0x00); // clear flip-flop
7354 outb(0x0005, base_count
);
7355 outb(0x0005, base_count
>>8);
7356 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7357 // transfer type=read, channel 2
7358 outb(0x000b, mode_register
);
7359 // port 81: DMA-1 Page Register, channel 2
7363 // set up floppy controller for transfer
7364 floppy_prepare_controller(drive
);
7366 // send format-track command (6 bytes) to controller
7367 outb(0x03f5, 0x4d); // 4d: format track
7368 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7369 outb(0x03f5, 2); // 512 byte sector size
7370 outb(0x03f5, num_sectors
); // number of sectors per track
7371 outb(0x03f5, 0); // Gap length
7372 outb(0x03f5, 0xf6); // Fill byte
7373 // turn on interrupts
7378 // wait on 40:3e bit 7 to become 1
7380 val8
= read_byte(0x0040, 0x0040);
7382 floppy_reset_controller();
7383 SET_AH(0x80); // drive not ready (timeout)
7384 set_diskette_ret_status(0x80);
7385 SET_CF(); // error occurred
7388 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7389 } while ( val8
== 0 );
7391 val8
= 0; // separate asm from while() loop
7392 // turn off interrupts
7396 // set 40:3e bit 7 to 0
7397 val8
= read_byte(0x0040, 0x003e);
7399 write_byte(0x0040, 0x003e, val8
);
7400 // check port 3f4 for accessibility to status bytes
7402 if ( (val8
& 0xc0) != 0xc0 )
7403 BX_PANIC("int13_diskette: ctrl not ready\n");
7405 // read 7 return status bytes from controller
7406 // using loop index broken, have to unroll...
7407 return_status
[0] = inb(0x3f5);
7408 return_status
[1] = inb(0x3f5);
7409 return_status
[2] = inb(0x3f5);
7410 return_status
[3] = inb(0x3f5);
7411 return_status
[4] = inb(0x3f5);
7412 return_status
[5] = inb(0x3f5);
7413 return_status
[6] = inb(0x3f5);
7414 // record in BIOS Data Area
7415 write_byte(0x0040, 0x0042, return_status
[0]);
7416 write_byte(0x0040, 0x0043, return_status
[1]);
7417 write_byte(0x0040, 0x0044, return_status
[2]);
7418 write_byte(0x0040, 0x0045, return_status
[3]);
7419 write_byte(0x0040, 0x0046, return_status
[4]);
7420 write_byte(0x0040, 0x0047, return_status
[5]);
7421 write_byte(0x0040, 0x0048, return_status
[6]);
7423 if ( (return_status
[0] & 0xc0) != 0 ) {
7424 if ( (return_status
[1] & 0x02) != 0 ) {
7425 // diskette not writable.
7426 // AH=status code=0x03 (tried to write on write-protected disk)
7427 // AL=number of sectors written=0
7432 BX_PANIC("int13_diskette_function: write error\n");
7437 set_diskette_ret_status(0);
7438 set_diskette_current_cyl(drive
, 0);
7439 CLEAR_CF(); // successful
7443 case 0x08: // read diskette drive parameters
7444 BX_DEBUG_INT13_FL("floppy f08\n");
7454 SET_DL(num_floppies
);
7459 drive_type
= inb_cmos(0x10);
7461 if (drive_type
& 0xf0)
7463 if (drive_type
& 0x0f)
7475 SET_DL(num_floppies
);
7477 switch (drive_type
) {
7480 SET_DH(0); // max head #
7483 case 1: // 360KB, 5.25"
7484 CX
= 0x2709; // 40 tracks, 9 sectors
7485 SET_DH(1); // max head #
7488 case 2: // 1.2MB, 5.25"
7489 CX
= 0x4f0f; // 80 tracks, 15 sectors
7490 SET_DH(1); // max head #
7493 case 3: // 720KB, 3.5"
7494 CX
= 0x4f09; // 80 tracks, 9 sectors
7495 SET_DH(1); // max head #
7498 case 4: // 1.44MB, 3.5"
7499 CX
= 0x4f12; // 80 tracks, 18 sectors
7500 SET_DH(1); // max head #
7503 case 5: // 2.88MB, 3.5"
7504 CX
= 0x4f24; // 80 tracks, 36 sectors
7505 SET_DH(1); // max head #
7508 case 6: // 160k, 5.25"
7509 CX
= 0x2708; // 40 tracks, 8 sectors
7510 SET_DH(0); // max head #
7513 case 7: // 180k, 5.25"
7514 CX
= 0x2709; // 40 tracks, 9 sectors
7515 SET_DH(0); // max head #
7518 case 8: // 320k, 5.25"
7519 CX
= 0x2708; // 40 tracks, 8 sectors
7520 SET_DH(1); // max head #
7524 BX_PANIC("floppy: int13: bad floppy type\n");
7527 /* set es & di to point to 11 byte diskette param table in ROM */
7531 mov ax
, #diskette_param_table2
7532 mov _int13_diskette_function
.DI
+2[bp
], ax
7533 mov _int13_diskette_function
.ES
+2[bp
], cs
7536 CLEAR_CF(); // success
7537 /* disk status not changed upon success */
7541 case 0x15: // read diskette drive type
7542 BX_DEBUG_INT13_FL("floppy f15\n");
7545 SET_AH(0); // only 2 drives supported
7546 // set_diskette_ret_status here ???
7550 drive_type
= inb_cmos(0x10);
7556 CLEAR_CF(); // successful, not present
7557 if (drive_type
==0) {
7558 SET_AH(0); // drive not present
7561 SET_AH(1); // drive present, does not support change line
7566 case 0x16: // get diskette change line status
7567 BX_DEBUG_INT13_FL("floppy f16\n");
7570 SET_AH(0x01); // invalid drive
7571 set_diskette_ret_status(0x01);
7576 SET_AH(0x06); // change line not supported
7577 set_diskette_ret_status(0x06);
7581 case 0x17: // set diskette type for format(old)
7582 BX_DEBUG_INT13_FL("floppy f17\n");
7583 /* not used for 1.44M floppies */
7584 SET_AH(0x01); // not supported
7585 set_diskette_ret_status(1); /* not supported */
7589 case 0x18: // set diskette type for format(new)
7590 BX_DEBUG_INT13_FL("floppy f18\n");
7591 SET_AH(0x01); // do later
7592 set_diskette_ret_status(1);
7597 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7599 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7600 SET_AH(0x01); // ???
7601 set_diskette_ret_status(1);
7607 #else // #if BX_SUPPORT_FLOPPY
7609 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7610 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7614 switch ( GET_AH() ) {
7616 case 0x01: // Read Diskette Status
7618 val8
= read_byte(0x0000, 0x0441);
7627 write_byte(0x0000, 0x0441, 0x01);
7631 #endif // #if BX_SUPPORT_FLOPPY
7634 set_diskette_ret_status(value
)
7637 write_byte(0x0040, 0x0041, value
);
7641 set_diskette_current_cyl(drive
, cyl
)
7646 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7647 write_byte(0x0040, 0x0094+drive
, cyl
);
7651 determine_floppy_media(drive
)
7655 Bit8u val8
, DOR
, ctrl_info
;
7657 ctrl_info
= read_byte(0x0040, 0x008F);
7665 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7668 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7672 if ( (ctrl_info
& 0x04) != 0x04 ) {
7673 // Drive not determined means no drive exists, done.
7678 // check Main Status Register for readiness
7679 val8
= inb(0x03f4) & 0x80; // Main Status Register
7681 BX_PANIC("d_f_m: MRQ bit not set\n");
7685 // existing BDA values
7687 // turn on drive motor
7688 outb(0x03f2, DOR
); // Digital Output Register
7691 BX_PANIC("d_f_m: OK so far\n");
7696 int17_function(regs
, ds
, iret_addr
)
7697 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7698 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7699 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7701 Bit16u addr
,timeout
;
7708 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7709 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7710 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7711 if (regs
.u
.r8
.ah
== 0) {
7712 outb(addr
, regs
.u
.r8
.al
);
7714 outb(addr
+2, val8
| 0x01); // send strobe
7718 outb(addr
+2, val8
& ~0x01);
7719 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7723 if (regs
.u
.r8
.ah
== 1) {
7725 outb(addr
+2, val8
& ~0x04); // send init
7729 outb(addr
+2, val8
| 0x04);
7732 regs
.u
.r8
.ah
= (val8
^ 0x48);
7733 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7734 ClearCF(iret_addr
.flags
);
7736 SetCF(iret_addr
.flags
); // Unsupported
7741 int19_function(seq_nr
)
7744 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7754 // if BX_ELTORITO_BOOT is not defined, old behavior
7755 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7756 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7757 // 0: system boot sequence, first drive C: then A:
7758 // 1: system boot sequence, first drive A: then C:
7759 // else BX_ELTORITO_BOOT is defined
7760 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7761 // CMOS reg 0x3D & 0x0f : 1st boot device
7762 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7763 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7764 // boot device codes:
7765 // 0x00 : not defined
7766 // 0x01 : first floppy
7767 // 0x02 : first harddrive
7768 // 0x03 : first cdrom
7769 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7770 // else : boot failure
7772 // Get the boot sequence
7773 #if BX_ELTORITO_BOOT
7774 bootdev
= inb_cmos(0x3d);
7775 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
7776 bootdev
>>= 4 * seq_nr
;
7778 if (bootdev
== 0) BX_PANIC("No bootable device.\n");
7780 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7783 if (seq_nr
==2) BX_PANIC("No more boot devices.");
7784 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
7785 /* Boot from floppy if the bit is set or it's the second boot */
7791 /* Read the boot device from the IPL table */
7792 if (get_boot_vector(bootdev
, &e
) == 0) {
7793 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
7797 /* Do the loading, and set up vector as a far pointer to the boot
7798 * address, and bootdrv as the boot drive */
7799 print_boot_device(e
.type
);
7802 case IPL_TYPE_FLOPPY
: /* FDD */
7803 case IPL_TYPE_HARDDISK
: /* HDD */
7805 bootdrv
= (e
.type
== IPL_TYPE_HARDDISK
) ? 0x80 : 0x00;
7817 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7818 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7819 mov es
, ax
;; segment
7820 xor bx
, bx
;; offset
7821 mov ah
, #0x02 ;; function 2, read diskette sector
7822 mov al
, #0x01 ;; read 1 sector
7823 mov ch
, #0x00 ;; track 0
7824 mov cl
, #0x01 ;; sector 1
7825 mov dh
, #0x00 ;; head 0
7826 int #0x13 ;; read sector
7829 mov _int19_function
.status
+ 2[bp
], ax
7840 print_boot_failure(e
.type
, 1);
7844 /* Always check the signature on a HDD boot sector; on FDD, only do
7845 * the check if the CMOS doesn't tell us to skip it */
7846 if ((e
.type
!= IPL_TYPE_FLOPPY
) || !((inb_cmos(0x38) & 0x01))) {
7847 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7848 print_boot_failure(e
.type
, 0);
7853 /* Canonicalize bootseg:bootip */
7854 bootip
= (bootseg
& 0x0fff) << 4;
7858 #if BX_ELTORITO_BOOT
7859 case IPL_TYPE_CDROM
: /* CD-ROM */
7860 status
= cdrom_boot();
7863 if ( (status
& 0x00ff) !=0 ) {
7864 print_cdromboot_failure(status
);
7865 print_boot_failure(e
.type
, 1);
7869 bootdrv
= (Bit8u
)(status
>>8);
7870 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7871 /* Canonicalize bootseg:bootip */
7872 bootip
= (bootseg
& 0x0fff) << 4;
7877 case IPL_TYPE_BEV
: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7878 bootseg
= e
.vector
>> 16;
7879 bootip
= e
.vector
& 0xffff;
7885 /* Debugging info */
7886 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
7888 /* Jump to the boot vector */
7891 ;; Build an iret stack frame that will take us to the boot vector
.
7892 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
7894 mov ax
, _int19_function
.bootseg
+ 0[bp
]
7896 mov ax
, _int19_function
.bootip
+ 0[bp
]
7898 ;; Set the magic number in ax
and the boot drive in dl
.
7900 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
7901 ;; Zero some of the other registers
.
7912 int1a_function(regs
, ds
, iret_addr
)
7913 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7914 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7915 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7919 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
);
7925 switch (regs
.u
.r8
.ah
) {
7926 case 0: // get current clock count
7930 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7931 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7932 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7933 BiosData
->midnight_flag
= 0; // reset flag
7938 ClearCF(iret_addr
.flags
); // OK
7941 case 1: // Set Current Clock Count
7945 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7946 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7947 BiosData
->midnight_flag
= 0; // reset flag
7952 ClearCF(iret_addr
.flags
); // OK
7956 case 2: // Read CMOS Time
7957 if (rtc_updating()) {
7958 SetCF(iret_addr
.flags
);
7962 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7963 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7964 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7965 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7967 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7968 ClearCF(iret_addr
.flags
); // OK
7971 case 3: // Set CMOS Time
7972 // Using a debugger, I notice the following masking/setting
7973 // of bits in Status Register B, by setting Reg B to
7974 // a few values and getting its value after INT 1A was called.
7976 // try#1 try#2 try#3
7977 // before 1111 1101 0111 1101 0000 0000
7978 // after 0110 0010 0110 0010 0000 0010
7980 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7981 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7982 if (rtc_updating()) {
7984 // fall through as if an update were not in progress
7986 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7987 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7988 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7989 // Set Daylight Savings time enabled bit to requested value
7990 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7991 // (reg B already selected)
7992 outb_cmos(0x0b, val8
);
7994 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7995 ClearCF(iret_addr
.flags
); // OK
7998 case 4: // Read CMOS Date
8000 if (rtc_updating()) {
8001 SetCF(iret_addr
.flags
);
8004 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
8005 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
8006 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
8007 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
8008 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8009 ClearCF(iret_addr
.flags
); // OK
8012 case 5: // Set CMOS Date
8013 // Using a debugger, I notice the following masking/setting
8014 // of bits in Status Register B, by setting Reg B to
8015 // a few values and getting its value after INT 1A was called.
8017 // try#1 try#2 try#3 try#4
8018 // before 1111 1101 0111 1101 0000 0010 0000 0000
8019 // after 0110 1101 0111 1101 0000 0010 0000 0000
8021 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8022 // My assumption: RegB = (RegB & 01111111b)
8023 if (rtc_updating()) {
8025 SetCF(iret_addr
.flags
);
8028 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
8029 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
8030 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
8031 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
8032 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8033 outb_cmos(0x0b, val8
);
8035 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
8036 ClearCF(iret_addr
.flags
); // OK
8039 case 6: // Set Alarm Time in CMOS
8040 // Using a debugger, I notice the following masking/setting
8041 // of bits in Status Register B, by setting Reg B to
8042 // a few values and getting its value after INT 1A was called.
8044 // try#1 try#2 try#3
8045 // before 1101 1111 0101 1111 0000 0000
8046 // after 0110 1111 0111 1111 0010 0000
8048 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8049 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8050 val8
= inb_cmos(0x0b); // Get Status Reg B
8053 // Alarm interrupt enabled already
8054 SetCF(iret_addr
.flags
); // Error: alarm in use
8057 if (rtc_updating()) {
8059 // fall through as if an update were not in progress
8061 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
8062 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
8063 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
8064 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8065 // enable Status Reg B alarm bit, clear halt clock bit
8066 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
8067 ClearCF(iret_addr
.flags
); // OK
8070 case 7: // Turn off Alarm
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 try#4
8076 // before 1111 1101 0111 1101 0010 0000 0010 0010
8077 // after 0100 0101 0101 0101 0000 0000 0000 0010
8079 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8080 // My assumption: RegB = (RegB & 01010111b)
8081 val8
= inb_cmos(0x0b); // Get Status Reg B
8082 // clear clock-halt bit, disable alarm bit
8083 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
8085 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8086 ClearCF(iret_addr
.flags
); // OK
8090 // real mode PCI BIOS functions now handled in assembler code
8091 // this C code handles the error code for information only
8092 if (regs
.u
.r8
.bl
== 0xff) {
8093 BX_INFO("PCI BIOS: PCI not present\n");
8094 } else if (regs
.u
.r8
.bl
== 0x81) {
8095 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8096 } else if (regs
.u
.r8
.bl
== 0x83) {
8097 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8098 } else if (regs
.u
.r8
.bl
== 0x86) {
8099 if (regs
.u
.r8
.al
== 0x02) {
8100 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8102 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
);
8105 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8106 SetCF(iret_addr
.flags
);
8111 SetCF(iret_addr
.flags
); // Unsupported
8116 int70_function(regs
, ds
, iret_addr
)
8117 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8118 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8119 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8121 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8122 Bit8u registerB
= 0, registerC
= 0;
8124 // Check which modes are enabled and have occurred.
8125 registerB
= inb_cmos( 0xB );
8126 registerC
= inb_cmos( 0xC );
8128 if( ( registerB
& 0x60 ) != 0 ) {
8129 if( ( registerC
& 0x20 ) != 0 ) {
8130 // Handle Alarm Interrupt.
8137 if( ( registerC
& 0x40 ) != 0 ) {
8138 // Handle Periodic Interrupt.
8140 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8141 // Wait Interval (Int 15, AH=83) active.
8142 Bit32u time
, toggle
;
8144 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8145 if( time
< 0x3D1 ) {
8147 Bit16u segment
, offset
;
8149 segment
= read_word( 0x40, 0x98 );
8150 offset
= read_word( 0x40, 0x9A );
8151 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8152 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8153 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8155 // Continue waiting.
8157 write_dword( 0x40, 0x9C, time
);
8170 ;------------------------------------------
8171 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8172 ;------------------------------------------
8177 push
#0x00 ;; placeholder for status
8178 push
#0x00 ;; placeholder for X
8179 push
#0x00 ;; placeholder for Y
8180 push
#0x00 ;; placeholder for Z
8181 push
#0x00 ;; placeholder for make_far_call boolean
8182 call _int74_function
8183 pop cx
;; remove make_far_call from stack
8186 ;; make far call to EBDA
:0022
8189 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8191 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8196 add sp
, #8 ;; pop status, x, y, z
8198 pop ds
;; restore DS
8203 ;; This will perform an IRET
, but will retain value of current CF
8204 ;; by altering flags on stack
. Better than RETF
#02.
8209 and BYTE
[bp
+ 0x06], #0xfe
8215 or BYTE
[bp
+ 0x06], #0x01
8220 ;----------------------
8221 ;- INT13h (relocated
) -
8222 ;----------------------
8224 ; int13_relocated is a little bit messed up since I played with it
8225 ; I have to rewrite it
:
8226 ; - call a function that detect which function to call
8227 ; - make all called C function get the same parameters list
8231 #if BX_ELTORITO_BOOT
8232 ;; check
for an eltorito function
8234 jb int13_not_eltorito
8236 ja int13_not_eltorito
8245 jmp _int13_eltorito
;; ELDX
not used
8253 ;; check
if emulation active
8254 call _cdemu_isactive
8256 je int13_cdemu_inactive
8258 ;; check
if access to the emulated drive
8259 call _cdemu_emulated_drive
8262 cmp al
,dl
;; int13 on emulated drive
8277 jmp _int13_cdemu
;; ELDX
not used
8280 and dl
,#0xE0 ;; mask to get device class, including cdroms
8281 cmp al
,dl
;; al is
0x00 or 0x80
8282 jne int13_cdemu_inactive
;; inactive
for device
class
8294 dec dl
;; real drive is dl
- 1
8297 int13_cdemu_inactive
:
8303 #endif // BX_ELTORITO_BOOT
8314 push dx
;; push eltorito value of dx instead of sp
8325 ;; now the
16-bit registers can be restored with
:
8326 ;; pop ds
; pop es
; popa
; iret
8327 ;; arguments passed to functions should be
8328 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8334 jmp _int13_diskette_function
8343 // ebx is modified: BSD 5.2.1 boot loader problem
8344 // someone should figure out which 32 bit register that actually are used
8361 ;; int13_harddisk modifies high word of EAX
8364 call _int13_harddisk
8377 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8385 ;; Get the boot sequence number out of the IPL memory
8387 mov ds
, bx
;; Set segment
8388 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8390 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8391 mov ds
, ax
;; and reset the segment to zero
.
8393 ;; Carry on in the INT
19h handler
, using the
new sequence number
8401 int19_relocated
: ;; Boot function
, relocated
8403 ;; int19 was beginning to be really
complex, so now it
8404 ;; just calls a C function that does the work
8415 ;; Start from the first boot
device (0, in AX
)
8417 mov ds
, bx
;; Set segment to write to the IPL memory
8418 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8419 mov ds
, ax
;; and reset the segment
.
8425 ;; Call the C code
for the next boot device
8426 call _int19_function
8428 ;; Boot failed
: invoke the boot recovery function
8434 int1c_handler
: ;; User Timer Tick
8438 ;----------------------
8439 ;- POST
: Floppy Drive
-
8440 ;----------------------
8446 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8448 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8450 mov
0x0440, al
;; diskette motor timeout counter
: not active
8451 mov
0x0441, al
;; diskette controller status
return code
8453 mov
0x0442, al
;; disk
& diskette controller status
register 0
8454 mov
0x0443, al
;; diskette controller status
register 1
8455 mov
0x0444, al
;; diskette controller status
register 2
8456 mov
0x0445, al
;; diskette controller cylinder number
8457 mov
0x0446, al
;; diskette controller head number
8458 mov
0x0447, al
;; diskette controller sector number
8459 mov
0x0448, al
;; diskette controller bytes written
8461 mov
0x048b, al
;; diskette configuration data
8463 ;; -----------------------------------------------------------------
8464 ;; (048F
) diskette controller information
8466 mov al
, #0x10 ;; get CMOS diskette drive type
8469 mov ah
, al
;; save byte to AH
8472 shr al
, #4 ;; look at top 4 bits for drive 0
8473 jz f0_missing
;; jump
if no drive0
8474 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8477 mov bl
, #0x00 ;; no drive0
8480 mov al
, ah
;; restore from AH
8481 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8482 jz f1_missing
;; jump
if no drive1
8483 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8485 ;; leave high bits in BL zerod
8486 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8487 ;; -----------------------------------------------------------------
8490 mov
0x0490, al
;; diskette
0 media state
8491 mov
0x0491, al
;; diskette
1 media state
8493 ;; diskette
0,1 operational starting state
8494 ;; drive type has
not been determined
,
8495 ;; has no changed detection line
8499 mov
0x0494, al
;; diskette
0 current cylinder
8500 mov
0x0495, al
;; diskette
1 current cylinder
8503 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8505 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8506 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8507 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8512 ;--------------------
8513 ;- POST
: HARD DRIVE
-
8514 ;--------------------
8515 ; relocated here because the primary POST area isnt big enough
.
8518 // INT 76h calls INT 15h function ax=9100
8520 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8526 mov
0x0474, al
/* hard disk status of last operation */
8527 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8528 mov
0x048c, al
/* hard disk status register */
8529 mov
0x048d, al
/* hard disk error register */
8530 mov
0x048e, al
/* hard disk task complete flag */
8532 mov
0x0475, al
/* hard disk number attached */
8534 mov
0x0476, al
/* hard disk control byte */
8535 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8536 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8537 ;; INT
41h
: hard disk
0 configuration pointer
8538 ;; INT
46h
: hard disk
1 configuration pointer
8539 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8540 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8542 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8554 cmp al
, #47 ;; decimal 47 - user definable
8558 ;; CMOS purpose param table offset
8559 ;; 1b cylinders low
0
8560 ;; 1c cylinders high
1
8562 ;; 1e write pre
-comp low
5
8563 ;; 1f write pre
-comp high
6
8564 ;; 20 retries
/bad map
/heads
>8 8
8565 ;; 21 landing zone low C
8566 ;; 22 landing zone high D
8567 ;; 23 sectors
/track E
8572 ;;; Filling EBDA table
for hard disk
0.
8580 mov (0x003d + 0x05), ax
;; write precomp word
8585 mov (0x003d + 0x08), al
;; drive control byte
8594 mov (0x003d + 0x0C), ax
;; landing zone word
8596 mov al
, #0x1c ;; get cylinders word in AX
8598 in al
, #0x71 ;; high byte
8602 in al
, #0x71 ;; low byte
8603 mov bx
, ax
;; BX
= cylinders
8608 mov cl
, al
;; CL
= heads
8613 mov dl
, al
;; DL
= sectors
8616 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8618 hd0_post_physical_chs
:
8619 ;; no logical CHS mapping used
, just physical CHS
8620 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8621 mov (0x003d + 0x00), bx
;; number of physical cylinders
8622 mov (0x003d + 0x02), cl
;; number of physical heads
8623 mov (0x003d + 0x0E), dl
;; number of physical sectors
8626 hd0_post_logical_chs
:
8627 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8628 mov (0x003d + 0x09), bx
;; number of physical cylinders
8629 mov (0x003d + 0x0b), cl
;; number of physical heads
8630 mov (0x003d + 0x04), dl
;; number of physical sectors
8631 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8633 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8636 jnbe hd0_post_above_2048
8637 ;; 1024 < c
<= 2048 cylinders
8640 jmp hd0_post_store_logical
8642 hd0_post_above_2048
:
8644 jnbe hd0_post_above_4096
8645 ;; 2048 < c
<= 4096 cylinders
8648 jmp hd0_post_store_logical
8650 hd0_post_above_4096
:
8652 jnbe hd0_post_above_8192
8653 ;; 4096 < c
<= 8192 cylinders
8656 jmp hd0_post_store_logical
8658 hd0_post_above_8192
:
8659 ;; 8192 < c
<= 16384 cylinders
8663 hd0_post_store_logical
:
8664 mov (0x003d + 0x00), bx
;; number of physical cylinders
8665 mov (0x003d + 0x02), cl
;; number of physical heads
8667 mov cl
, #0x0f ;; repeat count
8668 mov si
, #0x003d ;; offset to disk0 FDPT
8669 mov al
, #0x00 ;; sum
8670 hd0_post_checksum_loop
:
8674 jnz hd0_post_checksum_loop
8675 not al
;; now take
2s complement
8678 ;;; Done filling EBDA table
for hard disk
0.
8682 ;; is there really a second hard disk
? if not, return now
8690 ;; check that the hd type is really
0x0f.
8695 ;; check that the extended type is
47 - user definable
8699 cmp al
, #47 ;; decimal 47 - user definable
8704 ;; CMOS purpose param table offset
8705 ;; 0x24 cylinders low
0
8706 ;; 0x25 cylinders high
1
8708 ;; 0x27 write pre
-comp low
5
8709 ;; 0x28 write pre
-comp high
6
8711 ;; 0x2a landing zone low C
8712 ;; 0x2b landing zone high D
8713 ;; 0x2c sectors
/track E
8714 ;;; Fill EBDA table
for hard disk
1.
8724 mov (0x004d + 0x05), ax
;; write precomp word
8729 mov (0x004d + 0x08), al
;; drive control byte
8738 mov (0x004d + 0x0C), ax
;; landing zone word
8740 mov al
, #0x25 ;; get cylinders word in AX
8742 in al
, #0x71 ;; high byte
8746 in al
, #0x71 ;; low byte
8747 mov bx
, ax
;; BX
= cylinders
8752 mov cl
, al
;; CL
= heads
8757 mov dl
, al
;; DL
= sectors
8760 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8762 hd1_post_physical_chs
:
8763 ;; no logical CHS mapping used
, just physical CHS
8764 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8765 mov (0x004d + 0x00), bx
;; number of physical cylinders
8766 mov (0x004d + 0x02), cl
;; number of physical heads
8767 mov (0x004d + 0x0E), dl
;; number of physical sectors
8770 hd1_post_logical_chs
:
8771 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8772 mov (0x004d + 0x09), bx
;; number of physical cylinders
8773 mov (0x004d + 0x0b), cl
;; number of physical heads
8774 mov (0x004d + 0x04), dl
;; number of physical sectors
8775 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8777 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8780 jnbe hd1_post_above_2048
8781 ;; 1024 < c
<= 2048 cylinders
8784 jmp hd1_post_store_logical
8786 hd1_post_above_2048
:
8788 jnbe hd1_post_above_4096
8789 ;; 2048 < c
<= 4096 cylinders
8792 jmp hd1_post_store_logical
8794 hd1_post_above_4096
:
8796 jnbe hd1_post_above_8192
8797 ;; 4096 < c
<= 8192 cylinders
8800 jmp hd1_post_store_logical
8802 hd1_post_above_8192
:
8803 ;; 8192 < c
<= 16384 cylinders
8807 hd1_post_store_logical
:
8808 mov (0x004d + 0x00), bx
;; number of physical cylinders
8809 mov (0x004d + 0x02), cl
;; number of physical heads
8811 mov cl
, #0x0f ;; repeat count
8812 mov si
, #0x004d ;; offset to disk0 FDPT
8813 mov al
, #0x00 ;; sum
8814 hd1_post_checksum_loop
:
8818 jnz hd1_post_checksum_loop
8819 not al
;; now take
2s complement
8822 ;;; Done filling EBDA table
for hard disk
1.
8826 ;--------------------
8827 ;- POST
: EBDA segment
8828 ;--------------------
8829 ; relocated here because the primary POST area isnt big enough
.
8834 mov byte ptr
[0x0], #EBDA_SIZE
8836 xor ax
, ax
; mov EBDA seg into
40E
8838 mov word ptr
[0x40E], #EBDA_SEG
8841 ;--------------------
8842 ;- POST
: EOI
+ jmp via
[0x40:67)
8843 ;--------------------
8844 ; relocated here because the primary POST area isnt big enough
.
8854 ;--------------------
8857 out
#0xA0, al ;; slave PIC EOI
8860 out
#0x20, al ;; master PIC EOI
8863 ;--------------------
8865 ;; in
: AL in BCD format
8866 ;; out
: AL in binary format
, AH will always be
0
8869 and bl
, #0x0f ;; bl has low digit
8870 shr al
, #4 ;; al has high digit
8872 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8873 add al
, bl
;; then add low digit
8876 ;--------------------
8878 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8879 ;; Timer Ticks Roller
Flag (0x470:byte
)
8880 ;; The Timer Ticks Count needs to be set according to
8881 ;; the current CMOS time
, as
if ticks have been occurring
8882 ;; at
18.2hz since midnight up to
this point
. Calculating
8883 ;; this is a little complicated
. Here are the factors I gather
8884 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8885 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8886 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8887 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8888 ;; the timer
. With a maximum
16bit timer count
, this is again
8889 ;; divided down by
65536 to
18.2hz
.
8891 ;; 14,318,180 Hz clock
8892 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8893 ;; /4 = 1,193,181 Hz fed to timer
8894 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8895 ;; 1 second
= 18.20650736 ticks
8896 ;; 1 minute
= 1092.390442 ticks
8897 ;; 1 hour
= 65543.42651 ticks
8899 ;; Given the values in the CMOS clock
, one could calculate
8900 ;; the number of ticks by the following
:
8901 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8902 ;; (BcdToBin(minutes
) * 1092.3904)
8903 ;; (BcdToBin(hours
) * 65543.427)
8904 ;; To get a little more accuracy
, since Im
using integer
8905 ;; arithmatic
, I use
:
8906 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8907 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8908 ;; (BcdToBin(hours
) * 65543427) / 1000
8913 xor eax
, eax
;; clear EAX
8916 in al
, #0x71 ;; AL has CMOS seconds in BCD
8917 call BcdToBin
;; EAX now has seconds in binary
8923 mov ecx
, eax
;; ECX will accumulate total ticks
8926 xor eax
, eax
;; clear EAX
8929 in al
, #0x71 ;; AL has CMOS minutes in BCD
8930 call BcdToBin
;; EAX now has minutes in binary
8936 add ecx
, eax
;; add to total ticks
8939 xor eax
, eax
;; clear EAX
8942 in al
, #0x71 ;; AL has CMOS hours in BCD
8943 call BcdToBin
;; EAX now has hours in binary
8949 add ecx
, eax
;; add to total ticks
8951 mov
0x46C, ecx
;; Timer Ticks Count
8953 mov
0x470, al
;; Timer Ticks Rollover Flag
8956 ;--------------------
8958 ;; record completion in BIOS task complete flag
8970 ;--------------------
8975 #include "apmbios.S"
8979 #include "apmbios.S"
8982 #include "apmbios.S"
8986 ;--------------------
8991 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8992 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8993 db
0 ;; revision level
8994 ;; length in paragraphs
and checksum stored in a word to prevent errors
8995 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8996 & 0xff) << 8) + 0x01
8997 db
0,0,0,0,0 ;; reserved
9002 cmp eax
, #0x49435024 ;; "$PCI"
9004 mov eax
, #0x80000000
9009 #ifdef PCI_FIXED_HOST_BRIDGE
9010 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9013 ;; say ok
if a device is present
9014 cmp eax
, #0xffffffff
9017 mov ebx
, #0x000f0000
9019 mov edx
, #pcibios_protected
9026 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9037 cmp al
, #0x01 ;; installation check
9041 mov edx
, #0x20494350 ;; "PCI "
9044 pci_pro_f02
: ;; find pci device
9052 call pci_pro_select_reg
9066 pci_pro_f03
: ;; find
class code
9072 call pci_pro_select_reg
9077 jne pci_pro_nextdev2
9084 jne pci_pro_devloop2
9087 pci_pro_f08
: ;; read configuration byte
9090 call pci_pro_select_reg
9099 pci_pro_f09
: ;; read configuration word
9102 call pci_pro_select_reg
9111 pci_pro_f0a
: ;; read configuration dword
9114 call pci_pro_select_reg
9121 pci_pro_f0b
: ;; write configuration byte
9124 call pci_pro_select_reg
9133 pci_pro_f0c
: ;; write configuration word
9136 call pci_pro_select_reg
9145 pci_pro_f0d
: ;; write configuration dword
9148 call pci_pro_select_reg
9161 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9171 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9195 mov eax
, #0x80000000
9200 #ifdef PCI_FIXED_HOST_BRIDGE
9201 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9204 ;; say ok
if a device is present
9205 cmp eax
, #0xffffffff
9216 cmp al
, #0x01 ;; installation check
9221 mov edx
, #0x20494350 ;; "PCI "
9223 mov di
, #pcibios_protected
9226 pci_real_f02
: ;; find pci device
9236 call pci_real_select_reg
9240 jne pci_real_nextdev
9247 jne pci_real_devloop
9252 pci_real_f03
: ;; find
class code
9258 call pci_real_select_reg
9263 jne pci_real_nextdev2
9270 jne pci_real_devloop2
9275 pci_real_f08
: ;; read configuration byte
9278 call pci_real_select_reg
9287 pci_real_f09
: ;; read configuration word
9290 call pci_real_select_reg
9299 pci_real_f0a
: ;; read configuration dword
9302 call pci_real_select_reg
9309 pci_real_f0b
: ;; write configuration byte
9312 call pci_real_select_reg
9321 pci_real_f0c
: ;; write configuration word
9324 call pci_real_select_reg
9333 pci_real_f0d
: ;; write configuration dword
9336 call pci_real_select_reg
9343 pci_real_f0e
: ;; get irq routing options
9345 jne pci_real_unknown
9347 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9348 jb pci_real_too_small
9350 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9358 mov si
, #pci_routing_table_structure_start
9366 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9375 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9379 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9397 pci_real_select_reg
:
9411 pci_routing_table_structure
:
9412 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9414 dw
32 + (6 * 16) ;; table size
9415 db
0 ;; PCI interrupt router bus
9416 db
0x08 ;; PCI interrupt router DevFunc
9417 dw
0x0000 ;; PCI exclusive IRQs
9418 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9419 dw
0x7000 ;; compatible PCI interrupt router device ID
9420 dw
0,0 ;; Miniport data
9421 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9423 pci_routing_table_structure_start
:
9424 ;; first slot entry PCI
-to
-ISA (embedded
)
9425 db
0 ;; pci bus number
9426 db
0x08 ;; pci device
number (bit
7-3)
9427 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9428 dw
0xdef8 ;; IRQ bitmap INTA
#
9429 db
0x61 ;; link value INTB
#
9430 dw
0xdef8 ;; IRQ bitmap INTB
#
9431 db
0x62 ;; link value INTC
#
9432 dw
0xdef8 ;; IRQ bitmap INTC
#
9433 db
0x63 ;; link value INTD
#
9434 dw
0xdef8 ;; IRQ bitmap INTD
#
9435 db
0 ;; physical
slot (0 = embedded
)
9437 ;; second slot entry
: 1st PCI slot
9438 db
0 ;; pci bus number
9439 db
0x10 ;; pci device
number (bit
7-3)
9440 db
0x61 ;; link value INTA
#
9441 dw
0xdef8 ;; IRQ bitmap INTA
#
9442 db
0x62 ;; link value INTB
#
9443 dw
0xdef8 ;; IRQ bitmap INTB
#
9444 db
0x63 ;; link value INTC
#
9445 dw
0xdef8 ;; IRQ bitmap INTC
#
9446 db
0x60 ;; link value INTD
#
9447 dw
0xdef8 ;; IRQ bitmap INTD
#
9448 db
1 ;; physical
slot (0 = embedded
)
9450 ;; third slot entry
: 2nd PCI slot
9451 db
0 ;; pci bus number
9452 db
0x18 ;; pci device
number (bit
7-3)
9453 db
0x62 ;; link value INTA
#
9454 dw
0xdef8 ;; IRQ bitmap INTA
#
9455 db
0x63 ;; link value INTB
#
9456 dw
0xdef8 ;; IRQ bitmap INTB
#
9457 db
0x60 ;; link value INTC
#
9458 dw
0xdef8 ;; IRQ bitmap INTC
#
9459 db
0x61 ;; link value INTD
#
9460 dw
0xdef8 ;; IRQ bitmap INTD
#
9461 db
2 ;; physical
slot (0 = embedded
)
9463 ;; 4th slot entry
: 3rd PCI slot
9464 db
0 ;; pci bus number
9465 db
0x20 ;; pci device
number (bit
7-3)
9466 db
0x63 ;; link value INTA
#
9467 dw
0xdef8 ;; IRQ bitmap INTA
#
9468 db
0x60 ;; link value INTB
#
9469 dw
0xdef8 ;; IRQ bitmap INTB
#
9470 db
0x61 ;; link value INTC
#
9471 dw
0xdef8 ;; IRQ bitmap INTC
#
9472 db
0x62 ;; link value INTD
#
9473 dw
0xdef8 ;; IRQ bitmap INTD
#
9474 db
3 ;; physical
slot (0 = embedded
)
9476 ;; 5th slot entry
: 4rd PCI slot
9477 db
0 ;; pci bus number
9478 db
0x28 ;; pci device
number (bit
7-3)
9479 db
0x60 ;; link value INTA
#
9480 dw
0xdef8 ;; IRQ bitmap INTA
#
9481 db
0x61 ;; link value INTB
#
9482 dw
0xdef8 ;; IRQ bitmap INTB
#
9483 db
0x62 ;; link value INTC
#
9484 dw
0xdef8 ;; IRQ bitmap INTC
#
9485 db
0x63 ;; link value INTD
#
9486 dw
0xdef8 ;; IRQ bitmap INTD
#
9487 db
4 ;; physical
slot (0 = embedded
)
9489 ;; 6th slot entry
: 5rd PCI slot
9490 db
0 ;; pci bus number
9491 db
0x30 ;; pci device
number (bit
7-3)
9492 db
0x61 ;; link value INTA
#
9493 dw
0xdef8 ;; IRQ bitmap INTA
#
9494 db
0x62 ;; link value INTB
#
9495 dw
0xdef8 ;; IRQ bitmap INTB
#
9496 db
0x63 ;; link value INTC
#
9497 dw
0xdef8 ;; IRQ bitmap INTC
#
9498 db
0x60 ;; link value INTD
#
9499 dw
0xdef8 ;; IRQ bitmap INTD
#
9500 db
5 ;; physical
slot (0 = embedded
)
9502 pci_routing_table_structure_end
:
9508 pcibios_init_sel_reg
:
9520 pcibios_init_iomem_bases
:
9523 mov eax
, #0xe0000000 ;; base for memory init
9525 mov ax
, #0xc000 ;; base for i/o init
9527 mov ax
, #0x0010 ;; start at base address #0
9532 call pcibios_init_sel_reg
9537 mov dl
, #0x04 ;; disable i/o and memory space access
9538 call pcibios_init_sel_reg
9545 call pcibios_init_sel_reg
9551 mov eax
, #0xffffffff
9556 xor eax
, #0xffffffff
9560 add eax
, ecx
;; calculate next free mem base
9561 add eax
, #0x01000000
9562 and eax
, #0xff000000
9576 add ax
, cx
;; calculate next free i
/o base
9584 je enable_iomem_space
9585 mov byte ptr
[bp
-8], al
9586 jmp pci_init_io_loop2
9588 mov dl
, #0x04 ;; enable i/o and memory space access if available
9589 call pcibios_init_sel_reg
9595 mov byte ptr
[bp
-8], #0x10
9598 jne pci_init_io_loop1
9603 pcibios_init_set_elcr
:
9627 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9632 mov si
, #pci_routing_table_structure
9636 call pcibios_init_sel_reg
9639 cmp eax
, [si
+12] ;; check irq router
9642 call pcibios_init_sel_reg
9643 push bx
;; save irq router bus
+ devfunc
9646 out dx
, ax
;; reset PIRQ route control
9653 add si
, #0x20 ;; set pointer to 1st entry
9655 mov ax
, #pci_irq_list
9664 call pcibios_init_sel_reg
9668 jnz pci_test_int_pin
9674 call pcibios_init_sel_reg
9679 dec al
;; determine pirq reg
9688 call pcibios_init_sel_reg
9695 mov bx
, [bp
-2] ;; pci irq list pointer
9700 call pcibios_init_set_elcr
9704 add bl
, [bp
-3] ;; pci function number
9706 call pcibios_init_sel_reg
9713 jnz pci_init_irq_loop2
9716 mov byte ptr
[bp
-3], #0x00
9717 loop pci_init_irq_loop1
9724 #endif // BX_ROMBIOS32
9725 #endif // BX_PCIBIOS
9729 ;; save a20
and enable it
9735 ;; save SS
:SP to the BDA
9742 lidt
[pmode_IDT_info
]
9744 lgdt
[rombios32_gdt_48
]
9745 ;; set PE bit in CR0
9749 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
9752 dw
0x000f ;; high
16 bit address
9757 ;; init data segments
9767 ;; copy rombios32 code to
ram (ram offset
= 1MB
)
9768 mov esi
, #0xfffe0000
9769 mov edi
, #0x00040000
9770 mov ecx
, #0x10000 / 4
9774 ;; init the stack pointer
9775 mov esp
, #0x00080000
9777 ;; call rombios32 code
9778 mov eax
, #0x00040000
9781 ;; reset the
memory (some boot loaders such as syslinux suppose
9782 ;; that the memory is set to zero
)
9783 mov edi
, #0x00040000
9784 mov ecx
, #0x40000 / 4
9789 ;; return to
16 bit
protected mode first
9796 ;; restore data segment limits to
0xffff
9804 ;; reset PE bit in CR0
9809 ;; far jump to flush CPU queue after transition to real mode
9810 JMP_AP(0xf000, rombios32_real_mode
)
9812 rombios32_real_mode
:
9813 ;; restore IDT to normal real
-mode defaults
9815 lidt
[rmode_IDT_info
]
9823 ;; restore SS
:SP from the BDA
9840 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
9841 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
9842 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
9843 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
9847 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9852 and al
, #0xdf ; clear input mode
9862 mov
[bx
+0x408], dx
; Parallel I
/O address
9864 mov
[bx
+0x478], cl
; Parallel printer timeout
9869 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9888 mov
[bx
+0x400], dx
; Serial I
/O address
9890 mov
[bx
+0x47c], cl
; Serial timeout
9917 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
9918 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
9926 ;; Scan
for existence of valid expansion ROMS
.
9927 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9928 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9929 ;; System ROM
: only
0xE0000
9935 ;; 2 ROM length in
512-byte blocks
9936 ;; 3 ROM initialization entry
point (FAR CALL
)
9941 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9942 cmp
[0], #0xAA55 ;; look for signature
9943 jne rom_scan_increment
9945 jnz rom_scan_increment
9946 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9948 ;; We want our increment in
512-byte quantities
, rounded to
9949 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9951 jz block_count_rounded
9952 and al
, #0xfc ;; needs rounding up
9954 block_count_rounded
:
9956 xor bx
, bx
;; Restore DS back to
0000:
9960 ;; Push addr of ROM entry point
9962 push
#0x0003 ;; Push offset
9964 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
9965 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
9970 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9971 db
0xff ;; call_far ss
:[bp
+0]
9974 cli
;; In
case expansion ROM BIOS turns IF on
9975 add sp
, #2 ;; Pop offset value
9976 pop cx
;; Pop seg
value (restore CX
)
9978 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
9979 ;; to init all the ROMs
and then go back
and build an IPL table of
9980 ;; all the bootable devices
, but we can get away with one pass
.
9981 mov ds
, cx
;; ROM base
9982 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
9983 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
9984 cmp ax
, #0x5024 ;; we look for signature "$PnP"
9989 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
9990 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
9993 ;; Found a device that thinks it can boot the system
. Record its BEV
and product name string
.
9994 mov di
, 0x10[bx
] ;; Pointer to the product name string
or zero
if none
9995 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
9997 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
9998 cmp bx
, #IPL_TABLE_ENTRIES
9999 je no_bev
;; Get out
if the table is full
10000 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
10001 mov
0[bx
], #IPL_TYPE_BEV ;; This entry is a BEV device
10002 mov
6[bx
], cx
;; Build a far pointer from the segment
...
10003 mov
4[bx
], ax
;; and the offset
10006 mov
0xA[bx
], cx
;; Build a far pointer from the segment
...
10007 mov
8[bx
], di
;; and the offset
10009 shr bx
, #0x4 ;; Turn the offset back into a count
10010 inc bx
;; We have one more entry now
10011 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
10014 pop di
;; Restore DI
10015 pop ax
;; Restore AX
10016 rom_scan_increment
:
10017 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
10018 ;; because the segment selector is shifted left
4 bits
.
10020 pop ax
;; Restore AX
10024 xor ax
, ax
;; Restore DS back to
0000:
10028 ;; for 'C' strings
and other data
, insert them here with
10029 ;; a the following hack
:
10030 ;; DATA_SEG_DEFS_HERE
10033 ;; the following area can be used to write dynamically generated tables
10035 bios_table_area_start
:
10037 dd bios_table_area_end
- bios_table_area_start
- 8;
10042 .org
0xe05b ; POST Entry Point
10047 ;; first reset the DMA controllers
10051 ;; then initialize the DMA controllers
10053 out
0xD6, al
; cascade mode of channel
4 enabled
10055 out
0xD4, al
; unmask channel
4
10057 ;; Examine CMOS shutdown status
.
10065 ;; Reset CMOS shutdown status
.
10067 out
0x70, AL
; select CMOS
register Fh
10069 out
0x71, AL
; set shutdown action to normal
10071 ;; Examine CMOS shutdown status
.
10074 ;; 0x00, 0x09, 0x0D+ = normal startup
10082 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
10086 ;; Examine CMOS shutdown status
.
10087 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
10089 call _shutdown_status_panic
10095 ; 0xb0, 0x20, /* mov al, #0x20 */
10096 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10106 ; case 0: normal startup
10115 ;; zero out BIOS data
area (40:00..40:ff
)
10117 mov cx
, #0x0080 ;; 128 words
10123 call _log_bios_start
10125 ;; set all interrupts to
default handler
10126 xor bx
, bx
;; offset index
10127 mov cx
, #0x0100 ;; counter (256 interrupts)
10128 mov ax
, #dummy_iret_handler
10136 loop post_default_ints
10138 ;; set vector
0x79 to zero
10139 ;; this is used by
'gardian angel' protection system
10140 SET_INT_VECTOR(0x79, #0, #0)
10142 ;; base memory in K
40:13 (word
)
10143 mov ax
, #BASE_MEM_IN_K
10147 ;; Manufacturing Test
40:12
10150 ;; Warm Boot Flag
0040:0072
10151 ;; value of
1234h
= skip memory checks
10155 ;; Printer Services vector
10156 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10158 ;; Bootstrap failure vector
10159 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10161 ;; Bootstrap Loader vector
10162 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10164 ;; User Timer Tick vector
10165 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10167 ;; Memory Size Check vector
10168 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10170 ;; Equipment Configuration Check vector
10171 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10174 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10180 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10181 ;; int 1C already points at
dummy_iret_handler (above
)
10182 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10184 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10189 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10190 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10194 mov
0x0417, al
/* keyboard shift flags, set 1 */
10195 mov
0x0418, al
/* keyboard shift flags, set 2 */
10196 mov
0x0419, al
/* keyboard alt-numpad work area */
10197 mov
0x0471, al
/* keyboard ctrl-break flag */
10198 mov
0x0497, al
/* keyboard status flags 4 */
10200 mov
0x0496, al
/* keyboard status flags 3 */
10203 /* keyboard head of buffer pointer */
10207 /* keyboard end of buffer pointer */
10210 /* keyboard pointer to start of buffer */
10214 /* keyboard pointer to end of buffer */
10218 /* init the keyboard */
10219 call _keyboard_init
10221 ;; mov CMOS Equipment Byte to BDA Equipment Word
10230 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10234 mov cl
, #0x14 ; timeout value
10235 mov dx
, #0x378 ; Parallel I/O address, port 1
10236 call detect_parport
10237 mov dx
, #0x278 ; Parallel I/O address, port 2
10238 call detect_parport
10240 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10242 or ax
, bx
; set number of parallel ports
10246 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10247 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10249 mov cl
, #0x0a ; timeout value
10250 mov dx
, #0x03f8 ; Serial I/O address, port 1
10252 mov dx
, #0x02f8 ; Serial I/O address, port 2
10254 mov dx
, #0x03e8 ; Serial I/O address, port 3
10256 mov dx
, #0x02e8 ; Serial I/O address, port 4
10259 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10261 or ax
, bx
; set number of serial port
10265 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10266 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10267 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10268 ;; BIOS DATA AREA
0x4CE ???
10269 call timer_tick_post
10271 ;; PS
/2 mouse setup
10272 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10274 ;; IRQ13 (FPU exception
) setup
10275 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10278 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10281 mov al
, #0x11 ; send initialisation commands
10296 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10297 #if BX_USE_PS2_MOUSE
10302 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10304 mov cx
, #0xc000 ;; init vga bios
10308 call _print_bios_banner
10311 call rombios32_init
10314 call pcibios_init_iomem_bases
10315 call pcibios_init_irqs
10316 #endif //BX_PCIBIOS
10322 call floppy_drive_post
10327 ;; Hard Drive setup
10329 call hard_drive_post
10332 ;; ATA
/ATAPI driver setup
10337 #else // BX_USE_ATADRV
10340 ;; Hard Drive setup
10342 call hard_drive_post
10344 #endif // BX_USE_ATADRV
10346 #if BX_ELTORITO_BOOT
10348 ;; eltorito floppy
/harddisk emulation from cd
10352 #endif // BX_ELTORITO_BOOT
10354 call _init_boot_vectors
10356 mov cx
, #0xc800 ;; init option roms
10360 sti
;; enable interrupts
10363 .org
0xe2c3 ; NMI Handler Entry Point
10365 ;; FIXME the NMI handler should
not panic
10366 ;; but iret when called from
int75 (fpu exception
)
10367 call _nmi_handler_msg
10371 out
0xf0, al
// clear irq13
10372 call eoi_both_pics
// clear interrupt
10373 int 2 // legacy nmi call
10376 ;-------------------------------------------
10377 ;- INT
13h Fixed Disk Services Entry Point
-
10378 ;-------------------------------------------
10379 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10381 //JMPL(int13_relocated)
10382 jmp int13_relocated
10384 .org
0xe401 ; Fixed Disk Parameter Table
10389 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10392 jmp int19_relocated
10393 ;-------------------------------------------
10394 ;- System BIOS Configuration Data Table
10395 ;-------------------------------------------
10396 .org BIOS_CONFIG_TABLE
10397 db
0x08 ; Table
size (bytes
) -Lo
10398 db
0x00 ; Table
size (bytes
) -Hi
10403 ; b7
: 1=DMA channel
3 used by hard disk
10404 ; b6
: 1=2 interrupt controllers present
10405 ; b5
: 1=RTC present
10406 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10407 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10408 ; b2
: 1=extended BIOS data area used
10409 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10410 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10414 (BX_CALL_INT15_4F
<< 4) | \
10416 (BX_USE_EBDA
<< 2) | \
10420 ; b7
: 1=32-bit DMA supported
10421 ; b6
: 1=int16h
, function
9 supported
10422 ; b5
: 1=int15h
/C6h (get POS data
) supported
10423 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10424 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10425 ; b2
: 1=non
-8042 kb controller
10426 ; b1
: 1=data streaming supported
10440 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10441 ; b3
: SCSI on system board
10442 ; b2
: info panel installed
10443 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10444 ; b0
: SCSI supported in IML
10448 ; b6
: EEPROM present
10449 ; b5
-3: ABIOS
presence (011 = not supported
)
10451 ; b1
: memory split above
16Mb supported
10452 ; b0
: POSTEXT directly supported by POST
10454 ; Feature byte
5 (IBM
)
10455 ; b1
: enhanced mouse
10461 .org
0xe729 ; Baud Rate Generator Table
10466 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10472 call _int14_function
10478 ;----------------------------------------
10479 ;- INT
16h Keyboard Service Entry Point
-
10480 ;----------------------------------------
10496 call _int16_function
10506 and BYTE
[bp
+ 0x06], #0xbf
10514 or BYTE
[bp
+ 0x06], #0x40
10522 int16_wait_for_key
:
10526 jne int16_key_found
10530 /* no key yet, call int 15h, function AX=9002 */
10531 0x50, /* push AX */
10532 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10533 0xcd, 0x15, /* int 15h */
10535 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10537 jmp int16_wait_for_key
10542 call _int16_function
10547 /* notify int16 complete w/ int 15h, function AX=9102 */
10548 0x50, /* push AX */
10549 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10550 0xcd, 0x15, /* int 15h */
10557 ;-------------------------------------------------
10558 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10559 ;-------------------------------------------------
10565 mov al
, #0xAD ;;disable keyboard
10574 in al
, #0x60 ;;read key from keyboard controller
10578 #ifdef BX_CALL_INT15_4F
10579 mov ah
, #0x4f ;; allow for keyboard intercept
10585 ;; check
for extended key
10587 jne int09_check_pause
10590 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10592 mov BYTE
[0x496], al
10595 int09_check_pause
: ;; check
for pause key
10597 jne int09_process_key
10600 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10602 mov BYTE
[0x496], al
10608 call _int09_function
10614 call eoi_master_pic
10617 mov al
, #0xAE ;;enable keyboard
10623 ;----------------------------------------
10624 ;- INT
13h Diskette Service Entry Point
-
10625 ;----------------------------------------
10628 jmp int13_noeltorito
10630 ;---------------------------------------------
10631 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10632 ;---------------------------------------------
10633 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10643 mov al
, #0x08 ; sense interrupt status
10661 xor ax
, ax
;; segment
0000
10663 call eoi_master_pic
10665 or al
, #0x80 ;; diskette interrupt has occurred
10673 .org
0xefc7 ; Diskette Controller Parameter Table
10674 diskette_param_table
:
10675 ;; Since no provisions are made
for multiple drive types
, most
10676 ;; values in
this table are ignored
. I set parameters
for 1.44M
10679 db
0x02 ;; head load time
0000001, DMA used
10691 ;----------------------------------------
10692 ;- INT17h
: Printer Service Entry Point
-
10693 ;----------------------------------------
10700 call _int17_function
10705 diskette_param_table2
:
10706 ;; New diskette parameter table adding
3 parameters from IBM
10707 ;; Since no provisions are made
for multiple drive types
, most
10708 ;; values in
this table are ignored
. I set parameters
for 1.44M
10711 db
0x02 ;; head load time
0000001, DMA used
10721 db
79 ;; maximum track
10722 db
0 ;; data transfer rate
10723 db
4 ;; drive type in cmos
10725 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10732 .org
0xf065 ; INT
10h Video Support Service Entry Point
10734 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10737 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10742 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10743 ; ??? different
for Pentium (machine check
)?
10755 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10767 .org
0xf859 ; INT
15h System Services Entry Point
10781 #if BX_USE_PS2_MOUSE
10783 je int15_handler_mouse
10785 call _int15_function
10786 int15_handler_mouse_ret
:
10788 int15_handler32_ret
:
10798 #if BX_USE_PS2_MOUSE
10799 int15_handler_mouse
:
10800 call _int15_function_mouse
10801 jmp int15_handler_mouse_ret
10806 call _int15_function32
10808 jmp int15_handler32_ret
10810 ;; Protected mode IDT descriptor
10812 ;; I just make the limit
0, so the machine will shutdown
10813 ;; if an exception occurs during
protected mode memory
10816 ;; Set base to f0000 to correspond to beginning of BIOS
,
10817 ;; in
case I actually define an IDT later
10821 dw
0x0000 ;; limit
15:00
10822 dw
0x0000 ;; base
15:00
10823 db
0x0f ;; base
23:16
10825 ;; Real mode IDT descriptor
10827 ;; Set to typical real
-mode values
.
10832 dw
0x03ff ;; limit
15:00
10833 dw
0x0000 ;; base
15:00
10834 db
0x00 ;; base
23:16
10840 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10853 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10854 mov ds
, ax
; on
16bit
protected mode
.
10855 jmp int1a_callfunction
10862 int1a_callfunction
:
10863 call _int1a_function
10869 ;; int70h
: IRQ8
- CMOS RTC
10876 call _int70_function
10884 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10892 ;; time to turn off
drive(s
)?
10895 jz int08_floppy_off
10898 jnz int08_floppy_off
10899 ;; turn
motor(s
) off
10908 mov eax
, 0x046c ;; get ticks dword
10911 ;; compare eax to one days worth of timer ticks at
18.2 hz
10912 cmp eax
, #0x001800B0
10913 jb int08_store_ticks
10914 ;; there has been a midnight rollover at
this point
10915 xor eax
, eax
;; zero out counter
10916 inc BYTE
0x0470 ;; increment rollover flag
10919 mov
0x046c, eax
;; store
new ticks dword
10920 ;; chain to user timer tick INT
#0x1c
10922 //;; call_ep [ds:loc]
10923 //CALL_EP( 0x1c << 2 )
10926 call eoi_master_pic
10931 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10935 .ascii BIOS_COPYRIGHT_STRING
10937 ;------------------------------------------------
10938 ;- IRET Instruction
for Dummy Interrupt Handler
-
10939 ;------------------------------------------------
10940 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10941 dummy_iret_handler
:
10944 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10948 .org
0xfff0 ; Power
-up Entry Point
10951 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10952 .ascii BIOS_BUILD_DATE
10954 .org
0xfffe ; System Model ID
10958 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10961 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10962 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10963 * This font is public domain
10965 static Bit8u vgafont8
[128*8]=
10967 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10968 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10969 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10970 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10971 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10972 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10973 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10974 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10975 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10976 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10977 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10978 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10979 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10980 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10981 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10982 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10983 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10984 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10985 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10986 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10987 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10988 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10989 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10990 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10991 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10992 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10993 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10994 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10995 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10996 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10997 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10998 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10999 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11000 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11001 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11002 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11003 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11004 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11005 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11006 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11007 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11008 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11009 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11010 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11011 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11012 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11013 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11014 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11015 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11016 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11017 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11018 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11019 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11020 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11021 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11022 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11023 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11024 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11025 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11026 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11027 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11028 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11029 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11030 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11031 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11032 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11033 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11034 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11035 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11036 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11037 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11038 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11039 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11040 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11041 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11042 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11043 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11044 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11045 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11046 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11047 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11048 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11049 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11050 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11051 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11052 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11053 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11054 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11055 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11056 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11057 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11058 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11059 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11060 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11061 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11062 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11063 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11064 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11065 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11066 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11067 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11068 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11069 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11070 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11071 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11072 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11073 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11074 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11075 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11076 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11077 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11078 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11079 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11080 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11081 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11082 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11083 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11084 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11085 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11086 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11087 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11088 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11089 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11090 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11091 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11092 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11093 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11094 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11099 bios_table_area_end
:
11100 // bcc-generated data will be placed here