1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.191 2007/12/01 19:26:46 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
128 #define DEBUG_INT13_HD 0
129 #define DEBUG_INT13_CD 0
130 #define DEBUG_INT13_ET 0
131 #define DEBUG_INT13_FL 0
132 #define DEBUG_INT15 0
133 #define DEBUG_INT16 0
134 #define DEBUG_INT1A 0
135 #define DEBUG_INT74 0
139 #define BX_USE_PS2_MOUSE 1
140 #define BX_CALL_INT15_4F 1
141 #define BX_USE_EBDA 1
142 #define BX_SUPPORT_FLOPPY 1
143 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
147 #define BX_USE_ATADRV 1
148 #define BX_ELTORITO_BOOT 1
150 #define BX_MAX_ATA_INTERFACES 4
151 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
153 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
154 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
156 /* model byte 0xFC = AT */
157 #define SYS_MODEL_ID 0xFC
158 #define SYS_SUBMODEL_ID 0x00
159 #define BIOS_REVISION 1
160 #define BIOS_CONFIG_TABLE 0xe6f5
162 #ifndef BIOS_BUILD_DATE
163 # define BIOS_BUILD_DATE "06/23/99"
166 // 1K of base memory used for Extended Bios Data Area (EBDA)
167 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
168 #define EBDA_SEG 0x9FC0
169 #define EBDA_SIZE 1 // In KiB
170 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
172 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
173 #define IPL_SEG 0x9ff0
174 #define IPL_TABLE_OFFSET 0x0000
175 #define IPL_TABLE_ENTRIES 8
176 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
177 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
179 // Define the application NAME
181 # define BX_APPNAME "QEMU"
182 #elif defined(PLEX86)
183 # define BX_APPNAME "Plex86"
185 # define BX_APPNAME "Bochs"
189 #if BX_USE_ATADRV && BX_CPU<3
190 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
192 #if BX_USE_ATADRV && !BX_USE_EBDA
193 # error ATA/ATAPI Driver can only be used if EBDA is available
195 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
196 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
198 #if BX_PCIBIOS && BX_CPU<3
199 # error PCI BIOS can only be used with 386+ cpu
201 #if BX_APM && BX_CPU<3
202 # error APM BIOS can only be used with 386+ cpu
205 // define this if you want to make PCIBIOS working on a specific bridge only
206 // undef enables PCIBIOS when at least one PCI device is found
207 // i440FX is emulated by Bochs and QEMU
208 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
211 // #$20 is hex 20 = 32
212 // #0x20 is hex 20 = 32
219 // all hex literals should be prefixed with '0x'
220 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
221 // no mov SEG-REG, #value, must mov register into seg-reg
222 // grep -i "mov[ ]*.s" rombios.c
224 // This is for compiling with gcc2 and gcc3
225 #define ASM_START #asm
226 #define ASM_END #endasm
240 ;; the HALT macro is called with the line number of the HALT call
.
241 ;; The line number is then sent to the PANIC_PORT
, causing Bochs
/Plex
242 ;; to print a BX_PANIC message
. This will normally halt the simulation
243 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
244 ;; However
, users can choose to make panics non
-fatal
and continue.
271 typedef unsigned char Bit8u
;
272 typedef unsigned short Bit16u
;
273 typedef unsigned short bx_bool
;
274 typedef unsigned long Bit32u
;
277 void memsetb(seg
,offset
,value
,count
);
278 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
279 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
281 // memset of count bytes
283 memsetb(seg
,offset
,value
,count
)
298 mov cx
, 10[bp
] ; count
301 mov ax
, 4[bp
] ; segment
303 mov ax
, 6[bp
] ; offset
305 mov al
, 8[bp
] ; value
320 // memcpy of count bytes
322 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
340 mov cx
, 12[bp
] ; count
343 mov ax
, 4[bp
] ; dsegment
345 mov ax
, 6[bp
] ; doffset
347 mov ax
, 8[bp
] ; ssegment
349 mov ax
, 10[bp
] ; soffset
367 // memcpy of count dword
369 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
387 mov cx
, 12[bp
] ; count
390 mov ax
, 4[bp
] ; dsegment
392 mov ax
, 6[bp
] ; doffset
394 mov ax
, 8[bp
] ; ssegment
396 mov ax
, 10[bp
] ; soffset
414 // read_dword and write_dword functions
415 static Bit32u
read_dword();
416 static void write_dword();
419 read_dword(seg
, offset
)
429 mov ax
, 4[bp
] ; segment
431 mov bx
, 6[bp
] ; offset
435 ;; ax
= return value (word
)
436 ;; dx
= return value (word
)
445 write_dword(seg
, offset
, data
)
457 mov ax
, 4[bp
] ; segment
459 mov bx
, 6[bp
] ; offset
460 mov ax
, 8[bp
] ; data word
461 mov
[bx
], ax
; write data word
463 mov ax
, 10[bp
] ; data word
464 mov
[bx
], ax
; write data word
473 // Bit32u (unsigned long) and long helper functions
502 cmp eax
, dword ptr
[di
]
521 mul eax
, dword ptr
[di
]
617 // for access to RAM area which is used by interrupt vectors
618 // and BIOS Data Area
621 unsigned char filler1
[0x400];
622 unsigned char filler2
[0x6c];
628 #define BiosData ((bios_data_t *) 0)
632 Bit16u heads
; // # heads
633 Bit16u cylinders
; // # cylinders
634 Bit16u spt
; // # sectors / track
654 Bit8u iface
; // ISA or PCI
655 Bit16u iobase1
; // IO Base 1
656 Bit16u iobase2
; // IO Base 2
661 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
662 Bit8u device
; // Detected type of attached devices (hd/cd/none)
663 Bit8u removable
; // Removable device flag
664 Bit8u lock
; // Locks for removable devices
665 Bit8u mode
; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
666 Bit16u blksize
; // block size
668 Bit8u translation
; // type of translation
669 chs_t lchs
; // Logical CHS
670 chs_t pchs
; // Physical CHS
672 Bit32u sectors
; // Total sectors count
677 ata_channel_t channels
[BX_MAX_ATA_INTERFACES
];
680 ata_device_t devices
[BX_MAX_ATA_DEVICES
];
682 // map between (bios hd id - 0x80) and ata channels
683 Bit8u hdcount
, hdidmap
[BX_MAX_ATA_DEVICES
];
685 // map between (bios cd id - 0xE0) and ata channels
686 Bit8u cdcount
, cdidmap
[BX_MAX_ATA_DEVICES
];
688 // Buffer for DPTE table
691 // Count of transferred sectors and bytes
698 // ElTorito Device Emulation data
702 Bit8u emulated_drive
;
703 Bit8u controller_index
;
706 Bit16u buffer_segment
;
713 #endif // BX_ELTORITO_BOOT
715 // for access to EBDA area
716 // The EBDA structure should conform to
717 // http://www.frontiernet.net/~fys/rombios.htm document
718 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
719 // EBDA must be at most 768 bytes; it lives at 0x9fc00, and the boot
720 // device tables are at 0x9ff00 -- 0x9ffff
722 unsigned char filler1
[0x3D];
724 // FDPT - Can be splitted in data members if needed
725 unsigned char fdpt0
[0x10];
726 unsigned char fdpt1
[0x10];
728 unsigned char filler2
[0xC4];
734 // El Torito Emulation data
736 #endif // BX_ELTORITO_BOOT
740 #define EbdaData ((ebda_data_t *) 0)
742 // for access to the int13ext structure
753 #define Int13Ext ((int13ext_t *) 0)
755 // Disk Physical Table definition
762 Bit32u sector_count1
;
763 Bit32u sector_count2
;
774 Bit8u device_path
[8];
779 #define Int13DPT ((dpt_t *) 0)
781 #endif // BX_USE_ATADRV
786 Bit16u di
, si
, bp
, sp
;
787 Bit16u bx
, dx
, cx
, ax
;
791 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
799 Bit32u edi
, esi
, ebp
, esp
;
800 Bit32u ebx
, edx
, ecx
, eax
;
803 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
804 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
832 #define SetCF(x) x.u.r8.flagsl |= 0x01
833 #define SetZF(x) x.u.r8.flagsl |= 0x40
834 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
835 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
836 #define GetCF(x) (x.u.r8.flagsl & 0x01)
855 static Bit8u
inb_cmos();
857 static void outb_cmos();
860 static void init_rtc();
861 static bx_bool
rtc_updating();
863 static Bit8u
read_byte();
864 static Bit16u
read_word();
865 static void write_byte();
866 static void write_word();
867 static void bios_printf();
869 static Bit8u
inhibit_mouse_int_and_events();
870 static void enable_mouse_int_and_events();
871 static Bit8u
send_to_mouse_ctrl();
872 static Bit8u
get_mouse_data();
873 static void set_kbd_command_byte();
875 static void int09_function();
876 static void int13_harddisk();
877 static void int13_cdrom();
878 static void int13_cdemu();
879 static void int13_eltorito();
880 static void int13_diskette_function();
881 static void int14_function();
882 static void int15_function();
883 static void int16_function();
884 static void int17_function();
885 static void int19_function();
886 static void int1a_function();
887 static void int70_function();
888 static void int74_function();
889 static Bit16u
get_CS();
890 static Bit16u
get_SS();
891 static unsigned int enqueue_key();
892 static unsigned int dequeue_key();
893 static void get_hd_geometry();
894 static void set_diskette_ret_status();
895 static void set_diskette_current_cyl();
896 static void determine_floppy_media();
897 static bx_bool
floppy_drive_exists();
898 static bx_bool
floppy_drive_recal();
899 static bx_bool
floppy_media_known();
900 static bx_bool
floppy_media_sense();
901 static bx_bool
set_enable_a20();
902 static void debugger_on();
903 static void debugger_off();
904 static void keyboard_init();
905 static void keyboard_panic();
906 static void shutdown_status_panic();
907 static void nmi_handler_msg();
909 static void print_bios_banner();
910 static void print_boot_device();
911 static void print_boot_failure();
912 static void print_cdromboot_failure();
916 // ATA / ATAPI driver
921 Bit16u
ata_cmd_non_data();
922 Bit16u
ata_cmd_data_in();
923 Bit16u
ata_cmd_data_out();
924 Bit16u
ata_cmd_packet();
926 Bit16u
atapi_get_sense();
927 Bit16u
atapi_is_ready();
928 Bit16u
atapi_is_cdrom();
930 #endif // BX_USE_ATADRV
935 Bit8u
cdemu_isactive();
936 Bit8u
cdemu_emulated_drive();
940 #endif // BX_ELTORITO_BOOT
942 static char bios_cvs_version_string
[] = "$Revision: 1.191 $ $Date: 2007/12/01 19:26:46 $";
944 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
947 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
949 # define BX_DEBUG_ATA(a...)
952 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
954 # define BX_DEBUG_INT13_HD(a...)
957 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
959 # define BX_DEBUG_INT13_CD(a...)
962 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
964 # define BX_DEBUG_INT13_ET(a...)
967 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
969 # define BX_DEBUG_INT13_FL(a...)
972 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
974 # define BX_DEBUG_INT15(a...)
977 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
979 # define BX_DEBUG_INT16(a...)
982 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
984 # define BX_DEBUG_INT1A(a...)
987 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
989 # define BX_DEBUG_INT74(a...)
992 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
993 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
994 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
995 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
996 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
997 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
998 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
999 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1001 #define GET_AL() ( AX & 0x00ff )
1002 #define GET_BL() ( BX & 0x00ff )
1003 #define GET_CL() ( CX & 0x00ff )
1004 #define GET_DL() ( DX & 0x00ff )
1005 #define GET_AH() ( AX >> 8 )
1006 #define GET_BH() ( BX >> 8 )
1007 #define GET_CH() ( CX >> 8 )
1008 #define GET_DH() ( DX >> 8 )
1010 #define GET_ELDL() ( ELDX & 0x00ff )
1011 #define GET_ELDH() ( ELDX >> 8 )
1013 #define SET_CF() FLAGS |= 0x0001
1014 #define CLEAR_CF() FLAGS &= 0xfffe
1015 #define GET_CF() (FLAGS & 0x0001)
1017 #define SET_ZF() FLAGS |= 0x0040
1018 #define CLEAR_ZF() FLAGS &= 0xffbf
1019 #define GET_ZF() (FLAGS & 0x0040)
1021 #define UNSUPPORTED_FUNCTION 0x86
1024 #define MAX_SCAN_CODE 0x58
1032 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1033 { none
, none
, none
, none
, none
},
1034 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1035 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1036 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1037 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1038 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1039 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1040 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1041 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1042 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1043 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1044 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1045 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1046 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1047 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1048 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1049 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1050 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1051 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1052 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1053 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1054 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1055 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1056 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1057 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1058 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1059 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1060 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1061 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1062 { none
, none
, none
, none
, none
}, /* L Ctrl */
1063 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1064 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1065 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1066 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1067 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1068 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1069 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1070 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1071 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1072 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1073 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1074 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1075 { none
, none
, none
, none
, none
}, /* L shift */
1076 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1077 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1078 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1079 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1080 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1081 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1082 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1083 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1084 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1085 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1086 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1087 { none
, none
, none
, none
, none
}, /* R Shift */
1088 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1089 { none
, none
, none
, none
, none
}, /* L Alt */
1090 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1091 { none
, none
, none
, none
, none
}, /* caps lock */
1092 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1093 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1094 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1095 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1096 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1097 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1098 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1099 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1100 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1101 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1102 { none
, none
, none
, none
, none
}, /* Num Lock */
1103 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1104 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1105 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1106 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1107 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1108 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1109 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1110 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1111 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1112 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1113 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1114 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1115 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1116 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1117 { none
, none
, none
, none
, none
},
1118 { none
, none
, none
, none
, none
},
1119 { 0x565c, 0x567c, none
, none
, none
}, /* \| */
1120 { 0x5700, 0x5700, none
, none
, none
}, /* F11 */
1121 { 0x5800, 0x5800, none
, none
, none
} /* F12 */
1205 outb_cmos(cmos_reg
, val
)
1213 mov al
, 4[bp
] ;; cmos_reg
1215 mov al
, 6[bp
] ;; val
1230 mov al
, 4[bp
] ;; cmos_reg
1241 outb_cmos(0x0a, 0x26);
1242 outb_cmos(0x0b, 0x02);
1250 // This function checks to see if the update-in-progress bit
1251 // is set in CMOS Status Register A. If not, it returns 0.
1252 // If it is set, it tries to wait until there is a transition
1253 // to 0, and will return 0 if such a transition occurs. A 1
1254 // is returned only after timing out. The maximum period
1255 // that this bit should be set is constrained to 244useconds.
1256 // The count I use below guarantees coverage or more than
1257 // this time, with any reasonable IPS setting.
1262 while (--count
!= 0) {
1263 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1266 return(1); // update-in-progress never transitioned to 0
1271 read_byte(seg
, offset
)
1281 mov ax
, 4[bp
] ; segment
1283 mov bx
, 6[bp
] ; offset
1285 ;; al
= return value (byte
)
1294 read_word(seg
, offset
)
1304 mov ax
, 4[bp
] ; segment
1306 mov bx
, 6[bp
] ; offset
1308 ;; ax
= return value (word
)
1317 write_byte(seg
, offset
, data
)
1329 mov ax
, 4[bp
] ; segment
1331 mov bx
, 6[bp
] ; offset
1332 mov al
, 8[bp
] ; data byte
1333 mov
[bx
], al
; write data byte
1343 write_word(seg
, offset
, data
)
1355 mov ax
, 4[bp
] ; segment
1357 mov bx
, 6[bp
] ; offset
1358 mov ax
, 8[bp
] ; data word
1359 mov
[bx
], ax
; write data word
1385 /* serial debug port*/
1386 #define BX_DEBUG_PORT 0x03f8
1389 #define UART_RBR 0x00
1390 #define UART_THR 0x00
1393 #define UART_IER 0x01
1394 #define UART_IIR 0x02
1395 #define UART_FCR 0x02
1396 #define UART_LCR 0x03
1397 #define UART_MCR 0x04
1398 #define UART_DLL 0x00
1399 #define UART_DLM 0x01
1402 #define UART_LSR 0x05
1403 #define UART_MSR 0x06
1404 #define UART_SCR 0x07
1406 int uart_can_tx_byte(base_port
)
1409 return inb(base_port
+ UART_LSR
) & 0x20;
1412 void uart_wait_to_tx_byte(base_port
)
1415 while (!uart_can_tx_byte(base_port
));
1418 void uart_wait_until_sent(base_port
)
1421 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1424 void uart_tx_byte(base_port
, data
)
1428 uart_wait_to_tx_byte(base_port
);
1429 outb(base_port
+ UART_THR
, data
);
1430 uart_wait_until_sent(base_port
);
1459 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1460 uart_tx_byte(BX_DEBUG_PORT
, c
);
1462 #if BX_VIRTUAL_PORTS
1463 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1464 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1466 if (action
& BIOS_PRINTF_SCREEN
) {
1467 if (c
== '\n') wrch('\r');
1473 put_int(action
, val
, width
, neg
)
1478 short nval
= val
/ 10;
1480 put_int(action
, nval
, width
- 1, neg
);
1482 while (--width
> 0) send(action
, ' ');
1483 if (neg
) send(action
, '-');
1485 send(action
, val
- (nval
* 10) + '0');
1489 put_uint(action
, val
, width
, neg
)
1495 unsigned short nval
= val
/ 10;
1497 put_uint(action
, nval
, width
- 1, neg
);
1499 while (--width
> 0) send(action
, ' ');
1500 if (neg
) send(action
, '-');
1502 send(action
, val
- (nval
* 10) + '0');
1506 put_luint(action
, val
, width
, neg
)
1512 unsigned long nval
= val
/ 10;
1514 put_luint(action
, nval
, width
- 1, neg
);
1516 while (--width
> 0) send(action
, ' ');
1517 if (neg
) send(action
, '-');
1519 send(action
, val
- (nval
* 10) + '0');
1522 void put_str(action
, s
)
1530 while (c
= read_byte(get_CS(), s
)) {
1536 //--------------------------------------------------------------------------
1538 // A compact variable argument printf function.
1540 // Supports %[format_width][length]format
1541 // where format can be x,X,u,d,s,c
1542 // and the optional length modifier is l (ell)
1543 //--------------------------------------------------------------------------
1545 bios_printf(action
, s
)
1549 Bit8u c
, format_char
;
1553 Bit16u arg_seg
, arg
, nibble
, hibyte
, shift_count
, format_width
, hexadd
;
1561 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1562 #if BX_VIRTUAL_PORTS
1563 outb(PANIC_PORT2
, 0x00);
1565 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1568 while (c
= read_byte(get_CS(), s
)) {
1573 else if (in_format
) {
1574 if ( (c
>='0') && (c
<='9') ) {
1575 format_width
= (format_width
* 10) + (c
- '0');
1578 arg_ptr
++; // increment to next arg
1579 arg
= read_word(arg_seg
, arg_ptr
);
1580 if (c
== 'x' || c
== 'X') {
1581 if (format_width
== 0)
1587 for (i
=format_width
-1; i
>=0; i
--) {
1588 nibble
= (arg
>> (4 * i
)) & 0x000f;
1589 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1592 else if (c
== 'u') {
1593 put_uint(action
, arg
, format_width
, 0);
1595 else if (c
== 'l') {
1597 c
= read_byte(get_CS(), s
); /* is it ld,lx,lu? */
1598 arg_ptr
++; /* increment to next arg */
1599 hibyte
= read_word(arg_seg
, arg_ptr
);
1601 if (hibyte
& 0x8000)
1602 put_luint(action
, 0L-(((Bit32u
) hibyte
<< 16) | arg
), format_width
-1, 1);
1604 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1606 else if (c
== 'u') {
1607 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1609 else if (c
== 'x' || c
== 'X')
1611 if (format_width
== 0)
1617 for (i
=format_width
-1; i
>=0; i
--) {
1618 nibble
= ((((Bit32u
) hibyte
<<16) | arg
) >> (4 * i
)) & 0x000f;
1619 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1623 else if (c
== 'd') {
1625 put_int(action
, -arg
, format_width
- 1, 1);
1627 put_int(action
, arg
, format_width
, 0);
1629 else if (c
== 's') {
1630 put_str(action
, arg
);
1632 else if (c
== 'c') {
1636 BX_PANIC("bios_printf: unknown format\n");
1646 if (action
& BIOS_PRINTF_HALT
) {
1647 // freeze in a busy loop.
1657 //--------------------------------------------------------------------------
1659 //--------------------------------------------------------------------------
1660 // this file is based on LinuxBIOS implementation of keyboard.c
1661 // could convert to #asm to gain space
1667 /* ------------------- Flush buffers ------------------------*/
1668 /* Wait until buffer is empty */
1670 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1672 /* flush incoming keys */
1676 if (inb(0x64) & 0x01) {
1682 // Due to timer issues, and if the IPS setting is > 15000000,
1683 // the incoming keys might not be flushed here. That will
1684 // cause a panic a few lines below. See sourceforge bug report :
1685 // [ 642031 ] FATAL: Keyboard RESET error:993
1687 /* ------------------- controller side ----------------------*/
1688 /* send cmd = 0xAA, self test 8042 */
1691 /* Wait until buffer is empty */
1693 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1694 if (max
==0x0) keyboard_panic(00);
1698 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1699 if (max
==0x0) keyboard_panic(01);
1701 /* read self-test result, 0x55 should be returned from 0x60 */
1702 if ((inb(0x60) != 0x55)){
1703 keyboard_panic(991);
1706 /* send cmd = 0xAB, keyboard interface test */
1709 /* Wait until buffer is empty */
1711 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1712 if (max
==0x0) keyboard_panic(10);
1716 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1717 if (max
==0x0) keyboard_panic(11);
1719 /* read keyboard interface test result, */
1720 /* 0x00 should be returned form 0x60 */
1721 if ((inb(0x60) != 0x00)) {
1722 keyboard_panic(992);
1725 /* Enable Keyboard clock */
1729 /* ------------------- keyboard side ------------------------*/
1730 /* reset kerboard and self test (keyboard side) */
1733 /* Wait until buffer is empty */
1735 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1736 if (max
==0x0) keyboard_panic(20);
1740 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1741 if (max
==0x0) keyboard_panic(21);
1743 /* keyboard should return ACK */
1744 if ((inb(0x60) != 0xfa)) {
1745 keyboard_panic(993);
1750 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1751 if (max
==0x0) keyboard_panic(31);
1753 if ((inb(0x60) != 0xaa)) {
1754 keyboard_panic(994);
1757 /* Disable keyboard */
1760 /* Wait until buffer is empty */
1762 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1763 if (max
==0x0) keyboard_panic(40);
1767 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1768 if (max
==0x0) keyboard_panic(41);
1770 /* keyboard should return ACK */
1771 if ((inb(0x60) != 0xfa)) {
1772 keyboard_panic(995);
1775 /* Write Keyboard Mode */
1778 /* Wait until buffer is empty */
1780 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1781 if (max
==0x0) keyboard_panic(50);
1783 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1786 /* Wait until buffer is empty */
1788 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1789 if (max
==0x0) keyboard_panic(60);
1791 /* Enable keyboard */
1794 /* Wait until buffer is empty */
1796 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1797 if (max
==0x0) keyboard_panic(70);
1801 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1802 if (max
==0x0) keyboard_panic(70);
1804 /* keyboard should return ACK */
1805 if ((inb(0x60) != 0xfa)) {
1806 keyboard_panic(996);
1812 //--------------------------------------------------------------------------
1814 //--------------------------------------------------------------------------
1816 keyboard_panic(status
)
1819 // If you're getting a 993 keyboard panic here,
1820 // please see the comment in keyboard_init
1822 BX_PANIC("Keyboard error:%u\n",status
);
1825 //--------------------------------------------------------------------------
1826 // shutdown_status_panic
1827 // called when the shutdown statsu is not implemented, displays the status
1828 //--------------------------------------------------------------------------
1830 shutdown_status_panic(status
)
1833 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1836 //--------------------------------------------------------------------------
1837 // print_bios_banner
1838 // displays a the bios version
1839 //--------------------------------------------------------------------------
1843 printf(BX_APPNAME
" BIOS - build: %s\n%s\nOptions: ",
1844 BIOS_BUILD_DATE
, bios_cvs_version_string
);
1852 #if BX_ELTORITO_BOOT
1861 //--------------------------------------------------------------------------
1862 // BIOS Boot Specification 1.0.1 compatibility
1864 // Very basic support for the BIOS Boot Specification, which allows expansion
1865 // ROMs to register themselves as boot devices, instead of just stealing the
1866 // INT 19h boot vector.
1868 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1869 // one; we just lie to the option ROMs to make them behave correctly.
1870 // We also don't support letting option ROMs register as bootable disk
1871 // drives (BCVs), only as bootable devices (BEVs).
1873 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1874 //--------------------------------------------------------------------------
1882 Bit16u ss
= get_SS();
1884 /* Clear out the IPL table. */
1885 memsetb(IPL_SEG
, IPL_TABLE_OFFSET
, 0, 0xff);
1888 e
.type
= 1; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1889 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1893 e
.type
= 2; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1894 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1897 #if BX_ELTORITO_BOOT
1899 e
.type
= 3; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1900 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1904 /* Remember how many devices we have */
1905 write_word(IPL_SEG
, IPL_COUNT_OFFSET
, count
);
1906 /* Not tried booting anything yet */
1907 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xffff);
1911 get_boot_vector(i
, e
)
1912 Bit16u i
; ipl_entry_t
*e
;
1915 Bit16u ss
= get_SS();
1916 /* Get the count of boot devices, and refuse to overrun the array */
1917 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
1918 if (i
>= count
) return 0;
1919 /* OK to read this device */
1920 memcpyb(ss
, e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (*e
), sizeof (*e
));
1925 //--------------------------------------------------------------------------
1926 // print_boot_device
1927 // displays the boot device
1928 //--------------------------------------------------------------------------
1930 static char drivetypes
[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1933 print_boot_device(type
)
1936 /* NIC appears as type 0x80 */
1937 if (type
== 0x80 ) type
= 0x4;
1938 if (type
== 0 || type
> 0x4) BX_PANIC("Bad drive type\n");
1939 printf("Booting from %s...\n", drivetypes
[type
]);
1942 //--------------------------------------------------------------------------
1943 // print_boot_failure
1944 // displays the reason why boot failed
1945 //--------------------------------------------------------------------------
1947 print_boot_failure(type
, reason
)
1948 Bit16u type
; Bit8u reason
;
1950 if (type
== 0 || type
> 0x3) BX_PANIC("Bad drive type\n");
1952 printf("Boot from %s failed", drivetypes
[type
]);
1954 /* Report the reason too */
1956 printf(": not a bootable disk");
1958 printf(": could not read the boot disk");
1963 //--------------------------------------------------------------------------
1964 // print_cdromboot_failure
1965 // displays the reason why boot failed
1966 //--------------------------------------------------------------------------
1968 print_cdromboot_failure( code
)
1971 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1979 BX_PANIC("NMI Handler called\n");
1985 BX_PANIC("INT18: BOOT FAILURE\n");
1992 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
1994 BX_INFO("%s\n", bios_cvs_version_string
);
2003 // Use PS2 System Control port A to set A20 enable
2005 // get current setting first
2008 // change A20 status
2010 outb(0x92, oldval
| 0x02);
2012 outb(0x92, oldval
& 0xfd);
2014 return((oldval
& 0x02) != 0);
2031 // ---------------------------------------------------------------------------
2032 // Start of ATA/ATAPI Driver
2033 // ---------------------------------------------------------------------------
2035 // Global defines -- ATA register and register bits.
2036 // command block & control block regs
2037 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2038 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2039 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2040 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2041 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2042 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2043 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2044 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2045 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2046 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2047 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2048 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2049 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2051 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2052 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2053 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2054 #define ATA_CB_ER_MC 0x20 // ATA media change
2055 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2056 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2057 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2058 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2059 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2061 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2062 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2063 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2064 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2065 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2067 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2068 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2069 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2070 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2071 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2073 // bits 7-4 of the device/head (CB_DH) reg
2074 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2075 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2076 #define ATA_CB_DH_LBA 0x40 // use LBA
2078 // status reg (CB_STAT and CB_ASTAT) bits
2079 #define ATA_CB_STAT_BSY 0x80 // busy
2080 #define ATA_CB_STAT_RDY 0x40 // ready
2081 #define ATA_CB_STAT_DF 0x20 // device fault
2082 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2083 #define ATA_CB_STAT_SKC 0x10 // seek complete
2084 #define ATA_CB_STAT_SERV 0x10 // service
2085 #define ATA_CB_STAT_DRQ 0x08 // data request
2086 #define ATA_CB_STAT_CORR 0x04 // corrected
2087 #define ATA_CB_STAT_IDX 0x02 // index
2088 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2089 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2091 // device control reg (CB_DC) bits
2092 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2093 #define ATA_CB_DC_SRST 0x04 // soft reset
2094 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2096 // Most mandtory and optional ATA commands (from ATA-3),
2097 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2098 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2099 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2100 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2101 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2102 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2103 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2104 #define ATA_CMD_DEVICE_RESET 0x08
2105 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2106 #define ATA_CMD_FLUSH_CACHE 0xE7
2107 #define ATA_CMD_FORMAT_TRACK 0x50
2108 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2109 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2110 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2111 #define ATA_CMD_IDLE1 0xE3
2112 #define ATA_CMD_IDLE2 0x97
2113 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2114 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2115 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2116 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2117 #define ATA_CMD_NOP 0x00
2118 #define ATA_CMD_PACKET 0xA0
2119 #define ATA_CMD_READ_BUFFER 0xE4
2120 #define ATA_CMD_READ_DMA 0xC8
2121 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2122 #define ATA_CMD_READ_MULTIPLE 0xC4
2123 #define ATA_CMD_READ_SECTORS 0x20
2124 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2125 #define ATA_CMD_RECALIBRATE 0x10
2126 #define ATA_CMD_REQUEST_SENSE 0x03
2127 #define ATA_CMD_SEEK 0x70
2128 #define ATA_CMD_SET_FEATURES 0xEF
2129 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2130 #define ATA_CMD_SLEEP1 0xE6
2131 #define ATA_CMD_SLEEP2 0x99
2132 #define ATA_CMD_STANDBY1 0xE2
2133 #define ATA_CMD_STANDBY2 0x96
2134 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2135 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2136 #define ATA_CMD_WRITE_BUFFER 0xE8
2137 #define ATA_CMD_WRITE_DMA 0xCA
2138 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2139 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2140 #define ATA_CMD_WRITE_SECTORS 0x30
2141 #define ATA_CMD_WRITE_VERIFY 0x3C
2143 #define ATA_IFACE_NONE 0x00
2144 #define ATA_IFACE_ISA 0x00
2145 #define ATA_IFACE_PCI 0x01
2147 #define ATA_TYPE_NONE 0x00
2148 #define ATA_TYPE_UNKNOWN 0x01
2149 #define ATA_TYPE_ATA 0x02
2150 #define ATA_TYPE_ATAPI 0x03
2152 #define ATA_DEVICE_NONE 0x00
2153 #define ATA_DEVICE_HD 0xFF
2154 #define ATA_DEVICE_CDROM 0x05
2156 #define ATA_MODE_NONE 0x00
2157 #define ATA_MODE_PIO16 0x00
2158 #define ATA_MODE_PIO32 0x01
2159 #define ATA_MODE_ISADMA 0x02
2160 #define ATA_MODE_PCIDMA 0x03
2161 #define ATA_MODE_USEIRQ 0x10
2163 #define ATA_TRANSLATION_NONE 0
2164 #define ATA_TRANSLATION_LBA 1
2165 #define ATA_TRANSLATION_LARGE 2
2166 #define ATA_TRANSLATION_RECHS 3
2168 #define ATA_DATA_NO 0x00
2169 #define ATA_DATA_IN 0x01
2170 #define ATA_DATA_OUT 0x02
2172 // ---------------------------------------------------------------------------
2173 // ATA/ATAPI driver : initialization
2174 // ---------------------------------------------------------------------------
2177 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2178 Bit8u channel
, device
;
2180 // Channels info init.
2181 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2182 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2183 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2184 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2185 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2188 // Devices info init.
2189 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2190 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2191 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2192 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2193 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2194 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2195 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2196 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2197 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2198 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2199 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2200 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2201 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2202 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2204 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2207 // hdidmap and cdidmap init.
2208 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2209 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2210 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2213 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2214 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2220 #define NOT_BSY_DRQ 3
2221 #define NOT_BSY_NOT_DRQ 4
2222 #define NOT_BSY_RDY 5
2224 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
2227 static int await_ide(when_done
,base
,timeout
)
2232 Bit32u time
=0,last
=0;
2235 status
= inb(base
+ ATA_CB_STAT
); // for the times you're supposed to throw one away
2237 status
= inb(base
+ATA_CB_STAT
);
2239 if (when_done
== BSY
)
2240 result
= status
& ATA_CB_STAT_BSY
;
2241 else if (when_done
== NOT_BSY
)
2242 result
= !(status
& ATA_CB_STAT_BSY
);
2243 else if (when_done
== NOT_BSY_DRQ
)
2244 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_DRQ
);
2245 else if (when_done
== NOT_BSY_NOT_DRQ
)
2246 result
= !(status
& ATA_CB_STAT_BSY
) && !(status
& ATA_CB_STAT_DRQ
);
2247 else if (when_done
== NOT_BSY_RDY
)
2248 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_RDY
);
2249 else if (when_done
== TIMEOUT
)
2252 if (result
) return 0;
2253 if (time
>>16 != last
) // mod 2048 each 16 ms
2256 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
);
2258 if (status
& ATA_CB_STAT_ERR
)
2260 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
);
2263 if ((timeout
== 0) || ((time
>>11) > timeout
)) break;
2265 BX_INFO("IDE time out\n");
2269 // ---------------------------------------------------------------------------
2270 // ATA/ATAPI driver : device detection
2271 // ---------------------------------------------------------------------------
2275 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2276 Bit8u hdcount
, cdcount
, device
, type
;
2277 Bit8u buffer
[0x0200];
2279 #if BX_MAX_ATA_INTERFACES > 0
2280 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2281 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2282 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2283 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2285 #if BX_MAX_ATA_INTERFACES > 1
2286 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2287 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2288 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2289 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2291 #if BX_MAX_ATA_INTERFACES > 2
2292 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2293 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2294 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2295 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2297 #if BX_MAX_ATA_INTERFACES > 3
2298 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2299 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2300 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2301 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2303 #if BX_MAX_ATA_INTERFACES > 4
2304 #error Please fill the ATA interface informations
2310 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2311 Bit16u iobase1
, iobase2
;
2312 Bit8u channel
, slave
, shift
;
2313 Bit8u sc
, sn
, cl
, ch
, st
;
2315 channel
= device
/ 2;
2318 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2319 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2321 // Disable interrupts
2322 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2325 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2326 outb(iobase1
+ATA_CB_SC
, 0x55);
2327 outb(iobase1
+ATA_CB_SN
, 0xaa);
2328 outb(iobase1
+ATA_CB_SC
, 0xaa);
2329 outb(iobase1
+ATA_CB_SN
, 0x55);
2330 outb(iobase1
+ATA_CB_SC
, 0x55);
2331 outb(iobase1
+ATA_CB_SN
, 0xaa);
2333 // If we found something
2334 sc
= inb(iobase1
+ATA_CB_SC
);
2335 sn
= inb(iobase1
+ATA_CB_SN
);
2337 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2338 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2340 // reset the channel
2343 // check for ATA or ATAPI
2344 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2345 sc
= inb(iobase1
+ATA_CB_SC
);
2346 sn
= inb(iobase1
+ATA_CB_SN
);
2347 if ((sc
==0x01) && (sn
==0x01)) {
2348 cl
= inb(iobase1
+ATA_CB_CL
);
2349 ch
= inb(iobase1
+ATA_CB_CH
);
2350 st
= inb(iobase1
+ATA_CB_STAT
);
2352 if ((cl
==0x14) && (ch
==0xeb)) {
2353 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2354 } else if ((cl
==0x00) && (ch
==0x00) && (st
!=0x00)) {
2355 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2356 } else if ((cl
==0xff) && (ch
==0xff)) {
2357 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2362 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2364 // Now we send a IDENTIFY command to ATA device
2365 if(type
== ATA_TYPE_ATA
) {
2367 Bit16u cylinders
, heads
, spt
, blksize
;
2368 Bit8u translation
, removable
, mode
;
2370 //Temporary values to do the transfer
2371 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2372 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2374 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2375 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2377 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2378 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2379 blksize
= read_word(get_SS(),buffer
+10);
2381 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2382 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2383 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2385 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2387 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2388 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2389 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2390 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2391 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2392 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2393 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2394 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2395 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2397 translation
= inb_cmos(0x39 + channel
/2);
2398 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2399 translation
&= 0x03;
2401 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2403 switch (translation
) {
2404 case ATA_TRANSLATION_NONE
:
2407 case ATA_TRANSLATION_LBA
:
2410 case ATA_TRANSLATION_LARGE
:
2413 case ATA_TRANSLATION_RECHS
:
2417 switch (translation
) {
2418 case ATA_TRANSLATION_NONE
:
2420 case ATA_TRANSLATION_LBA
:
2423 heads
= sectors
/ 1024;
2424 if (heads
>128) heads
= 255;
2425 else if (heads
>64) heads
= 128;
2426 else if (heads
>32) heads
= 64;
2427 else if (heads
>16) heads
= 32;
2429 cylinders
= sectors
/ heads
;
2431 case ATA_TRANSLATION_RECHS
:
2432 // Take care not to overflow
2434 if(cylinders
>61439) cylinders
=61439;
2436 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2438 // then go through the large bitshift process
2439 case ATA_TRANSLATION_LARGE
:
2440 while(cylinders
> 1024) {
2444 // If we max out the head count
2445 if (heads
> 127) break;
2449 // clip to 1024 cylinders in lchs
2450 if (cylinders
> 1024) cylinders
=1024;
2451 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2453 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2454 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2455 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2458 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2462 // Now we send a IDENTIFY command to ATAPI device
2463 if(type
== ATA_TYPE_ATAPI
) {
2465 Bit8u type
, removable
, mode
;
2468 //Temporary values to do the transfer
2469 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2470 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2472 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2473 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2475 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2476 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2477 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2480 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2481 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2482 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2483 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2486 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2493 Bit8u c
, i
, version
, model
[41];
2497 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2499 case ATA_TYPE_ATAPI
:
2500 // Read ATA/ATAPI version
2501 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2502 for(version
=15;version
>0;version
--) {
2503 if((ataversion
&(1<<version
))!=0)
2509 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2510 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2514 write_byte(get_SS(),model
+40,0x00);
2516 if(read_byte(get_SS(),model
+i
)==0x20)
2517 write_byte(get_SS(),model
+i
,0x00);
2525 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2526 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2527 if (sizeinmb
< (1UL<<16))
2528 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version
, (Bit16u
)sizeinmb
);
2530 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version
, (Bit16u
)(sizeinmb
>>10));
2532 case ATA_TYPE_ATAPI
:
2533 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2534 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2535 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2536 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2538 printf(" ATAPI-%d Device\n",version
);
2540 case ATA_TYPE_UNKNOWN
:
2541 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2547 // Store the devices counts
2548 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2549 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2550 write_byte(0x40,0x75, hdcount
);
2554 // FIXME : should use bios=cmos|auto|disable bits
2555 // FIXME : should know about translation bits
2556 // FIXME : move hard_drive_post here
2560 // ---------------------------------------------------------------------------
2561 // ATA/ATAPI driver : software reset
2562 // ---------------------------------------------------------------------------
2564 // 8.2.1 Software reset - Device 0
2566 void ata_reset(device
)
2569 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2570 Bit16u iobase1
, iobase2
;
2571 Bit8u channel
, slave
, sn
, sc
;
2575 channel
= device
/ 2;
2578 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2579 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2583 // 8.2.1 (a) -- set SRST in DC
2584 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2586 // 8.2.1 (b) -- wait for BSY
2587 if (await_ide(BSY
, iobase1
, 20)) return;
2589 // 8.2.1 (f) -- clear SRST
2590 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2592 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2593 if (type
!= ATA_TYPE_NONE
) {
2595 // 8.2.1 (g) -- check for sc==sn==0x01
2597 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2598 sc
= inb(iobase1
+ATA_CB_SC
);
2599 sn
= inb(iobase1
+ATA_CB_SN
);
2601 if ( (sc
==0x01) && (sn
==0x01) ) {
2602 if (type
== ATA_TYPE_ATA
) //ATA
2603 await_ide(NOT_BSY_RDY
, iobase1
, IDE_TIMEOUT
);
2605 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2608 // 8.2.1 (h) -- wait for not BSY
2609 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2612 // Enable interrupts
2613 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2616 // ---------------------------------------------------------------------------
2617 // ATA/ATAPI driver : execute a non data command
2618 // ---------------------------------------------------------------------------
2620 Bit16u
ata_cmd_non_data()
2623 // ---------------------------------------------------------------------------
2624 // ATA/ATAPI driver : execute a data-in command
2625 // ---------------------------------------------------------------------------
2630 // 3 : expected DRQ=1
2631 // 4 : no sectors left to read/verify
2632 // 5 : more sectors to read/verify
2633 // 6 : no sectors left to write
2634 // 7 : more sectors to write
2635 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2636 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2639 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2640 Bit16u iobase1
, iobase2
, blksize
;
2641 Bit8u channel
, slave
;
2642 Bit8u status
, current
, mode
;
2644 channel
= device
/ 2;
2647 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2648 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2649 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2650 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2651 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2654 //!!FIXME!! this only works up to 28-bit LBA
2655 // sector will be 0 only on lba access. Convert to lba-chs
2657 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2658 cylinder
= (Bit16u
) ((lba
>>8) & 0x0000ffffL
);
2659 head
= ((Bit16u
) ((lba
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2662 // Reset count of transferred data
2663 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2664 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2667 status
= inb(iobase1
+ ATA_CB_STAT
);
2668 if (status
& ATA_CB_STAT_BSY
) return 1;
2670 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2671 outb(iobase1
+ ATA_CB_FR
, 0x00);
2672 outb(iobase1
+ ATA_CB_SC
, count
);
2673 outb(iobase1
+ ATA_CB_SN
, sector
);
2674 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2675 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2676 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2677 outb(iobase1
+ ATA_CB_CMD
, command
);
2679 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2680 status
= inb(iobase1
+ ATA_CB_STAT
);
2682 if (status
& ATA_CB_STAT_ERR
) {
2683 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2685 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2686 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2690 // FIXME : move seg/off translation here
2693 sti
;; enable higher priority interrupts
2701 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2702 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2703 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2705 ;; adjust
if there will be an overrun
. 2K max sector size
2707 jbe ata_in_no_adjust
2710 sub di
, #0x0800 ;; sub 2 kbytes from offset
2711 add ax
, #0x0080 ;; add 2 Kbytes to segment
2714 mov es
, ax
;; segment in es
2716 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2718 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2719 cmp ah
, #ATA_MODE_PIO32
2724 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2729 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2732 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2733 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2738 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2740 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2741 status
= inb(iobase1
+ ATA_CB_STAT
);
2743 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2744 != ATA_CB_STAT_RDY
) {
2745 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2751 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2752 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2753 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2759 // Enable interrupts
2760 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2764 // ---------------------------------------------------------------------------
2765 // ATA/ATAPI driver : execute a data-out command
2766 // ---------------------------------------------------------------------------
2771 // 3 : expected DRQ=1
2772 // 4 : no sectors left to read/verify
2773 // 5 : more sectors to read/verify
2774 // 6 : no sectors left to write
2775 // 7 : more sectors to write
2776 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2777 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2780 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2781 Bit16u iobase1
, iobase2
, blksize
;
2782 Bit8u channel
, slave
;
2783 Bit8u status
, current
, mode
;
2785 channel
= device
/ 2;
2788 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2789 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2790 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2791 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2792 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2795 //!!FIXME!! this only works up to 28-bit LBA
2796 // sector will be 0 only on lba access. Convert to lba-chs
2798 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2799 cylinder
= (Bit16u
) ((lba
>>8) & 0x0000ffffL
);
2800 head
= ((Bit16u
) ((lba
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2803 // Reset count of transferred data
2804 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2805 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2808 status
= inb(iobase1
+ ATA_CB_STAT
);
2809 if (status
& ATA_CB_STAT_BSY
) return 1;
2811 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2812 outb(iobase1
+ ATA_CB_FR
, 0x00);
2813 outb(iobase1
+ ATA_CB_SC
, count
);
2814 outb(iobase1
+ ATA_CB_SN
, sector
);
2815 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2816 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2817 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2818 outb(iobase1
+ ATA_CB_CMD
, command
);
2820 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2821 status
= inb(iobase1
+ ATA_CB_STAT
);
2823 if (status
& ATA_CB_STAT_ERR
) {
2824 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2826 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2827 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2831 // FIXME : move seg/off translation here
2834 sti
;; enable higher priority interrupts
2842 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2843 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2844 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2846 ;; adjust
if there will be an overrun
. 2K max sector size
2848 jbe ata_out_no_adjust
2851 sub si
, #0x0800 ;; sub 2 kbytes from offset
2852 add ax
, #0x0080 ;; add 2 Kbytes to segment
2855 mov es
, ax
;; segment in es
2857 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2859 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2860 cmp ah
, #ATA_MODE_PIO32
2866 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2872 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2875 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2876 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2881 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2883 status
= inb(iobase1
+ ATA_CB_STAT
);
2885 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2886 != ATA_CB_STAT_RDY
) {
2887 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2893 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2894 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2895 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2901 // Enable interrupts
2902 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2906 // ---------------------------------------------------------------------------
2907 // ATA/ATAPI driver : execute a packet command
2908 // ---------------------------------------------------------------------------
2911 // 1 : error in parameters
2915 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2917 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2921 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2922 Bit16u iobase1
, iobase2
;
2923 Bit16u lcount
, lbefore
, lafter
, count
;
2924 Bit8u channel
, slave
;
2925 Bit8u status
, mode
, lmode
;
2926 Bit32u total
, transfer
;
2928 channel
= device
/ 2;
2931 // Data out is not supported yet
2932 if (inout
== ATA_DATA_OUT
) {
2933 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2937 // The header length must be even
2939 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2943 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2944 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2945 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2948 if (cmdlen
< 12) cmdlen
=12;
2949 if (cmdlen
> 12) cmdlen
=16;
2952 // Reset count of transferred data
2953 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2954 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2956 status
= inb(iobase1
+ ATA_CB_STAT
);
2957 if (status
& ATA_CB_STAT_BSY
) return 2;
2959 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2960 outb(iobase1
+ ATA_CB_FR
, 0x00);
2961 outb(iobase1
+ ATA_CB_SC
, 0x00);
2962 outb(iobase1
+ ATA_CB_SN
, 0x00);
2963 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2964 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2965 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2966 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2968 // Device should ok to receive command
2969 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2970 status
= inb(iobase1
+ ATA_CB_STAT
);
2972 if (status
& ATA_CB_STAT_ERR
) {
2973 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2975 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2976 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2980 // Normalize address
2981 cmdseg
+= (cmdoff
/ 16);
2984 // Send command to device
2986 sti
;; enable higher priority interrupts
2991 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
2992 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
2993 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
2994 mov es
, ax
;; segment in es
2996 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
3000 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
3005 if (inout
== ATA_DATA_NO
) {
3006 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3007 status
= inb(iobase1
+ ATA_CB_STAT
);
3014 if (loops
== 0) {//first time through
3015 status
= inb(iobase2
+ ATA_CB_ASTAT
);
3016 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3019 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3022 status
= inb(iobase1
+ ATA_CB_STAT
);
3023 sc
= inb(iobase1
+ ATA_CB_SC
);
3025 // Check if command completed
3026 if(((inb(iobase1
+ ATA_CB_SC
)&0x7)==0x3) &&
3027 ((status
& (ATA_CB_STAT_RDY
| ATA_CB_STAT_ERR
)) == ATA_CB_STAT_RDY
)) break;
3029 if (status
& ATA_CB_STAT_ERR
) {
3030 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
3034 // Normalize address
3035 bufseg
+= (bufoff
/ 16);
3038 // Get the byte count
3039 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
3041 // adjust to read what we want
3054 lafter
=lcount
-length
;
3066 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
3067 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
3069 // If counts not dividable by 4, use 16bits mode
3071 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
3072 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
3073 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
3075 // adds an extra byte if count are odd. before is always even
3076 if (lcount
& 0x01) {
3078 if ((lafter
> 0) && (lafter
& 0x01)) {
3083 if (lmode
== ATA_MODE_PIO32
) {
3084 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
3087 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
3096 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
3098 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
3099 jcxz ata_packet_no_before
3101 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3102 cmp ah
, #ATA_MODE_PIO32
3103 je ata_packet_in_before_32
3105 ata_packet_in_before_16
:
3107 loop ata_packet_in_before_16
3108 jmp ata_packet_no_before
3110 ata_packet_in_before_32
:
3112 ata_packet_in_before_32_loop
:
3114 loop ata_packet_in_before_32_loop
3117 ata_packet_no_before
:
3118 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3119 jcxz ata_packet_after
3121 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3122 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3125 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3126 cmp ah
, #ATA_MODE_PIO32
3131 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3132 jmp ata_packet_after
3136 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3139 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3140 jcxz ata_packet_done
3142 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3143 cmp ah
, #ATA_MODE_PIO32
3144 je ata_packet_in_after_32
3146 ata_packet_in_after_16
:
3148 loop ata_packet_in_after_16
3151 ata_packet_in_after_32
:
3153 ata_packet_in_after_32_loop
:
3155 loop ata_packet_in_after_32_loop
3162 // Compute new buffer address
3165 // Save transferred bytes count
3167 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3171 // Final check, device must be ready
3172 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3173 != ATA_CB_STAT_RDY
) {
3174 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3178 // Enable interrupts
3179 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3183 // ---------------------------------------------------------------------------
3184 // End of ATA/ATAPI Driver
3185 // ---------------------------------------------------------------------------
3187 // ---------------------------------------------------------------------------
3188 // Start of ATA/ATAPI generic functions
3189 // ---------------------------------------------------------------------------
3192 atapi_get_sense(device
, seg
, asc
, ascq
)
3199 memsetb(get_SS(),atacmd
,0,12);
3202 atacmd
[0]=ATA_CMD_REQUEST_SENSE
;
3203 atacmd
[4]=sizeof(buffer
);
3204 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 18L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3207 write_byte(seg
,asc
,buffer
[12]);
3208 write_byte(seg
,ascq
,buffer
[13]);
3214 atapi_is_ready(device
)
3221 Bit32u timeout
; //measured in ms
3225 Bit16u ebda_seg
= read_word(0x0040,0x000E);
3226 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
) {
3227 printf("not implemented for non-ATAPI device\n");
3231 BX_DEBUG_ATA("ata_detect_medium: begin\n");
3232 memsetb(get_SS(),packet
, 0, sizeof packet
);
3233 packet
[0] = 0x25; /* READ CAPACITY */
3235 /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
3236 * is reported by the device. If the device reports "IN PROGRESS",
3237 * 30 seconds is added. */
3241 while (time
< timeout
) {
3242 if (ata_cmd_packet(device
, sizeof(packet
), get_SS(), packet
, 0, 8L, ATA_DATA_IN
, get_SS(), buf
) == 0)
3245 if (atapi_get_sense(device
, get_SS(), &asc
, &ascq
) == 0) {
3246 if (asc
== 0x3a) { /* MEDIUM NOT PRESENT */
3247 BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
3251 if (asc
== 0x04 && ascq
== 0x01 && !in_progress
) {
3252 /* IN PROGRESS OF BECOMING READY */
3253 printf("Waiting for device to detect medium... ");
3254 /* Allow 30 seconds more */
3261 BX_DEBUG_ATA("read capacity failed\n");
3265 block_len
= (Bit32u
) buf
[4] << 24
3266 | (Bit32u
) buf
[5] << 16
3267 | (Bit32u
) buf
[6] << 8
3268 | (Bit32u
) buf
[7] << 0;
3269 BX_DEBUG_ATA("block_len=%u\n", block_len
);
3271 if (block_len
!= 2048 && block_len
!= 512)
3273 printf("Unsupported sector size %u\n", block_len
);
3276 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, block_len
);
3278 sectors
= (Bit32u
) buf
[0] << 24
3279 | (Bit32u
) buf
[1] << 16
3280 | (Bit32u
) buf
[2] << 8
3281 | (Bit32u
) buf
[3] << 0;
3283 BX_DEBUG_ATA("sectors=%u\n", sectors
);
3284 if (block_len
== 2048)
3285 sectors
<<= 2; /* # of sectors in 512-byte "soft" sector */
3286 if (sectors
!= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
))
3287 printf("%dMB medium detected\n", sectors
>>(20-9));
3288 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
3293 atapi_is_cdrom(device
)
3296 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3298 if (device
>= BX_MAX_ATA_DEVICES
)
3301 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3304 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3310 // ---------------------------------------------------------------------------
3311 // End of ATA/ATAPI generic functions
3312 // ---------------------------------------------------------------------------
3314 #endif // BX_USE_ATADRV
3316 #if BX_ELTORITO_BOOT
3318 // ---------------------------------------------------------------------------
3319 // Start of El-Torito boot functions
3320 // ---------------------------------------------------------------------------
3325 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3327 // the only important data is this one for now
3328 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3334 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3336 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3340 cdemu_emulated_drive()
3342 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3344 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3347 static char isotag
[6]="CD001";
3348 static char eltorito
[24]="EL TORITO SPECIFICATION";
3350 // Returns ah: emulated drive, al: error code
3355 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3356 Bit8u atacmd
[12], buffer
[2048];
3358 Bit16u boot_segment
, nbsectors
, i
, error
;
3361 // Find out the first cdrom
3362 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3363 if (atapi_is_cdrom(device
)) break;
3366 if(error
= atapi_is_ready(device
) != 0)
3367 BX_INFO("ata_is_ready returned %d\n",error
);
3370 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3372 // Read the Boot Record Volume Descriptor
3373 memsetb(get_SS(),atacmd
,0,12);
3374 atacmd
[0]=0x28; // READ command
3375 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3376 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3377 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3378 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3379 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3380 atacmd
[5]=(0x11 & 0x000000ff);
3381 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3385 if(buffer
[0]!=0)return 4;
3387 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3390 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3392 // ok, now we calculate the Boot catalog address
3393 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3395 // And we read the Boot Catalog
3396 memsetb(get_SS(),atacmd
,0,12);
3397 atacmd
[0]=0x28; // READ command
3398 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3399 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3400 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3401 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3402 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3403 atacmd
[5]=(lba
& 0x000000ff);
3404 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3408 if(buffer
[0x00]!=0x01)return 8; // Header
3409 if(buffer
[0x01]!=0x00)return 9; // Platform
3410 if(buffer
[0x1E]!=0x55)return 10; // key 1
3411 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3413 // Initial/Default Entry
3414 if(buffer
[0x20]!=0x88)return 11; // Bootable
3416 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3417 if(buffer
[0x21]==0){
3418 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3419 // Win2000 cd boot needs to know it booted from cd
3420 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3422 else if(buffer
[0x21]<4)
3423 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3425 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3427 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3428 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3430 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3431 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3433 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3434 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3436 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3437 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3439 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3440 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3442 // And we read the image in memory
3443 memsetb(get_SS(),atacmd
,0,12);
3444 atacmd
[0]=0x28; // READ command
3445 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3446 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3447 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3448 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3449 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3450 atacmd
[5]=(lba
& 0x000000ff);
3451 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3454 // Remember the media type
3455 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3456 case 0x01: // 1.2M floppy
3457 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3458 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3459 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3461 case 0x02: // 1.44M floppy
3462 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3463 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3464 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3466 case 0x03: // 2.88M floppy
3467 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3468 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3469 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3471 case 0x04: // Harddrive
3472 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3473 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3474 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3475 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3479 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3480 // Increase bios installed hardware number of devices
3481 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3482 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3484 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3488 // everything is ok, so from now on, the emulation is active
3489 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3490 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3492 // return the boot drive + no error
3493 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3496 // ---------------------------------------------------------------------------
3497 // End of El-Torito boot functions
3498 // ---------------------------------------------------------------------------
3499 #endif // BX_ELTORITO_BOOT
3502 int14_function(regs
, ds
, iret_addr
)
3503 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3504 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3505 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3507 Bit16u addr
,timer
,val16
;
3514 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3515 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3516 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3517 switch (regs
.u
.r8
.ah
) {
3519 outb(addr
+3, inb(addr
+3) | 0x80);
3520 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3524 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3525 outb(addr
, val16
& 0xFF);
3526 outb(addr
+1, val16
>> 8);
3528 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3529 regs
.u
.r8
.ah
= inb(addr
+5);
3530 regs
.u
.r8
.al
= inb(addr
+6);
3531 ClearCF(iret_addr
.flags
);
3534 timer
= read_word(0x0040, 0x006C);
3535 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3536 val16
= read_word(0x0040, 0x006C);
3537 if (val16
!= timer
) {
3542 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3543 regs
.u
.r8
.ah
= inb(addr
+5);
3544 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3545 ClearCF(iret_addr
.flags
);
3548 timer
= read_word(0x0040, 0x006C);
3549 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3550 val16
= read_word(0x0040, 0x006C);
3551 if (val16
!= timer
) {
3558 regs
.u
.r8
.al
= inb(addr
);
3560 regs
.u
.r8
.ah
= inb(addr
+5);
3562 ClearCF(iret_addr
.flags
);
3565 regs
.u
.r8
.ah
= inb(addr
+5);
3566 regs
.u
.r8
.al
= inb(addr
+6);
3567 ClearCF(iret_addr
.flags
);
3570 SetCF(iret_addr
.flags
); // Unsupported
3573 SetCF(iret_addr
.flags
); // Unsupported
3578 int15_function(regs
, ES
, DS
, FLAGS
)
3579 pusha_regs_t regs
; // REGS pushed via pusha
3580 Bit16u ES
, DS
, FLAGS
;
3582 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3583 bx_bool prev_a20_enable
;
3592 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3594 switch (regs
.u
.r8
.ah
) {
3595 case 0x24: /* A20 Control */
3596 switch (regs
.u
.r8
.al
) {
3608 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3618 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3620 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3626 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3630 /* keyboard intercept */
3632 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3639 case 0x52: // removable media eject
3641 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3645 if( regs
.u
.r8
.al
== 0 ) {
3646 // Set Interval requested.
3647 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3648 // Interval not already set.
3649 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3650 write_word( 0x40, 0x98, ES
); // Byte location, segment
3651 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3652 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3653 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3655 irqDisable
= inb( 0xA1 );
3656 outb( 0xA1, irqDisable
& 0xFE );
3657 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3658 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3660 // Interval already set.
3661 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3663 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3665 } else if( regs
.u
.r8
.al
== 1 ) {
3666 // Clear Interval requested
3667 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3669 bRegister
= inb_cmos( 0xB );
3670 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3672 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3674 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3683 # error "Int15 function 87h not supported on < 80386"
3685 // +++ should probably have descriptor checks
3686 // +++ should have exception handlers
3688 // turn off interrupts
3693 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3695 // 128K max of transfer on 386+ ???
3696 // source == destination ???
3698 // ES:SI points to descriptor table
3699 // offset use initially comments
3700 // ==============================================
3701 // 00..07 Unused zeros Null descriptor
3702 // 08..0f GDT zeros filled in by BIOS
3703 // 10..17 source ssssssss source of data
3704 // 18..1f dest dddddddd destination of data
3705 // 20..27 CS zeros filled in by BIOS
3706 // 28..2f SS zeros filled in by BIOS
3713 // check for access rights of source & dest here
3715 // Initialize GDT descriptor
3716 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3717 base23_16
= ES
>> 12;
3718 if (base15_00
< (ES
<<4))
3720 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3721 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3722 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3723 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3724 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3726 // Initialize CS descriptor
3727 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3728 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3729 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3730 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3731 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3733 // Initialize SS descriptor
3735 base15_00
= ss
<< 4;
3736 base23_16
= ss
>> 12;
3737 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3738 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3739 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3740 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3741 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3745 // Compile generates locals offset info relative to SP.
3746 // Get CX (word count) from stack.
3749 mov cx
, _int15_function
.CX
[bx
]
3751 // since we need to set SS:SP, save them to the BDA
3752 // for future restore
3762 lidt
[pmode_IDT_info
]
3763 ;; perhaps
do something with IDT here
3765 ;; set PE bit in CR0
3769 ;; far jump to flush CPU queue after transition to
protected mode
3770 JMP_AP(0x0020, protected_mode
)
3773 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3774 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3776 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3778 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3784 movsw
;; move CX words from DS
:SI to ES
:DI
3786 ;; make sure DS
and ES limits are
64KB
3791 ;; reset PG bit in CR0
???
3796 ;; far jump to flush CPU queue after transition to real mode
3797 JMP_AP(0xf000, real_mode
)
3800 ;; restore IDT to normal real
-mode defaults
3802 lidt
[rmode_IDT_info
]
3804 // restore SS:SP from the BDA
3812 set_enable_a20(prev_a20_enable
);
3814 // turn back on interrupts
3825 // Get the amount of extended memory (above 1M)
3827 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3830 regs
.u
.r8
.al
= inb_cmos(0x30);
3831 regs
.u
.r8
.ah
= inb_cmos(0x31);
3833 // According to Ralf Brown's interrupt the limit should be 15M,
3834 // but real machines mostly return max. 63M.
3835 if(regs
.u
.r16
.ax
> 0xffc0)
3836 regs
.u
.r16
.ax
= 0xffc0;
3843 /* Device busy interrupt. Called by Int 16h when no key available */
3847 /* Interrupt complete. Called by Int 16h when key becomes available */
3851 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3853 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3859 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3864 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3874 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3876 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3880 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3881 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3883 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3888 #if BX_USE_PS2_MOUSE
3890 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3891 pusha_regs_t regs
; // REGS pushed via pusha
3892 Bit16u ES
, DS
, FLAGS
;
3894 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3895 Bit8u mouse_flags_1
, mouse_flags_2
;
3896 Bit16u mouse_driver_seg
;
3897 Bit16u mouse_driver_offset
;
3898 Bit8u comm_byte
, prev_command_byte
;
3899 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3901 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3903 switch (regs
.u
.r8
.ah
) {
3905 // Return Codes status in AH
3906 // =========================
3908 // 01: invalid subfunction (AL > 7)
3909 // 02: invalid input value (out of allowable range)
3910 // 03: interface error
3911 // 04: resend command received from mouse controller,
3912 // device driver should attempt command again
3913 // 05: cannot enable mouse, since no far call has been installed
3914 // 80/86: mouse service not implemented
3916 switch (regs
.u
.r8
.al
) {
3917 case 0: // Disable/Enable Mouse
3918 BX_DEBUG_INT15("case 0:\n");
3919 switch (regs
.u
.r8
.bh
) {
3920 case 0: // Disable Mouse
3921 BX_DEBUG_INT15("case 0: disable mouse\n");
3922 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3923 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3925 ret
= get_mouse_data(&mouse_data1
);
3926 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3939 case 1: // Enable Mouse
3940 BX_DEBUG_INT15("case 1: enable mouse\n");
3941 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3942 if ( (mouse_flags_2
& 0x80) == 0 ) {
3943 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3945 regs
.u
.r8
.ah
= 5; // no far call installed
3948 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3949 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3951 ret
= get_mouse_data(&mouse_data1
);
3952 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3953 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3963 default: // invalid subfunction
3964 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3966 regs
.u
.r8
.ah
= 1; // invalid subfunction
3971 case 1: // Reset Mouse
3972 case 5: // Initialize Mouse
3973 BX_DEBUG_INT15("case 1 or 5:\n");
3974 if (regs
.u
.r8
.al
== 5) {
3975 if (regs
.u
.r8
.bh
!= 3) {
3977 regs
.u
.r8
.ah
= 0x02; // invalid input
3980 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3981 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3982 mouse_flags_1
= 0x00;
3983 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3984 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3987 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3988 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
3990 ret
= get_mouse_data(&mouse_data3
);
3991 // if no mouse attached, it will return RESEND
3992 if (mouse_data3
== 0xfe) {
3996 if (mouse_data3
!= 0xfa)
3997 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
3999 ret
= get_mouse_data(&mouse_data1
);
4001 ret
= get_mouse_data(&mouse_data2
);
4003 // turn IRQ12 and packet generation on
4004 enable_mouse_int_and_events();
4007 regs
.u
.r8
.bl
= mouse_data1
;
4008 regs
.u
.r8
.bh
= mouse_data2
;
4020 case 2: // Set Sample Rate
4021 BX_DEBUG_INT15("case 2:\n");
4022 switch (regs
.u
.r8
.bh
) {
4023 case 0: mouse_data1
= 10; break; // 10 reports/sec
4024 case 1: mouse_data1
= 20; break; // 20 reports/sec
4025 case 2: mouse_data1
= 40; break; // 40 reports/sec
4026 case 3: mouse_data1
= 60; break; // 60 reports/sec
4027 case 4: mouse_data1
= 80; break; // 80 reports/sec
4028 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
4029 case 6: mouse_data1
= 200; break; // 200 reports/sec
4030 default: mouse_data1
= 0;
4032 if (mouse_data1
> 0) {
4033 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
4035 ret
= get_mouse_data(&mouse_data2
);
4036 ret
= send_to_mouse_ctrl(mouse_data1
);
4037 ret
= get_mouse_data(&mouse_data2
);
4043 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4048 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4052 case 3: // Set Resolution
4053 BX_DEBUG_INT15("case 3:\n");
4055 // 0 = 25 dpi, 1 count per millimeter
4056 // 1 = 50 dpi, 2 counts per millimeter
4057 // 2 = 100 dpi, 4 counts per millimeter
4058 // 3 = 200 dpi, 8 counts per millimeter
4059 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4060 if (regs
.u
.r8
.bh
< 4) {
4061 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
4063 ret
= get_mouse_data(&mouse_data1
);
4064 if (mouse_data1
!= 0xfa)
4065 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4066 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
4067 ret
= get_mouse_data(&mouse_data1
);
4068 if (mouse_data1
!= 0xfa)
4069 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4075 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4080 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4082 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4085 case 4: // Get Device ID
4086 BX_DEBUG_INT15("case 4:\n");
4087 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4088 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
4090 ret
= get_mouse_data(&mouse_data1
);
4091 ret
= get_mouse_data(&mouse_data2
);
4094 regs
.u
.r8
.bh
= mouse_data2
;
4098 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4102 case 6: // Return Status & Set Scaling Factor...
4103 BX_DEBUG_INT15("case 6:\n");
4104 switch (regs
.u
.r8
.bh
) {
4105 case 0: // Return Status
4106 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4107 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4109 ret
= get_mouse_data(&mouse_data1
);
4110 if (mouse_data1
!= 0xfa)
4111 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4113 ret
= get_mouse_data(&mouse_data1
);
4115 ret
= get_mouse_data(&mouse_data2
);
4117 ret
= get_mouse_data(&mouse_data3
);
4121 regs
.u
.r8
.bl
= mouse_data1
;
4122 regs
.u
.r8
.cl
= mouse_data2
;
4123 regs
.u
.r8
.dl
= mouse_data3
;
4124 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4135 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4138 case 1: // Set Scaling Factor to 1:1
4139 case 2: // Set Scaling Factor to 2:1
4140 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4141 if (regs
.u
.r8
.bh
== 1) {
4142 ret
= send_to_mouse_ctrl(0xE6);
4144 ret
= send_to_mouse_ctrl(0xE7);
4147 get_mouse_data(&mouse_data1
);
4148 ret
= (mouse_data1
!= 0xFA);
4156 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4158 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4162 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4166 case 7: // Set Mouse Handler Address
4167 BX_DEBUG_INT15("case 7:\n");
4168 mouse_driver_seg
= ES
;
4169 mouse_driver_offset
= regs
.u
.r16
.bx
;
4170 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4171 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4172 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4173 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4174 /* remove handler */
4175 if ( (mouse_flags_2
& 0x80) != 0 ) {
4176 mouse_flags_2
&= ~0x80;
4177 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4181 /* install handler */
4182 mouse_flags_2
|= 0x80;
4184 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4190 BX_DEBUG_INT15("case default:\n");
4191 regs
.u
.r8
.ah
= 1; // invalid function
4197 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4198 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4200 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4207 void set_e820_range(ES
, DI
, start
, end
, type
)
4214 write_word(ES
, DI
, start
);
4215 write_word(ES
, DI
+2, start
>> 16);
4216 write_word(ES
, DI
+4, 0x00);
4217 write_word(ES
, DI
+6, 0x00);
4220 write_word(ES
, DI
+8, end
);
4221 write_word(ES
, DI
+10, end
>> 16);
4222 write_word(ES
, DI
+12, 0x0000);
4223 write_word(ES
, DI
+14, 0x0000);
4225 write_word(ES
, DI
+16, type
);
4226 write_word(ES
, DI
+18, 0x0);
4230 int15_function32(regs
, ES
, DS
, FLAGS
)
4231 pushad_regs_t regs
; // REGS pushed via pushad
4232 Bit16u ES
, DS
, FLAGS
;
4234 Bit32u extended_memory_size
=0; // 64bits long
4237 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4239 switch (regs
.u
.r8
.ah
) {
4241 // Wait for CX:DX microseconds. currently using the
4242 // refresh request port 0x61 bit4, toggling every 15usec
4250 ;; Get the count in eax
4253 mov ax
, _int15_function32
.CX
[bx
]
4256 mov ax
, _int15_function32
.DX
[bx
]
4258 ;; convert to numbers of
15usec ticks
4264 ;; wait
for ecx number of refresh requests
4285 switch(regs
.u
.r8
.al
)
4287 case 0x20: // coded by osmaker aka K.J.
4288 if(regs
.u
.r32
.edx
== 0x534D4150)
4290 extended_memory_size
= inb_cmos(0x35);
4291 extended_memory_size
<<= 8;
4292 extended_memory_size
|= inb_cmos(0x34);
4293 extended_memory_size
*= 64;
4294 // greater than EFF00000???
4295 if(extended_memory_size
> 0x3bc000) {
4296 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4298 extended_memory_size
*= 1024;
4299 extended_memory_size
+= (16L * 1024 * 1024);
4301 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4302 extended_memory_size
= inb_cmos(0x31);
4303 extended_memory_size
<<= 8;
4304 extended_memory_size
|= inb_cmos(0x30);
4305 extended_memory_size
*= 1024;
4308 switch(regs
.u
.r16
.bx
)
4311 set_e820_range(ES
, regs
.u
.r16
.di
,
4312 0x0000000L
, 0x0009fc00L
, 1);
4314 regs
.u
.r32
.eax
= 0x534D4150;
4315 regs
.u
.r32
.ecx
= 0x14;
4320 set_e820_range(ES
, regs
.u
.r16
.di
,
4321 0x0009fc00L
, 0x000a0000L
, 2);
4323 regs
.u
.r32
.eax
= 0x534D4150;
4324 regs
.u
.r32
.ecx
= 0x14;
4329 set_e820_range(ES
, regs
.u
.r16
.di
,
4330 0x000e8000L
, 0x00100000L
, 2);
4332 regs
.u
.r32
.eax
= 0x534D4150;
4333 regs
.u
.r32
.ecx
= 0x14;
4338 set_e820_range(ES
, regs
.u
.r16
.di
,
4340 extended_memory_size
- ACPI_DATA_SIZE
, 1);
4342 regs
.u
.r32
.eax
= 0x534D4150;
4343 regs
.u
.r32
.ecx
= 0x14;
4348 set_e820_range(ES
, regs
.u
.r16
.di
,
4349 extended_memory_size
- ACPI_DATA_SIZE
,
4350 extended_memory_size
, 3); // ACPI RAM
4352 regs
.u
.r32
.eax
= 0x534D4150;
4353 regs
.u
.r32
.ecx
= 0x14;
4358 /* 256KB BIOS area at the end of 4 GB */
4359 set_e820_range(ES
, regs
.u
.r16
.di
,
4360 0xfffc0000L
, 0x00000000L
, 2);
4362 regs
.u
.r32
.eax
= 0x534D4150;
4363 regs
.u
.r32
.ecx
= 0x14;
4366 default: /* AX=E820, DX=534D4150, BX unrecognized */
4367 goto int15_unimplemented
;
4371 // if DX != 0x534D4150)
4372 goto int15_unimplemented
;
4377 // do we have any reason to fail here ?
4380 // my real system sets ax and bx to 0
4381 // this is confirmed by Ralph Brown list
4382 // but syslinux v1.48 is known to behave
4383 // strangely if ax is set to 0
4384 // regs.u.r16.ax = 0;
4385 // regs.u.r16.bx = 0;
4387 // Get the amount of extended memory (above 1M)
4388 regs
.u
.r8
.cl
= inb_cmos(0x30);
4389 regs
.u
.r8
.ch
= inb_cmos(0x31);
4392 if(regs
.u
.r16
.cx
> 0x3c00)
4394 regs
.u
.r16
.cx
= 0x3c00;
4397 // Get the amount of extended memory above 16M in 64k blocs
4398 regs
.u
.r8
.dl
= inb_cmos(0x34);
4399 regs
.u
.r8
.dh
= inb_cmos(0x35);
4401 // Set configured memory equal to extended memory
4402 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4403 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4405 default: /* AH=0xE8?? but not implemented */
4406 goto int15_unimplemented
;
4409 int15_unimplemented
:
4410 // fall into the default
4412 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4413 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4415 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4421 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4422 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4424 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4425 Bit16u kbd_code
, max
;
4427 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4429 shift_flags
= read_byte(0x0040, 0x17);
4430 led_flags
= read_byte(0x0040, 0x97);
4431 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4436 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4437 if ((inb(0x60) == 0xfa)) {
4439 led_flags
|= ((shift_flags
>> 4) & 0x07);
4440 outb(0x60, led_flags
& 0x07);
4441 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4443 write_byte(0x0040, 0x97, led_flags
);
4451 case 0x00: /* read keyboard input */
4453 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4454 BX_PANIC("KBD: int16h: out of keyboard input\n");
4456 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4457 else if (ascii_code
== 0xE0) ascii_code
= 0;
4458 AX
= (scan_code
<< 8) | ascii_code
;
4461 case 0x01: /* check keyboard status */
4462 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4466 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4467 else if (ascii_code
== 0xE0) ascii_code
= 0;
4468 AX
= (scan_code
<< 8) | ascii_code
;
4472 case 0x02: /* get shift flag status */
4473 shift_flags
= read_byte(0x0040, 0x17);
4474 SET_AL(shift_flags
);
4477 case 0x05: /* store key-stroke into buffer */
4478 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4486 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4487 // bit Bochs Description
4489 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4490 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4491 // 4 1 INT 16/AH=0Ah supported
4492 // 3 0 INT 16/AX=0306h supported
4493 // 2 0 INT 16/AX=0305h supported
4494 // 1 0 INT 16/AX=0304h supported
4495 // 0 0 INT 16/AX=0300h supported
4500 case 0x0A: /* GET KEYBOARD ID */
4506 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4508 if ((inb(0x60) == 0xfa)) {
4511 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4514 kbd_code
|= (inb(0x60) << 8);
4516 } while (--count
>0);
4522 case 0x10: /* read MF-II keyboard input */
4524 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4525 BX_PANIC("KBD: int16h: out of keyboard input\n");
4527 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4528 AX
= (scan_code
<< 8) | ascii_code
;
4531 case 0x11: /* check MF-II keyboard status */
4532 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4536 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4537 AX
= (scan_code
<< 8) | ascii_code
;
4541 case 0x12: /* get extended keyboard status */
4542 shift_flags
= read_byte(0x0040, 0x17);
4543 SET_AL(shift_flags
);
4544 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4545 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4546 SET_AH(shift_flags
);
4547 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4550 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4551 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4554 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4555 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4559 if (GET_AL() == 0x08)
4560 SET_AH(0x02); // unsupported, aka normal keyboard
4563 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4568 dequeue_key(scan_code
, ascii_code
, incr
)
4573 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4578 buffer_start
= 0x001E;
4579 buffer_end
= 0x003E;
4581 buffer_start
= read_word(0x0040, 0x0080);
4582 buffer_end
= read_word(0x0040, 0x0082);
4585 buffer_head
= read_word(0x0040, 0x001a);
4586 buffer_tail
= read_word(0x0040, 0x001c);
4588 if (buffer_head
!= buffer_tail
) {
4590 acode
= read_byte(0x0040, buffer_head
);
4591 scode
= read_byte(0x0040, buffer_head
+1);
4592 write_byte(ss
, ascii_code
, acode
);
4593 write_byte(ss
, scan_code
, scode
);
4597 if (buffer_head
>= buffer_end
)
4598 buffer_head
= buffer_start
;
4599 write_word(0x0040, 0x001a, buffer_head
);
4608 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4611 inhibit_mouse_int_and_events()
4613 Bit8u command_byte
, prev_command_byte
;
4615 // Turn off IRQ generation and aux data line
4616 if ( inb(0x64) & 0x02 )
4617 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4618 outb(0x64, 0x20); // get command byte
4619 while ( (inb(0x64) & 0x01) != 0x01 );
4620 prev_command_byte
= inb(0x60);
4621 command_byte
= prev_command_byte
;
4622 //while ( (inb(0x64) & 0x02) );
4623 if ( inb(0x64) & 0x02 )
4624 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4625 command_byte
&= 0xfd; // turn off IRQ 12 generation
4626 command_byte
|= 0x20; // disable mouse serial clock line
4627 outb(0x64, 0x60); // write command byte
4628 outb(0x60, command_byte
);
4629 return(prev_command_byte
);
4633 enable_mouse_int_and_events()
4637 // Turn on IRQ generation and aux data line
4638 if ( inb(0x64) & 0x02 )
4639 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4640 outb(0x64, 0x20); // get command byte
4641 while ( (inb(0x64) & 0x01) != 0x01 );
4642 command_byte
= inb(0x60);
4643 //while ( (inb(0x64) & 0x02) );
4644 if ( inb(0x64) & 0x02 )
4645 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4646 command_byte
|= 0x02; // turn on IRQ 12 generation
4647 command_byte
&= 0xdf; // enable mouse serial clock line
4648 outb(0x64, 0x60); // write command byte
4649 outb(0x60, command_byte
);
4653 send_to_mouse_ctrl(sendbyte
)
4658 // wait for chance to write to ctrl
4659 if ( inb(0x64) & 0x02 )
4660 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4662 outb(0x60, sendbyte
);
4668 get_mouse_data(data
)
4674 while ( (inb(0x64) & 0x21) != 0x21 ) {
4677 response
= inb(0x60);
4680 write_byte(ss
, data
, response
);
4685 set_kbd_command_byte(command_byte
)
4688 if ( inb(0x64) & 0x02 )
4689 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4692 outb(0x64, 0x60); // write command byte
4693 outb(0x60, command_byte
);
4697 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4698 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4700 Bit8u scancode
, asciicode
, shift_flags
;
4701 Bit8u mf2_flags
, mf2_state
;
4704 // DS has been set to F000 before call
4708 scancode
= GET_AL();
4710 if (scancode
== 0) {
4711 BX_INFO("KBD: int09 handler: AL=0\n");
4716 shift_flags
= read_byte(0x0040, 0x17);
4717 mf2_flags
= read_byte(0x0040, 0x18);
4718 mf2_state
= read_byte(0x0040, 0x96);
4722 case 0x3a: /* Caps Lock press */
4723 shift_flags
^= 0x40;
4724 write_byte(0x0040, 0x17, shift_flags
);
4726 write_byte(0x0040, 0x18, mf2_flags
);
4728 case 0xba: /* Caps Lock release */
4730 write_byte(0x0040, 0x18, mf2_flags
);
4733 case 0x2a: /* L Shift press */
4734 shift_flags
|= 0x02;
4735 write_byte(0x0040, 0x17, shift_flags
);
4737 case 0xaa: /* L Shift release */
4738 shift_flags
&= ~0x02;
4739 write_byte(0x0040, 0x17, shift_flags
);
4742 case 0x36: /* R Shift press */
4743 shift_flags
|= 0x01;
4744 write_byte(0x0040, 0x17, shift_flags
);
4746 case 0xb6: /* R Shift release */
4747 shift_flags
&= ~0x01;
4748 write_byte(0x0040, 0x17, shift_flags
);
4751 case 0x1d: /* Ctrl press */
4752 if ((mf2_state
& 0x01) == 0) {
4753 shift_flags
|= 0x04;
4754 write_byte(0x0040, 0x17, shift_flags
);
4755 if (mf2_state
& 0x02) {
4757 write_byte(0x0040, 0x96, mf2_state
);
4760 write_byte(0x0040, 0x18, mf2_flags
);
4764 case 0x9d: /* Ctrl release */
4765 if ((mf2_state
& 0x01) == 0) {
4766 shift_flags
&= ~0x04;
4767 write_byte(0x0040, 0x17, shift_flags
);
4768 if (mf2_state
& 0x02) {
4770 write_byte(0x0040, 0x96, mf2_state
);
4773 write_byte(0x0040, 0x18, mf2_flags
);
4778 case 0x38: /* Alt press */
4779 shift_flags
|= 0x08;
4780 write_byte(0x0040, 0x17, shift_flags
);
4781 if (mf2_state
& 0x02) {
4783 write_byte(0x0040, 0x96, mf2_state
);
4786 write_byte(0x0040, 0x18, mf2_flags
);
4789 case 0xb8: /* Alt release */
4790 shift_flags
&= ~0x08;
4791 write_byte(0x0040, 0x17, shift_flags
);
4792 if (mf2_state
& 0x02) {
4794 write_byte(0x0040, 0x96, mf2_state
);
4797 write_byte(0x0040, 0x18, mf2_flags
);
4801 case 0x45: /* Num Lock press */
4802 if ((mf2_state
& 0x03) == 0) {
4804 write_byte(0x0040, 0x18, mf2_flags
);
4805 shift_flags
^= 0x20;
4806 write_byte(0x0040, 0x17, shift_flags
);
4809 case 0xc5: /* Num Lock release */
4810 if ((mf2_state
& 0x03) == 0) {
4812 write_byte(0x0040, 0x18, mf2_flags
);
4816 case 0x46: /* Scroll Lock press */
4818 write_byte(0x0040, 0x18, mf2_flags
);
4819 shift_flags
^= 0x10;
4820 write_byte(0x0040, 0x17, shift_flags
);
4823 case 0xc6: /* Scroll Lock release */
4825 write_byte(0x0040, 0x18, mf2_flags
);
4829 if (scancode
& 0x80) {
4830 break; /* toss key releases ... */
4832 if (scancode
> MAX_SCAN_CODE
) {
4833 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4836 if (shift_flags
& 0x08) { /* ALT */
4837 asciicode
= scan_to_scanascii
[scancode
].alt
;
4838 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4839 } else if (shift_flags
& 0x04) { /* CONTROL */
4840 asciicode
= scan_to_scanascii
[scancode
].control
;
4841 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4842 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
4843 /* extended keys handling */
4845 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4846 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4847 /* check if lock state should be ignored
4848 * because a SHIFT key are pressed */
4850 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4851 asciicode
= scan_to_scanascii
[scancode
].normal
;
4852 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4854 asciicode
= scan_to_scanascii
[scancode
].shift
;
4855 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4858 /* check if lock is on */
4859 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4860 asciicode
= scan_to_scanascii
[scancode
].shift
;
4861 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4863 asciicode
= scan_to_scanascii
[scancode
].normal
;
4864 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4867 if (scancode
==0 && asciicode
==0) {
4868 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4870 enqueue_key(scancode
, asciicode
);
4873 if ((scancode
& 0x7f) != 0x1d) {
4877 write_byte(0x0040, 0x96, mf2_state
);
4881 enqueue_key(scan_code
, ascii_code
)
4882 Bit8u scan_code
, ascii_code
;
4884 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4887 buffer_start
= 0x001E;
4888 buffer_end
= 0x003E;
4890 buffer_start
= read_word(0x0040, 0x0080);
4891 buffer_end
= read_word(0x0040, 0x0082);
4894 buffer_head
= read_word(0x0040, 0x001A);
4895 buffer_tail
= read_word(0x0040, 0x001C);
4897 temp_tail
= buffer_tail
;
4899 if (buffer_tail
>= buffer_end
)
4900 buffer_tail
= buffer_start
;
4902 if (buffer_tail
== buffer_head
) {
4906 write_byte(0x0040, temp_tail
, ascii_code
);
4907 write_byte(0x0040, temp_tail
+1, scan_code
);
4908 write_word(0x0040, 0x001C, buffer_tail
);
4914 int74_function(make_farcall
, Z
, Y
, X
, status
)
4915 Bit16u make_farcall
, Z
, Y
, X
, status
;
4917 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4918 Bit8u in_byte
, index
, package_count
;
4919 Bit8u mouse_flags_1
, mouse_flags_2
;
4921 BX_DEBUG_INT74("entering int74_function\n");
4924 in_byte
= inb(0x64);
4925 if ( (in_byte
& 0x21) != 0x21 ) {
4928 in_byte
= inb(0x60);
4929 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4931 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4932 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4934 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4938 package_count
= mouse_flags_2
& 0x07;
4939 index
= mouse_flags_1
& 0x07;
4940 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4942 if ( (index
+1) >= package_count
) {
4943 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4944 status
= read_byte(ebda_seg
, 0x0028 + 0);
4945 X
= read_byte(ebda_seg
, 0x0028 + 1);
4946 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4949 // check if far call handler installed
4950 if (mouse_flags_2
& 0x80)
4956 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4959 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4964 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4965 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4968 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4969 Bit16u cylinder
, head
, sector
;
4970 Bit16u segment
, offset
;
4971 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4973 Bit8u device
, status
;
4975 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4977 write_byte(0x0040, 0x008e, 0); // clear completion flag
4979 // basic check : device has to be defined
4980 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4981 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4985 // Get the ata channel
4986 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
4988 // basic check : device has to be valid
4989 if (device
>= BX_MAX_ATA_DEVICES
) {
4990 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4996 case 0x00: /* disk controller reset */
5001 case 0x01: /* read disk status */
5002 status
= read_byte(0x0040, 0x0074);
5004 SET_DISK_RET_STATUS(0);
5005 /* set CF if error status read */
5006 if (status
) goto int13_fail_nostatus
;
5007 else goto int13_success_noah
;
5010 case 0x02: // read disk sectors
5011 case 0x03: // write disk sectors
5012 case 0x04: // verify disk sectors
5015 cylinder
= GET_CH();
5016 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5017 sector
= (GET_CL() & 0x3f);
5023 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
5024 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5028 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5029 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5030 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5032 // sanity check on cyl heads, sec
5033 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
5034 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
5039 if ( GET_AH() == 0x04 ) goto int13_success
;
5041 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5042 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5044 // if needed, translate lchs to lba, and execute command
5045 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
5046 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
5047 sector
= 0; // this forces the command to be lba
5050 if ( GET_AH() == 0x02 )
5051 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5053 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
5055 // Set nb of sector transferred
5056 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
5059 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5061 goto int13_fail_noah
;
5067 case 0x05: /* format disk track */
5068 BX_INFO("format disk track called\n");
5073 case 0x08: /* read disk drive parameters */
5075 // Get logical geometry from table
5076 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5077 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5078 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5079 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5081 nlc
= nlc
- 2; /* 0 based , last sector not used */
5084 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5086 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5088 // FIXME should set ES & DI
5093 case 0x10: /* check drive ready */
5094 // should look at 40:8E also???
5096 // Read the status from controller
5097 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5098 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5103 goto int13_fail_noah
;
5107 case 0x15: /* read disk drive size */
5109 // Get logical geometry from table
5110 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5111 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5112 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5114 // Compute sector count seen by int13
5115 lba
= (Bit32u
)(nlc
- 1) * (Bit32u
)nlh
* (Bit32u
)nlspt
;
5119 SET_AH(3); // hard disk accessible
5120 goto int13_success_noah
;
5123 case 0x41: // IBM/MS installation check
5124 BX
=0xaa55; // install check
5125 SET_AH(0x30); // EDD 3.0
5126 CX
=0x0007; // ext disk access and edd, removable supported
5127 goto int13_success_noah
;
5130 case 0x42: // IBM/MS extended read
5131 case 0x43: // IBM/MS extended write
5132 case 0x44: // IBM/MS verify
5133 case 0x47: // IBM/MS extended seek
5135 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5136 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5137 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5139 // Can't use 64 bits lba
5140 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5142 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5146 // Get 32 bits lba and check
5147 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5148 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
5149 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5153 // If verify or seek
5154 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5157 // Execute the command
5158 if ( GET_AH() == 0x42 )
5159 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5161 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
5163 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5164 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5167 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5169 goto int13_fail_noah
;
5175 case 0x45: // IBM/MS lock/unlock drive
5176 case 0x49: // IBM/MS extended media change
5177 goto int13_success
; // Always success for HD
5180 case 0x46: // IBM/MS eject media
5181 SET_AH(0xb2); // Volume Not Removable
5182 goto int13_fail_noah
; // Always fail for HD
5185 case 0x48: // IBM/MS get drive parameters
5186 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5188 // Buffer is too small
5196 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5197 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5198 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5199 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
5200 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5202 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5203 if ((lba
/npspt
)/nph
> 0x3fff)
5205 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x00); // geometry is invalid
5206 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0x3fff);
5210 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5211 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5213 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5214 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5215 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
5216 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
5217 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5222 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5223 Bit16u iobase1
, iobase2
, options
;
5225 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5227 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5228 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5231 channel
= device
/ 2;
5232 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5233 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5234 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5235 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5236 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5238 options
= (translation
==ATA_TRANSLATION_NONE
?0:1)<<3; // chs translation
5239 options
|= (1<<4); // lba translation
5240 options
|= (mode
==ATA_MODE_PIO32
?1:0)<<7;
5241 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0)<<9;
5242 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0)<<9;
5244 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5245 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5246 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5247 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5248 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5249 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5250 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5251 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5252 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5253 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5255 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5257 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x10);
5260 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5261 checksum
= ~checksum
;
5262 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5267 Bit8u channel
, iface
, checksum
, i
;
5270 channel
= device
/ 2;
5271 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5272 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5274 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5275 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5276 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5277 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5278 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5280 if (iface
==ATA_IFACE_ISA
) {
5281 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5282 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5283 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5284 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5289 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5290 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5291 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5292 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5294 if (iface
==ATA_IFACE_ISA
) {
5295 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5296 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5297 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5302 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5303 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5304 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5305 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5308 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5309 checksum
= ~checksum
;
5310 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5316 case 0x4e: // // IBM/MS set hardware configuration
5317 // DMA, prefetch, PIO maximum not supported
5330 case 0x09: /* initialize drive parameters */
5331 case 0x0c: /* seek to specified cylinder */
5332 case 0x0d: /* alternate disk reset */
5333 case 0x11: /* recalibrate */
5334 case 0x14: /* controller internal diagnostic */
5335 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5339 case 0x0a: /* read disk sectors with ECC */
5340 case 0x0b: /* write disk sectors with ECC */
5341 case 0x18: // set media type for format
5342 case 0x50: // IBM/MS send packet command
5344 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5350 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5352 SET_DISK_RET_STATUS(GET_AH());
5353 int13_fail_nostatus
:
5354 SET_CF(); // error occurred
5358 SET_AH(0x00); // no error
5360 SET_DISK_RET_STATUS(0x00);
5361 CLEAR_CF(); // no error
5365 // ---------------------------------------------------------------------------
5366 // Start of int13 for cdrom
5367 // ---------------------------------------------------------------------------
5370 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5371 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5373 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5374 Bit8u device
, status
, locks
;
5377 Bit16u count
, segment
, offset
, i
, size
;
5379 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5381 SET_DISK_RET_STATUS(0x00);
5383 /* basic check : device should be 0xE0+ */
5384 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5385 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5389 // Get the ata channel
5390 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5392 /* basic check : device has to be valid */
5393 if (device
>= BX_MAX_ATA_DEVICES
) {
5394 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5400 // all those functions return SUCCESS
5401 case 0x00: /* disk controller reset */
5402 case 0x09: /* initialize drive parameters */
5403 case 0x0c: /* seek to specified cylinder */
5404 case 0x0d: /* alternate disk reset */
5405 case 0x10: /* check drive ready */
5406 case 0x11: /* recalibrate */
5407 case 0x14: /* controller internal diagnostic */
5408 case 0x16: /* detect disk change */
5412 // all those functions return disk write-protected
5413 case 0x03: /* write disk sectors */
5414 case 0x05: /* format disk track */
5415 case 0x43: // IBM/MS extended write
5417 goto int13_fail_noah
;
5420 case 0x01: /* read disk status */
5421 status
= read_byte(0x0040, 0x0074);
5423 SET_DISK_RET_STATUS(0);
5425 /* set CF if error status read */
5426 if (status
) goto int13_fail_nostatus
;
5427 else goto int13_success_noah
;
5430 case 0x15: /* read disk drive size */
5432 goto int13_fail_noah
;
5435 case 0x41: // IBM/MS installation check
5436 BX
=0xaa55; // install check
5437 SET_AH(0x30); // EDD 2.1
5438 CX
=0x0007; // ext disk access, removable and edd
5439 goto int13_success_noah
;
5442 case 0x42: // IBM/MS extended read
5443 case 0x44: // IBM/MS verify sectors
5444 case 0x47: // IBM/MS extended seek
5446 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5447 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5448 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5450 // Can't use 64 bits lba
5451 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5453 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5458 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5460 // If verify or seek
5461 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5464 memsetb(get_SS(),atacmd
,0,12);
5465 atacmd
[0]=0x28; // READ command
5466 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5467 atacmd
[8]=(count
& 0x00ff); // Sectors
5468 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5469 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5470 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5471 atacmd
[5]=(lba
& 0x000000ff);
5472 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5474 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5475 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5478 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5480 goto int13_fail_noah
;
5486 case 0x45: // IBM/MS lock/unlock drive
5487 if (GET_AL() > 2) goto int13_fail
;
5489 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5493 if (locks
== 0xff) {
5496 goto int13_fail_noah
;
5498 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5502 if (locks
== 0x00) {
5505 goto int13_fail_noah
;
5507 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5508 SET_AL(locks
==0?0:1);
5511 SET_AL(locks
==0?0:1);
5517 case 0x46: // IBM/MS eject media
5518 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5521 SET_AH(0xb1); // media locked
5522 goto int13_fail_noah
;
5524 // FIXME should handle 0x31 no media in device
5525 // FIXME should handle 0xb5 valid request failed
5527 // Call removable media eject
5534 mov _int13_cdrom
.status
+ 2[bp
], ah
5535 jnc int13_cdrom_rme_end
5536 mov _int13_cdrom
.status
, #1
5537 int13_cdrom_rme_end
:
5542 SET_AH(0xb1); // media locked
5543 goto int13_fail_noah
;
5549 case 0x48: // IBM/MS get drive parameters
5550 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5552 // Buffer is too small
5558 Bit16u cylinders
, heads
, spt
, blksize
;
5560 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5562 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5563 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5564 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5565 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5566 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5567 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5568 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5569 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5574 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5575 Bit16u iobase1
, iobase2
, options
;
5577 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5579 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5580 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5583 channel
= device
/ 2;
5584 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5585 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5586 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5587 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5589 // FIXME atapi device
5590 options
= (1<<4); // lba translation
5591 options
|= (1<<5); // removable device
5592 options
|= (1<<6); // atapi device
5593 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5595 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5596 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5597 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5598 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5599 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5600 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5601 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5602 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5603 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5604 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5605 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5608 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5609 checksum
= ~checksum
;
5610 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5615 Bit8u channel
, iface
, checksum
, i
;
5618 channel
= device
/ 2;
5619 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5620 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5622 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5623 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5624 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5625 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5626 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5628 if (iface
==ATA_IFACE_ISA
) {
5629 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5630 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5631 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5632 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5637 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5638 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5639 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5640 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5642 if (iface
==ATA_IFACE_ISA
) {
5643 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5644 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5645 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5650 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5651 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5652 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5653 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5656 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5657 checksum
= ~checksum
;
5658 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5664 case 0x49: // IBM/MS extended media change
5665 // always send changed ??
5667 goto int13_fail_nostatus
;
5670 case 0x4e: // // IBM/MS set hardware configuration
5671 // DMA, prefetch, PIO maximum not supported
5684 // all those functions return unimplemented
5685 case 0x02: /* read sectors */
5686 case 0x04: /* verify sectors */
5687 case 0x08: /* read disk drive parameters */
5688 case 0x0a: /* read disk sectors with ECC */
5689 case 0x0b: /* write disk sectors with ECC */
5690 case 0x18: /* set media type for format */
5691 case 0x50: // ? - send packet command
5693 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5699 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5701 SET_DISK_RET_STATUS(GET_AH());
5702 int13_fail_nostatus
:
5703 SET_CF(); // error occurred
5707 SET_AH(0x00); // no error
5709 SET_DISK_RET_STATUS(0x00);
5710 CLEAR_CF(); // no error
5714 // ---------------------------------------------------------------------------
5715 // End of int13 for cdrom
5716 // ---------------------------------------------------------------------------
5718 #if BX_ELTORITO_BOOT
5719 // ---------------------------------------------------------------------------
5720 // Start of int13 for eltorito functions
5721 // ---------------------------------------------------------------------------
5724 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5725 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5727 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5729 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5730 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5734 // FIXME ElTorito Various. Should be implemented
5735 case 0x4a: // ElTorito - Initiate disk emu
5736 case 0x4c: // ElTorito - Initiate disk emu and boot
5737 case 0x4d: // ElTorito - Return Boot catalog
5738 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5742 case 0x4b: // ElTorito - Terminate disk emu
5743 // FIXME ElTorito Hardcoded
5744 write_byte(DS
,SI
+0x00,0x13);
5745 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5746 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5747 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5748 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5749 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5750 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5751 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5752 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5753 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5754 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5755 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5757 // If we have to terminate emulation
5758 if(GET_AL() == 0x00) {
5759 // FIXME ElTorito Various. Should be handled accordingly to spec
5760 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5767 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5773 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5774 SET_DISK_RET_STATUS(GET_AH());
5775 SET_CF(); // error occurred
5779 SET_AH(0x00); // no error
5780 SET_DISK_RET_STATUS(0x00);
5781 CLEAR_CF(); // no error
5785 // ---------------------------------------------------------------------------
5786 // End of int13 for eltorito functions
5787 // ---------------------------------------------------------------------------
5789 // ---------------------------------------------------------------------------
5790 // Start of int13 when emulating a device from the cd
5791 // ---------------------------------------------------------------------------
5794 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5795 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5797 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5798 Bit8u device
, status
;
5799 Bit16u vheads
, vspt
, vcylinders
;
5800 Bit16u head
, sector
, cylinder
, nbsectors
;
5801 Bit32u vlba
, ilba
, slba
, elba
;
5802 Bit16u before
, segment
, offset
;
5805 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5807 /* at this point, we are emulating a floppy/harddisk */
5809 // Recompute the device number
5810 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5811 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5813 SET_DISK_RET_STATUS(0x00);
5815 /* basic checks : emulation should be active, dl should equal the emulated drive */
5816 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5817 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5818 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5824 // all those functions return SUCCESS
5825 case 0x00: /* disk controller reset */
5826 case 0x09: /* initialize drive parameters */
5827 case 0x0c: /* seek to specified cylinder */
5828 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5829 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5830 case 0x11: /* recalibrate */
5831 case 0x14: /* controller internal diagnostic */
5832 case 0x16: /* detect disk change */
5836 // all those functions return disk write-protected
5837 case 0x03: /* write disk sectors */
5838 case 0x05: /* format disk track */
5840 goto int13_fail_noah
;
5843 case 0x01: /* read disk status */
5844 status
=read_byte(0x0040, 0x0074);
5846 SET_DISK_RET_STATUS(0);
5848 /* set CF if error status read */
5849 if (status
) goto int13_fail_nostatus
;
5850 else goto int13_success_noah
;
5853 case 0x02: // read disk sectors
5854 case 0x04: // verify disk sectors
5855 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5856 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5857 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5859 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5861 sector
= GET_CL() & 0x003f;
5862 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5864 nbsectors
= GET_AL();
5868 // no sector to read ?
5869 if(nbsectors
==0) goto int13_success
;
5871 // sanity checks sco openserver needs this!
5873 || (cylinder
>= vcylinders
)
5874 || (head
>= vheads
)) {
5878 // After controls, verify do nothing
5879 if (GET_AH() == 0x04) goto int13_success
;
5881 segment
= ES
+(BX
/ 16);
5884 // calculate the virtual lba inside the image
5885 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5887 // In advance so we don't loose the count
5891 slba
= (Bit32u
)vlba
/4;
5892 before
= (Bit16u
)vlba
%4;
5895 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5897 memsetb(get_SS(),atacmd
,0,12);
5898 atacmd
[0]=0x28; // READ command
5899 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5900 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5901 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5902 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5903 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5904 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5905 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5906 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5909 goto int13_fail_noah
;
5915 case 0x08: /* read disk drive parameters */
5916 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5917 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5918 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5922 SET_CH( vcylinders
& 0xff );
5923 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5925 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5926 // FIXME ElTorito Harddisk. should send the HD count
5928 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5929 case 0x01: SET_BL( 0x02 ); break;
5930 case 0x02: SET_BL( 0x04 ); break;
5931 case 0x03: SET_BL( 0x06 ); break;
5937 mov ax
, #diskette_param_table2
5938 mov _int13_cdemu
.DI
+2[bp
], ax
5939 mov _int13_cdemu
.ES
+2[bp
], cs
5945 case 0x15: /* read disk drive size */
5946 // FIXME ElTorito Harddisk. What geometry to send ?
5948 goto int13_success_noah
;
5951 // all those functions return unimplemented
5952 case 0x0a: /* read disk sectors with ECC */
5953 case 0x0b: /* write disk sectors with ECC */
5954 case 0x18: /* set media type for format */
5955 case 0x41: // IBM/MS installation check
5956 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5957 case 0x42: // IBM/MS extended read
5958 case 0x43: // IBM/MS extended write
5959 case 0x44: // IBM/MS verify sectors
5960 case 0x45: // IBM/MS lock/unlock drive
5961 case 0x46: // IBM/MS eject media
5962 case 0x47: // IBM/MS extended seek
5963 case 0x48: // IBM/MS get drive parameters
5964 case 0x49: // IBM/MS extended media change
5965 case 0x4e: // ? - set hardware configuration
5966 case 0x50: // ? - send packet command
5968 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5974 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5976 SET_DISK_RET_STATUS(GET_AH());
5977 int13_fail_nostatus
:
5978 SET_CF(); // error occurred
5982 SET_AH(0x00); // no error
5984 SET_DISK_RET_STATUS(0x00);
5985 CLEAR_CF(); // no error
5989 // ---------------------------------------------------------------------------
5990 // End of int13 when emulating a device from the cd
5991 // ---------------------------------------------------------------------------
5993 #endif // BX_ELTORITO_BOOT
5995 #else //BX_USE_ATADRV
5998 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
6013 mov ax
,4[bp
] // cylinder
6015 mov bl
,6[bp
] // hd_heads
6018 mov bl
,8[bp
] // head
6020 mov bl
,10[bp
] // hd_sectors
6022 mov bl
,12[bp
] // sector
6051 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6052 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6054 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
6058 Bit16u max_cylinder
, cylinder
, total_sectors
;
6059 Bit16u hd_cylinders
;
6060 Bit8u hd_heads
, hd_sectors
;
6067 Bit16u count
, segment
, offset
;
6071 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6073 write_byte(0x0040, 0x008e, 0); // clear completion flag
6075 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6077 /* check how many disks first (cmos reg 0x12), return an error if
6078 drive not present */
6079 drive_map
= inb_cmos(0x12);
6080 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6081 (((drive_map
& 0x0f)==0) ? 0 : 2);
6082 n_drives
= (drive_map
==0) ? 0 :
6083 ((drive_map
==3) ? 2 : 1);
6085 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6087 SET_DISK_RET_STATUS(0x01);
6088 SET_CF(); /* error occurred */
6094 case 0x00: /* disk controller reset */
6095 BX_DEBUG_INT13_HD("int13_f00\n");
6098 SET_DISK_RET_STATUS(0);
6099 set_diskette_ret_status(0);
6100 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6101 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6102 CLEAR_CF(); /* successful */
6106 case 0x01: /* read disk status */
6107 BX_DEBUG_INT13_HD("int13_f01\n");
6108 status
= read_byte(0x0040, 0x0074);
6110 SET_DISK_RET_STATUS(0);
6111 /* set CF if error status read */
6112 if (status
) SET_CF();
6117 case 0x04: // verify disk sectors
6118 case 0x02: // read disk sectors
6120 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6122 num_sectors
= GET_AL();
6123 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6124 sector
= (GET_CL() & 0x3f);
6128 if (hd_cylinders
> 1024) {
6129 if (hd_cylinders
<= 2048) {
6132 else if (hd_cylinders
<= 4096) {
6135 else if (hd_cylinders
<= 8192) {
6138 else { // hd_cylinders <= 16384
6142 ax
= head
/ hd_heads
;
6143 cyl_mod
= ax
& 0xff;
6145 cylinder
|= cyl_mod
;
6148 if ( (cylinder
>= hd_cylinders
) ||
6149 (sector
> hd_sectors
) ||
6150 (head
>= hd_heads
) ) {
6152 SET_DISK_RET_STATUS(1);
6153 SET_CF(); /* error occurred */
6157 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6158 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6161 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6163 if ( GET_AH() == 0x04 ) {
6165 SET_DISK_RET_STATUS(0);
6170 status
= inb(0x1f7);
6171 if (status
& 0x80) {
6172 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6174 outb(0x01f2, num_sectors
);
6175 /* activate LBA? (tomv) */
6176 if (hd_heads
> 16) {
6177 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6178 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6181 outb(0x01f3, sector
);
6182 outb(0x01f4, cylinder
& 0x00ff);
6183 outb(0x01f5, cylinder
>> 8);
6184 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6189 status
= inb(0x1f7);
6190 if ( !(status
& 0x80) ) break;
6193 if (status
& 0x01) {
6194 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6195 } else if ( !(status
& 0x08) ) {
6196 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6197 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6204 sti
;; enable higher priority interrupts
6209 ;; store temp bx in real DI
register
6212 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6215 ;; adjust
if there will be an overrun
6217 jbe i13_f02_no_adjust
6219 sub di
, #0x0200 ; sub 512 bytes from offset
6221 add ax
, #0x0020 ; add 512 to segment
6225 mov cx
, #0x0100 ;; counter (256 words = 512b)
6226 mov dx
, #0x01f0 ;; AT data read port
6229 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6232 ;; store real DI
register back to temp bx
6235 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6241 if (num_sectors
== 0) {
6242 status
= inb(0x1f7);
6243 if ( (status
& 0xc9) != 0x40 )
6244 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6248 status
= inb(0x1f7);
6249 if ( (status
& 0xc9) != 0x48 )
6250 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6256 SET_DISK_RET_STATUS(0);
6257 SET_AL(sector_count
);
6258 CLEAR_CF(); /* successful */
6263 case 0x03: /* write disk sectors */
6264 BX_DEBUG_INT13_HD("int13_f03\n");
6265 drive
= GET_ELDL ();
6266 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6268 num_sectors
= GET_AL();
6269 cylinder
= GET_CH();
6270 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6271 sector
= (GET_CL() & 0x3f);
6274 if (hd_cylinders
> 1024) {
6275 if (hd_cylinders
<= 2048) {
6278 else if (hd_cylinders
<= 4096) {
6281 else if (hd_cylinders
<= 8192) {
6284 else { // hd_cylinders <= 16384
6288 ax
= head
/ hd_heads
;
6289 cyl_mod
= ax
& 0xff;
6291 cylinder
|= cyl_mod
;
6294 if ( (cylinder
>= hd_cylinders
) ||
6295 (sector
> hd_sectors
) ||
6296 (head
>= hd_heads
) ) {
6298 SET_DISK_RET_STATUS(1);
6299 SET_CF(); /* error occurred */
6303 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6304 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6307 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6309 status
= inb(0x1f7);
6310 if (status
& 0x80) {
6311 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6313 // should check for Drive Ready Bit also in status reg
6314 outb(0x01f2, num_sectors
);
6316 /* activate LBA? (tomv) */
6317 if (hd_heads
> 16) {
6318 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6319 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6322 outb(0x01f3, sector
);
6323 outb(0x01f4, cylinder
& 0x00ff);
6324 outb(0x01f5, cylinder
>> 8);
6325 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6329 // wait for busy bit to turn off after seeking
6331 status
= inb(0x1f7);
6332 if ( !(status
& 0x80) ) break;
6335 if ( !(status
& 0x08) ) {
6336 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6337 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6344 sti
;; enable higher priority interrupts
6349 ;; store temp bx in real SI
register
6352 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6355 ;; adjust
if there will be an overrun
6357 jbe i13_f03_no_adjust
6359 sub si
, #0x0200 ; sub 512 bytes from offset
6361 add ax
, #0x0020 ; add 512 to segment
6365 mov cx
, #0x0100 ;; counter (256 words = 512b)
6366 mov dx
, #0x01f0 ;; AT data read port
6370 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6372 ;; store real SI
register back to temp bx
6375 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6381 if (num_sectors
== 0) {
6382 status
= inb(0x1f7);
6383 if ( (status
& 0xe9) != 0x40 )
6384 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6388 status
= inb(0x1f7);
6389 if ( (status
& 0xc9) != 0x48 )
6390 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6396 SET_DISK_RET_STATUS(0);
6397 SET_AL(sector_count
);
6398 CLEAR_CF(); /* successful */
6402 case 0x05: /* format disk track */
6403 BX_DEBUG_INT13_HD("int13_f05\n");
6404 BX_PANIC("format disk track called\n");
6407 SET_DISK_RET_STATUS(0);
6408 CLEAR_CF(); /* successful */
6412 case 0x08: /* read disk drive parameters */
6413 BX_DEBUG_INT13_HD("int13_f08\n");
6415 drive
= GET_ELDL ();
6416 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6420 if (hd_cylinders
<= 1024) {
6421 // hd_cylinders >>= 0;
6424 else if (hd_cylinders
<= 2048) {
6428 else if (hd_cylinders
<= 4096) {
6432 else if (hd_cylinders
<= 8192) {
6436 else { // hd_cylinders <= 16384
6441 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6443 SET_CH(max_cylinder
& 0xff);
6444 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6445 SET_DH(hd_heads
- 1);
6446 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6448 SET_DISK_RET_STATUS(0);
6449 CLEAR_CF(); /* successful */
6454 case 0x09: /* initialize drive parameters */
6455 BX_DEBUG_INT13_HD("int13_f09\n");
6457 SET_DISK_RET_STATUS(0);
6458 CLEAR_CF(); /* successful */
6462 case 0x0a: /* read disk sectors with ECC */
6463 BX_DEBUG_INT13_HD("int13_f0a\n");
6464 case 0x0b: /* write disk sectors with ECC */
6465 BX_DEBUG_INT13_HD("int13_f0b\n");
6466 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6470 case 0x0c: /* seek to specified cylinder */
6471 BX_DEBUG_INT13_HD("int13_f0c\n");
6472 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6474 SET_DISK_RET_STATUS(0);
6475 CLEAR_CF(); /* successful */
6479 case 0x0d: /* alternate disk reset */
6480 BX_DEBUG_INT13_HD("int13_f0d\n");
6482 SET_DISK_RET_STATUS(0);
6483 CLEAR_CF(); /* successful */
6487 case 0x10: /* check drive ready */
6488 BX_DEBUG_INT13_HD("int13_f10\n");
6490 //SET_DISK_RET_STATUS(0);
6491 //CLEAR_CF(); /* successful */
6495 // should look at 40:8E also???
6496 status
= inb(0x01f7);
6497 if ( (status
& 0xc0) == 0x40 ) {
6499 SET_DISK_RET_STATUS(0);
6500 CLEAR_CF(); // drive ready
6505 SET_DISK_RET_STATUS(0xAA);
6506 SET_CF(); // not ready
6511 case 0x11: /* recalibrate */
6512 BX_DEBUG_INT13_HD("int13_f11\n");
6514 SET_DISK_RET_STATUS(0);
6515 CLEAR_CF(); /* successful */
6519 case 0x14: /* controller internal diagnostic */
6520 BX_DEBUG_INT13_HD("int13_f14\n");
6522 SET_DISK_RET_STATUS(0);
6523 CLEAR_CF(); /* successful */
6528 case 0x15: /* read disk drive size */
6530 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6534 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6535 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6536 mul al
, ah
;; ax
= heads
* sectors
6537 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6538 dec bx
;; use (cylinders
- 1) ???
6539 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6540 ;; now we need to move the
32bit result dx
:ax to what the
6541 ;; BIOS wants which is cx
:dx
.
6542 ;; and then into CX
:DX on the stack
6543 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6544 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6547 SET_AH(3); // hard disk accessible
6548 SET_DISK_RET_STATUS(0); // ??? should this be 0
6549 CLEAR_CF(); // successful
6553 case 0x18: // set media type for format
6554 case 0x41: // IBM/MS
6555 case 0x42: // IBM/MS
6556 case 0x43: // IBM/MS
6557 case 0x44: // IBM/MS
6558 case 0x45: // IBM/MS lock/unlock drive
6559 case 0x46: // IBM/MS eject media
6560 case 0x47: // IBM/MS extended seek
6561 case 0x49: // IBM/MS extended media change
6562 case 0x50: // IBM/MS send packet command
6564 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6566 SET_AH(1); // code=invalid function in AH or invalid parameter
6567 SET_DISK_RET_STATUS(1);
6568 SET_CF(); /* unsuccessful */
6574 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6575 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6578 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6580 Bit16u
*hd_cylinders
;
6590 if (drive
== 0x80) {
6591 hd_type
= inb_cmos(0x12) & 0xf0;
6592 if (hd_type
!= 0xf0)
6593 BX_INFO(panic_msg_reg12h
,0);
6594 hd_type
= inb_cmos(0x19); // HD0: extended type
6596 BX_INFO(panic_msg_reg19h
,0,0x19);
6599 hd_type
= inb_cmos(0x12) & 0x0f;
6600 if (hd_type
!= 0x0f)
6601 BX_INFO(panic_msg_reg12h
,1);
6602 hd_type
= inb_cmos(0x1a); // HD0: extended type
6604 BX_INFO(panic_msg_reg19h
,0,0x1a);
6609 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6610 write_word(ss
, hd_cylinders
, cylinders
);
6613 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6615 // sectors per track
6616 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6619 #endif //else BX_USE_ATADRV
6621 #if BX_SUPPORT_FLOPPY
6623 //////////////////////
6624 // FLOPPY functions //
6625 //////////////////////
6627 void floppy_reset_controller()
6633 outb(0x03f2, val8
& ~0x04);
6634 outb(0x03f2, val8
| 0x04);
6636 // Wait for controller to come out of reset
6639 } while ( (val8
& 0xc0) != 0x80 );
6642 void floppy_prepare_controller(drive
)
6645 Bit8u val8
, dor
, prev_reset
;
6647 // set 40:3e bit 7 to 0
6648 val8
= read_byte(0x0040, 0x003e);
6650 write_byte(0x0040, 0x003e, val8
);
6652 // turn on motor of selected drive, DMA & int enabled, normal operation
6653 prev_reset
= inb(0x03f2) & 0x04;
6662 // reset the disk motor timeout value of INT 08
6663 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6665 // wait for drive readiness
6668 } while ( (val8
& 0xc0) != 0x80 );
6670 if (prev_reset
== 0) {
6671 // turn on interrupts
6675 // wait on 40:3e bit 7 to become 1
6677 val8
= read_byte(0x0040, 0x003e);
6678 } while ( (val8
& 0x80) == 0 );
6683 write_byte(0x0040, 0x003e, val8
);
6688 floppy_media_known(drive
)
6692 Bit16u media_state_offset
;
6694 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6701 media_state_offset
= 0x0090;
6703 media_state_offset
+= 1;
6705 val8
= read_byte(0x0040, media_state_offset
);
6706 val8
= (val8
>> 4) & 0x01;
6710 // check pass, return KNOWN
6715 floppy_media_sense(drive
)
6719 Bit16u media_state_offset
;
6720 Bit8u drive_type
, config_data
, media_state
;
6722 if (floppy_drive_recal(drive
) == 0) {
6726 // for now cheat and get drive type from CMOS,
6727 // assume media is same as drive type
6729 // ** config_data **
6730 // Bitfields for diskette media control:
6731 // Bit(s) Description (Table M0028)
6732 // 7-6 last data rate set by controller
6733 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6734 // 5-4 last diskette drive step rate selected
6735 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6736 // 3-2 {data rate at start of operation}
6739 // ** media_state **
6740 // Bitfields for diskette drive media state:
6741 // Bit(s) Description (Table M0030)
6743 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6744 // 5 double stepping required (e.g. 360kB in 1.2MB)
6745 // 4 media type established
6746 // 3 drive capable of supporting 4MB media
6747 // 2-0 on exit from BIOS, contains
6748 // 000 trying 360kB in 360kB
6749 // 001 trying 360kB in 1.2MB
6750 // 010 trying 1.2MB in 1.2MB
6751 // 011 360kB in 360kB established
6752 // 100 360kB in 1.2MB established
6753 // 101 1.2MB in 1.2MB established
6755 // 111 all other formats/drives
6757 drive_type
= inb_cmos(0x10);
6762 if ( drive_type
== 1 ) {
6764 config_data
= 0x00; // 0000 0000
6765 media_state
= 0x25; // 0010 0101
6768 else if ( drive_type
== 2 ) {
6769 // 1.2 MB 5.25" drive
6770 config_data
= 0x00; // 0000 0000
6771 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6774 else if ( drive_type
== 3 ) {
6776 config_data
= 0x00; // 0000 0000 ???
6777 media_state
= 0x17; // 0001 0111
6780 else if ( drive_type
== 4 ) {
6781 // 1.44 MB 3.5" drive
6782 config_data
= 0x00; // 0000 0000
6783 media_state
= 0x17; // 0001 0111
6786 else if ( drive_type
== 5 ) {
6787 // 2.88 MB 3.5" drive
6788 config_data
= 0xCC; // 1100 1100
6789 media_state
= 0xD7; // 1101 0111
6793 // Extended floppy size uses special cmos setting
6794 else if ( drive_type
== 6 ) {
6796 config_data
= 0x00; // 0000 0000
6797 media_state
= 0x27; // 0010 0111
6800 else if ( drive_type
== 7 ) {
6802 config_data
= 0x00; // 0000 0000
6803 media_state
= 0x27; // 0010 0111
6806 else if ( drive_type
== 8 ) {
6808 config_data
= 0x00; // 0000 0000
6809 media_state
= 0x27; // 0010 0111
6815 config_data
= 0x00; // 0000 0000
6816 media_state
= 0x00; // 0000 0000
6821 media_state_offset
= 0x90;
6823 media_state_offset
= 0x91;
6824 write_byte(0x0040, 0x008B, config_data
);
6825 write_byte(0x0040, media_state_offset
, media_state
);
6831 floppy_drive_recal(drive
)
6835 Bit16u curr_cyl_offset
;
6837 floppy_prepare_controller(drive
);
6839 // send Recalibrate command (2 bytes) to controller
6840 outb(0x03f5, 0x07); // 07: Recalibrate
6841 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6843 // turn on interrupts
6848 // wait on 40:3e bit 7 to become 1
6850 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6851 } while ( val8
== 0 );
6853 val8
= 0; // separate asm from while() loop
6854 // turn off interrupts
6859 // set 40:3e bit 7 to 0, and calibrated bit
6860 val8
= read_byte(0x0040, 0x003e);
6863 val8
|= 0x02; // Drive 1 calibrated
6864 curr_cyl_offset
= 0x0095;
6866 val8
|= 0x01; // Drive 0 calibrated
6867 curr_cyl_offset
= 0x0094;
6869 write_byte(0x0040, 0x003e, val8
);
6870 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6878 floppy_drive_exists(drive
)
6883 // check CMOS to see if drive exists
6884 drive_type
= inb_cmos(0x10);
6889 if ( drive_type
== 0 )
6896 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6897 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6899 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6900 Bit16u base_address
, base_count
, base_es
;
6901 Bit8u page
, mode_register
, val8
, dor
;
6902 Bit8u return_status
[7];
6903 Bit8u drive_type
, num_floppies
, ah
;
6904 Bit16u es
, last_addr
;
6906 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6911 case 0x00: // diskette controller reset
6912 BX_DEBUG_INT13_FL("floppy f00\n");
6915 SET_AH(1); // invalid param
6916 set_diskette_ret_status(1);
6920 drive_type
= inb_cmos(0x10);
6926 if (drive_type
== 0) {
6927 SET_AH(0x80); // drive not responding
6928 set_diskette_ret_status(0x80);
6933 set_diskette_ret_status(0);
6934 CLEAR_CF(); // successful
6935 set_diskette_current_cyl(drive
, 0); // current cylinder
6938 case 0x01: // Read Diskette Status
6940 val8
= read_byte(0x0000, 0x0441);
6947 case 0x02: // Read Diskette Sectors
6948 case 0x03: // Write Diskette Sectors
6949 case 0x04: // Verify Diskette Sectors
6950 num_sectors
= GET_AL();
6956 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
6957 (num_sectors
== 0) || (num_sectors
> 72)) {
6958 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
6960 set_diskette_ret_status(1);
6961 SET_AL(0); // no sectors read
6962 SET_CF(); // error occurred
6966 // see if drive exists
6967 if (floppy_drive_exists(drive
) == 0) {
6968 SET_AH(0x80); // not responding
6969 set_diskette_ret_status(0x80);
6970 SET_AL(0); // no sectors read
6971 SET_CF(); // error occurred
6975 // see if media in drive, and type is known
6976 if (floppy_media_known(drive
) == 0) {
6977 if (floppy_media_sense(drive
) == 0) {
6978 SET_AH(0x0C); // Media type not found
6979 set_diskette_ret_status(0x0C);
6980 SET_AL(0); // no sectors read
6981 SET_CF(); // error occurred
6987 // Read Diskette Sectors
6989 //-----------------------------------
6990 // set up DMA controller for transfer
6991 //-----------------------------------
6993 // es:bx = pointer to where to place information from diskette
6994 // port 04: DMA-1 base and current address, channel 2
6995 // port 05: DMA-1 base and current count, channel 2
6996 page
= (ES
>> 12); // upper 4 bits
6997 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6998 base_address
= base_es
+ BX
; // lower 16 bits of address
6999 // contributed by ES:BX
7000 if ( base_address
< base_es
) {
7001 // in case of carry, adjust page by 1
7004 base_count
= (num_sectors
* 512) - 1;
7006 // check for 64K boundary overrun
7007 last_addr
= base_address
+ base_count
;
7008 if (last_addr
< base_address
) {
7010 set_diskette_ret_status(0x09);
7011 SET_AL(0); // no sectors read
7012 SET_CF(); // error occurred
7016 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7019 BX_DEBUG_INT13_FL("clear flip-flop\n");
7020 outb(0x000c, 0x00); // clear flip-flop
7021 outb(0x0004, base_address
);
7022 outb(0x0004, base_address
>>8);
7023 BX_DEBUG_INT13_FL("clear flip-flop\n");
7024 outb(0x000c, 0x00); // clear flip-flop
7025 outb(0x0005, base_count
);
7026 outb(0x0005, base_count
>>8);
7028 // port 0b: DMA-1 Mode Register
7029 mode_register
= 0x46; // single mode, increment, autoinit disable,
7030 // transfer type=write, channel 2
7031 BX_DEBUG_INT13_FL("setting mode register\n");
7032 outb(0x000b, mode_register
);
7034 BX_DEBUG_INT13_FL("setting page register\n");
7035 // port 81: DMA-1 Page Register, channel 2
7038 BX_DEBUG_INT13_FL("unmask chan 2\n");
7039 outb(0x000a, 0x02); // unmask channel 2
7041 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7044 //--------------------------------------
7045 // set up floppy controller for transfer
7046 //--------------------------------------
7047 floppy_prepare_controller(drive
);
7049 // send read-normal-data command (9 bytes) to controller
7050 outb(0x03f5, 0xe6); // e6: read normal data
7051 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7052 outb(0x03f5, track
);
7054 outb(0x03f5, sector
);
7055 outb(0x03f5, 2); // 512 byte sector size
7056 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
7057 outb(0x03f5, 0); // Gap length
7058 outb(0x03f5, 0xff); // Gap length
7060 // turn on interrupts
7065 // wait on 40:3e bit 7 to become 1
7067 val8
= read_byte(0x0040, 0x0040);
7069 floppy_reset_controller();
7070 SET_AH(0x80); // drive not ready (timeout)
7071 set_diskette_ret_status(0x80);
7072 SET_AL(0); // no sectors read
7073 SET_CF(); // error occurred
7076 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7077 } while ( val8
== 0 );
7079 val8
= 0; // separate asm from while() loop
7080 // turn off interrupts
7085 // set 40:3e bit 7 to 0
7086 val8
= read_byte(0x0040, 0x003e);
7088 write_byte(0x0040, 0x003e, val8
);
7090 // check port 3f4 for accessibility to status bytes
7092 if ( (val8
& 0xc0) != 0xc0 )
7093 BX_PANIC("int13_diskette: ctrl not ready\n");
7095 // read 7 return status bytes from controller
7096 // using loop index broken, have to unroll...
7097 return_status
[0] = inb(0x3f5);
7098 return_status
[1] = inb(0x3f5);
7099 return_status
[2] = inb(0x3f5);
7100 return_status
[3] = inb(0x3f5);
7101 return_status
[4] = inb(0x3f5);
7102 return_status
[5] = inb(0x3f5);
7103 return_status
[6] = inb(0x3f5);
7104 // record in BIOS Data Area
7105 write_byte(0x0040, 0x0042, return_status
[0]);
7106 write_byte(0x0040, 0x0043, return_status
[1]);
7107 write_byte(0x0040, 0x0044, return_status
[2]);
7108 write_byte(0x0040, 0x0045, return_status
[3]);
7109 write_byte(0x0040, 0x0046, return_status
[4]);
7110 write_byte(0x0040, 0x0047, return_status
[5]);
7111 write_byte(0x0040, 0x0048, return_status
[6]);
7113 if ( (return_status
[0] & 0xc0) != 0 ) {
7115 set_diskette_ret_status(0x20);
7116 SET_AL(0); // no sectors read
7117 SET_CF(); // error occurred
7121 // ??? should track be new val from return_status[3] ?
7122 set_diskette_current_cyl(drive
, track
);
7123 // AL = number of sectors read (same value as passed)
7124 SET_AH(0x00); // success
7125 CLEAR_CF(); // success
7127 } else if (ah
== 0x03) {
7128 // Write Diskette Sectors
7130 //-----------------------------------
7131 // set up DMA controller for transfer
7132 //-----------------------------------
7134 // es:bx = pointer to where to place information from diskette
7135 // port 04: DMA-1 base and current address, channel 2
7136 // port 05: DMA-1 base and current count, channel 2
7137 page
= (ES
>> 12); // upper 4 bits
7138 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7139 base_address
= base_es
+ BX
; // lower 16 bits of address
7140 // contributed by ES:BX
7141 if ( base_address
< base_es
) {
7142 // in case of carry, adjust page by 1
7145 base_count
= (num_sectors
* 512) - 1;
7147 // check for 64K boundary overrun
7148 last_addr
= base_address
+ base_count
;
7149 if (last_addr
< base_address
) {
7151 set_diskette_ret_status(0x09);
7152 SET_AL(0); // no sectors read
7153 SET_CF(); // error occurred
7157 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7160 outb(0x000c, 0x00); // clear flip-flop
7161 outb(0x0004, base_address
);
7162 outb(0x0004, base_address
>>8);
7163 outb(0x000c, 0x00); // clear flip-flop
7164 outb(0x0005, base_count
);
7165 outb(0x0005, base_count
>>8);
7167 // port 0b: DMA-1 Mode Register
7168 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7169 // transfer type=read, channel 2
7170 outb(0x000b, mode_register
);
7172 // port 81: DMA-1 Page Register, channel 2
7175 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7178 //--------------------------------------
7179 // set up floppy controller for transfer
7180 //--------------------------------------
7181 floppy_prepare_controller(drive
);
7183 // send write-normal-data command (9 bytes) to controller
7184 outb(0x03f5, 0xc5); // c5: write normal data
7185 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7186 outb(0x03f5, track
);
7188 outb(0x03f5, sector
);
7189 outb(0x03f5, 2); // 512 byte sector size
7190 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7191 outb(0x03f5, 0); // Gap length
7192 outb(0x03f5, 0xff); // Gap length
7194 // turn on interrupts
7199 // wait on 40:3e bit 7 to become 1
7201 val8
= read_byte(0x0040, 0x0040);
7203 floppy_reset_controller();
7204 SET_AH(0x80); // drive not ready (timeout)
7205 set_diskette_ret_status(0x80);
7206 SET_AL(0); // no sectors written
7207 SET_CF(); // error occurred
7210 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7211 } while ( val8
== 0 );
7213 val8
= 0; // separate asm from while() loop
7214 // turn off interrupts
7219 // set 40:3e bit 7 to 0
7220 val8
= read_byte(0x0040, 0x003e);
7222 write_byte(0x0040, 0x003e, val8
);
7224 // check port 3f4 for accessibility to status bytes
7226 if ( (val8
& 0xc0) != 0xc0 )
7227 BX_PANIC("int13_diskette: ctrl not ready\n");
7229 // read 7 return status bytes from controller
7230 // using loop index broken, have to unroll...
7231 return_status
[0] = inb(0x3f5);
7232 return_status
[1] = inb(0x3f5);
7233 return_status
[2] = inb(0x3f5);
7234 return_status
[3] = inb(0x3f5);
7235 return_status
[4] = inb(0x3f5);
7236 return_status
[5] = inb(0x3f5);
7237 return_status
[6] = inb(0x3f5);
7238 // record in BIOS Data Area
7239 write_byte(0x0040, 0x0042, return_status
[0]);
7240 write_byte(0x0040, 0x0043, return_status
[1]);
7241 write_byte(0x0040, 0x0044, return_status
[2]);
7242 write_byte(0x0040, 0x0045, return_status
[3]);
7243 write_byte(0x0040, 0x0046, return_status
[4]);
7244 write_byte(0x0040, 0x0047, return_status
[5]);
7245 write_byte(0x0040, 0x0048, return_status
[6]);
7247 if ( (return_status
[0] & 0xc0) != 0 ) {
7248 if ( (return_status
[1] & 0x02) != 0 ) {
7249 // diskette not writable.
7250 // AH=status code=0x03 (tried to write on write-protected disk)
7251 // AL=number of sectors written=0
7256 BX_PANIC("int13_diskette_function: read error\n");
7260 // ??? should track be new val from return_status[3] ?
7261 set_diskette_current_cyl(drive
, track
);
7262 // AL = number of sectors read (same value as passed)
7263 SET_AH(0x00); // success
7264 CLEAR_CF(); // success
7266 } else { // if (ah == 0x04)
7267 // Verify Diskette Sectors
7269 // ??? should track be new val from return_status[3] ?
7270 set_diskette_current_cyl(drive
, track
);
7271 // AL = number of sectors verified (same value as passed)
7272 CLEAR_CF(); // success
7273 SET_AH(0x00); // success
7278 case 0x05: // format diskette track
7279 BX_DEBUG_INT13_FL("floppy f05\n");
7281 num_sectors
= GET_AL();
7286 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7287 (num_sectors
== 0) || (num_sectors
> 18)) {
7289 set_diskette_ret_status(1);
7290 SET_CF(); // error occurred
7293 // see if drive exists
7294 if (floppy_drive_exists(drive
) == 0) {
7295 SET_AH(0x80); // drive not responding
7296 set_diskette_ret_status(0x80);
7297 SET_CF(); // error occurred
7301 // see if media in drive, and type is known
7302 if (floppy_media_known(drive
) == 0) {
7303 if (floppy_media_sense(drive
) == 0) {
7304 SET_AH(0x0C); // Media type not found
7305 set_diskette_ret_status(0x0C);
7306 SET_AL(0); // no sectors read
7307 SET_CF(); // error occurred
7312 // set up DMA controller for transfer
7313 page
= (ES
>> 12); // upper 4 bits
7314 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7315 base_address
= base_es
+ BX
; // lower 16 bits of address
7316 // contributed by ES:BX
7317 if ( base_address
< base_es
) {
7318 // in case of carry, adjust page by 1
7321 base_count
= (num_sectors
* 4) - 1;
7323 // check for 64K boundary overrun
7324 last_addr
= base_address
+ base_count
;
7325 if (last_addr
< base_address
) {
7327 set_diskette_ret_status(0x09);
7328 SET_AL(0); // no sectors read
7329 SET_CF(); // error occurred
7334 outb(0x000c, 0x00); // clear flip-flop
7335 outb(0x0004, base_address
);
7336 outb(0x0004, base_address
>>8);
7337 outb(0x000c, 0x00); // clear flip-flop
7338 outb(0x0005, base_count
);
7339 outb(0x0005, base_count
>>8);
7340 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7341 // transfer type=read, channel 2
7342 outb(0x000b, mode_register
);
7343 // port 81: DMA-1 Page Register, channel 2
7347 // set up floppy controller for transfer
7348 floppy_prepare_controller(drive
);
7350 // send format-track command (6 bytes) to controller
7351 outb(0x03f5, 0x4d); // 4d: format track
7352 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7353 outb(0x03f5, 2); // 512 byte sector size
7354 outb(0x03f5, num_sectors
); // number of sectors per track
7355 outb(0x03f5, 0); // Gap length
7356 outb(0x03f5, 0xf6); // Fill byte
7357 // turn on interrupts
7362 // wait on 40:3e bit 7 to become 1
7364 val8
= read_byte(0x0040, 0x0040);
7366 floppy_reset_controller();
7367 SET_AH(0x80); // drive not ready (timeout)
7368 set_diskette_ret_status(0x80);
7369 SET_CF(); // error occurred
7372 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7373 } while ( val8
== 0 );
7375 val8
= 0; // separate asm from while() loop
7376 // turn off interrupts
7380 // set 40:3e bit 7 to 0
7381 val8
= read_byte(0x0040, 0x003e);
7383 write_byte(0x0040, 0x003e, val8
);
7384 // check port 3f4 for accessibility to status bytes
7386 if ( (val8
& 0xc0) != 0xc0 )
7387 BX_PANIC("int13_diskette: ctrl not ready\n");
7389 // read 7 return status bytes from controller
7390 // using loop index broken, have to unroll...
7391 return_status
[0] = inb(0x3f5);
7392 return_status
[1] = inb(0x3f5);
7393 return_status
[2] = inb(0x3f5);
7394 return_status
[3] = inb(0x3f5);
7395 return_status
[4] = inb(0x3f5);
7396 return_status
[5] = inb(0x3f5);
7397 return_status
[6] = inb(0x3f5);
7398 // record in BIOS Data Area
7399 write_byte(0x0040, 0x0042, return_status
[0]);
7400 write_byte(0x0040, 0x0043, return_status
[1]);
7401 write_byte(0x0040, 0x0044, return_status
[2]);
7402 write_byte(0x0040, 0x0045, return_status
[3]);
7403 write_byte(0x0040, 0x0046, return_status
[4]);
7404 write_byte(0x0040, 0x0047, return_status
[5]);
7405 write_byte(0x0040, 0x0048, return_status
[6]);
7407 if ( (return_status
[0] & 0xc0) != 0 ) {
7408 if ( (return_status
[1] & 0x02) != 0 ) {
7409 // diskette not writable.
7410 // AH=status code=0x03 (tried to write on write-protected disk)
7411 // AL=number of sectors written=0
7416 BX_PANIC("int13_diskette_function: write error\n");
7421 set_diskette_ret_status(0);
7422 set_diskette_current_cyl(drive
, 0);
7423 CLEAR_CF(); // successful
7427 case 0x08: // read diskette drive parameters
7428 BX_DEBUG_INT13_FL("floppy f08\n");
7438 SET_DL(num_floppies
);
7443 drive_type
= inb_cmos(0x10);
7445 if (drive_type
& 0xf0)
7447 if (drive_type
& 0x0f)
7459 SET_DL(num_floppies
);
7461 switch (drive_type
) {
7464 SET_DH(0); // max head #
7467 case 1: // 360KB, 5.25"
7468 CX
= 0x2709; // 40 tracks, 9 sectors
7469 SET_DH(1); // max head #
7472 case 2: // 1.2MB, 5.25"
7473 CX
= 0x4f0f; // 80 tracks, 15 sectors
7474 SET_DH(1); // max head #
7477 case 3: // 720KB, 3.5"
7478 CX
= 0x4f09; // 80 tracks, 9 sectors
7479 SET_DH(1); // max head #
7482 case 4: // 1.44MB, 3.5"
7483 CX
= 0x4f12; // 80 tracks, 18 sectors
7484 SET_DH(1); // max head #
7487 case 5: // 2.88MB, 3.5"
7488 CX
= 0x4f24; // 80 tracks, 36 sectors
7489 SET_DH(1); // max head #
7492 case 6: // 160k, 5.25"
7493 CX
= 0x2708; // 40 tracks, 8 sectors
7494 SET_DH(0); // max head #
7497 case 7: // 180k, 5.25"
7498 CX
= 0x2709; // 40 tracks, 9 sectors
7499 SET_DH(0); // max head #
7502 case 8: // 320k, 5.25"
7503 CX
= 0x2708; // 40 tracks, 8 sectors
7504 SET_DH(1); // max head #
7508 BX_PANIC("floppy: int13: bad floppy type\n");
7511 /* set es & di to point to 11 byte diskette param table in ROM */
7515 mov ax
, #diskette_param_table2
7516 mov _int13_diskette_function
.DI
+2[bp
], ax
7517 mov _int13_diskette_function
.ES
+2[bp
], cs
7520 CLEAR_CF(); // success
7521 /* disk status not changed upon success */
7525 case 0x15: // read diskette drive type
7526 BX_DEBUG_INT13_FL("floppy f15\n");
7529 SET_AH(0); // only 2 drives supported
7530 // set_diskette_ret_status here ???
7534 drive_type
= inb_cmos(0x10);
7540 CLEAR_CF(); // successful, not present
7541 if (drive_type
==0) {
7542 SET_AH(0); // drive not present
7545 SET_AH(1); // drive present, does not support change line
7550 case 0x16: // get diskette change line status
7551 BX_DEBUG_INT13_FL("floppy f16\n");
7554 SET_AH(0x01); // invalid drive
7555 set_diskette_ret_status(0x01);
7560 SET_AH(0x06); // change line not supported
7561 set_diskette_ret_status(0x06);
7565 case 0x17: // set diskette type for format(old)
7566 BX_DEBUG_INT13_FL("floppy f17\n");
7567 /* not used for 1.44M floppies */
7568 SET_AH(0x01); // not supported
7569 set_diskette_ret_status(1); /* not supported */
7573 case 0x18: // set diskette type for format(new)
7574 BX_DEBUG_INT13_FL("floppy f18\n");
7575 SET_AH(0x01); // do later
7576 set_diskette_ret_status(1);
7581 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7583 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7584 SET_AH(0x01); // ???
7585 set_diskette_ret_status(1);
7591 #else // #if BX_SUPPORT_FLOPPY
7593 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7594 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7598 switch ( GET_AH() ) {
7600 case 0x01: // Read Diskette Status
7602 val8
= read_byte(0x0000, 0x0441);
7611 write_byte(0x0000, 0x0441, 0x01);
7615 #endif // #if BX_SUPPORT_FLOPPY
7618 set_diskette_ret_status(value
)
7621 write_byte(0x0040, 0x0041, value
);
7625 set_diskette_current_cyl(drive
, cyl
)
7630 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7631 write_byte(0x0040, 0x0094+drive
, cyl
);
7635 determine_floppy_media(drive
)
7639 Bit8u val8
, DOR
, ctrl_info
;
7641 ctrl_info
= read_byte(0x0040, 0x008F);
7649 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7652 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7656 if ( (ctrl_info
& 0x04) != 0x04 ) {
7657 // Drive not determined means no drive exists, done.
7662 // check Main Status Register for readiness
7663 val8
= inb(0x03f4) & 0x80; // Main Status Register
7665 BX_PANIC("d_f_m: MRQ bit not set\n");
7669 // existing BDA values
7671 // turn on drive motor
7672 outb(0x03f2, DOR
); // Digital Output Register
7675 BX_PANIC("d_f_m: OK so far\n");
7680 int17_function(regs
, ds
, iret_addr
)
7681 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7682 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7683 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7685 Bit16u addr
,timeout
;
7692 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7693 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7694 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7695 if (regs
.u
.r8
.ah
== 0) {
7696 outb(addr
, regs
.u
.r8
.al
);
7698 outb(addr
+2, val8
| 0x01); // send strobe
7702 outb(addr
+2, val8
& ~0x01);
7703 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7707 if (regs
.u
.r8
.ah
== 1) {
7709 outb(addr
+2, val8
& ~0x04); // send init
7713 outb(addr
+2, val8
| 0x04);
7716 regs
.u
.r8
.ah
= (val8
^ 0x48);
7717 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7718 ClearCF(iret_addr
.flags
);
7720 SetCF(iret_addr
.flags
); // Unsupported
7725 int19_function(seq_nr
)
7728 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7738 // if BX_ELTORITO_BOOT is not defined, old behavior
7739 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7740 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7741 // 0: system boot sequence, first drive C: then A:
7742 // 1: system boot sequence, first drive A: then C:
7743 // else BX_ELTORITO_BOOT is defined
7744 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7745 // CMOS reg 0x3D & 0x0f : 1st boot device
7746 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7747 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7748 // boot device codes:
7749 // 0x00 : not defined
7750 // 0x01 : first floppy
7751 // 0x02 : first harddrive
7752 // 0x03 : first cdrom
7753 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7754 // else : boot failure
7756 // Get the boot sequence
7757 #if BX_ELTORITO_BOOT
7758 bootdev
= inb_cmos(0x3d);
7759 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
7760 bootdev
>>= 4 * seq_nr
;
7762 if (bootdev
== 0) BX_PANIC("No bootable device.\n");
7764 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7767 if (seq_nr
==2) BX_PANIC("No more boot devices.");
7768 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
7769 /* Boot from floppy if the bit is set or it's the second boot */
7775 /* Read the boot device from the IPL table */
7776 if (get_boot_vector(bootdev
, &e
) == 0) {
7777 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
7781 /* Do the loading, and set up vector as a far pointer to the boot
7782 * address, and bootdrv as the boot drive */
7783 print_boot_device(e
.type
);
7786 case 0x01: /* FDD */
7787 case 0x02: /* HDD */
7789 bootdrv
= (e
.type
== 0x02) ? 0x80 : 0x00;
7801 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7802 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7803 mov es
, ax
;; segment
7804 xor bx
, bx
;; offset
7805 mov ah
, #0x02 ;; function 2, read diskette sector
7806 mov al
, #0x01 ;; read 1 sector
7807 mov ch
, #0x00 ;; track 0
7808 mov cl
, #0x01 ;; sector 1
7809 mov dh
, #0x00 ;; head 0
7810 int #0x13 ;; read sector
7813 mov _int19_function
.status
+ 2[bp
], ax
7824 print_boot_failure(e
.type
, 1);
7828 /* Always check the signature on a HDD boot sector; on FDD, only do
7829 * the check if the CMOS doesn't tell us to skip it */
7830 if ((e
.type
!= 0x01) || !((inb_cmos(0x38) & 0x01))) {
7831 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7832 print_boot_failure(e
.type
, 0);
7837 /* Canonicalize bootseg:bootip */
7838 bootip
= (bootseg
& 0x0fff) << 4;
7842 #if BX_ELTORITO_BOOT
7843 case 0x03: /* CD-ROM */
7844 status
= cdrom_boot();
7847 if ( (status
& 0x00ff) !=0 ) {
7848 print_cdromboot_failure(status
);
7849 print_boot_failure(e
.type
, 1);
7853 bootdrv
= (Bit8u
)(status
>>8);
7854 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7855 /* Canonicalize bootseg:bootip */
7856 bootip
= (bootseg
& 0x0fff) << 4;
7861 case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7862 bootseg
= e
.vector
>> 16;
7863 bootip
= e
.vector
& 0xffff;
7869 /* Debugging info */
7870 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
7872 /* Jump to the boot vector */
7875 ;; Build an iret stack frame that will take us to the boot vector
.
7876 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
7878 mov ax
, _int19_function
.bootseg
+ 0[bp
]
7880 mov ax
, _int19_function
.bootip
+ 0[bp
]
7882 ;; Set the magic number in ax
and the boot drive in dl
.
7884 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
7885 ;; Zero some of the other registers
.
7896 int1a_function(regs
, ds
, iret_addr
)
7897 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7898 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7899 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7903 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
);
7909 switch (regs
.u
.r8
.ah
) {
7910 case 0: // get current clock count
7914 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7915 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7916 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7917 BiosData
->midnight_flag
= 0; // reset flag
7922 ClearCF(iret_addr
.flags
); // OK
7925 case 1: // Set Current Clock Count
7929 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7930 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7931 BiosData
->midnight_flag
= 0; // reset flag
7936 ClearCF(iret_addr
.flags
); // OK
7940 case 2: // Read CMOS Time
7941 if (rtc_updating()) {
7942 SetCF(iret_addr
.flags
);
7946 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7947 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7948 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7949 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7951 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7952 ClearCF(iret_addr
.flags
); // OK
7955 case 3: // Set CMOS Time
7956 // Using a debugger, I notice the following masking/setting
7957 // of bits in Status Register B, by setting Reg B to
7958 // a few values and getting its value after INT 1A was called.
7960 // try#1 try#2 try#3
7961 // before 1111 1101 0111 1101 0000 0000
7962 // after 0110 0010 0110 0010 0000 0010
7964 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7965 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7966 if (rtc_updating()) {
7968 // fall through as if an update were not in progress
7970 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7971 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7972 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7973 // Set Daylight Savings time enabled bit to requested value
7974 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7975 // (reg B already selected)
7976 outb_cmos(0x0b, val8
);
7978 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7979 ClearCF(iret_addr
.flags
); // OK
7982 case 4: // Read CMOS Date
7984 if (rtc_updating()) {
7985 SetCF(iret_addr
.flags
);
7988 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
7989 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
7990 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
7991 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
7992 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7993 ClearCF(iret_addr
.flags
); // OK
7996 case 5: // Set CMOS Date
7997 // Using a debugger, I notice the following masking/setting
7998 // of bits in Status Register B, by setting Reg B to
7999 // a few values and getting its value after INT 1A was called.
8001 // try#1 try#2 try#3 try#4
8002 // before 1111 1101 0111 1101 0000 0010 0000 0000
8003 // after 0110 1101 0111 1101 0000 0010 0000 0000
8005 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8006 // My assumption: RegB = (RegB & 01111111b)
8007 if (rtc_updating()) {
8009 SetCF(iret_addr
.flags
);
8012 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
8013 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
8014 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
8015 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
8016 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8017 outb_cmos(0x0b, val8
);
8019 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
8020 ClearCF(iret_addr
.flags
); // OK
8023 case 6: // Set Alarm Time in CMOS
8024 // Using a debugger, I notice the following masking/setting
8025 // of bits in Status Register B, by setting Reg B to
8026 // a few values and getting its value after INT 1A was called.
8028 // try#1 try#2 try#3
8029 // before 1101 1111 0101 1111 0000 0000
8030 // after 0110 1111 0111 1111 0010 0000
8032 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8033 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8034 val8
= inb_cmos(0x0b); // Get Status Reg B
8037 // Alarm interrupt enabled already
8038 SetCF(iret_addr
.flags
); // Error: alarm in use
8041 if (rtc_updating()) {
8043 // fall through as if an update were not in progress
8045 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
8046 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
8047 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
8048 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8049 // enable Status Reg B alarm bit, clear halt clock bit
8050 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
8051 ClearCF(iret_addr
.flags
); // OK
8054 case 7: // Turn off Alarm
8055 // Using a debugger, I notice the following masking/setting
8056 // of bits in Status Register B, by setting Reg B to
8057 // a few values and getting its value after INT 1A was called.
8059 // try#1 try#2 try#3 try#4
8060 // before 1111 1101 0111 1101 0010 0000 0010 0010
8061 // after 0100 0101 0101 0101 0000 0000 0000 0010
8063 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8064 // My assumption: RegB = (RegB & 01010111b)
8065 val8
= inb_cmos(0x0b); // Get Status Reg B
8066 // clear clock-halt bit, disable alarm bit
8067 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
8069 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8070 ClearCF(iret_addr
.flags
); // OK
8074 // real mode PCI BIOS functions now handled in assembler code
8075 // this C code handles the error code for information only
8076 if (regs
.u
.r8
.bl
== 0xff) {
8077 BX_INFO("PCI BIOS: PCI not present\n");
8078 } else if (regs
.u
.r8
.bl
== 0x81) {
8079 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8080 } else if (regs
.u
.r8
.bl
== 0x83) {
8081 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8082 } else if (regs
.u
.r8
.bl
== 0x86) {
8083 if (regs
.u
.r8
.al
== 0x02) {
8084 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8086 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
);
8089 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8090 SetCF(iret_addr
.flags
);
8095 SetCF(iret_addr
.flags
); // Unsupported
8100 int70_function(regs
, ds
, iret_addr
)
8101 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8102 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8103 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8105 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8106 Bit8u registerB
= 0, registerC
= 0;
8108 // Check which modes are enabled and have occurred.
8109 registerB
= inb_cmos( 0xB );
8110 registerC
= inb_cmos( 0xC );
8112 if( ( registerB
& 0x60 ) != 0 ) {
8113 if( ( registerC
& 0x20 ) != 0 ) {
8114 // Handle Alarm Interrupt.
8121 if( ( registerC
& 0x40 ) != 0 ) {
8122 // Handle Periodic Interrupt.
8124 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8125 // Wait Interval (Int 15, AH=83) active.
8126 Bit32u time
, toggle
;
8128 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8129 if( time
< 0x3D1 ) {
8131 Bit16u segment
, offset
;
8133 segment
= read_word( 0x40, 0x98 );
8134 offset
= read_word( 0x40, 0x9A );
8135 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8136 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8137 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8139 // Continue waiting.
8141 write_dword( 0x40, 0x9C, time
);
8154 ;------------------------------------------
8155 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8156 ;------------------------------------------
8161 push
#0x00 ;; placeholder for status
8162 push
#0x00 ;; placeholder for X
8163 push
#0x00 ;; placeholder for Y
8164 push
#0x00 ;; placeholder for Z
8165 push
#0x00 ;; placeholder for make_far_call boolean
8166 call _int74_function
8167 pop cx
;; remove make_far_call from stack
8170 ;; make far call to EBDA
:0022
8173 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8175 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8180 add sp
, #8 ;; pop status, x, y, z
8182 pop ds
;; restore DS
8187 ;; This will perform an IRET
, but will retain value of current CF
8188 ;; by altering flags on stack
. Better than RETF
#02.
8193 and BYTE
[bp
+ 0x06], #0xfe
8199 or BYTE
[bp
+ 0x06], #0x01
8204 ;----------------------
8205 ;- INT13h (relocated
) -
8206 ;----------------------
8208 ; int13_relocated is a little bit messed up since I played with it
8209 ; I have to rewrite it
:
8210 ; - call a function that detect which function to call
8211 ; - make all called C function get the same parameters list
8215 #if BX_ELTORITO_BOOT
8216 ;; check
for an eltorito function
8218 jb int13_not_eltorito
8220 ja int13_not_eltorito
8229 jmp _int13_eltorito
;; ELDX
not used
8237 ;; check
if emulation active
8238 call _cdemu_isactive
8240 je int13_cdemu_inactive
8242 ;; check
if access to the emulated drive
8243 call _cdemu_emulated_drive
8246 cmp al
,dl
;; int13 on emulated drive
8261 jmp _int13_cdemu
;; ELDX
not used
8264 and dl
,#0xE0 ;; mask to get device class, including cdroms
8265 cmp al
,dl
;; al is
0x00 or 0x80
8266 jne int13_cdemu_inactive
;; inactive
for device
class
8278 dec dl
;; real drive is dl
- 1
8281 int13_cdemu_inactive
:
8287 #endif // BX_ELTORITO_BOOT
8298 push dx
;; push eltorito value of dx instead of sp
8309 ;; now the
16-bit registers can be restored with
:
8310 ;; pop ds
; pop es
; popa
; iret
8311 ;; arguments passed to functions should be
8312 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8318 jmp _int13_diskette_function
8327 // ebx is modified: BSD 5.2.1 boot loader problem
8328 // someone should figure out which 32 bit register that actually are used
8345 ;; int13_harddisk modifies high word of EAX
8348 call _int13_harddisk
8361 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8369 ;; Get the boot sequence number out of the IPL memory
8371 mov ds
, bx
;; Set segment
8372 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8374 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8375 mov ds
, ax
;; and reset the segment to zero
.
8377 ;; Carry on in the INT
19h handler
, using the
new sequence number
8385 int19_relocated
: ;; Boot function
, relocated
8387 ;; int19 was beginning to be really
complex, so now it
8388 ;; just calls a C function that does the work
8399 ;; Start from the first boot
device (0, in AX
)
8401 mov ds
, bx
;; Set segment to write to the IPL memory
8402 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8403 mov ds
, ax
;; and reset the segment
.
8409 ;; Call the C code
for the next boot device
8410 call _int19_function
8412 ;; Boot failed
: invoke the boot recovery function
8418 int1c_handler
: ;; User Timer Tick
8422 ;----------------------
8423 ;- POST
: Floppy Drive
-
8424 ;----------------------
8430 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8432 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8434 mov
0x0440, al
;; diskette motor timeout counter
: not active
8435 mov
0x0441, al
;; diskette controller status
return code
8437 mov
0x0442, al
;; disk
& diskette controller status
register 0
8438 mov
0x0443, al
;; diskette controller status
register 1
8439 mov
0x0444, al
;; diskette controller status
register 2
8440 mov
0x0445, al
;; diskette controller cylinder number
8441 mov
0x0446, al
;; diskette controller head number
8442 mov
0x0447, al
;; diskette controller sector number
8443 mov
0x0448, al
;; diskette controller bytes written
8445 mov
0x048b, al
;; diskette configuration data
8447 ;; -----------------------------------------------------------------
8448 ;; (048F
) diskette controller information
8450 mov al
, #0x10 ;; get CMOS diskette drive type
8453 mov ah
, al
;; save byte to AH
8456 shr al
, #4 ;; look at top 4 bits for drive 0
8457 jz f0_missing
;; jump
if no drive0
8458 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8461 mov bl
, #0x00 ;; no drive0
8464 mov al
, ah
;; restore from AH
8465 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8466 jz f1_missing
;; jump
if no drive1
8467 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8469 ;; leave high bits in BL zerod
8470 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8471 ;; -----------------------------------------------------------------
8474 mov
0x0490, al
;; diskette
0 media state
8475 mov
0x0491, al
;; diskette
1 media state
8477 ;; diskette
0,1 operational starting state
8478 ;; drive type has
not been determined
,
8479 ;; has no changed detection line
8483 mov
0x0494, al
;; diskette
0 current cylinder
8484 mov
0x0495, al
;; diskette
1 current cylinder
8487 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8489 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8490 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8491 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8496 ;--------------------
8497 ;- POST
: HARD DRIVE
-
8498 ;--------------------
8499 ; relocated here because the primary POST area isnt big enough
.
8502 // INT 76h calls INT 15h function ax=9100
8504 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8510 mov
0x0474, al
/* hard disk status of last operation */
8511 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8512 mov
0x048c, al
/* hard disk status register */
8513 mov
0x048d, al
/* hard disk error register */
8514 mov
0x048e, al
/* hard disk task complete flag */
8516 mov
0x0475, al
/* hard disk number attached */
8518 mov
0x0476, al
/* hard disk control byte */
8519 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8520 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8521 ;; INT
41h
: hard disk
0 configuration pointer
8522 ;; INT
46h
: hard disk
1 configuration pointer
8523 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8524 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8526 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8538 cmp al
, #47 ;; decimal 47 - user definable
8542 ;; CMOS purpose param table offset
8543 ;; 1b cylinders low
0
8544 ;; 1c cylinders high
1
8546 ;; 1e write pre
-comp low
5
8547 ;; 1f write pre
-comp high
6
8548 ;; 20 retries
/bad map
/heads
>8 8
8549 ;; 21 landing zone low C
8550 ;; 22 landing zone high D
8551 ;; 23 sectors
/track E
8556 ;;; Filling EBDA table
for hard disk
0.
8564 mov (0x003d + 0x05), ax
;; write precomp word
8569 mov (0x003d + 0x08), al
;; drive control byte
8578 mov (0x003d + 0x0C), ax
;; landing zone word
8580 mov al
, #0x1c ;; get cylinders word in AX
8582 in al
, #0x71 ;; high byte
8586 in al
, #0x71 ;; low byte
8587 mov bx
, ax
;; BX
= cylinders
8592 mov cl
, al
;; CL
= heads
8597 mov dl
, al
;; DL
= sectors
8600 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8602 hd0_post_physical_chs
:
8603 ;; no logical CHS mapping used
, just physical CHS
8604 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8605 mov (0x003d + 0x00), bx
;; number of physical cylinders
8606 mov (0x003d + 0x02), cl
;; number of physical heads
8607 mov (0x003d + 0x0E), dl
;; number of physical sectors
8610 hd0_post_logical_chs
:
8611 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8612 mov (0x003d + 0x09), bx
;; number of physical cylinders
8613 mov (0x003d + 0x0b), cl
;; number of physical heads
8614 mov (0x003d + 0x04), dl
;; number of physical sectors
8615 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8617 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8620 jnbe hd0_post_above_2048
8621 ;; 1024 < c
<= 2048 cylinders
8624 jmp hd0_post_store_logical
8626 hd0_post_above_2048
:
8628 jnbe hd0_post_above_4096
8629 ;; 2048 < c
<= 4096 cylinders
8632 jmp hd0_post_store_logical
8634 hd0_post_above_4096
:
8636 jnbe hd0_post_above_8192
8637 ;; 4096 < c
<= 8192 cylinders
8640 jmp hd0_post_store_logical
8642 hd0_post_above_8192
:
8643 ;; 8192 < c
<= 16384 cylinders
8647 hd0_post_store_logical
:
8648 mov (0x003d + 0x00), bx
;; number of physical cylinders
8649 mov (0x003d + 0x02), cl
;; number of physical heads
8651 mov cl
, #0x0f ;; repeat count
8652 mov si
, #0x003d ;; offset to disk0 FDPT
8653 mov al
, #0x00 ;; sum
8654 hd0_post_checksum_loop
:
8658 jnz hd0_post_checksum_loop
8659 not al
;; now take
2s complement
8662 ;;; Done filling EBDA table
for hard disk
0.
8666 ;; is there really a second hard disk
? if not, return now
8674 ;; check that the hd type is really
0x0f.
8679 ;; check that the extended type is
47 - user definable
8683 cmp al
, #47 ;; decimal 47 - user definable
8688 ;; CMOS purpose param table offset
8689 ;; 0x24 cylinders low
0
8690 ;; 0x25 cylinders high
1
8692 ;; 0x27 write pre
-comp low
5
8693 ;; 0x28 write pre
-comp high
6
8695 ;; 0x2a landing zone low C
8696 ;; 0x2b landing zone high D
8697 ;; 0x2c sectors
/track E
8698 ;;; Fill EBDA table
for hard disk
1.
8708 mov (0x004d + 0x05), ax
;; write precomp word
8713 mov (0x004d + 0x08), al
;; drive control byte
8722 mov (0x004d + 0x0C), ax
;; landing zone word
8724 mov al
, #0x25 ;; get cylinders word in AX
8726 in al
, #0x71 ;; high byte
8730 in al
, #0x71 ;; low byte
8731 mov bx
, ax
;; BX
= cylinders
8736 mov cl
, al
;; CL
= heads
8741 mov dl
, al
;; DL
= sectors
8744 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8746 hd1_post_physical_chs
:
8747 ;; no logical CHS mapping used
, just physical CHS
8748 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8749 mov (0x004d + 0x00), bx
;; number of physical cylinders
8750 mov (0x004d + 0x02), cl
;; number of physical heads
8751 mov (0x004d + 0x0E), dl
;; number of physical sectors
8754 hd1_post_logical_chs
:
8755 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8756 mov (0x004d + 0x09), bx
;; number of physical cylinders
8757 mov (0x004d + 0x0b), cl
;; number of physical heads
8758 mov (0x004d + 0x04), dl
;; number of physical sectors
8759 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8761 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8764 jnbe hd1_post_above_2048
8765 ;; 1024 < c
<= 2048 cylinders
8768 jmp hd1_post_store_logical
8770 hd1_post_above_2048
:
8772 jnbe hd1_post_above_4096
8773 ;; 2048 < c
<= 4096 cylinders
8776 jmp hd1_post_store_logical
8778 hd1_post_above_4096
:
8780 jnbe hd1_post_above_8192
8781 ;; 4096 < c
<= 8192 cylinders
8784 jmp hd1_post_store_logical
8786 hd1_post_above_8192
:
8787 ;; 8192 < c
<= 16384 cylinders
8791 hd1_post_store_logical
:
8792 mov (0x004d + 0x00), bx
;; number of physical cylinders
8793 mov (0x004d + 0x02), cl
;; number of physical heads
8795 mov cl
, #0x0f ;; repeat count
8796 mov si
, #0x004d ;; offset to disk0 FDPT
8797 mov al
, #0x00 ;; sum
8798 hd1_post_checksum_loop
:
8802 jnz hd1_post_checksum_loop
8803 not al
;; now take
2s complement
8806 ;;; Done filling EBDA table
for hard disk
1.
8810 ;--------------------
8811 ;- POST
: EBDA segment
8812 ;--------------------
8813 ; relocated here because the primary POST area isnt big enough
.
8818 mov byte ptr
[0x0], #EBDA_SIZE
8820 xor ax
, ax
; mov EBDA seg into
40E
8822 mov word ptr
[0x40E], #EBDA_SEG
8825 ;--------------------
8826 ;- POST
: EOI
+ jmp via
[0x40:67)
8827 ;--------------------
8828 ; relocated here because the primary POST area isnt big enough
.
8838 ;--------------------
8841 out
#0xA0, al ;; slave PIC EOI
8844 out
#0x20, al ;; master PIC EOI
8847 ;--------------------
8849 ;; in
: AL in BCD format
8850 ;; out
: AL in binary format
, AH will always be
0
8853 and bl
, #0x0f ;; bl has low digit
8854 shr al
, #4 ;; al has high digit
8856 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8857 add al
, bl
;; then add low digit
8860 ;--------------------
8862 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8863 ;; Timer Ticks Roller
Flag (0x470:byte
)
8864 ;; The Timer Ticks Count needs to be set according to
8865 ;; the current CMOS time
, as
if ticks have been occurring
8866 ;; at
18.2hz since midnight up to
this point
. Calculating
8867 ;; this is a little complicated
. Here are the factors I gather
8868 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8869 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8870 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8871 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8872 ;; the timer
. With a maximum
16bit timer count
, this is again
8873 ;; divided down by
65536 to
18.2hz
.
8875 ;; 14,318,180 Hz clock
8876 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8877 ;; /4 = 1,193,181 Hz fed to timer
8878 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8879 ;; 1 second
= 18.20650736 ticks
8880 ;; 1 minute
= 1092.390442 ticks
8881 ;; 1 hour
= 65543.42651 ticks
8883 ;; Given the values in the CMOS clock
, one could calculate
8884 ;; the number of ticks by the following
:
8885 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8886 ;; (BcdToBin(minutes
) * 1092.3904)
8887 ;; (BcdToBin(hours
) * 65543.427)
8888 ;; To get a little more accuracy
, since Im
using integer
8889 ;; arithmatic
, I use
:
8890 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8891 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8892 ;; (BcdToBin(hours
) * 65543427) / 1000
8897 xor eax
, eax
;; clear EAX
8900 in al
, #0x71 ;; AL has CMOS seconds in BCD
8901 call BcdToBin
;; EAX now has seconds in binary
8907 mov ecx
, eax
;; ECX will accumulate total ticks
8910 xor eax
, eax
;; clear EAX
8913 in al
, #0x71 ;; AL has CMOS minutes in BCD
8914 call BcdToBin
;; EAX now has minutes in binary
8920 add ecx
, eax
;; add to total ticks
8923 xor eax
, eax
;; clear EAX
8926 in al
, #0x71 ;; AL has CMOS hours in BCD
8927 call BcdToBin
;; EAX now has hours in binary
8933 add ecx
, eax
;; add to total ticks
8935 mov
0x46C, ecx
;; Timer Ticks Count
8937 mov
0x470, al
;; Timer Ticks Rollover Flag
8940 ;--------------------
8942 ;; record completion in BIOS task complete flag
8954 ;--------------------
8959 #include "apmbios.S"
8963 #include "apmbios.S"
8966 #include "apmbios.S"
8970 ;--------------------
8975 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8976 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8977 db
0 ;; revision level
8978 ;; length in paragraphs
and checksum stored in a word to prevent errors
8979 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8980 & 0xff) << 8) + 0x01
8981 db
0,0,0,0,0 ;; reserved
8986 cmp eax
, #0x49435024 ;; "$PCI"
8988 mov eax
, #0x80000000
8993 #ifdef PCI_FIXED_HOST_BRIDGE
8994 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8997 ;; say ok
if a device is present
8998 cmp eax
, #0xffffffff
9001 mov ebx
, #0x000f0000
9003 mov edx
, #pcibios_protected
9010 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9021 cmp al
, #0x01 ;; installation check
9025 mov edx
, #0x20494350 ;; "PCI "
9028 pci_pro_f02
: ;; find pci device
9036 call pci_pro_select_reg
9050 pci_pro_f03
: ;; find
class code
9056 call pci_pro_select_reg
9061 jne pci_pro_nextdev2
9068 jne pci_pro_devloop2
9071 pci_pro_f08
: ;; read configuration byte
9074 call pci_pro_select_reg
9083 pci_pro_f09
: ;; read configuration word
9086 call pci_pro_select_reg
9095 pci_pro_f0a
: ;; read configuration dword
9098 call pci_pro_select_reg
9105 pci_pro_f0b
: ;; write configuration byte
9108 call pci_pro_select_reg
9117 pci_pro_f0c
: ;; write configuration word
9120 call pci_pro_select_reg
9129 pci_pro_f0d
: ;; write configuration dword
9132 call pci_pro_select_reg
9145 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9155 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9179 mov eax
, #0x80000000
9184 #ifdef PCI_FIXED_HOST_BRIDGE
9185 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9188 ;; say ok
if a device is present
9189 cmp eax
, #0xffffffff
9200 cmp al
, #0x01 ;; installation check
9205 mov edx
, #0x20494350 ;; "PCI "
9207 mov di
, #pcibios_protected
9210 pci_real_f02
: ;; find pci device
9220 call pci_real_select_reg
9224 jne pci_real_nextdev
9231 jne pci_real_devloop
9236 pci_real_f03
: ;; find
class code
9242 call pci_real_select_reg
9247 jne pci_real_nextdev2
9254 jne pci_real_devloop2
9259 pci_real_f08
: ;; read configuration byte
9262 call pci_real_select_reg
9271 pci_real_f09
: ;; read configuration word
9274 call pci_real_select_reg
9283 pci_real_f0a
: ;; read configuration dword
9286 call pci_real_select_reg
9293 pci_real_f0b
: ;; write configuration byte
9296 call pci_real_select_reg
9305 pci_real_f0c
: ;; write configuration word
9308 call pci_real_select_reg
9317 pci_real_f0d
: ;; write configuration dword
9320 call pci_real_select_reg
9327 pci_real_f0e
: ;; get irq routing options
9329 jne pci_real_unknown
9331 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9332 jb pci_real_too_small
9334 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9342 mov si
, #pci_routing_table_structure_start
9350 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9359 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9363 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9381 pci_real_select_reg
:
9395 pci_routing_table_structure
:
9396 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9398 dw
32 + (6 * 16) ;; table size
9399 db
0 ;; PCI interrupt router bus
9400 db
0x08 ;; PCI interrupt router DevFunc
9401 dw
0x0000 ;; PCI exclusive IRQs
9402 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9403 dw
0x7000 ;; compatible PCI interrupt router device ID
9404 dw
0,0 ;; Miniport data
9405 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9407 pci_routing_table_structure_start
:
9408 ;; first slot entry PCI
-to
-ISA (embedded
)
9409 db
0 ;; pci bus number
9410 db
0x08 ;; pci device
number (bit
7-3)
9411 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9412 dw
0xdef8 ;; IRQ bitmap INTA
#
9413 db
0x61 ;; link value INTB
#
9414 dw
0xdef8 ;; IRQ bitmap INTB
#
9415 db
0x62 ;; link value INTC
#
9416 dw
0xdef8 ;; IRQ bitmap INTC
#
9417 db
0x63 ;; link value INTD
#
9418 dw
0xdef8 ;; IRQ bitmap INTD
#
9419 db
0 ;; physical
slot (0 = embedded
)
9421 ;; second slot entry
: 1st PCI slot
9422 db
0 ;; pci bus number
9423 db
0x10 ;; pci device
number (bit
7-3)
9424 db
0x61 ;; link value INTA
#
9425 dw
0xdef8 ;; IRQ bitmap INTA
#
9426 db
0x62 ;; link value INTB
#
9427 dw
0xdef8 ;; IRQ bitmap INTB
#
9428 db
0x63 ;; link value INTC
#
9429 dw
0xdef8 ;; IRQ bitmap INTC
#
9430 db
0x60 ;; link value INTD
#
9431 dw
0xdef8 ;; IRQ bitmap INTD
#
9432 db
1 ;; physical
slot (0 = embedded
)
9434 ;; third slot entry
: 2nd PCI slot
9435 db
0 ;; pci bus number
9436 db
0x18 ;; pci device
number (bit
7-3)
9437 db
0x62 ;; link value INTA
#
9438 dw
0xdef8 ;; IRQ bitmap INTA
#
9439 db
0x63 ;; link value INTB
#
9440 dw
0xdef8 ;; IRQ bitmap INTB
#
9441 db
0x60 ;; link value INTC
#
9442 dw
0xdef8 ;; IRQ bitmap INTC
#
9443 db
0x61 ;; link value INTD
#
9444 dw
0xdef8 ;; IRQ bitmap INTD
#
9445 db
2 ;; physical
slot (0 = embedded
)
9447 ;; 4th slot entry
: 3rd PCI slot
9448 db
0 ;; pci bus number
9449 db
0x20 ;; pci device
number (bit
7-3)
9450 db
0x63 ;; link value INTA
#
9451 dw
0xdef8 ;; IRQ bitmap INTA
#
9452 db
0x60 ;; link value INTB
#
9453 dw
0xdef8 ;; IRQ bitmap INTB
#
9454 db
0x61 ;; link value INTC
#
9455 dw
0xdef8 ;; IRQ bitmap INTC
#
9456 db
0x62 ;; link value INTD
#
9457 dw
0xdef8 ;; IRQ bitmap INTD
#
9458 db
3 ;; physical
slot (0 = embedded
)
9460 ;; 5th slot entry
: 4rd PCI slot
9461 db
0 ;; pci bus number
9462 db
0x28 ;; pci device
number (bit
7-3)
9463 db
0x60 ;; link value INTA
#
9464 dw
0xdef8 ;; IRQ bitmap INTA
#
9465 db
0x61 ;; link value INTB
#
9466 dw
0xdef8 ;; IRQ bitmap INTB
#
9467 db
0x62 ;; link value INTC
#
9468 dw
0xdef8 ;; IRQ bitmap INTC
#
9469 db
0x63 ;; link value INTD
#
9470 dw
0xdef8 ;; IRQ bitmap INTD
#
9471 db
4 ;; physical
slot (0 = embedded
)
9473 ;; 6th slot entry
: 5rd PCI slot
9474 db
0 ;; pci bus number
9475 db
0x30 ;; pci device
number (bit
7-3)
9476 db
0x61 ;; link value INTA
#
9477 dw
0xdef8 ;; IRQ bitmap INTA
#
9478 db
0x62 ;; link value INTB
#
9479 dw
0xdef8 ;; IRQ bitmap INTB
#
9480 db
0x63 ;; link value INTC
#
9481 dw
0xdef8 ;; IRQ bitmap INTC
#
9482 db
0x60 ;; link value INTD
#
9483 dw
0xdef8 ;; IRQ bitmap INTD
#
9484 db
5 ;; physical
slot (0 = embedded
)
9486 pci_routing_table_structure_end
:
9492 pcibios_init_sel_reg
:
9504 pcibios_init_iomem_bases
:
9507 mov eax
, #0xe0000000 ;; base for memory init
9509 mov ax
, #0xc000 ;; base for i/o init
9511 mov ax
, #0x0010 ;; start at base address #0
9516 call pcibios_init_sel_reg
9521 mov dl
, #0x04 ;; disable i/o and memory space access
9522 call pcibios_init_sel_reg
9529 call pcibios_init_sel_reg
9535 mov eax
, #0xffffffff
9540 xor eax
, #0xffffffff
9544 add eax
, ecx
;; calculate next free mem base
9545 add eax
, #0x01000000
9546 and eax
, #0xff000000
9560 add ax
, cx
;; calculate next free i
/o base
9568 je enable_iomem_space
9569 mov byte ptr
[bp
-8], al
9570 jmp pci_init_io_loop2
9572 mov dl
, #0x04 ;; enable i/o and memory space access if available
9573 call pcibios_init_sel_reg
9579 mov byte ptr
[bp
-8], #0x10
9582 jne pci_init_io_loop1
9587 pcibios_init_set_elcr
:
9611 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9616 mov si
, #pci_routing_table_structure
9620 call pcibios_init_sel_reg
9623 cmp eax
, [si
+12] ;; check irq router
9626 call pcibios_init_sel_reg
9627 push bx
;; save irq router bus
+ devfunc
9630 out dx
, ax
;; reset PIRQ route control
9637 add si
, #0x20 ;; set pointer to 1st entry
9639 mov ax
, #pci_irq_list
9648 call pcibios_init_sel_reg
9652 jnz pci_test_int_pin
9658 call pcibios_init_sel_reg
9663 dec al
;; determine pirq reg
9672 call pcibios_init_sel_reg
9679 mov bx
, [bp
-2] ;; pci irq list pointer
9684 call pcibios_init_set_elcr
9688 add bl
, [bp
-3] ;; pci function number
9690 call pcibios_init_sel_reg
9697 jnz pci_init_irq_loop2
9700 mov byte ptr
[bp
-3], #0x00
9701 loop pci_init_irq_loop1
9708 #endif // BX_ROMBIOS32
9709 #endif // BX_PCIBIOS
9713 ;; save a20
and enable it
9719 ;; save SS
:SP to the BDA
9726 lidt
[pmode_IDT_info
]
9728 lgdt
[rombios32_gdt_48
]
9729 ;; set PE bit in CR0
9733 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
9736 dw
0x000f ;; high
16 bit address
9741 ;; init data segments
9751 ;; copy rombios32 code to
ram (ram offset
= 1MB
)
9752 mov esi
, #0xfffe0000
9753 mov edi
, #0x00040000
9754 mov ecx
, #0x10000 / 4
9758 ;; init the stack pointer
9759 mov esp
, #0x00080000
9761 ;; call rombios32 code
9762 mov eax
, #0x00040000
9765 ;; reset the
memory (some boot loaders such as syslinux suppose
9766 ;; that the memory is set to zero
)
9767 mov edi
, #0x00040000
9768 mov ecx
, #0x40000 / 4
9773 ;; return to
16 bit
protected mode first
9780 ;; restore data segment limits to
0xffff
9788 ;; reset PE bit in CR0
9793 ;; far jump to flush CPU queue after transition to real mode
9794 JMP_AP(0xf000, rombios32_real_mode
)
9796 rombios32_real_mode
:
9797 ;; restore IDT to normal real
-mode defaults
9799 lidt
[rmode_IDT_info
]
9807 ;; restore SS
:SP from the BDA
9824 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
9825 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
9826 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
9827 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
9831 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9836 and al
, #0xdf ; clear input mode
9846 mov
[bx
+0x408], dx
; Parallel I
/O address
9848 mov
[bx
+0x478], cl
; Parallel printer timeout
9853 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9872 mov
[bx
+0x400], dx
; Serial I
/O address
9874 mov
[bx
+0x47c], cl
; Serial timeout
9901 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
9902 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
9910 ;; Scan
for existence of valid expansion ROMS
.
9911 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9912 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9913 ;; System ROM
: only
0xE0000
9919 ;; 2 ROM length in
512-byte blocks
9920 ;; 3 ROM initialization entry
point (FAR CALL
)
9925 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9926 cmp
[0], #0xAA55 ;; look for signature
9927 jne rom_scan_increment
9929 jnz rom_scan_increment
9930 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9932 ;; We want our increment in
512-byte quantities
, rounded to
9933 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9935 jz block_count_rounded
9936 and al
, #0xfc ;; needs rounding up
9938 block_count_rounded
:
9940 xor bx
, bx
;; Restore DS back to
0000:
9944 ;; Push addr of ROM entry point
9946 push
#0x0003 ;; Push offset
9948 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
9949 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
9954 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9955 db
0xff ;; call_far ss
:[bp
+0]
9958 cli
;; In
case expansion ROM BIOS turns IF on
9959 add sp
, #2 ;; Pop offset value
9960 pop cx
;; Pop seg
value (restore CX
)
9962 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
9963 ;; to init all the ROMs
and then go back
and build an IPL table of
9964 ;; all the bootable devices
, but we can get away with one pass
.
9965 mov ds
, cx
;; ROM base
9966 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
9967 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
9968 cmp ax
, #0x5024 ;; we look for signature "$PnP"
9973 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
9974 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
9977 ;; Found a device that thinks it can boot the system
. Record its BEV
and product name string
.
9978 mov di
, 0x10[bx
] ;; Pointer to the product name string
or zero
if none
9979 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
9981 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
9982 cmp bx
, #IPL_TABLE_ENTRIES
9983 je no_bev
;; Get out
if the table is full
9984 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
9985 mov
0[bx
], #0x80 ;; This entry is a BEV device
9986 mov
6[bx
], cx
;; Build a far pointer from the segment
...
9987 mov
4[bx
], ax
;; and the offset
9990 mov
0xA[bx
], cx
;; Build a far pointer from the segment
...
9991 mov
8[bx
], di
;; and the offset
9993 shr bx
, #0x4 ;; Turn the offset back into a count
9994 inc bx
;; We have one more entry now
9995 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
9998 pop di
;; Restore DI
9999 pop ax
;; Restore AX
10000 rom_scan_increment
:
10001 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
10002 ;; because the segment selector is shifted left
4 bits
.
10007 xor ax
, ax
;; Restore DS back to
0000:
10011 ;; for 'C' strings
and other data
, insert them here with
10012 ;; a the following hack
:
10013 ;; DATA_SEG_DEFS_HERE
10016 ;; the following area can be used to write dynamically generated tables
10018 bios_table_area_start
:
10020 dd bios_table_area_end
- bios_table_area_start
- 8;
10025 .org
0xe05b ; POST Entry Point
10026 bios_table_area_end
:
10031 ;; first reset the DMA controllers
10035 ;; then initialize the DMA controllers
10037 out
0xD6, al
; cascade mode of channel
4 enabled
10039 out
0xD4, al
; unmask channel
4
10041 ;; Examine CMOS shutdown status
.
10049 ;; Reset CMOS shutdown status
.
10051 out
0x70, AL
; select CMOS
register Fh
10053 out
0x71, AL
; set shutdown action to normal
10055 ;; Examine CMOS shutdown status
.
10058 ;; 0x00, 0x09, 0x0D+ = normal startup
10066 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
10070 ;; Examine CMOS shutdown status
.
10071 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
10073 call _shutdown_status_panic
10079 ; 0xb0, 0x20, /* mov al, #0x20 */
10080 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10090 ; case 0: normal startup
10099 ;; zero out BIOS data
area (40:00..40:ff
)
10101 mov cx
, #0x0080 ;; 128 words
10107 call _log_bios_start
10109 ;; set all interrupts to
default handler
10110 xor bx
, bx
;; offset index
10111 mov cx
, #0x0100 ;; counter (256 interrupts)
10112 mov ax
, #dummy_iret_handler
10120 loop post_default_ints
10122 ;; set vector
0x79 to zero
10123 ;; this is used by
'gardian angel' protection system
10124 SET_INT_VECTOR(0x79, #0, #0)
10126 ;; base memory in K
40:13 (word
)
10127 mov ax
, #BASE_MEM_IN_K
10131 ;; Manufacturing Test
40:12
10134 ;; Warm Boot Flag
0040:0072
10135 ;; value of
1234h
= skip memory checks
10139 ;; Printer Services vector
10140 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10142 ;; Bootstrap failure vector
10143 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10145 ;; Bootstrap Loader vector
10146 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10148 ;; User Timer Tick vector
10149 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10151 ;; Memory Size Check vector
10152 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10154 ;; Equipment Configuration Check vector
10155 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10158 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10164 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10165 ;; int 1C already points at
dummy_iret_handler (above
)
10166 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10168 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10173 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10174 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10178 mov
0x0417, al
/* keyboard shift flags, set 1 */
10179 mov
0x0418, al
/* keyboard shift flags, set 2 */
10180 mov
0x0419, al
/* keyboard alt-numpad work area */
10181 mov
0x0471, al
/* keyboard ctrl-break flag */
10182 mov
0x0497, al
/* keyboard status flags 4 */
10184 mov
0x0496, al
/* keyboard status flags 3 */
10187 /* keyboard head of buffer pointer */
10191 /* keyboard end of buffer pointer */
10194 /* keyboard pointer to start of buffer */
10198 /* keyboard pointer to end of buffer */
10202 /* init the keyboard */
10203 call _keyboard_init
10205 ;; mov CMOS Equipment Byte to BDA Equipment Word
10214 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10218 mov cl
, #0x14 ; timeout value
10219 mov dx
, #0x378 ; Parallel I/O address, port 1
10220 call detect_parport
10221 mov dx
, #0x278 ; Parallel I/O address, port 2
10222 call detect_parport
10224 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10226 or ax
, bx
; set number of parallel ports
10230 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10231 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10233 mov cl
, #0x0a ; timeout value
10234 mov dx
, #0x03f8 ; Serial I/O address, port 1
10236 mov dx
, #0x02f8 ; Serial I/O address, port 2
10238 mov dx
, #0x03e8 ; Serial I/O address, port 3
10240 mov dx
, #0x02e8 ; Serial I/O address, port 4
10243 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10245 or ax
, bx
; set number of serial port
10249 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10250 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10251 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10252 ;; BIOS DATA AREA
0x4CE ???
10253 call timer_tick_post
10255 ;; PS
/2 mouse setup
10256 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10258 ;; IRQ13 (FPU exception
) setup
10259 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10262 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10265 mov al
, #0x11 ; send initialisation commands
10280 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10281 #if BX_USE_PS2_MOUSE
10286 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10289 call rombios32_init
10292 call pcibios_init_iomem_bases
10293 call pcibios_init_irqs
10294 #endif //BX_PCIBIOS
10297 call _init_boot_vectors
10301 call _print_bios_banner
10306 call floppy_drive_post
10311 ;; Hard Drive setup
10313 call hard_drive_post
10316 ;; ATA
/ATAPI driver setup
10321 #else // BX_USE_ATADRV
10324 ;; Hard Drive setup
10326 call hard_drive_post
10328 #endif // BX_USE_ATADRV
10330 #if BX_ELTORITO_BOOT
10332 ;; eltorito floppy
/harddisk emulation from cd
10336 #endif // BX_ELTORITO_BOOT
10338 sti
;; enable interrupts
10342 .org
0xe2c3 ; NMI Handler Entry Point
10344 ;; FIXME the NMI handler should
not panic
10345 ;; but iret when called from
int75 (fpu exception
)
10346 call _nmi_handler_msg
10350 out
0xf0, al
// clear irq13
10351 call eoi_both_pics
// clear interrupt
10352 int 2 // legacy nmi call
10355 ;-------------------------------------------
10356 ;- INT
13h Fixed Disk Services Entry Point
-
10357 ;-------------------------------------------
10358 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10360 //JMPL(int13_relocated)
10361 jmp int13_relocated
10363 .org
0xe401 ; Fixed Disk Parameter Table
10368 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10371 jmp int19_relocated
10372 ;-------------------------------------------
10373 ;- System BIOS Configuration Data Table
10374 ;-------------------------------------------
10375 .org BIOS_CONFIG_TABLE
10376 db
0x08 ; Table
size (bytes
) -Lo
10377 db
0x00 ; Table
size (bytes
) -Hi
10382 ; b7
: 1=DMA channel
3 used by hard disk
10383 ; b6
: 1=2 interrupt controllers present
10384 ; b5
: 1=RTC present
10385 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10386 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10387 ; b2
: 1=extended BIOS data area used
10388 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10389 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10393 (BX_CALL_INT15_4F
<< 4) | \
10395 (BX_USE_EBDA
<< 2) | \
10399 ; b7
: 1=32-bit DMA supported
10400 ; b6
: 1=int16h
, function
9 supported
10401 ; b5
: 1=int15h
/C6h (get POS data
) supported
10402 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10403 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10404 ; b2
: 1=non
-8042 kb controller
10405 ; b1
: 1=data streaming supported
10419 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10420 ; b3
: SCSI on system board
10421 ; b2
: info panel installed
10422 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10423 ; b0
: SCSI supported in IML
10427 ; b6
: EEPROM present
10428 ; b5
-3: ABIOS
presence (011 = not supported
)
10430 ; b1
: memory split above
16Mb supported
10431 ; b0
: POSTEXT directly supported by POST
10433 ; Feature byte
5 (IBM
)
10434 ; b1
: enhanced mouse
10440 .org
0xe729 ; Baud Rate Generator Table
10445 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10451 call _int14_function
10457 ;----------------------------------------
10458 ;- INT
16h Keyboard Service Entry Point
-
10459 ;----------------------------------------
10475 call _int16_function
10485 and BYTE
[bp
+ 0x06], #0xbf
10493 or BYTE
[bp
+ 0x06], #0x40
10501 int16_wait_for_key
:
10505 jne int16_key_found
10509 /* no key yet, call int 15h, function AX=9002 */
10510 0x50, /* push AX */
10511 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10512 0xcd, 0x15, /* int 15h */
10514 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10516 jmp int16_wait_for_key
10521 call _int16_function
10526 /* notify int16 complete w/ int 15h, function AX=9102 */
10527 0x50, /* push AX */
10528 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10529 0xcd, 0x15, /* int 15h */
10536 ;-------------------------------------------------
10537 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10538 ;-------------------------------------------------
10544 mov al
, #0xAD ;;disable keyboard
10553 in al
, #0x60 ;;read key from keyboard controller
10557 #ifdef BX_CALL_INT15_4F
10558 mov ah
, #0x4f ;; allow for keyboard intercept
10564 ;; check
for extended key
10566 jne int09_check_pause
10569 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10571 mov BYTE
[0x496], al
10574 int09_check_pause
: ;; check
for pause key
10576 jne int09_process_key
10579 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10581 mov BYTE
[0x496], al
10587 call _int09_function
10593 call eoi_master_pic
10596 mov al
, #0xAE ;;enable keyboard
10602 ;----------------------------------------
10603 ;- INT
13h Diskette Service Entry Point
-
10604 ;----------------------------------------
10607 jmp int13_noeltorito
10609 ;---------------------------------------------
10610 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10611 ;---------------------------------------------
10612 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10622 mov al
, #0x08 ; sense interrupt status
10640 xor ax
, ax
;; segment
0000
10642 call eoi_master_pic
10644 or al
, #0x80 ;; diskette interrupt has occurred
10652 .org
0xefc7 ; Diskette Controller Parameter Table
10653 diskette_param_table
:
10654 ;; Since no provisions are made
for multiple drive types
, most
10655 ;; values in
this table are ignored
. I set parameters
for 1.44M
10658 db
0x02 ;; head load time
0000001, DMA used
10670 ;----------------------------------------
10671 ;- INT17h
: Printer Service Entry Point
-
10672 ;----------------------------------------
10679 call _int17_function
10684 diskette_param_table2
:
10685 ;; New diskette parameter table adding
3 parameters from IBM
10686 ;; Since no provisions are made
for multiple drive types
, most
10687 ;; values in
this table are ignored
. I set parameters
for 1.44M
10690 db
0x02 ;; head load time
0000001, DMA used
10700 db
79 ;; maximum track
10701 db
0 ;; data transfer rate
10702 db
4 ;; drive type in cmos
10704 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10711 .org
0xf065 ; INT
10h Video Support Service Entry Point
10713 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10716 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10721 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10722 ; ??? different
for Pentium (machine check
)?
10734 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10746 .org
0xf859 ; INT
15h System Services Entry Point
10760 #if BX_USE_PS2_MOUSE
10762 je int15_handler_mouse
10764 call _int15_function
10765 int15_handler_mouse_ret
:
10767 int15_handler32_ret
:
10777 #if BX_USE_PS2_MOUSE
10778 int15_handler_mouse
:
10779 call _int15_function_mouse
10780 jmp int15_handler_mouse_ret
10785 call _int15_function32
10787 jmp int15_handler32_ret
10789 ;; Protected mode IDT descriptor
10791 ;; I just make the limit
0, so the machine will shutdown
10792 ;; if an exception occurs during
protected mode memory
10795 ;; Set base to f0000 to correspond to beginning of BIOS
,
10796 ;; in
case I actually define an IDT later
10800 dw
0x0000 ;; limit
15:00
10801 dw
0x0000 ;; base
15:00
10802 db
0x0f ;; base
23:16
10804 ;; Real mode IDT descriptor
10806 ;; Set to typical real
-mode values
.
10811 dw
0x03ff ;; limit
15:00
10812 dw
0x0000 ;; base
15:00
10813 db
0x00 ;; base
23:16
10819 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10832 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10833 mov ds
, ax
; on
16bit
protected mode
.
10834 jmp int1a_callfunction
10841 int1a_callfunction
:
10842 call _int1a_function
10848 ;; int70h
: IRQ8
- CMOS RTC
10855 call _int70_function
10863 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10871 ;; time to turn off
drive(s
)?
10874 jz int08_floppy_off
10877 jnz int08_floppy_off
10878 ;; turn
motor(s
) off
10887 mov eax
, 0x046c ;; get ticks dword
10890 ;; compare eax to one days worth of timer ticks at
18.2 hz
10891 cmp eax
, #0x001800B0
10892 jb int08_store_ticks
10893 ;; there has been a midnight rollover at
this point
10894 xor eax
, eax
;; zero out counter
10895 inc BYTE
0x0470 ;; increment rollover flag
10898 mov
0x046c, eax
;; store
new ticks dword
10899 ;; chain to user timer tick INT
#0x1c
10901 //;; call_ep [ds:loc]
10902 //CALL_EP( 0x1c << 2 )
10905 call eoi_master_pic
10910 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10914 .ascii BIOS_COPYRIGHT_STRING
10916 ;------------------------------------------------
10917 ;- IRET Instruction
for Dummy Interrupt Handler
-
10918 ;------------------------------------------------
10919 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10920 dummy_iret_handler
:
10923 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10927 .org
0xfff0 ; Power
-up Entry Point
10930 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10931 .ascii BIOS_BUILD_DATE
10933 .org
0xfffe ; System Model ID
10937 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10940 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10941 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10942 * This font is public domain
10944 static Bit8u vgafont8
[128*8]=
10946 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10947 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10948 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10949 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10950 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10951 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10952 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10953 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10954 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10955 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10956 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10957 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10958 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10959 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10960 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10961 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10962 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10963 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10964 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10965 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10966 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10967 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10968 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10969 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10970 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10971 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10972 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10973 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10974 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10975 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10976 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10977 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10979 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10980 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10981 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10982 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10983 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10984 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10985 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10986 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10987 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10988 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10989 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10990 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10991 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10992 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10993 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10994 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10995 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10996 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10997 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10998 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10999 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11000 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11001 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11002 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11003 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11004 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11005 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11006 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11007 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11008 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11009 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11010 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11011 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11012 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11013 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11014 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11015 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11016 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11017 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11018 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11019 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11020 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11021 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11022 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11023 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11024 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11025 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11026 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11027 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11028 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11029 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11030 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11031 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11032 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11033 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11034 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11035 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11036 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11037 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11038 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11039 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11040 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11042 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11043 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11044 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11045 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11046 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11047 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11048 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11049 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11050 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11051 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11052 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11053 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11054 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11055 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11056 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11057 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11058 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11059 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11060 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11061 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11062 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11063 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11064 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11065 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11066 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11067 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11068 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11069 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11070 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11071 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11072 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11073 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11078 // bcc-generated data will be placed here