1 /////////////////////////////////////////////////////////////////////////
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
128 #define DEBUG_INT13_HD 0
129 #define DEBUG_INT13_CD 0
130 #define DEBUG_INT13_ET 0
131 #define DEBUG_INT13_FL 0
132 #define DEBUG_INT15 0
133 #define DEBUG_INT16 0
134 #define DEBUG_INT1A 0
135 #define DEBUG_INT74 0
139 #define BX_USE_PS2_MOUSE 1
140 #define BX_CALL_INT15_4F 1
141 #define BX_USE_EBDA 1
142 #define BX_SUPPORT_FLOPPY 1
143 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
147 #define BX_USE_ATADRV 1
148 #define BX_ELTORITO_BOOT 1
150 #define BX_MAX_ATA_INTERFACES 4
151 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
153 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
154 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
156 /* model byte 0xFC = AT */
157 #define SYS_MODEL_ID 0xFC
158 #define SYS_SUBMODEL_ID 0x00
159 #define BIOS_REVISION 1
160 #define BIOS_CONFIG_TABLE 0xe6f5
162 #ifndef BIOS_BUILD_DATE
163 # define BIOS_BUILD_DATE "06/23/99"
166 // 1K of base memory used for Extended Bios Data Area (EBDA)
167 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
168 #define EBDA_SEG 0x9FC0
169 #define EBDA_SIZE 1 // In KiB
170 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
172 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
173 #define IPL_SEG 0x9ff0
174 #define IPL_TABLE_OFFSET 0x0000
175 #define IPL_TABLE_ENTRIES 8
176 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
177 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
178 #define IPL_BOOTFIRST_OFFSET 0x0084 /* u16: user selected device */
179 #define IPL_SIZE 0xff
180 #define IPL_TYPE_FLOPPY 0x01
181 #define IPL_TYPE_HARDDISK 0x02
182 #define IPL_TYPE_CDROM 0x03
183 #define IPL_TYPE_BEV 0x80
186 #if BX_USE_ATADRV && BX_CPU<3
187 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
189 #if BX_USE_ATADRV && !BX_USE_EBDA
190 # error ATA/ATAPI Driver can only be used if EBDA is available
192 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
193 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
195 #if BX_PCIBIOS && BX_CPU<3
196 # error PCI BIOS can only be used with 386+ cpu
198 #if BX_APM && BX_CPU<3
199 # error APM BIOS can only be used with 386+ cpu
202 // define this if you want to make PCIBIOS working on a specific bridge only
203 // undef enables PCIBIOS when at least one PCI device is found
204 // i440FX is emulated by Bochs and QEMU
205 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
208 // #$20 is hex 20 = 32
209 // #0x20 is hex 20 = 32
216 // all hex literals should be prefixed with '0x'
217 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
218 // no mov SEG-REG, #value, must mov register into seg-reg
219 // grep -i "mov[ ]*.s" rombios.c
221 // This is for compiling with gcc2 and gcc3
222 #define ASM_START #asm
223 #define ASM_END #endasm
237 ;; the HALT macro is called with the line number of the HALT call
.
238 ;; The line number is then sent to the PANIC_PORT
, causing Bochs
/Plex
239 ;; to print a BX_PANIC message
. This will normally halt the simulation
240 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
241 ;; However
, users can choose to make panics non
-fatal
and continue.
268 typedef unsigned char Bit8u
;
269 typedef unsigned short Bit16u
;
270 typedef unsigned short bx_bool
;
271 typedef unsigned long Bit32u
;
274 void memsetb(seg
,offset
,value
,count
);
275 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
276 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
278 // memset of count bytes
280 memsetb(seg
,offset
,value
,count
)
295 mov cx
, 10[bp
] ; count
298 mov ax
, 4[bp
] ; segment
300 mov ax
, 6[bp
] ; offset
302 mov al
, 8[bp
] ; value
317 // memcpy of count bytes
319 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
337 mov cx
, 12[bp
] ; count
340 mov ax
, 4[bp
] ; dsegment
342 mov ax
, 6[bp
] ; doffset
344 mov ax
, 8[bp
] ; ssegment
346 mov ax
, 10[bp
] ; soffset
364 // memcpy of count dword
366 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
384 mov cx
, 12[bp
] ; count
387 mov ax
, 4[bp
] ; dsegment
389 mov ax
, 6[bp
] ; doffset
391 mov ax
, 8[bp
] ; ssegment
393 mov ax
, 10[bp
] ; soffset
411 // read_dword and write_dword functions
412 static Bit32u
read_dword();
413 static void write_dword();
416 read_dword(seg
, offset
)
426 mov ax
, 4[bp
] ; segment
428 mov bx
, 6[bp
] ; offset
432 ;; ax
= return value (word
)
433 ;; dx
= return value (word
)
442 write_dword(seg
, offset
, data
)
454 mov ax
, 4[bp
] ; segment
456 mov bx
, 6[bp
] ; offset
457 mov ax
, 8[bp
] ; data word
458 mov
[bx
], ax
; write data word
460 mov ax
, 10[bp
] ; data word
461 mov
[bx
], ax
; write data word
470 // Bit32u (unsigned long) and long helper functions
499 cmp eax
, dword ptr
[di
]
518 mul eax
, dword ptr
[di
]
614 // for access to RAM area which is used by interrupt vectors
615 // and BIOS Data Area
618 unsigned char filler1
[0x400];
619 unsigned char filler2
[0x6c];
625 #define BiosData ((bios_data_t *) 0)
629 Bit16u heads
; // # heads
630 Bit16u cylinders
; // # cylinders
631 Bit16u spt
; // # sectors / track
651 Bit8u iface
; // ISA or PCI
652 Bit16u iobase1
; // IO Base 1
653 Bit16u iobase2
; // IO Base 2
658 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
659 Bit8u device
; // Detected type of attached devices (hd/cd/none)
660 Bit8u removable
; // Removable device flag
661 Bit8u lock
; // Locks for removable devices
662 Bit8u mode
; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
663 Bit16u blksize
; // block size
665 Bit8u translation
; // type of translation
666 chs_t lchs
; // Logical CHS
667 chs_t pchs
; // Physical CHS
669 Bit32u sectors_low
; // Total sectors count
675 ata_channel_t channels
[BX_MAX_ATA_INTERFACES
];
678 ata_device_t devices
[BX_MAX_ATA_DEVICES
];
680 // map between (bios hd id - 0x80) and ata channels
681 Bit8u hdcount
, hdidmap
[BX_MAX_ATA_DEVICES
];
683 // map between (bios cd id - 0xE0) and ata channels
684 Bit8u cdcount
, cdidmap
[BX_MAX_ATA_DEVICES
];
686 // Buffer for DPTE table
689 // Count of transferred sectors and bytes
695 // ElTorito Device Emulation data
699 Bit8u emulated_drive
;
700 Bit8u controller_index
;
703 Bit16u buffer_segment
;
710 #endif // BX_ELTORITO_BOOT
712 // for access to EBDA area
713 // The EBDA structure should conform to
714 // http://www.frontiernet.net/~fys/rombios.htm document
715 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
716 // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot
717 // device tables are at IPL_SEG
719 unsigned char filler1
[0x3D];
721 // FDPT - Can be splitted in data members if needed
722 unsigned char fdpt0
[0x10];
723 unsigned char fdpt1
[0x10];
725 unsigned char filler2
[0xC4];
731 // El Torito Emulation data
733 #endif // BX_ELTORITO_BOOT
736 #define EbdaData ((ebda_data_t *) 0)
738 // for access to the int13ext structure
749 #define Int13Ext ((int13ext_t *) 0)
751 // Disk Physical Table definition
758 Bit32u sector_count1
;
759 Bit32u sector_count2
;
770 Bit8u device_path
[8];
775 #define Int13DPT ((dpt_t *) 0)
777 #endif // BX_USE_ATADRV
782 Bit16u di
, si
, bp
, sp
;
783 Bit16u bx
, dx
, cx
, ax
;
787 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
795 Bit32u edi
, esi
, ebp
, esp
;
796 Bit32u ebx
, edx
, ecx
, eax
;
799 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
800 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
828 #define SetCF(x) x.u.r8.flagsl |= 0x01
829 #define SetZF(x) x.u.r8.flagsl |= 0x40
830 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
831 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
832 #define GetCF(x) (x.u.r8.flagsl & 0x01)
850 static Bit8u
inb_cmos();
852 static void outb_cmos();
855 static void init_rtc();
856 static bx_bool
rtc_updating();
858 static Bit8u
read_byte();
859 static Bit16u
read_word();
860 static void write_byte();
861 static void write_word();
862 static void bios_printf();
864 static Bit8u
inhibit_mouse_int_and_events();
865 static void enable_mouse_int_and_events();
866 static Bit8u
send_to_mouse_ctrl();
867 static Bit8u
get_mouse_data();
868 static void set_kbd_command_byte();
870 static void int09_function();
871 static void int13_harddisk();
872 static void int13_cdrom();
873 static void int13_cdemu();
874 static void int13_eltorito();
875 static void int13_diskette_function();
876 static void int14_function();
877 static void int15_function();
878 static void int16_function();
879 static void int17_function();
880 static void int19_function();
881 static void int1a_function();
882 static void int70_function();
883 static void int74_function();
884 static Bit16u
get_CS();
885 static Bit16u
get_SS();
886 static unsigned int enqueue_key();
887 static unsigned int dequeue_key();
888 static void get_hd_geometry();
889 static void set_diskette_ret_status();
890 static void set_diskette_current_cyl();
891 static void determine_floppy_media();
892 static bx_bool
floppy_drive_exists();
893 static bx_bool
floppy_drive_recal();
894 static bx_bool
floppy_media_known();
895 static bx_bool
floppy_media_sense();
896 static bx_bool
set_enable_a20();
897 static void debugger_on();
898 static void debugger_off();
899 static void keyboard_init();
900 static void keyboard_panic();
901 static void shutdown_status_panic();
902 static void nmi_handler_msg();
903 static void delay_ticks();
904 static void delay_ticks_and_check_for_keystroke();
906 static void interactive_bootkey();
907 static void print_bios_banner();
908 static void print_boot_device();
909 static void print_boot_failure();
910 static void print_cdromboot_failure();
914 // ATA / ATAPI driver
919 Bit16u
ata_cmd_non_data();
920 Bit16u
ata_cmd_data_in();
921 Bit16u
ata_cmd_data_out();
922 Bit16u
ata_cmd_packet();
924 Bit16u
atapi_get_sense();
925 Bit16u
atapi_is_ready();
926 Bit16u
atapi_is_cdrom();
928 #endif // BX_USE_ATADRV
933 Bit8u
cdemu_isactive();
934 Bit8u
cdemu_emulated_drive();
938 #endif // BX_ELTORITO_BOOT
940 static char bios_cvs_version_string
[] = "$Revision$ $Date$";
942 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
945 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
947 # define BX_DEBUG_ATA(a...)
950 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
952 # define BX_DEBUG_INT13_HD(a...)
955 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
957 # define BX_DEBUG_INT13_CD(a...)
960 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
962 # define BX_DEBUG_INT13_ET(a...)
965 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
967 # define BX_DEBUG_INT13_FL(a...)
970 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
972 # define BX_DEBUG_INT15(a...)
975 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
977 # define BX_DEBUG_INT16(a...)
980 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
982 # define BX_DEBUG_INT1A(a...)
985 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
987 # define BX_DEBUG_INT74(a...)
990 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
991 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
992 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
993 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
994 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
995 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
996 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
997 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
999 #define GET_AL() ( AX & 0x00ff )
1000 #define GET_BL() ( BX & 0x00ff )
1001 #define GET_CL() ( CX & 0x00ff )
1002 #define GET_DL() ( DX & 0x00ff )
1003 #define GET_AH() ( AX >> 8 )
1004 #define GET_BH() ( BX >> 8 )
1005 #define GET_CH() ( CX >> 8 )
1006 #define GET_DH() ( DX >> 8 )
1008 #define GET_ELDL() ( ELDX & 0x00ff )
1009 #define GET_ELDH() ( ELDX >> 8 )
1011 #define SET_CF() FLAGS |= 0x0001
1012 #define CLEAR_CF() FLAGS &= 0xfffe
1013 #define GET_CF() (FLAGS & 0x0001)
1015 #define SET_ZF() FLAGS |= 0x0040
1016 #define CLEAR_ZF() FLAGS &= 0xffbf
1017 #define GET_ZF() (FLAGS & 0x0040)
1019 #define UNSUPPORTED_FUNCTION 0x86
1022 #define MAX_SCAN_CODE 0x58
1030 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1031 { none
, none
, none
, none
, none
},
1032 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1033 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1034 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1035 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1036 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1037 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1038 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1039 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1040 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1041 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1042 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1043 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1044 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1045 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1046 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1047 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1048 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1049 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1050 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1051 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1052 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1053 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1054 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1055 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1056 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1057 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1058 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1059 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1060 { none
, none
, none
, none
, none
}, /* L Ctrl */
1061 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1062 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1063 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1064 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1065 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1066 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1067 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1068 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1069 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1070 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1071 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1072 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1073 { none
, none
, none
, none
, none
}, /* L shift */
1074 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1075 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1076 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1077 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1078 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1079 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1080 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1081 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1082 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1083 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1084 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1085 { none
, none
, none
, none
, none
}, /* R Shift */
1086 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1087 { none
, none
, none
, none
, none
}, /* L Alt */
1088 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1089 { none
, none
, none
, none
, none
}, /* caps lock */
1090 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1091 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1092 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1093 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1094 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1095 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1096 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1097 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1098 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1099 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1100 { none
, none
, none
, none
, none
}, /* Num Lock */
1101 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1102 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1103 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1104 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1105 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1106 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1107 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1108 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1109 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1110 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1111 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1112 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1113 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1114 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1115 { none
, none
, none
, none
, none
},
1116 { none
, none
, none
, none
, none
},
1117 { 0x565c, 0x567c, none
, none
, none
}, /* \| */
1118 { 0x8500, 0x8700, 0x8900, 0x8b00, none
}, /* F11 */
1119 { 0x8600, 0x8800, 0x8a00, 0x8c00, none
}, /* F12 */
1203 outb_cmos(cmos_reg
, val
)
1211 mov al
, 4[bp
] ;; cmos_reg
1213 mov al
, 6[bp
] ;; val
1228 mov al
, 4[bp
] ;; cmos_reg
1239 outb_cmos(0x0a, 0x26);
1240 outb_cmos(0x0b, 0x02);
1248 // This function checks to see if the update-in-progress bit
1249 // is set in CMOS Status Register A. If not, it returns 0.
1250 // If it is set, it tries to wait until there is a transition
1251 // to 0, and will return 0 if such a transition occurs. A 1
1252 // is returned only after timing out. The maximum period
1253 // that this bit should be set is constrained to 244useconds.
1254 // The count I use below guarantees coverage or more than
1255 // this time, with any reasonable IPS setting.
1260 while (--count
!= 0) {
1261 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1264 return(1); // update-in-progress never transitioned to 0
1269 read_byte(seg
, offset
)
1279 mov ax
, 4[bp
] ; segment
1281 mov bx
, 6[bp
] ; offset
1283 ;; al
= return value (byte
)
1292 read_word(seg
, offset
)
1302 mov ax
, 4[bp
] ; segment
1304 mov bx
, 6[bp
] ; offset
1306 ;; ax
= return value (word
)
1315 write_byte(seg
, offset
, data
)
1327 mov ax
, 4[bp
] ; segment
1329 mov bx
, 6[bp
] ; offset
1330 mov al
, 8[bp
] ; data byte
1331 mov
[bx
], al
; write data byte
1341 write_word(seg
, offset
, data
)
1353 mov ax
, 4[bp
] ; segment
1355 mov bx
, 6[bp
] ; offset
1356 mov ax
, 8[bp
] ; data word
1357 mov
[bx
], ax
; write data word
1383 /* serial debug port*/
1384 #define BX_DEBUG_PORT 0x03f8
1387 #define UART_RBR 0x00
1388 #define UART_THR 0x00
1391 #define UART_IER 0x01
1392 #define UART_IIR 0x02
1393 #define UART_FCR 0x02
1394 #define UART_LCR 0x03
1395 #define UART_MCR 0x04
1396 #define UART_DLL 0x00
1397 #define UART_DLM 0x01
1400 #define UART_LSR 0x05
1401 #define UART_MSR 0x06
1402 #define UART_SCR 0x07
1404 int uart_can_tx_byte(base_port
)
1407 return inb(base_port
+ UART_LSR
) & 0x20;
1410 void uart_wait_to_tx_byte(base_port
)
1413 while (!uart_can_tx_byte(base_port
));
1416 void uart_wait_until_sent(base_port
)
1419 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1422 void uart_tx_byte(base_port
, data
)
1426 uart_wait_to_tx_byte(base_port
);
1427 outb(base_port
+ UART_THR
, data
);
1428 uart_wait_until_sent(base_port
);
1457 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1458 uart_tx_byte(BX_DEBUG_PORT
, c
);
1460 #if BX_VIRTUAL_PORTS
1461 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1462 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1464 if (action
& BIOS_PRINTF_SCREEN
) {
1465 if (c
== '\n') wrch('\r');
1471 put_int(action
, val
, width
, neg
)
1476 short nval
= val
/ 10;
1478 put_int(action
, nval
, width
- 1, neg
);
1480 while (--width
> 0) send(action
, ' ');
1481 if (neg
) send(action
, '-');
1483 send(action
, val
- (nval
* 10) + '0');
1487 put_uint(action
, val
, width
, neg
)
1493 unsigned short nval
= val
/ 10;
1495 put_uint(action
, nval
, width
- 1, neg
);
1497 while (--width
> 0) send(action
, ' ');
1498 if (neg
) send(action
, '-');
1500 send(action
, val
- (nval
* 10) + '0');
1504 put_luint(action
, val
, width
, neg
)
1510 unsigned long nval
= val
/ 10;
1512 put_luint(action
, nval
, width
- 1, neg
);
1514 while (--width
> 0) send(action
, ' ');
1515 if (neg
) send(action
, '-');
1517 send(action
, val
- (nval
* 10) + '0');
1520 void put_str(action
, segment
, offset
)
1527 while (c
= read_byte(segment
, offset
)) {
1537 long ticks_to_wait
, delta
;
1538 Bit32u prev_ticks
, t
;
1541 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
1542 * We also have to be careful about interrupt storms.
1548 ticks_to_wait
= ticks
;
1549 prev_ticks
= read_dword(0x0, 0x46c);
1555 t
= read_dword(0x0, 0x46c);
1558 delta
= t
- prev_ticks
; /* The temp var is required or bcc screws up. */
1559 ticks_to_wait
-= delta
;
1561 else if (t
< prev_ticks
)
1563 ticks_to_wait
-= t
; /* wrapped */
1567 } while (ticks_to_wait
> 0);
1575 check_for_keystroke()
1600 delay_ticks_and_check_for_keystroke(ticks
, count
)
1601 Bit16u ticks
, count
;
1604 for (i
= 1; i
<= count
; i
++) {
1606 if (check_for_keystroke())
1611 //--------------------------------------------------------------------------
1613 // A compact variable argument printf function.
1615 // Supports %[format_width][length]format
1616 // where format can be x,X,u,d,s,S,c
1617 // and the optional length modifier is l (ell)
1618 //--------------------------------------------------------------------------
1620 bios_printf(action
, s
)
1624 Bit8u c
, format_char
;
1628 Bit16u arg_seg
, arg
, nibble
, hibyte
, shift_count
, format_width
, hexadd
;
1636 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1637 #if BX_VIRTUAL_PORTS
1638 outb(PANIC_PORT2
, 0x00);
1640 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1643 while (c
= read_byte(get_CS(), s
)) {
1648 else if (in_format
) {
1649 if ( (c
>='0') && (c
<='9') ) {
1650 format_width
= (format_width
* 10) + (c
- '0');
1653 arg_ptr
++; // increment to next arg
1654 arg
= read_word(arg_seg
, arg_ptr
);
1655 if (c
== 'x' || c
== 'X') {
1656 if (format_width
== 0)
1662 for (i
=format_width
-1; i
>=0; i
--) {
1663 nibble
= (arg
>> (4 * i
)) & 0x000f;
1664 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1667 else if (c
== 'u') {
1668 put_uint(action
, arg
, format_width
, 0);
1670 else if (c
== 'l') {
1672 c
= read_byte(get_CS(), s
); /* is it ld,lx,lu? */
1673 arg_ptr
++; /* increment to next arg */
1674 hibyte
= read_word(arg_seg
, arg_ptr
);
1676 if (hibyte
& 0x8000)
1677 put_luint(action
, 0L-(((Bit32u
) hibyte
<< 16) | arg
), format_width
-1, 1);
1679 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1681 else if (c
== 'u') {
1682 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1684 else if (c
== 'x' || c
== 'X')
1686 if (format_width
== 0)
1692 for (i
=format_width
-1; i
>=0; i
--) {
1693 nibble
= ((((Bit32u
) hibyte
<<16) | arg
) >> (4 * i
)) & 0x000f;
1694 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1698 else if (c
== 'd') {
1700 put_int(action
, -arg
, format_width
- 1, 1);
1702 put_int(action
, arg
, format_width
, 0);
1704 else if (c
== 's') {
1705 put_str(action
, get_CS(), arg
);
1707 else if (c
== 'S') {
1710 arg
= read_word(arg_seg
, arg_ptr
);
1711 put_str(action
, hibyte
, arg
);
1713 else if (c
== 'c') {
1717 BX_PANIC("bios_printf: unknown format\n");
1727 if (action
& BIOS_PRINTF_HALT
) {
1728 // freeze in a busy loop.
1738 //--------------------------------------------------------------------------
1740 //--------------------------------------------------------------------------
1741 // this file is based on LinuxBIOS implementation of keyboard.c
1742 // could convert to #asm to gain space
1748 /* ------------------- Flush buffers ------------------------*/
1749 /* Wait until buffer is empty */
1751 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1753 /* flush incoming keys */
1757 if (inb(0x64) & 0x01) {
1763 // Due to timer issues, and if the IPS setting is > 15000000,
1764 // the incoming keys might not be flushed here. That will
1765 // cause a panic a few lines below. See sourceforge bug report :
1766 // [ 642031 ] FATAL: Keyboard RESET error:993
1768 /* ------------------- controller side ----------------------*/
1769 /* send cmd = 0xAA, self test 8042 */
1772 /* Wait until buffer is empty */
1774 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1775 if (max
==0x0) keyboard_panic(00);
1779 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1780 if (max
==0x0) keyboard_panic(01);
1782 /* read self-test result, 0x55 should be returned from 0x60 */
1783 if ((inb(0x60) != 0x55)){
1784 keyboard_panic(991);
1787 /* send cmd = 0xAB, keyboard interface test */
1790 /* Wait until buffer is empty */
1792 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1793 if (max
==0x0) keyboard_panic(10);
1797 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1798 if (max
==0x0) keyboard_panic(11);
1800 /* read keyboard interface test result, */
1801 /* 0x00 should be returned form 0x60 */
1802 if ((inb(0x60) != 0x00)) {
1803 keyboard_panic(992);
1806 /* Enable Keyboard clock */
1810 /* ------------------- keyboard side ------------------------*/
1811 /* reset kerboard and self test (keyboard side) */
1814 /* Wait until buffer is empty */
1816 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1817 if (max
==0x0) keyboard_panic(20);
1821 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1822 if (max
==0x0) keyboard_panic(21);
1824 /* keyboard should return ACK */
1825 if ((inb(0x60) != 0xfa)) {
1826 keyboard_panic(993);
1831 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1832 if (max
==0x0) keyboard_panic(31);
1834 if ((inb(0x60) != 0xaa)) {
1835 keyboard_panic(994);
1838 /* Disable keyboard */
1841 /* Wait until buffer is empty */
1843 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1844 if (max
==0x0) keyboard_panic(40);
1848 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1849 if (max
==0x0) keyboard_panic(41);
1851 /* keyboard should return ACK */
1852 if ((inb(0x60) != 0xfa)) {
1853 keyboard_panic(995);
1856 /* Write Keyboard Mode */
1859 /* Wait until buffer is empty */
1861 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1862 if (max
==0x0) keyboard_panic(50);
1864 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1867 /* Wait until buffer is empty */
1869 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1870 if (max
==0x0) keyboard_panic(60);
1872 /* Enable keyboard */
1875 /* Wait until buffer is empty */
1877 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1878 if (max
==0x0) keyboard_panic(70);
1882 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1883 if (max
==0x0) keyboard_panic(70);
1885 /* keyboard should return ACK */
1886 if ((inb(0x60) != 0xfa)) {
1887 keyboard_panic(996);
1893 //--------------------------------------------------------------------------
1895 //--------------------------------------------------------------------------
1897 keyboard_panic(status
)
1900 // If you're getting a 993 keyboard panic here,
1901 // please see the comment in keyboard_init
1903 BX_PANIC("Keyboard error:%u\n",status
);
1906 //--------------------------------------------------------------------------
1907 // shutdown_status_panic
1908 // called when the shutdown statsu is not implemented, displays the status
1909 //--------------------------------------------------------------------------
1911 shutdown_status_panic(status
)
1914 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1917 void s3_resume_panic()
1919 BX_PANIC("Returned from s3_resume.\n");
1922 //--------------------------------------------------------------------------
1923 // print_bios_banner
1924 // displays a the bios version
1925 //--------------------------------------------------------------------------
1929 printf(BX_APPNAME
" BIOS - build: %s\n%s\nOptions: ",
1930 BIOS_BUILD_DATE
, bios_cvs_version_string
);
1938 #if BX_ELTORITO_BOOT
1947 //--------------------------------------------------------------------------
1948 // BIOS Boot Specification 1.0.1 compatibility
1950 // Very basic support for the BIOS Boot Specification, which allows expansion
1951 // ROMs to register themselves as boot devices, instead of just stealing the
1952 // INT 19h boot vector.
1954 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1955 // one; we just lie to the option ROMs to make them behave correctly.
1956 // We also don't support letting option ROMs register as bootable disk
1957 // drives (BCVs), only as bootable devices (BEVs).
1959 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1960 //--------------------------------------------------------------------------
1962 static char drivetypes
[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1969 Bit16u ss
= get_SS();
1971 /* Clear out the IPL table. */
1972 memsetb(IPL_SEG
, IPL_TABLE_OFFSET
, 0, IPL_SIZE
);
1974 /* User selected device not set */
1975 write_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
, 0xFFFF);
1978 e
.type
= IPL_TYPE_FLOPPY
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1979 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1983 e
.type
= IPL_TYPE_HARDDISK
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1984 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1987 #if BX_ELTORITO_BOOT
1989 e
.type
= IPL_TYPE_CDROM
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1990 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1994 /* Remember how many devices we have */
1995 write_word(IPL_SEG
, IPL_COUNT_OFFSET
, count
);
1996 /* Not tried booting anything yet */
1997 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xffff);
2001 get_boot_vector(i
, e
)
2002 Bit16u i
; ipl_entry_t
*e
;
2005 Bit16u ss
= get_SS();
2006 /* Get the count of boot devices, and refuse to overrun the array */
2007 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
2008 if (i
>= count
) return 0;
2009 /* OK to read this device */
2010 memcpyb(ss
, e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (*e
), sizeof (*e
));
2014 #if BX_ELTORITO_BOOT
2016 interactive_bootkey()
2020 char description
[33];
2023 Bit16u ss
= get_SS();
2024 Bit16u valid_choice
= 0;
2026 while (check_for_keystroke())
2029 printf("Press F12 for boot menu.\n\n");
2031 delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */
2032 if (check_for_keystroke())
2034 scan_code
= get_keystroke();
2035 if (scan_code
== 0x86) /* F12 */
2037 while (check_for_keystroke())
2040 printf("Select boot device:\n\n");
2042 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
2043 for (i
= 0; i
< count
; i
++)
2045 memcpyb(ss
, &e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (e
), sizeof (e
));
2046 printf("%d. ", i
+1);
2049 case IPL_TYPE_FLOPPY
:
2050 case IPL_TYPE_HARDDISK
:
2051 case IPL_TYPE_CDROM
:
2052 printf("%s\n", drivetypes
[e
.type
]);
2055 printf("%s", drivetypes
[4]);
2056 if (e
.description
!= 0)
2058 memcpyb(ss
, &description
, (Bit16u
)(e
.description
>> 16), (Bit16u
)(e
.description
& 0xffff), 32);
2059 description
[32] = 0;
2060 printf(" [%S]", ss
, description
);
2068 while (!valid_choice
) {
2069 scan_code
= get_keystroke();
2070 if (scan_code
== 0x01 || scan_code
== 0x58) /* ESC or F12 */
2074 else if (scan_code
<= count
)
2078 /* Set user selected device */
2079 write_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
, scan_code
);
2087 #endif // BX_ELTORITO_BOOT
2089 //--------------------------------------------------------------------------
2090 // print_boot_device
2091 // displays the boot device
2092 //--------------------------------------------------------------------------
2095 print_boot_device(e
)
2099 char description
[33];
2100 Bit16u ss
= get_SS();
2102 /* NIC appears as type 0x80 */
2103 if (type
== IPL_TYPE_BEV
) type
= 0x4;
2104 if (type
== 0 || type
> 0x4) BX_PANIC("Bad drive type\n");
2105 printf("Booting from %s", drivetypes
[type
]);
2106 /* print product string if BEV */
2107 if (type
== 4 && e
->description
!= 0) {
2108 /* first 32 bytes are significant */
2109 memcpyb(ss
, &description
, (Bit16u
)(e
->description
>> 16), (Bit16u
)(e
->description
& 0xffff), 32);
2110 /* terminate string */
2111 description
[32] = 0;
2112 printf(" [%S]", ss
, description
);
2117 //--------------------------------------------------------------------------
2118 // print_boot_failure
2119 // displays the reason why boot failed
2120 //--------------------------------------------------------------------------
2122 print_boot_failure(type
, reason
)
2123 Bit16u type
; Bit8u reason
;
2125 if (type
== 0 || type
> 0x3) BX_PANIC("Bad drive type\n");
2127 printf("Boot failed");
2129 /* Report the reason too */
2131 printf(": not a bootable disk");
2133 printf(": could not read the boot disk");
2138 //--------------------------------------------------------------------------
2139 // print_cdromboot_failure
2140 // displays the reason why boot failed
2141 //--------------------------------------------------------------------------
2143 print_cdromboot_failure( code
)
2146 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
2154 BX_PANIC("NMI Handler called\n");
2160 BX_PANIC("INT18: BOOT FAILURE\n");
2167 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
2169 BX_INFO("%s\n", bios_cvs_version_string
);
2178 // Use PS2 System Control port A to set A20 enable
2180 // get current setting first
2183 // change A20 status
2185 outb(0x92, oldval
| 0x02);
2187 outb(0x92, oldval
& 0xfd);
2189 return((oldval
& 0x02) != 0);
2207 Bit32u s3_wakeup_vector
;
2208 Bit8u s3_resume_flag
;
2210 s3_resume_flag
= read_byte(0x40, 0xb0);
2211 s3_wakeup_vector
= read_dword(0x40, 0xb2);
2213 BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag
, s3_wakeup_vector
);
2214 if (s3_resume_flag
!= 0xFE || !s3_wakeup_vector
)
2217 write_byte(0x40, 0xb0, 0);
2219 /* setup wakeup vector */
2220 write_word(0x40, 0xb6, (s3_wakeup_vector
& 0xF)); /* IP */
2221 write_word(0x40, 0xb8, (s3_wakeup_vector
>> 4)); /* CS */
2223 BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector
>> 4),
2224 (s3_wakeup_vector
& 0xF));
2233 // ---------------------------------------------------------------------------
2234 // Start of ATA/ATAPI Driver
2235 // ---------------------------------------------------------------------------
2237 // Global defines -- ATA register and register bits.
2238 // command block & control block regs
2239 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2240 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2241 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2242 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2243 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2244 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2245 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2246 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2247 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2248 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2249 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2250 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2251 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2253 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2254 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2255 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2256 #define ATA_CB_ER_MC 0x20 // ATA media change
2257 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2258 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2259 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2260 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2261 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2263 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2264 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2265 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2266 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2267 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2269 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2270 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2271 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2272 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2273 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2275 // bits 7-4 of the device/head (CB_DH) reg
2276 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2277 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2278 #define ATA_CB_DH_LBA 0x40 // use LBA
2280 // status reg (CB_STAT and CB_ASTAT) bits
2281 #define ATA_CB_STAT_BSY 0x80 // busy
2282 #define ATA_CB_STAT_RDY 0x40 // ready
2283 #define ATA_CB_STAT_DF 0x20 // device fault
2284 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2285 #define ATA_CB_STAT_SKC 0x10 // seek complete
2286 #define ATA_CB_STAT_SERV 0x10 // service
2287 #define ATA_CB_STAT_DRQ 0x08 // data request
2288 #define ATA_CB_STAT_CORR 0x04 // corrected
2289 #define ATA_CB_STAT_IDX 0x02 // index
2290 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2291 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2293 // device control reg (CB_DC) bits
2294 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2295 #define ATA_CB_DC_SRST 0x04 // soft reset
2296 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2298 // Most mandtory and optional ATA commands (from ATA-3),
2299 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2300 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2301 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2302 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2303 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2304 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2305 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2306 #define ATA_CMD_DEVICE_RESET 0x08
2307 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2308 #define ATA_CMD_FLUSH_CACHE 0xE7
2309 #define ATA_CMD_FORMAT_TRACK 0x50
2310 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2311 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2312 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2313 #define ATA_CMD_IDLE1 0xE3
2314 #define ATA_CMD_IDLE2 0x97
2315 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2316 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2317 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2318 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2319 #define ATA_CMD_NOP 0x00
2320 #define ATA_CMD_PACKET 0xA0
2321 #define ATA_CMD_READ_BUFFER 0xE4
2322 #define ATA_CMD_READ_DMA 0xC8
2323 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2324 #define ATA_CMD_READ_MULTIPLE 0xC4
2325 #define ATA_CMD_READ_SECTORS 0x20
2326 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2327 #define ATA_CMD_RECALIBRATE 0x10
2328 #define ATA_CMD_REQUEST_SENSE 0x03
2329 #define ATA_CMD_SEEK 0x70
2330 #define ATA_CMD_SET_FEATURES 0xEF
2331 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2332 #define ATA_CMD_SLEEP1 0xE6
2333 #define ATA_CMD_SLEEP2 0x99
2334 #define ATA_CMD_STANDBY1 0xE2
2335 #define ATA_CMD_STANDBY2 0x96
2336 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2337 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2338 #define ATA_CMD_WRITE_BUFFER 0xE8
2339 #define ATA_CMD_WRITE_DMA 0xCA
2340 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2341 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2342 #define ATA_CMD_WRITE_SECTORS 0x30
2343 #define ATA_CMD_WRITE_VERIFY 0x3C
2345 #define ATA_IFACE_NONE 0x00
2346 #define ATA_IFACE_ISA 0x00
2347 #define ATA_IFACE_PCI 0x01
2349 #define ATA_TYPE_NONE 0x00
2350 #define ATA_TYPE_UNKNOWN 0x01
2351 #define ATA_TYPE_ATA 0x02
2352 #define ATA_TYPE_ATAPI 0x03
2354 #define ATA_DEVICE_NONE 0x00
2355 #define ATA_DEVICE_HD 0xFF
2356 #define ATA_DEVICE_CDROM 0x05
2358 #define ATA_MODE_NONE 0x00
2359 #define ATA_MODE_PIO16 0x00
2360 #define ATA_MODE_PIO32 0x01
2361 #define ATA_MODE_ISADMA 0x02
2362 #define ATA_MODE_PCIDMA 0x03
2363 #define ATA_MODE_USEIRQ 0x10
2365 #define ATA_TRANSLATION_NONE 0
2366 #define ATA_TRANSLATION_LBA 1
2367 #define ATA_TRANSLATION_LARGE 2
2368 #define ATA_TRANSLATION_RECHS 3
2370 #define ATA_DATA_NO 0x00
2371 #define ATA_DATA_IN 0x01
2372 #define ATA_DATA_OUT 0x02
2374 // ---------------------------------------------------------------------------
2375 // ATA/ATAPI driver : initialization
2376 // ---------------------------------------------------------------------------
2379 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2380 Bit8u channel
, device
;
2382 // Channels info init.
2383 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2384 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2385 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2386 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2387 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2390 // Devices info init.
2391 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2392 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2393 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2394 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2395 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2396 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2397 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2398 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2399 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2400 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2401 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2402 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2403 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2404 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2406 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
,0L);
2407 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_high
,0L);
2410 // hdidmap and cdidmap init.
2411 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2412 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2413 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2416 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2417 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2423 #define NOT_BSY_DRQ 3
2424 #define NOT_BSY_NOT_DRQ 4
2425 #define NOT_BSY_RDY 5
2427 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
2430 static int await_ide(when_done
,base
,timeout
)
2435 Bit32u time
=0,last
=0;
2438 status
= inb(base
+ ATA_CB_STAT
); // for the times you're supposed to throw one away
2440 status
= inb(base
+ATA_CB_STAT
);
2442 if (when_done
== BSY
)
2443 result
= status
& ATA_CB_STAT_BSY
;
2444 else if (when_done
== NOT_BSY
)
2445 result
= !(status
& ATA_CB_STAT_BSY
);
2446 else if (when_done
== NOT_BSY_DRQ
)
2447 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_DRQ
);
2448 else if (when_done
== NOT_BSY_NOT_DRQ
)
2449 result
= !(status
& ATA_CB_STAT_BSY
) && !(status
& ATA_CB_STAT_DRQ
);
2450 else if (when_done
== NOT_BSY_RDY
)
2451 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_RDY
);
2452 else if (when_done
== TIMEOUT
)
2455 if (result
) return 0;
2456 if (time
>>16 != last
) // mod 2048 each 16 ms
2459 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
);
2461 if (status
& ATA_CB_STAT_ERR
)
2463 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
);
2466 if ((timeout
== 0) || ((time
>>11) > timeout
)) break;
2468 BX_INFO("IDE time out\n");
2472 // ---------------------------------------------------------------------------
2473 // ATA/ATAPI driver : device detection
2474 // ---------------------------------------------------------------------------
2478 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2479 Bit8u hdcount
, cdcount
, device
, type
;
2480 Bit8u buffer
[0x0200];
2482 #if BX_MAX_ATA_INTERFACES > 0
2483 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2484 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2485 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2486 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2488 #if BX_MAX_ATA_INTERFACES > 1
2489 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2490 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2491 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2492 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2494 #if BX_MAX_ATA_INTERFACES > 2
2495 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2496 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2497 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2498 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2500 #if BX_MAX_ATA_INTERFACES > 3
2501 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2502 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2503 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2504 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2506 #if BX_MAX_ATA_INTERFACES > 4
2507 #error Please fill the ATA interface informations
2513 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2514 Bit16u iobase1
, iobase2
;
2515 Bit8u channel
, slave
, shift
;
2516 Bit8u sc
, sn
, cl
, ch
, st
;
2518 channel
= device
/ 2;
2521 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2522 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2524 // Disable interrupts
2525 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2528 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2529 outb(iobase1
+ATA_CB_SC
, 0x55);
2530 outb(iobase1
+ATA_CB_SN
, 0xaa);
2531 outb(iobase1
+ATA_CB_SC
, 0xaa);
2532 outb(iobase1
+ATA_CB_SN
, 0x55);
2533 outb(iobase1
+ATA_CB_SC
, 0x55);
2534 outb(iobase1
+ATA_CB_SN
, 0xaa);
2536 // If we found something
2537 sc
= inb(iobase1
+ATA_CB_SC
);
2538 sn
= inb(iobase1
+ATA_CB_SN
);
2540 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2541 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2543 // reset the channel
2546 // check for ATA or ATAPI
2547 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2548 sc
= inb(iobase1
+ATA_CB_SC
);
2549 sn
= inb(iobase1
+ATA_CB_SN
);
2550 if ((sc
==0x01) && (sn
==0x01)) {
2551 cl
= inb(iobase1
+ATA_CB_CL
);
2552 ch
= inb(iobase1
+ATA_CB_CH
);
2553 st
= inb(iobase1
+ATA_CB_STAT
);
2555 if ((cl
==0x14) && (ch
==0xeb)) {
2556 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2557 } else if ((cl
==0x00) && (ch
==0x00) && (st
!=0x00)) {
2558 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2559 } else if ((cl
==0xff) && (ch
==0xff)) {
2560 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2565 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2567 // Now we send a IDENTIFY command to ATA device
2568 if(type
== ATA_TYPE_ATA
) {
2569 Bit32u sectors_low
, sectors_high
;
2570 Bit16u cylinders
, heads
, spt
, blksize
;
2571 Bit8u translation
, removable
, mode
;
2573 //Temporary values to do the transfer
2574 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2575 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2577 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer
) !=0 )
2578 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2580 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2581 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2582 blksize
= read_word(get_SS(),buffer
+10);
2584 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2585 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2586 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2588 if (read_word(get_SS(),buffer
+(83*2)) & (1 << 10)) { // word 83 - lba48 support
2589 sectors_low
= read_dword(get_SS(),buffer
+(100*2)); // word 100 and word 101
2590 sectors_high
= read_dword(get_SS(),buffer
+(102*2)); // word 102 and word 103
2592 sectors_low
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2596 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2597 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2598 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2599 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2600 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2601 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2602 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2603 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
, sectors_low
);
2604 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_high
, sectors_high
);
2605 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2607 translation
= inb_cmos(0x39 + channel
/2);
2608 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2609 translation
&= 0x03;
2611 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2613 switch (translation
) {
2614 case ATA_TRANSLATION_NONE
:
2617 case ATA_TRANSLATION_LBA
:
2620 case ATA_TRANSLATION_LARGE
:
2623 case ATA_TRANSLATION_RECHS
:
2628 switch (translation
) {
2629 case ATA_TRANSLATION_NONE
:
2631 case ATA_TRANSLATION_LBA
:
2634 heads
= sectors_low
/ 1024;
2635 if (heads
>128) heads
= 255;
2636 else if (heads
>64) heads
= 128;
2637 else if (heads
>32) heads
= 64;
2638 else if (heads
>16) heads
= 32;
2640 cylinders
= sectors_low
/ heads
;
2642 case ATA_TRANSLATION_RECHS
:
2643 // Take care not to overflow
2645 if(cylinders
>61439) cylinders
=61439;
2647 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2649 // then go through the large bitshift process
2650 case ATA_TRANSLATION_LARGE
:
2651 while(cylinders
> 1024) {
2655 // If we max out the head count
2656 if (heads
> 127) break;
2661 // clip to 1024 cylinders in lchs
2662 if (cylinders
> 1024) cylinders
=1024;
2663 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2665 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2666 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2667 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2670 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2674 // Now we send a IDENTIFY command to ATAPI device
2675 if(type
== ATA_TYPE_ATAPI
) {
2677 Bit8u type
, removable
, mode
;
2680 //Temporary values to do the transfer
2681 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2682 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2684 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer
) != 0)
2685 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2687 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2688 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2689 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2692 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2693 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2694 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2695 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2698 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2705 Bit8u c
, i
, version
, model
[41];
2709 sizeinmb
= (read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_high
) << 21)
2710 | (read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
) >> 11);
2711 case ATA_TYPE_ATAPI
:
2712 // Read ATA/ATAPI version
2713 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2714 for(version
=15;version
>0;version
--) {
2715 if((ataversion
&(1<<version
))!=0)
2721 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2722 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2726 write_byte(get_SS(),model
+40,0x00);
2728 if(read_byte(get_SS(),model
+i
)==0x20)
2729 write_byte(get_SS(),model
+i
,0x00);
2733 write_byte(get_SS(),model
+36,0x00);
2735 write_byte(get_SS(),model
+i
,0x2E);
2743 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2745 while(c
=read_byte(get_SS(),model
+i
++))
2747 if (sizeinmb
< (1UL<<16))
2748 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version
, (Bit16u
)sizeinmb
);
2750 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version
, (Bit16u
)(sizeinmb
>>10));
2752 case ATA_TYPE_ATAPI
:
2753 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2754 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2755 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2756 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2758 printf(" ATAPI-%d Device\n",version
);
2760 case ATA_TYPE_UNKNOWN
:
2761 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2767 // Store the devices counts
2768 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2769 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2770 write_byte(0x40,0x75, hdcount
);
2774 // FIXME : should use bios=cmos|auto|disable bits
2775 // FIXME : should know about translation bits
2776 // FIXME : move hard_drive_post here
2780 // ---------------------------------------------------------------------------
2781 // ATA/ATAPI driver : software reset
2782 // ---------------------------------------------------------------------------
2784 // 8.2.1 Software reset - Device 0
2786 void ata_reset(device
)
2789 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2790 Bit16u iobase1
, iobase2
;
2791 Bit8u channel
, slave
, sn
, sc
;
2795 channel
= device
/ 2;
2798 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2799 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2803 // 8.2.1 (a) -- set SRST in DC
2804 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2806 // 8.2.1 (b) -- wait for BSY
2807 await_ide(BSY
, iobase1
, 20);
2809 // 8.2.1 (f) -- clear SRST
2810 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2812 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2813 if (type
!= ATA_TYPE_NONE
) {
2815 // 8.2.1 (g) -- check for sc==sn==0x01
2817 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2818 sc
= inb(iobase1
+ATA_CB_SC
);
2819 sn
= inb(iobase1
+ATA_CB_SN
);
2821 if ( (sc
==0x01) && (sn
==0x01) ) {
2822 if (type
== ATA_TYPE_ATA
) //ATA
2823 await_ide(NOT_BSY_RDY
, iobase1
, IDE_TIMEOUT
);
2825 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2828 // 8.2.1 (h) -- wait for not BSY
2829 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2832 // Enable interrupts
2833 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2836 // ---------------------------------------------------------------------------
2837 // ATA/ATAPI driver : execute a non data command
2838 // ---------------------------------------------------------------------------
2840 Bit16u
ata_cmd_non_data()
2843 // ---------------------------------------------------------------------------
2844 // ATA/ATAPI driver : execute a data-in command
2845 // ---------------------------------------------------------------------------
2850 // 3 : expected DRQ=1
2851 // 4 : no sectors left to read/verify
2852 // 5 : more sectors to read/verify
2853 // 6 : no sectors left to write
2854 // 7 : more sectors to write
2855 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
)
2856 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2857 Bit32u lba_low
, lba_high
;
2859 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2860 Bit16u iobase1
, iobase2
, blksize
;
2861 Bit8u channel
, slave
;
2862 Bit8u status
, current
, mode
;
2864 channel
= device
/ 2;
2867 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2868 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2869 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2870 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2871 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2874 // Reset count of transferred data
2875 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2876 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2879 status
= inb(iobase1
+ ATA_CB_STAT
);
2880 if (status
& ATA_CB_STAT_BSY
) return 1;
2882 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2884 // sector will be 0 only on lba access. Convert to lba-chs
2886 if ((count
>= 1 << 8) || lba_high
|| (lba_low
+ count
>= 1UL << 28)) {
2887 outb(iobase1
+ ATA_CB_FR
, 0x00);
2888 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2889 outb(iobase1
+ ATA_CB_SN
, lba_low
>> 24);
2890 outb(iobase1
+ ATA_CB_CL
, lba_high
& 0xff);
2891 outb(iobase1
+ ATA_CB_CH
, lba_high
>> 8);
2893 count
&= (1UL << 8) - 1;
2894 lba_low
&= (1UL << 24) - 1;
2896 sector
= (Bit16u
) (lba_low
& 0x000000ffL
);
2897 cylinder
= (Bit16u
) ((lba_low
>>8) & 0x0000ffffL
);
2898 head
= ((Bit16u
) ((lba_low
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2901 outb(iobase1
+ ATA_CB_FR
, 0x00);
2902 outb(iobase1
+ ATA_CB_SC
, count
);
2903 outb(iobase1
+ ATA_CB_SN
, sector
);
2904 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2905 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2906 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2907 outb(iobase1
+ ATA_CB_CMD
, command
);
2909 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2910 status
= inb(iobase1
+ ATA_CB_STAT
);
2912 if (status
& ATA_CB_STAT_ERR
) {
2913 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2915 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2916 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2920 // FIXME : move seg/off translation here
2923 sti
;; enable higher priority interrupts
2931 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2932 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2933 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2935 ;; adjust
if there will be an overrun
. 2K max sector size
2937 jbe ata_in_no_adjust
2940 sub di
, #0x0800 ;; sub 2 kbytes from offset
2941 add ax
, #0x0080 ;; add 2 Kbytes to segment
2944 mov es
, ax
;; segment in es
2946 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2948 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2949 cmp ah
, #ATA_MODE_PIO32
2954 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2959 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2962 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2963 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2968 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2970 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2971 status
= inb(iobase1
+ ATA_CB_STAT
);
2973 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2974 != ATA_CB_STAT_RDY
) {
2975 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2981 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2982 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2983 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2989 // Enable interrupts
2990 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2994 // ---------------------------------------------------------------------------
2995 // ATA/ATAPI driver : execute a data-out command
2996 // ---------------------------------------------------------------------------
3001 // 3 : expected DRQ=1
3002 // 4 : no sectors left to read/verify
3003 // 5 : more sectors to read/verify
3004 // 6 : no sectors left to write
3005 // 7 : more sectors to write
3006 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
)
3007 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
3008 Bit32u lba_low
, lba_high
;
3010 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3011 Bit16u iobase1
, iobase2
, blksize
;
3012 Bit8u channel
, slave
;
3013 Bit8u status
, current
, mode
;
3015 channel
= device
/ 2;
3018 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
3019 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
3020 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
3021 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3022 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
3025 // Reset count of transferred data
3026 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
3027 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
3030 status
= inb(iobase1
+ ATA_CB_STAT
);
3031 if (status
& ATA_CB_STAT_BSY
) return 1;
3033 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
3035 // sector will be 0 only on lba access. Convert to lba-chs
3037 if ((count
>= 1 << 8) || lba_high
|| (lba_low
+ count
>= 1UL << 28)) {
3038 outb(iobase1
+ ATA_CB_FR
, 0x00);
3039 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
3040 outb(iobase1
+ ATA_CB_SN
, lba_low
>> 24);
3041 outb(iobase1
+ ATA_CB_CL
, lba_high
& 0xff);
3042 outb(iobase1
+ ATA_CB_CH
, lba_high
>> 8);
3044 count
&= (1UL << 8) - 1;
3045 lba_low
&= (1UL << 24) - 1;
3047 sector
= (Bit16u
) (lba_low
& 0x000000ffL
);
3048 cylinder
= (Bit16u
) ((lba_low
>>8) & 0x0000ffffL
);
3049 head
= ((Bit16u
) ((lba_low
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
3052 outb(iobase1
+ ATA_CB_FR
, 0x00);
3053 outb(iobase1
+ ATA_CB_SC
, count
);
3054 outb(iobase1
+ ATA_CB_SN
, sector
);
3055 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
3056 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
3057 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
3058 outb(iobase1
+ ATA_CB_CMD
, command
);
3060 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3061 status
= inb(iobase1
+ ATA_CB_STAT
);
3063 if (status
& ATA_CB_STAT_ERR
) {
3064 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3066 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
3067 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
3071 // FIXME : move seg/off translation here
3074 sti
;; enable higher priority interrupts
3082 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
3083 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
3084 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
3086 ;; adjust
if there will be an overrun
. 2K max sector size
3088 jbe ata_out_no_adjust
3091 sub si
, #0x0800 ;; sub 2 kbytes from offset
3092 add ax
, #0x0080 ;; add 2 Kbytes to segment
3095 mov es
, ax
;; segment in es
3097 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
3099 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
3100 cmp ah
, #ATA_MODE_PIO32
3106 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
3112 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
3115 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
3116 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
3121 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
3123 status
= inb(iobase1
+ ATA_CB_STAT
);
3125 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3126 != ATA_CB_STAT_RDY
) {
3127 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
3133 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3134 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
3135 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
3141 // Enable interrupts
3142 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3146 // ---------------------------------------------------------------------------
3147 // ATA/ATAPI driver : execute a packet command
3148 // ---------------------------------------------------------------------------
3151 // 1 : error in parameters
3155 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
3157 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
3161 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3162 Bit16u iobase1
, iobase2
;
3163 Bit16u lcount
, lbefore
, lafter
, count
;
3164 Bit8u channel
, slave
;
3165 Bit8u status
, mode
, lmode
;
3166 Bit32u total
, transfer
;
3168 channel
= device
/ 2;
3171 // Data out is not supported yet
3172 if (inout
== ATA_DATA_OUT
) {
3173 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3177 // The header length must be even
3179 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
3183 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
3184 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
3185 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
3188 if (cmdlen
< 12) cmdlen
=12;
3189 if (cmdlen
> 12) cmdlen
=16;
3192 // Reset count of transferred data
3193 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
3194 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
3196 status
= inb(iobase1
+ ATA_CB_STAT
);
3197 if (status
& ATA_CB_STAT_BSY
) return 2;
3199 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
3200 outb(iobase1
+ ATA_CB_FR
, 0x00);
3201 outb(iobase1
+ ATA_CB_SC
, 0x00);
3202 outb(iobase1
+ ATA_CB_SN
, 0x00);
3203 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
3204 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
3205 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
3206 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
3208 // Device should ok to receive command
3209 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3210 status
= inb(iobase1
+ ATA_CB_STAT
);
3212 if (status
& ATA_CB_STAT_ERR
) {
3213 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
3215 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
3216 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
3220 // Normalize address
3221 cmdseg
+= (cmdoff
/ 16);
3224 // Send command to device
3226 sti
;; enable higher priority interrupts
3231 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
3232 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
3233 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
3234 mov es
, ax
;; segment in es
3236 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
3240 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
3245 if (inout
== ATA_DATA_NO
) {
3246 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3247 status
= inb(iobase1
+ ATA_CB_STAT
);
3255 if (loops
== 0) {//first time through
3256 status
= inb(iobase2
+ ATA_CB_ASTAT
);
3257 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3260 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3263 status
= inb(iobase1
+ ATA_CB_STAT
);
3264 sc
= inb(iobase1
+ ATA_CB_SC
);
3266 // Check if command completed
3267 if(((inb(iobase1
+ ATA_CB_SC
)&0x7)==0x3) &&
3268 ((status
& (ATA_CB_STAT_RDY
| ATA_CB_STAT_ERR
)) == ATA_CB_STAT_RDY
)) break;
3270 if (status
& ATA_CB_STAT_ERR
) {
3271 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
3275 // Normalize address
3276 bufseg
+= (bufoff
/ 16);
3279 // Get the byte count
3280 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
3282 // adjust to read what we want
3295 lafter
=lcount
-length
;
3307 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
3308 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
3310 // If counts not dividable by 4, use 16bits mode
3312 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
3313 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
3314 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
3316 // adds an extra byte if count are odd. before is always even
3317 if (lcount
& 0x01) {
3319 if ((lafter
> 0) && (lafter
& 0x01)) {
3324 if (lmode
== ATA_MODE_PIO32
) {
3325 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
3328 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
3337 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
3339 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
3340 jcxz ata_packet_no_before
3342 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3343 cmp ah
, #ATA_MODE_PIO32
3344 je ata_packet_in_before_32
3346 ata_packet_in_before_16
:
3348 loop ata_packet_in_before_16
3349 jmp ata_packet_no_before
3351 ata_packet_in_before_32
:
3353 ata_packet_in_before_32_loop
:
3355 loop ata_packet_in_before_32_loop
3358 ata_packet_no_before
:
3359 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3360 jcxz ata_packet_after
3362 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3363 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3366 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3367 cmp ah
, #ATA_MODE_PIO32
3372 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3373 jmp ata_packet_after
3377 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3380 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3381 jcxz ata_packet_done
3383 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3384 cmp ah
, #ATA_MODE_PIO32
3385 je ata_packet_in_after_32
3387 ata_packet_in_after_16
:
3389 loop ata_packet_in_after_16
3392 ata_packet_in_after_32
:
3394 ata_packet_in_after_32_loop
:
3396 loop ata_packet_in_after_32_loop
3403 // Compute new buffer address
3406 // Save transferred bytes count
3408 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3412 // Final check, device must be ready
3413 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3414 != ATA_CB_STAT_RDY
) {
3415 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3419 // Enable interrupts
3420 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3424 // ---------------------------------------------------------------------------
3425 // End of ATA/ATAPI Driver
3426 // ---------------------------------------------------------------------------
3428 // ---------------------------------------------------------------------------
3429 // Start of ATA/ATAPI generic functions
3430 // ---------------------------------------------------------------------------
3433 atapi_get_sense(device
, seg
, asc
, ascq
)
3440 memsetb(get_SS(),atacmd
,0,12);
3443 atacmd
[0]=ATA_CMD_REQUEST_SENSE
;
3444 atacmd
[4]=sizeof(buffer
);
3445 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 18L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3448 write_byte(seg
,asc
,buffer
[12]);
3449 write_byte(seg
,ascq
,buffer
[13]);
3455 atapi_is_ready(device
)
3462 Bit32u timeout
; //measured in ms
3466 Bit16u ebda_seg
= read_word(0x0040,0x000E);
3467 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
) {
3468 printf("not implemented for non-ATAPI device\n");
3472 BX_DEBUG_ATA("ata_detect_medium: begin\n");
3473 memsetb(get_SS(),packet
, 0, sizeof packet
);
3474 packet
[0] = 0x25; /* READ CAPACITY */
3476 /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
3477 * is reported by the device. If the device reports "IN PROGRESS",
3478 * 30 seconds is added. */
3482 while (time
< timeout
) {
3483 if (ata_cmd_packet(device
, sizeof(packet
), get_SS(), packet
, 0, 8L, ATA_DATA_IN
, get_SS(), buf
) == 0)
3486 if (atapi_get_sense(device
, get_SS(), &asc
, &ascq
) == 0) {
3487 if (asc
== 0x3a) { /* MEDIUM NOT PRESENT */
3488 BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
3492 if (asc
== 0x04 && ascq
== 0x01 && !in_progress
) {
3493 /* IN PROGRESS OF BECOMING READY */
3494 printf("Waiting for device to detect medium... ");
3495 /* Allow 30 seconds more */
3502 BX_DEBUG_ATA("read capacity failed\n");
3506 block_len
= (Bit32u
) buf
[4] << 24
3507 | (Bit32u
) buf
[5] << 16
3508 | (Bit32u
) buf
[6] << 8
3509 | (Bit32u
) buf
[7] << 0;
3510 BX_DEBUG_ATA("block_len=%u\n", block_len
);
3512 if (block_len
!= 2048 && block_len
!= 512)
3514 printf("Unsupported sector size %u\n", block_len
);
3517 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, block_len
);
3519 sectors
= (Bit32u
) buf
[0] << 24
3520 | (Bit32u
) buf
[1] << 16
3521 | (Bit32u
) buf
[2] << 8
3522 | (Bit32u
) buf
[3] << 0;
3524 BX_DEBUG_ATA("sectors=%u\n", sectors
);
3525 if (block_len
== 2048)
3526 sectors
<<= 2; /* # of sectors in 512-byte "soft" sector */
3527 if (sectors
!= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
))
3528 printf("%dMB medium detected\n", sectors
>>(20-9));
3529 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
, sectors
);
3534 atapi_is_cdrom(device
)
3537 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3539 if (device
>= BX_MAX_ATA_DEVICES
)
3542 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3545 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3551 // ---------------------------------------------------------------------------
3552 // End of ATA/ATAPI generic functions
3553 // ---------------------------------------------------------------------------
3555 #endif // BX_USE_ATADRV
3557 #if BX_ELTORITO_BOOT
3559 // ---------------------------------------------------------------------------
3560 // Start of El-Torito boot functions
3561 // ---------------------------------------------------------------------------
3566 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3568 // the only important data is this one for now
3569 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3575 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3577 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3581 cdemu_emulated_drive()
3583 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3585 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3588 static char isotag
[6]="CD001";
3589 static char eltorito
[24]="EL TORITO SPECIFICATION";
3591 // Returns ah: emulated drive, al: error code
3596 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3597 Bit8u atacmd
[12], buffer
[2048];
3599 Bit16u boot_segment
, nbsectors
, i
, error
;
3602 // Find out the first cdrom
3603 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3604 if (atapi_is_cdrom(device
)) break;
3608 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3610 if(error
= atapi_is_ready(device
) != 0)
3611 BX_INFO("ata_is_ready returned %d\n",error
);
3613 // Read the Boot Record Volume Descriptor
3614 memsetb(get_SS(),atacmd
,0,12);
3615 atacmd
[0]=0x28; // READ command
3616 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3617 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3618 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3619 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3620 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3621 atacmd
[5]=(0x11 & 0x000000ff);
3622 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3626 if(buffer
[0]!=0) return 4;
3628 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
])) return 5;
3631 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
])) return 6;
3633 // ok, now we calculate the Boot catalog address
3634 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3636 // And we read the Boot Catalog
3637 memsetb(get_SS(),atacmd
,0,12);
3638 atacmd
[0]=0x28; // READ command
3639 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3640 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3641 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3642 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3643 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3644 atacmd
[5]=(lba
& 0x000000ff);
3645 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3649 if(buffer
[0x00]!=0x01)return 8; // Header
3650 if(buffer
[0x01]!=0x00)return 9; // Platform
3651 if(buffer
[0x1E]!=0x55)return 10; // key 1
3652 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3654 // Initial/Default Entry
3655 if(buffer
[0x20]!=0x88)return 11; // Bootable
3657 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3658 if(buffer
[0x21]==0){
3659 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3660 // Win2000 cd boot needs to know it booted from cd
3661 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3663 else if(buffer
[0x21]<4)
3664 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3666 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3668 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3669 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3671 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3672 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3674 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3675 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3677 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3678 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3680 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3681 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3683 // And we read the image in memory
3684 memsetb(get_SS(),atacmd
,0,12);
3685 atacmd
[0]=0x28; // READ command
3686 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3687 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3688 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3689 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3690 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3691 atacmd
[5]=(lba
& 0x000000ff);
3692 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3695 // Remember the media type
3696 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3697 case 0x01: // 1.2M floppy
3698 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3699 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3700 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3702 case 0x02: // 1.44M floppy
3703 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3704 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3705 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3707 case 0x03: // 2.88M floppy
3708 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3709 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3710 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3712 case 0x04: // Harddrive
3713 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3714 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3715 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3716 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3720 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3721 // Increase bios installed hardware number of devices
3722 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3723 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3725 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3728 // everything is ok, so from now on, the emulation is active
3729 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3730 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3732 // return the boot drive + no error
3733 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3736 // ---------------------------------------------------------------------------
3737 // End of El-Torito boot functions
3738 // ---------------------------------------------------------------------------
3739 #endif // BX_ELTORITO_BOOT
3741 void int14_function(regs
, ds
, iret_addr
)
3742 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3743 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3744 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3746 Bit16u addr
,timer
,val16
;
3753 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3754 counter
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3755 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3756 switch (regs
.u
.r8
.ah
) {
3758 outb(addr
+3, inb(addr
+3) | 0x80);
3759 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3763 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3764 outb(addr
, val16
& 0xFF);
3765 outb(addr
+1, val16
>> 8);
3767 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3768 regs
.u
.r8
.ah
= inb(addr
+5);
3769 regs
.u
.r8
.al
= inb(addr
+6);
3770 ClearCF(iret_addr
.flags
);
3773 timer
= read_word(0x0040, 0x006C);
3774 while (((inb(addr
+5) & 0x60) != 0x60) && (counter
)) {
3775 val16
= read_word(0x0040, 0x006C);
3776 if (val16
!= timer
) {
3782 outb(addr
, regs
.u
.r8
.al
);
3783 regs
.u
.r8
.ah
= inb(addr
+5);
3785 regs
.u
.r8
.ah
= 0x80;
3787 ClearCF(iret_addr
.flags
);
3790 timer
= read_word(0x0040, 0x006C);
3791 while (((inb(addr
+5) & 0x01) == 0) && (counter
)) {
3792 val16
= read_word(0x0040, 0x006C);
3793 if (val16
!= timer
) {
3799 regs
.u
.r8
.ah
= inb(addr
+5);
3800 regs
.u
.r8
.al
= inb(addr
);
3802 regs
.u
.r8
.ah
= 0x80;
3804 ClearCF(iret_addr
.flags
);
3807 regs
.u
.r8
.ah
= inb(addr
+5);
3808 regs
.u
.r8
.al
= inb(addr
+6);
3809 ClearCF(iret_addr
.flags
);
3812 SetCF(iret_addr
.flags
); // Unsupported
3815 SetCF(iret_addr
.flags
); // Unsupported
3820 int15_function(regs
, ES
, DS
, FLAGS
)
3821 pusha_regs_t regs
; // REGS pushed via pusha
3822 Bit16u ES
, DS
, FLAGS
;
3824 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3825 bx_bool prev_a20_enable
;
3834 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3836 switch (regs
.u
.r8
.ah
) {
3837 case 0x24: /* A20 Control */
3838 switch (regs
.u
.r8
.al
) {
3850 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3860 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3862 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3868 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3872 /* keyboard intercept */
3874 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3881 case 0x52: // removable media eject
3883 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3887 if( regs
.u
.r8
.al
== 0 ) {
3888 // Set Interval requested.
3889 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3890 // Interval not already set.
3891 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3892 write_word( 0x40, 0x98, ES
); // Byte location, segment
3893 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3894 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3895 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3897 irqDisable
= inb( 0xA1 );
3898 outb( 0xA1, irqDisable
& 0xFE );
3899 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3900 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3902 // Interval already set.
3903 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3905 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3907 } else if( regs
.u
.r8
.al
== 1 ) {
3908 // Clear Interval requested
3909 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3911 bRegister
= inb_cmos( 0xB );
3912 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3914 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3916 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3925 # error "Int15 function 87h not supported on < 80386"
3927 // +++ should probably have descriptor checks
3928 // +++ should have exception handlers
3930 // turn off interrupts
3935 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3937 // 128K max of transfer on 386+ ???
3938 // source == destination ???
3940 // ES:SI points to descriptor table
3941 // offset use initially comments
3942 // ==============================================
3943 // 00..07 Unused zeros Null descriptor
3944 // 08..0f GDT zeros filled in by BIOS
3945 // 10..17 source ssssssss source of data
3946 // 18..1f dest dddddddd destination of data
3947 // 20..27 CS zeros filled in by BIOS
3948 // 28..2f SS zeros filled in by BIOS
3955 // check for access rights of source & dest here
3957 // Initialize GDT descriptor
3958 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3959 base23_16
= ES
>> 12;
3960 if (base15_00
< (ES
<<4))
3962 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3963 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3964 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3965 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3966 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3968 // Initialize CS descriptor
3969 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3970 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3971 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3972 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3973 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3975 // Initialize SS descriptor
3977 base15_00
= ss
<< 4;
3978 base23_16
= ss
>> 12;
3979 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3980 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3981 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3982 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3983 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3987 // Compile generates locals offset info relative to SP.
3988 // Get CX (word count) from stack.
3991 mov cx
, _int15_function
.CX
[bx
]
3993 // since we need to set SS:SP, save them to the BDA
3994 // for future restore
4004 lidt
[pmode_IDT_info
]
4005 ;; perhaps
do something with IDT here
4007 ;; set PE bit in CR0
4011 ;; far jump to flush CPU queue after transition to
protected mode
4012 JMP_AP(0x0020, protected_mode
)
4015 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
4016 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4018 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4020 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4026 movsw
;; move CX words from DS
:SI to ES
:DI
4028 ;; make sure DS
and ES limits are
64KB
4033 ;; reset PG bit in CR0
???
4038 ;; far jump to flush CPU queue after transition to real mode
4039 JMP_AP(0xf000, real_mode
)
4042 ;; restore IDT to normal real
-mode defaults
4044 lidt
[rmode_IDT_info
]
4046 // restore SS:SP from the BDA
4054 set_enable_a20(prev_a20_enable
);
4056 // turn back on interrupts
4067 // Get the amount of extended memory (above 1M)
4069 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4072 regs
.u
.r8
.al
= inb_cmos(0x30);
4073 regs
.u
.r8
.ah
= inb_cmos(0x31);
4075 // According to Ralf Brown's interrupt the limit should be 15M,
4076 // but real machines mostly return max. 63M.
4077 if(regs
.u
.r16
.ax
> 0xffc0)
4078 regs
.u
.r16
.ax
= 0xffc0;
4085 /* Device busy interrupt. Called by Int 16h when no key available */
4089 /* Interrupt complete. Called by Int 16h when key becomes available */
4093 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4095 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4101 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4106 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
4116 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
4118 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4122 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4123 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4125 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4130 #if BX_USE_PS2_MOUSE
4132 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
4133 pusha_regs_t regs
; // REGS pushed via pusha
4134 Bit16u ES
, DS
, FLAGS
;
4136 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4137 Bit8u mouse_flags_1
, mouse_flags_2
;
4138 Bit16u mouse_driver_seg
;
4139 Bit16u mouse_driver_offset
;
4140 Bit8u comm_byte
, prev_command_byte
;
4141 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
4143 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4145 switch (regs
.u
.r8
.ah
) {
4147 // Return Codes status in AH
4148 // =========================
4150 // 01: invalid subfunction (AL > 7)
4151 // 02: invalid input value (out of allowable range)
4152 // 03: interface error
4153 // 04: resend command received from mouse controller,
4154 // device driver should attempt command again
4155 // 05: cannot enable mouse, since no far call has been installed
4156 // 80/86: mouse service not implemented
4158 switch (regs
.u
.r8
.al
) {
4159 case 0: // Disable/Enable Mouse
4160 BX_DEBUG_INT15("case 0:\n");
4161 switch (regs
.u
.r8
.bh
) {
4162 case 0: // Disable Mouse
4163 BX_DEBUG_INT15("case 0: disable mouse\n");
4164 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4165 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
4167 ret
= get_mouse_data(&mouse_data1
);
4168 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
4181 case 1: // Enable Mouse
4182 BX_DEBUG_INT15("case 1: enable mouse\n");
4183 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4184 if ( (mouse_flags_2
& 0x80) == 0 ) {
4185 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4187 regs
.u
.r8
.ah
= 5; // no far call installed
4190 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4191 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
4193 ret
= get_mouse_data(&mouse_data1
);
4194 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
4195 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4205 default: // invalid subfunction
4206 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4208 regs
.u
.r8
.ah
= 1; // invalid subfunction
4213 case 1: // Reset Mouse
4214 case 5: // Initialize Mouse
4215 BX_DEBUG_INT15("case 1 or 5:\n");
4216 if (regs
.u
.r8
.al
== 5) {
4217 if (regs
.u
.r8
.bh
!= 3) {
4219 regs
.u
.r8
.ah
= 0x02; // invalid input
4222 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4223 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
4224 mouse_flags_1
= 0x00;
4225 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4226 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4229 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4230 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
4232 ret
= get_mouse_data(&mouse_data3
);
4233 // if no mouse attached, it will return RESEND
4234 if (mouse_data3
== 0xfe) {
4238 if (mouse_data3
!= 0xfa)
4239 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
4241 ret
= get_mouse_data(&mouse_data1
);
4243 ret
= get_mouse_data(&mouse_data2
);
4245 // turn IRQ12 and packet generation on
4246 enable_mouse_int_and_events();
4249 regs
.u
.r8
.bl
= mouse_data1
;
4250 regs
.u
.r8
.bh
= mouse_data2
;
4262 case 2: // Set Sample Rate
4263 BX_DEBUG_INT15("case 2:\n");
4264 switch (regs
.u
.r8
.bh
) {
4265 case 0: mouse_data1
= 10; break; // 10 reports/sec
4266 case 1: mouse_data1
= 20; break; // 20 reports/sec
4267 case 2: mouse_data1
= 40; break; // 40 reports/sec
4268 case 3: mouse_data1
= 60; break; // 60 reports/sec
4269 case 4: mouse_data1
= 80; break; // 80 reports/sec
4270 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
4271 case 6: mouse_data1
= 200; break; // 200 reports/sec
4272 default: mouse_data1
= 0;
4274 if (mouse_data1
> 0) {
4275 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
4277 ret
= get_mouse_data(&mouse_data2
);
4278 ret
= send_to_mouse_ctrl(mouse_data1
);
4279 ret
= get_mouse_data(&mouse_data2
);
4285 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4290 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4294 case 3: // Set Resolution
4295 BX_DEBUG_INT15("case 3:\n");
4297 // 0 = 25 dpi, 1 count per millimeter
4298 // 1 = 50 dpi, 2 counts per millimeter
4299 // 2 = 100 dpi, 4 counts per millimeter
4300 // 3 = 200 dpi, 8 counts per millimeter
4301 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4302 if (regs
.u
.r8
.bh
< 4) {
4303 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
4305 ret
= get_mouse_data(&mouse_data1
);
4306 if (mouse_data1
!= 0xfa)
4307 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4308 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
4309 ret
= get_mouse_data(&mouse_data1
);
4310 if (mouse_data1
!= 0xfa)
4311 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4317 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4322 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4324 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4327 case 4: // Get Device ID
4328 BX_DEBUG_INT15("case 4:\n");
4329 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4330 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
4332 ret
= get_mouse_data(&mouse_data1
);
4333 ret
= get_mouse_data(&mouse_data2
);
4336 regs
.u
.r8
.bh
= mouse_data2
;
4340 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4344 case 6: // Return Status & Set Scaling Factor...
4345 BX_DEBUG_INT15("case 6:\n");
4346 switch (regs
.u
.r8
.bh
) {
4347 case 0: // Return Status
4348 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4349 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4351 ret
= get_mouse_data(&mouse_data1
);
4352 if (mouse_data1
!= 0xfa)
4353 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4355 ret
= get_mouse_data(&mouse_data1
);
4357 ret
= get_mouse_data(&mouse_data2
);
4359 ret
= get_mouse_data(&mouse_data3
);
4363 regs
.u
.r8
.bl
= mouse_data1
;
4364 regs
.u
.r8
.cl
= mouse_data2
;
4365 regs
.u
.r8
.dl
= mouse_data3
;
4366 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4377 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4380 case 1: // Set Scaling Factor to 1:1
4381 case 2: // Set Scaling Factor to 2:1
4382 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4383 if (regs
.u
.r8
.bh
== 1) {
4384 ret
= send_to_mouse_ctrl(0xE6);
4386 ret
= send_to_mouse_ctrl(0xE7);
4389 get_mouse_data(&mouse_data1
);
4390 ret
= (mouse_data1
!= 0xFA);
4398 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4400 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4404 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4408 case 7: // Set Mouse Handler Address
4409 BX_DEBUG_INT15("case 7:\n");
4410 mouse_driver_seg
= ES
;
4411 mouse_driver_offset
= regs
.u
.r16
.bx
;
4412 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4413 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4414 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4415 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4416 /* remove handler */
4417 if ( (mouse_flags_2
& 0x80) != 0 ) {
4418 mouse_flags_2
&= ~0x80;
4419 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4423 /* install handler */
4424 mouse_flags_2
|= 0x80;
4426 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4432 BX_DEBUG_INT15("case default:\n");
4433 regs
.u
.r8
.ah
= 1; // invalid function
4439 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4440 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4442 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4446 #endif // BX_USE_PS2_MOUSE
4449 void set_e820_range(ES
, DI
, start
, end
, extra_start
, extra_end
, type
)
4458 write_word(ES
, DI
, start
);
4459 write_word(ES
, DI
+2, start
>> 16);
4460 write_word(ES
, DI
+4, extra_start
);
4461 write_word(ES
, DI
+6, 0x00);
4464 extra_end
-= extra_start
;
4465 write_word(ES
, DI
+8, end
);
4466 write_word(ES
, DI
+10, end
>> 16);
4467 write_word(ES
, DI
+12, extra_end
);
4468 write_word(ES
, DI
+14, 0x0000);
4470 write_word(ES
, DI
+16, type
);
4471 write_word(ES
, DI
+18, 0x0);
4475 int15_function32(regs
, ES
, DS
, FLAGS
)
4476 pushad_regs_t regs
; // REGS pushed via pushad
4477 Bit16u ES
, DS
, FLAGS
;
4479 Bit32u extended_memory_size
=0; // 64bits long
4480 Bit32u extra_lowbits_memory_size
=0;
4482 Bit8u extra_highbits_memory_size
=0;
4484 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4486 switch (regs
.u
.r8
.ah
) {
4488 // Wait for CX:DX microseconds. currently using the
4489 // refresh request port 0x61 bit4, toggling every 15usec
4497 ;; Get the count in eax
4500 mov ax
, _int15_function32
.CX
[bx
]
4503 mov ax
, _int15_function32
.DX
[bx
]
4505 ;; convert to numbers of
15usec ticks
4511 ;; wait
for ecx number of refresh requests
4532 switch(regs
.u
.r8
.al
) {
4533 case 0x20: // coded by osmaker aka K.J.
4534 if(regs
.u
.r32
.edx
== 0x534D4150)
4536 extended_memory_size
= inb_cmos(0x35);
4537 extended_memory_size
<<= 8;
4538 extended_memory_size
|= inb_cmos(0x34);
4539 extended_memory_size
*= 64;
4540 // greater than EFF00000???
4541 if(extended_memory_size
> 0x3bc000) {
4542 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4544 extended_memory_size
*= 1024;
4545 extended_memory_size
+= (16L * 1024 * 1024);
4547 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4548 extended_memory_size
= inb_cmos(0x31);
4549 extended_memory_size
<<= 8;
4550 extended_memory_size
|= inb_cmos(0x30);
4551 extended_memory_size
*= 1024;
4552 extended_memory_size
+= (1L * 1024 * 1024);
4555 extra_lowbits_memory_size
= inb_cmos(0x5c);
4556 extra_lowbits_memory_size
<<= 8;
4557 extra_lowbits_memory_size
|= inb_cmos(0x5b);
4558 extra_lowbits_memory_size
*= 64;
4559 extra_lowbits_memory_size
*= 1024;
4560 extra_highbits_memory_size
= inb_cmos(0x5d);
4562 switch(regs
.u
.r16
.bx
)
4565 set_e820_range(ES
, regs
.u
.r16
.di
,
4566 0x0000000L
, 0x0009f000L
, 0, 0, 1);
4570 set_e820_range(ES
, regs
.u
.r16
.di
,
4571 0x0009f000L
, 0x000a0000L
, 0, 0, 2);
4575 set_e820_range(ES
, regs
.u
.r16
.di
,
4576 0x000e8000L
, 0x00100000L
, 0, 0, 2);
4581 set_e820_range(ES
, regs
.u
.r16
.di
,
4583 extended_memory_size
- ACPI_DATA_SIZE
, 0, 0, 1);
4586 set_e820_range(ES
, regs
.u
.r16
.di
,
4588 extended_memory_size
, 0, 0, 1);
4593 set_e820_range(ES
, regs
.u
.r16
.di
,
4594 extended_memory_size
- ACPI_DATA_SIZE
,
4595 extended_memory_size
, 0, 0, 3); // ACPI RAM
4599 /* 256KB BIOS area at the end of 4 GB */
4600 set_e820_range(ES
, regs
.u
.r16
.di
,
4601 0xfffc0000L
, 0x00000000L
, 0, 0, 2);
4602 if (extra_highbits_memory_size
|| extra_lowbits_memory_size
)
4608 /* Maping of memory above 4 GB */
4609 set_e820_range(ES
, regs
.u
.r16
.di
, 0x00000000L
,
4610 extra_lowbits_memory_size
, 1, extra_highbits_memory_size
4614 default: /* AX=E820, DX=534D4150, BX unrecognized */
4615 goto int15_unimplemented
;
4618 regs
.u
.r32
.eax
= 0x534D4150;
4619 regs
.u
.r32
.ecx
= 0x14;
4622 // if DX != 0x534D4150)
4623 goto int15_unimplemented
;
4628 // do we have any reason to fail here ?
4631 // my real system sets ax and bx to 0
4632 // this is confirmed by Ralph Brown list
4633 // but syslinux v1.48 is known to behave
4634 // strangely if ax is set to 0
4635 // regs.u.r16.ax = 0;
4636 // regs.u.r16.bx = 0;
4638 // Get the amount of extended memory (above 1M)
4639 regs
.u
.r8
.cl
= inb_cmos(0x30);
4640 regs
.u
.r8
.ch
= inb_cmos(0x31);
4643 if(regs
.u
.r16
.cx
> 0x3c00)
4645 regs
.u
.r16
.cx
= 0x3c00;
4648 // Get the amount of extended memory above 16M in 64k blocs
4649 regs
.u
.r8
.dl
= inb_cmos(0x34);
4650 regs
.u
.r8
.dh
= inb_cmos(0x35);
4652 // Set configured memory equal to extended memory
4653 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4654 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4656 default: /* AH=0xE8?? but not implemented */
4657 goto int15_unimplemented
;
4660 int15_unimplemented
:
4661 // fall into the default
4663 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4664 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4666 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4672 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4673 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4675 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4676 Bit16u kbd_code
, max
;
4678 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4680 shift_flags
= read_byte(0x0040, 0x17);
4681 led_flags
= read_byte(0x0040, 0x97);
4682 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4687 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4688 if ((inb(0x60) == 0xfa)) {
4690 led_flags
|= ((shift_flags
>> 4) & 0x07);
4691 outb(0x60, led_flags
& 0x07);
4692 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4694 write_byte(0x0040, 0x97, led_flags
);
4702 case 0x00: /* read keyboard input */
4704 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4705 BX_PANIC("KBD: int16h: out of keyboard input\n");
4707 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4708 else if (ascii_code
== 0xE0) ascii_code
= 0;
4709 AX
= (scan_code
<< 8) | ascii_code
;
4712 case 0x01: /* check keyboard status */
4713 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4717 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4718 else if (ascii_code
== 0xE0) ascii_code
= 0;
4719 AX
= (scan_code
<< 8) | ascii_code
;
4723 case 0x02: /* get shift flag status */
4724 shift_flags
= read_byte(0x0040, 0x17);
4725 SET_AL(shift_flags
);
4728 case 0x05: /* store key-stroke into buffer */
4729 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4737 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4738 // bit Bochs Description
4740 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4741 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4742 // 4 1 INT 16/AH=0Ah supported
4743 // 3 0 INT 16/AX=0306h supported
4744 // 2 0 INT 16/AX=0305h supported
4745 // 1 0 INT 16/AX=0304h supported
4746 // 0 0 INT 16/AX=0300h supported
4751 case 0x0A: /* GET KEYBOARD ID */
4757 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4759 if ((inb(0x60) == 0xfa)) {
4762 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4765 kbd_code
|= (inb(0x60) << 8);
4767 } while (--count
>0);
4773 case 0x10: /* read MF-II keyboard input */
4775 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4776 BX_PANIC("KBD: int16h: out of keyboard input\n");
4778 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4779 AX
= (scan_code
<< 8) | ascii_code
;
4782 case 0x11: /* check MF-II keyboard status */
4783 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4787 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4788 AX
= (scan_code
<< 8) | ascii_code
;
4792 case 0x12: /* get extended keyboard status */
4793 shift_flags
= read_byte(0x0040, 0x17);
4794 SET_AL(shift_flags
);
4795 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4796 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4797 SET_AH(shift_flags
);
4798 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4801 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4802 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4805 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4806 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4810 if (GET_AL() == 0x08)
4811 SET_AH(0x02); // unsupported, aka normal keyboard
4814 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4819 dequeue_key(scan_code
, ascii_code
, incr
)
4824 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4829 buffer_start
= 0x001E;
4830 buffer_end
= 0x003E;
4832 buffer_start
= read_word(0x0040, 0x0080);
4833 buffer_end
= read_word(0x0040, 0x0082);
4836 buffer_head
= read_word(0x0040, 0x001a);
4837 buffer_tail
= read_word(0x0040, 0x001c);
4839 if (buffer_head
!= buffer_tail
) {
4841 acode
= read_byte(0x0040, buffer_head
);
4842 scode
= read_byte(0x0040, buffer_head
+1);
4843 write_byte(ss
, ascii_code
, acode
);
4844 write_byte(ss
, scan_code
, scode
);
4848 if (buffer_head
>= buffer_end
)
4849 buffer_head
= buffer_start
;
4850 write_word(0x0040, 0x001a, buffer_head
);
4859 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4862 inhibit_mouse_int_and_events()
4864 Bit8u command_byte
, prev_command_byte
;
4866 // Turn off IRQ generation and aux data line
4867 if ( inb(0x64) & 0x02 )
4868 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4869 outb(0x64, 0x20); // get command byte
4870 while ( (inb(0x64) & 0x01) != 0x01 );
4871 prev_command_byte
= inb(0x60);
4872 command_byte
= prev_command_byte
;
4873 //while ( (inb(0x64) & 0x02) );
4874 if ( inb(0x64) & 0x02 )
4875 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4876 command_byte
&= 0xfd; // turn off IRQ 12 generation
4877 command_byte
|= 0x20; // disable mouse serial clock line
4878 outb(0x64, 0x60); // write command byte
4879 outb(0x60, command_byte
);
4880 return(prev_command_byte
);
4884 enable_mouse_int_and_events()
4888 // Turn on IRQ generation and aux data line
4889 if ( inb(0x64) & 0x02 )
4890 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4891 outb(0x64, 0x20); // get command byte
4892 while ( (inb(0x64) & 0x01) != 0x01 );
4893 command_byte
= inb(0x60);
4894 //while ( (inb(0x64) & 0x02) );
4895 if ( inb(0x64) & 0x02 )
4896 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4897 command_byte
|= 0x02; // turn on IRQ 12 generation
4898 command_byte
&= 0xdf; // enable mouse serial clock line
4899 outb(0x64, 0x60); // write command byte
4900 outb(0x60, command_byte
);
4904 send_to_mouse_ctrl(sendbyte
)
4909 // wait for chance to write to ctrl
4910 if ( inb(0x64) & 0x02 )
4911 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4913 outb(0x60, sendbyte
);
4919 get_mouse_data(data
)
4925 while ((inb(0x64) & 0x21) != 0x21) { }
4927 response
= inb(0x60);
4930 write_byte(ss
, data
, response
);
4935 set_kbd_command_byte(command_byte
)
4938 if ( inb(0x64) & 0x02 )
4939 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4942 outb(0x64, 0x60); // write command byte
4943 outb(0x60, command_byte
);
4947 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4948 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4950 Bit8u scancode
, asciicode
, shift_flags
;
4951 Bit8u mf2_flags
, mf2_state
;
4954 // DS has been set to F000 before call
4958 scancode
= GET_AL();
4960 if (scancode
== 0) {
4961 BX_INFO("KBD: int09 handler: AL=0\n");
4966 shift_flags
= read_byte(0x0040, 0x17);
4967 mf2_flags
= read_byte(0x0040, 0x18);
4968 mf2_state
= read_byte(0x0040, 0x96);
4972 case 0x3a: /* Caps Lock press */
4973 shift_flags
^= 0x40;
4974 write_byte(0x0040, 0x17, shift_flags
);
4976 write_byte(0x0040, 0x18, mf2_flags
);
4978 case 0xba: /* Caps Lock release */
4980 write_byte(0x0040, 0x18, mf2_flags
);
4983 case 0x2a: /* L Shift press */
4984 shift_flags
|= 0x02;
4985 write_byte(0x0040, 0x17, shift_flags
);
4987 case 0xaa: /* L Shift release */
4988 shift_flags
&= ~0x02;
4989 write_byte(0x0040, 0x17, shift_flags
);
4992 case 0x36: /* R Shift press */
4993 shift_flags
|= 0x01;
4994 write_byte(0x0040, 0x17, shift_flags
);
4996 case 0xb6: /* R Shift release */
4997 shift_flags
&= ~0x01;
4998 write_byte(0x0040, 0x17, shift_flags
);
5001 case 0x1d: /* Ctrl press */
5002 if ((mf2_state
& 0x01) == 0) {
5003 shift_flags
|= 0x04;
5004 write_byte(0x0040, 0x17, shift_flags
);
5005 if (mf2_state
& 0x02) {
5007 write_byte(0x0040, 0x96, mf2_state
);
5010 write_byte(0x0040, 0x18, mf2_flags
);
5014 case 0x9d: /* Ctrl release */
5015 if ((mf2_state
& 0x01) == 0) {
5016 shift_flags
&= ~0x04;
5017 write_byte(0x0040, 0x17, shift_flags
);
5018 if (mf2_state
& 0x02) {
5020 write_byte(0x0040, 0x96, mf2_state
);
5023 write_byte(0x0040, 0x18, mf2_flags
);
5028 case 0x38: /* Alt press */
5029 shift_flags
|= 0x08;
5030 write_byte(0x0040, 0x17, shift_flags
);
5031 if (mf2_state
& 0x02) {
5033 write_byte(0x0040, 0x96, mf2_state
);
5036 write_byte(0x0040, 0x18, mf2_flags
);
5039 case 0xb8: /* Alt release */
5040 shift_flags
&= ~0x08;
5041 write_byte(0x0040, 0x17, shift_flags
);
5042 if (mf2_state
& 0x02) {
5044 write_byte(0x0040, 0x96, mf2_state
);
5047 write_byte(0x0040, 0x18, mf2_flags
);
5051 case 0x45: /* Num Lock press */
5052 if ((mf2_state
& 0x03) == 0) {
5054 write_byte(0x0040, 0x18, mf2_flags
);
5055 shift_flags
^= 0x20;
5056 write_byte(0x0040, 0x17, shift_flags
);
5059 case 0xc5: /* Num Lock release */
5060 if ((mf2_state
& 0x03) == 0) {
5062 write_byte(0x0040, 0x18, mf2_flags
);
5066 case 0x46: /* Scroll Lock press */
5068 write_byte(0x0040, 0x18, mf2_flags
);
5069 shift_flags
^= 0x10;
5070 write_byte(0x0040, 0x17, shift_flags
);
5073 case 0xc6: /* Scroll Lock release */
5075 write_byte(0x0040, 0x18, mf2_flags
);
5079 if (scancode
& 0x80) {
5080 break; /* toss key releases ... */
5082 if (scancode
> MAX_SCAN_CODE
) {
5083 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
5086 if (shift_flags
& 0x08) { /* ALT */
5087 asciicode
= scan_to_scanascii
[scancode
].alt
;
5088 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
5089 } else if (shift_flags
& 0x04) { /* CONTROL */
5090 asciicode
= scan_to_scanascii
[scancode
].control
;
5091 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
5092 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
5093 /* extended keys handling */
5095 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5096 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
5097 /* check if lock state should be ignored
5098 * because a SHIFT key are pressed */
5100 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
5101 asciicode
= scan_to_scanascii
[scancode
].normal
;
5102 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5104 asciicode
= scan_to_scanascii
[scancode
].shift
;
5105 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
5108 /* check if lock is on */
5109 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
5110 asciicode
= scan_to_scanascii
[scancode
].shift
;
5111 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
5113 asciicode
= scan_to_scanascii
[scancode
].normal
;
5114 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5117 if (scancode
==0 && asciicode
==0) {
5118 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5120 enqueue_key(scancode
, asciicode
);
5123 if ((scancode
& 0x7f) != 0x1d) {
5127 write_byte(0x0040, 0x96, mf2_state
);
5131 enqueue_key(scan_code
, ascii_code
)
5132 Bit8u scan_code
, ascii_code
;
5134 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
5137 buffer_start
= 0x001E;
5138 buffer_end
= 0x003E;
5140 buffer_start
= read_word(0x0040, 0x0080);
5141 buffer_end
= read_word(0x0040, 0x0082);
5144 buffer_head
= read_word(0x0040, 0x001A);
5145 buffer_tail
= read_word(0x0040, 0x001C);
5147 temp_tail
= buffer_tail
;
5149 if (buffer_tail
>= buffer_end
)
5150 buffer_tail
= buffer_start
;
5152 if (buffer_tail
== buffer_head
) {
5156 write_byte(0x0040, temp_tail
, ascii_code
);
5157 write_byte(0x0040, temp_tail
+1, scan_code
);
5158 write_word(0x0040, 0x001C, buffer_tail
);
5163 int74_function(make_farcall
, Z
, Y
, X
, status
)
5164 Bit16u make_farcall
, Z
, Y
, X
, status
;
5166 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5167 Bit8u in_byte
, index
, package_count
;
5168 Bit8u mouse_flags_1
, mouse_flags_2
;
5170 BX_DEBUG_INT74("entering int74_function\n");
5173 in_byte
= inb(0x64);
5174 if ((in_byte
& 0x21) != 0x21) {
5178 in_byte
= inb(0x60);
5179 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
5181 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
5182 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
5184 if ((mouse_flags_2
& 0x80) != 0x80) {
5188 package_count
= mouse_flags_2
& 0x07;
5189 index
= mouse_flags_1
& 0x07;
5190 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
5192 if ( (index
+1) >= package_count
) {
5193 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5194 status
= read_byte(ebda_seg
, 0x0028 + 0);
5195 X
= read_byte(ebda_seg
, 0x0028 + 1);
5196 Y
= read_byte(ebda_seg
, 0x0028 + 2);
5199 // check if far call handler installed
5200 if (mouse_flags_2
& 0x80)
5206 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
5209 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5214 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5215 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5217 Bit32u lba_low
, lba_high
;
5218 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5219 Bit16u cylinder
, head
, sector
;
5220 Bit16u segment
, offset
;
5221 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
5223 Bit8u device
, status
;
5225 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5227 write_byte(0x0040, 0x008e, 0); // clear completion flag
5229 // basic check : device has to be defined
5230 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
5231 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5235 // Get the ata channel
5236 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
5238 // basic check : device has to be valid
5239 if (device
>= BX_MAX_ATA_DEVICES
) {
5240 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5246 case 0x00: /* disk controller reset */
5251 case 0x01: /* read disk status */
5252 status
= read_byte(0x0040, 0x0074);
5254 SET_DISK_RET_STATUS(0);
5255 /* set CF if error status read */
5256 if (status
) goto int13_fail_nostatus
;
5257 else goto int13_success_noah
;
5260 case 0x02: // read disk sectors
5261 case 0x03: // write disk sectors
5262 case 0x04: // verify disk sectors
5265 cylinder
= GET_CH();
5266 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5267 sector
= (GET_CL() & 0x3f);
5273 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
5274 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5278 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5279 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5280 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5282 // sanity check on cyl heads, sec
5283 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
) ) {
5284 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
5289 if (GET_AH() == 0x04) goto int13_success
;
5291 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5292 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5294 // if needed, translate lchs to lba, and execute command
5295 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
5296 lba_low
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
5298 sector
= 0; // this forces the command to be lba
5301 if (GET_AH() == 0x02)
5302 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
);
5304 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
);
5306 // Set nb of sector transferred
5307 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
5310 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5312 goto int13_fail_noah
;
5318 case 0x05: /* format disk track */
5319 BX_INFO("format disk track called\n");
5324 case 0x08: /* read disk drive parameters */
5326 // Get logical geometry from table
5327 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5328 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5329 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5330 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5332 nlc
= nlc
- 2; /* 0 based, last sector not used */
5335 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5337 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5339 // FIXME should set ES & DI
5344 case 0x10: /* check drive ready */
5345 // should look at 40:8E also???
5347 // Read the status from controller
5348 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5349 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5354 goto int13_fail_noah
;
5358 case 0x15: /* read disk drive size */
5360 // Get logical geometry from table
5361 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5362 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5363 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5365 // Compute sector count seen by int13
5366 lba_low
= (Bit32u
)(nlc
- 1) * (Bit32u
)nlh
* (Bit32u
)nlspt
;
5368 DX
= lba_low
& 0xffff;
5370 SET_AH(3); // hard disk accessible
5371 goto int13_success_noah
;
5374 case 0x41: // IBM/MS installation check
5375 BX
=0xaa55; // install check
5376 SET_AH(0x30); // EDD 3.0
5377 CX
=0x0007; // ext disk access and edd, removable supported
5378 goto int13_success_noah
;
5381 case 0x42: // IBM/MS extended read
5382 case 0x43: // IBM/MS extended write
5383 case 0x44: // IBM/MS verify
5384 case 0x47: // IBM/MS extended seek
5386 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5387 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5388 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5390 // Get 32 msb lba and check
5391 lba_high
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5392 if (lba_high
> read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
) ) {
5393 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5397 // Get 32 lsb lba and check
5398 lba_low
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5399 if (lba_high
== read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
)
5400 && lba_low
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_low
) ) {
5401 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5405 // If verify or seek
5406 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5409 // Execute the command
5410 if (GET_AH() == 0x42)
5411 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba_low
, lba_high
, segment
, offset
);
5413 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba_low
, lba_high
, segment
, offset
);
5415 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5416 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5419 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5421 goto int13_fail_noah
;
5427 case 0x45: // IBM/MS lock/unlock drive
5428 case 0x49: // IBM/MS extended media change
5429 goto int13_success
; // Always success for HD
5432 case 0x46: // IBM/MS eject media
5433 SET_AH(0xb2); // Volume Not Removable
5434 goto int13_fail_noah
; // Always fail for HD
5437 case 0x48: // IBM/MS get drive parameters
5438 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5440 // Buffer is too small
5448 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5449 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5450 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5451 lba_low
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_low
);
5452 lba_high
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
);
5453 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5455 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5456 if (lba_high
|| (lba_low
/npspt
)/nph
> 0x3fff)
5458 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x00); // geometry is invalid
5459 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0x3fff);
5463 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5464 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5466 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5467 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5468 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba_low
);
5469 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, lba_high
);
5470 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5475 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5476 Bit16u iobase1
, iobase2
, options
;
5478 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5480 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5481 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5484 channel
= device
/ 2;
5485 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5486 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5487 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5488 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5489 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5491 options
= (translation
==ATA_TRANSLATION_NONE
?0:1)<<3; // chs translation
5492 options
|= (1<<4); // lba translation
5493 options
|= (mode
==ATA_MODE_PIO32
?1:0)<<7;
5494 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0)<<9;
5495 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0)<<9;
5497 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5498 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5499 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5500 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5501 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5502 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5503 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5504 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5505 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5506 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5508 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5510 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x10);
5513 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5514 checksum
= ~checksum
;
5515 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5520 Bit8u channel
, iface
, checksum
, i
;
5523 channel
= device
/ 2;
5524 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5525 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5527 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5528 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5529 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5530 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5531 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5533 if (iface
==ATA_IFACE_ISA
) {
5534 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5535 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5536 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5537 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5542 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5543 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5544 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5545 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5547 if (iface
==ATA_IFACE_ISA
) {
5548 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5549 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5550 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5555 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5556 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5557 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5558 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5561 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5562 checksum
= ~checksum
;
5563 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5569 case 0x4e: // // IBM/MS set hardware configuration
5570 // DMA, prefetch, PIO maximum not supported
5583 case 0x09: /* initialize drive parameters */
5584 case 0x0c: /* seek to specified cylinder */
5585 case 0x0d: /* alternate disk reset */
5586 case 0x11: /* recalibrate */
5587 case 0x14: /* controller internal diagnostic */
5588 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5592 case 0x0a: /* read disk sectors with ECC */
5593 case 0x0b: /* write disk sectors with ECC */
5594 case 0x18: // set media type for format
5595 case 0x50: // IBM/MS send packet command
5597 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5603 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5605 SET_DISK_RET_STATUS(GET_AH());
5606 int13_fail_nostatus
:
5607 SET_CF(); // error occurred
5611 SET_AH(0x00); // no error
5613 SET_DISK_RET_STATUS(0x00);
5614 CLEAR_CF(); // no error
5617 // ---------------------------------------------------------------------------
5618 // Start of int13 for cdrom
5619 // ---------------------------------------------------------------------------
5622 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5623 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5625 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5626 Bit8u device
, status
, locks
;
5629 Bit16u count
, segment
, offset
, i
, size
;
5631 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5633 SET_DISK_RET_STATUS(0x00);
5635 /* basic check : device should be 0xE0+ */
5636 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5637 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5641 // Get the ata channel
5642 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5644 /* basic check : device has to be valid */
5645 if (device
>= BX_MAX_ATA_DEVICES
) {
5646 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5652 // all those functions return SUCCESS
5653 case 0x00: /* disk controller reset */
5654 case 0x09: /* initialize drive parameters */
5655 case 0x0c: /* seek to specified cylinder */
5656 case 0x0d: /* alternate disk reset */
5657 case 0x10: /* check drive ready */
5658 case 0x11: /* recalibrate */
5659 case 0x14: /* controller internal diagnostic */
5660 case 0x16: /* detect disk change */
5664 // all those functions return disk write-protected
5665 case 0x03: /* write disk sectors */
5666 case 0x05: /* format disk track */
5667 case 0x43: // IBM/MS extended write
5669 goto int13_fail_noah
;
5672 case 0x01: /* read disk status */
5673 status
= read_byte(0x0040, 0x0074);
5675 SET_DISK_RET_STATUS(0);
5677 /* set CF if error status read */
5678 if (status
) goto int13_fail_nostatus
;
5679 else goto int13_success_noah
;
5682 case 0x15: /* read disk drive size */
5684 goto int13_fail_noah
;
5687 case 0x41: // IBM/MS installation check
5688 BX
=0xaa55; // install check
5689 SET_AH(0x30); // EDD 2.1
5690 CX
=0x0007; // ext disk access, removable and edd
5691 goto int13_success_noah
;
5694 case 0x42: // IBM/MS extended read
5695 case 0x44: // IBM/MS verify sectors
5696 case 0x47: // IBM/MS extended seek
5698 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5699 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5700 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5702 // Can't use 64 bits lba
5703 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5705 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5710 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5712 // If verify or seek
5713 if ((GET_AH() == 0x44) || (GET_AH() == 0x47))
5716 memsetb(get_SS(),atacmd
,0,12);
5717 atacmd
[0]=0x28; // READ command
5718 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5719 atacmd
[8]=(count
& 0x00ff); // Sectors
5720 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5721 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5722 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5723 atacmd
[5]=(lba
& 0x000000ff);
5724 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5726 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5727 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5730 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5732 goto int13_fail_noah
;
5738 case 0x45: // IBM/MS lock/unlock drive
5739 if (GET_AL() > 2) goto int13_fail
;
5741 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5745 if (locks
== 0xff) {
5748 goto int13_fail_noah
;
5750 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5754 if (locks
== 0x00) {
5757 goto int13_fail_noah
;
5759 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5760 SET_AL(locks
==0?0:1);
5763 SET_AL(locks
==0?0:1);
5770 case 0x46: // IBM/MS eject media
5771 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5774 SET_AH(0xb1); // media locked
5775 goto int13_fail_noah
;
5777 // FIXME should handle 0x31 no media in device
5778 // FIXME should handle 0xb5 valid request failed
5780 // Call removable media eject
5787 mov _int13_cdrom
.status
+ 2[bp
], ah
5788 jnc int13_cdrom_rme_end
5789 mov _int13_cdrom
.status
, #1
5790 int13_cdrom_rme_end
:
5795 SET_AH(0xb1); // media locked
5796 goto int13_fail_noah
;
5802 case 0x48: // IBM/MS get drive parameters
5803 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5805 // Buffer is too small
5811 Bit16u cylinders
, heads
, spt
, blksize
;
5813 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5815 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5816 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5817 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5818 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5819 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5820 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5821 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5822 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5827 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5828 Bit16u iobase1
, iobase2
, options
;
5830 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5832 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5833 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5836 channel
= device
/ 2;
5837 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5838 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5839 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5840 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5842 // FIXME atapi device
5843 options
= (1<<4); // lba translation
5844 options
|= (1<<5); // removable device
5845 options
|= (1<<6); // atapi device
5846 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5848 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5849 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5850 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5851 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5852 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5853 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5854 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5855 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5856 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5857 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5858 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5861 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5862 checksum
= ~checksum
;
5863 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5868 Bit8u channel
, iface
, checksum
, i
;
5871 channel
= device
/ 2;
5872 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5873 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5875 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5876 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5877 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5878 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5879 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5881 if (iface
==ATA_IFACE_ISA
) {
5882 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5883 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5884 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5885 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5890 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5891 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5892 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5893 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5895 if (iface
==ATA_IFACE_ISA
) {
5896 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5897 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5898 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5903 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5904 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5905 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5906 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5909 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5910 checksum
= ~checksum
;
5911 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5917 case 0x49: // IBM/MS extended media change
5918 // always send changed ??
5920 goto int13_fail_nostatus
;
5923 case 0x4e: // // IBM/MS set hardware configuration
5924 // DMA, prefetch, PIO maximum not supported
5937 // all those functions return unimplemented
5938 case 0x02: /* read sectors */
5939 case 0x04: /* verify sectors */
5940 case 0x08: /* read disk drive parameters */
5941 case 0x0a: /* read disk sectors with ECC */
5942 case 0x0b: /* write disk sectors with ECC */
5943 case 0x18: /* set media type for format */
5944 case 0x50: // ? - send packet command
5946 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5952 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5954 SET_DISK_RET_STATUS(GET_AH());
5955 int13_fail_nostatus
:
5956 SET_CF(); // error occurred
5960 SET_AH(0x00); // no error
5962 SET_DISK_RET_STATUS(0x00);
5963 CLEAR_CF(); // no error
5966 // ---------------------------------------------------------------------------
5967 // End of int13 for cdrom
5968 // ---------------------------------------------------------------------------
5970 #if BX_ELTORITO_BOOT
5971 // ---------------------------------------------------------------------------
5972 // Start of int13 for eltorito functions
5973 // ---------------------------------------------------------------------------
5976 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5977 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5979 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5981 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5982 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5986 // FIXME ElTorito Various. Should be implemented
5987 case 0x4a: // ElTorito - Initiate disk emu
5988 case 0x4c: // ElTorito - Initiate disk emu and boot
5989 case 0x4d: // ElTorito - Return Boot catalog
5990 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5994 case 0x4b: // ElTorito - Terminate disk emu
5995 // FIXME ElTorito Hardcoded
5996 write_byte(DS
,SI
+0x00,0x13);
5997 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5998 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5999 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
6000 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
6001 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
6002 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
6003 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
6004 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
6005 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
6006 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
6007 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
6009 // If we have to terminate emulation
6010 if(GET_AL() == 0x00) {
6011 // FIXME ElTorito Various. Should be handled accordingly to spec
6012 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
6019 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6025 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6026 SET_DISK_RET_STATUS(GET_AH());
6027 SET_CF(); // error occurred
6031 SET_AH(0x00); // no error
6032 SET_DISK_RET_STATUS(0x00);
6033 CLEAR_CF(); // no error
6036 // ---------------------------------------------------------------------------
6037 // End of int13 for eltorito functions
6038 // ---------------------------------------------------------------------------
6040 // ---------------------------------------------------------------------------
6041 // Start of int13 when emulating a device from the cd
6042 // ---------------------------------------------------------------------------
6045 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6046 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6048 Bit16u ebda_seg
=read_word(0x0040,0x000E);
6049 Bit8u device
, status
;
6050 Bit16u vheads
, vspt
, vcylinders
;
6051 Bit16u head
, sector
, cylinder
, nbsectors
;
6052 Bit32u vlba
, ilba
, slba
, elba
;
6053 Bit16u before
, segment
, offset
;
6056 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6058 /* at this point, we are emulating a floppy/harddisk */
6060 // Recompute the device number
6061 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
6062 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
6064 SET_DISK_RET_STATUS(0x00);
6066 /* basic checks : emulation should be active, dl should equal the emulated drive */
6067 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0) ||
6068 (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
6069 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6075 // all those functions return SUCCESS
6076 case 0x00: /* disk controller reset */
6077 case 0x09: /* initialize drive parameters */
6078 case 0x0c: /* seek to specified cylinder */
6079 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6080 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6081 case 0x11: /* recalibrate */
6082 case 0x14: /* controller internal diagnostic */
6083 case 0x16: /* detect disk change */
6087 // all those functions return disk write-protected
6088 case 0x03: /* write disk sectors */
6089 case 0x05: /* format disk track */
6091 goto int13_fail_noah
;
6094 case 0x01: /* read disk status */
6095 status
=read_byte(0x0040, 0x0074);
6097 SET_DISK_RET_STATUS(0);
6099 /* set CF if error status read */
6100 if (status
) goto int13_fail_nostatus
;
6101 else goto int13_success_noah
;
6104 case 0x02: // read disk sectors
6105 case 0x04: // verify disk sectors
6106 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
6107 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
6108 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
6110 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
6112 sector
= GET_CL() & 0x003f;
6113 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6115 nbsectors
= GET_AL();
6119 // no sector to read ?
6120 if(nbsectors
==0) goto int13_success
;
6122 // sanity checks sco openserver needs this!
6124 || (cylinder
>= vcylinders
)
6125 || (head
>= vheads
)) {
6129 // After controls, verify do nothing
6130 if (GET_AH() == 0x04) goto int13_success
;
6132 segment
= ES
+(BX
/ 16);
6135 // calculate the virtual lba inside the image
6136 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
6138 // In advance so we don't loose the count
6142 slba
= (Bit32u
)vlba
/4;
6143 before
= (Bit16u
)vlba
%4;
6146 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
6148 memsetb(get_SS(),atacmd
,0,12);
6149 atacmd
[0]=0x28; // READ command
6150 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
6151 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
6152 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
6153 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
6154 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
6155 atacmd
[5]=(ilba
+slba
& 0x000000ff);
6156 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
6157 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
6160 goto int13_fail_noah
;
6166 case 0x08: /* read disk drive parameters */
6167 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
6168 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
6169 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
6173 SET_CH(vcylinders
& 0xff);
6174 SET_CL(((vcylinders
>> 2) & 0xc0) | (vspt
& 0x3f));
6176 SET_DL(0x02); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6177 // FIXME ElTorito Harddisk. should send the HD count
6179 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
6180 case 0x01: SET_BL( 0x02 ); break;
6181 case 0x02: SET_BL( 0x04 ); break;
6182 case 0x03: SET_BL( 0x06 ); break;
6188 mov ax
, #diskette_param_table2
6189 mov _int13_cdemu
.DI
+2[bp
], ax
6190 mov _int13_cdemu
.ES
+2[bp
], cs
6196 case 0x15: /* read disk drive size */
6197 // FIXME ElTorito Harddisk. What geometry to send ?
6199 goto int13_success_noah
;
6202 // all those functions return unimplemented
6203 case 0x0a: /* read disk sectors with ECC */
6204 case 0x0b: /* write disk sectors with ECC */
6205 case 0x18: /* set media type for format */
6206 case 0x41: // IBM/MS installation check
6207 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6208 case 0x42: // IBM/MS extended read
6209 case 0x43: // IBM/MS extended write
6210 case 0x44: // IBM/MS verify sectors
6211 case 0x45: // IBM/MS lock/unlock drive
6212 case 0x46: // IBM/MS eject media
6213 case 0x47: // IBM/MS extended seek
6214 case 0x48: // IBM/MS get drive parameters
6215 case 0x49: // IBM/MS extended media change
6216 case 0x4e: // ? - set hardware configuration
6217 case 0x50: // ? - send packet command
6219 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6225 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6227 SET_DISK_RET_STATUS(GET_AH());
6228 int13_fail_nostatus
:
6229 SET_CF(); // error occurred
6233 SET_AH(0x00); // no error
6235 SET_DISK_RET_STATUS(0x00);
6236 CLEAR_CF(); // no error
6239 // ---------------------------------------------------------------------------
6240 // End of int13 when emulating a device from the cd
6241 // ---------------------------------------------------------------------------
6243 #endif // BX_ELTORITO_BOOT
6245 #else //BX_USE_ATADRV
6248 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
6263 mov ax
,4[bp
] // cylinder
6265 mov bl
,6[bp
] // hd_heads
6268 mov bl
,8[bp
] // head
6270 mov bl
,10[bp
] // hd_sectors
6272 mov bl
,12[bp
] // sector
6301 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6302 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6304 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
6308 Bit16u max_cylinder
, cylinder
, total_sectors
;
6309 Bit16u hd_cylinders
;
6310 Bit8u hd_heads
, hd_sectors
;
6317 Bit16u count
, segment
, offset
;
6321 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6323 write_byte(0x0040, 0x008e, 0); // clear completion flag
6325 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6327 /* check how many disks first (cmos reg 0x12), return an error if
6328 drive not present */
6329 drive_map
= inb_cmos(0x12);
6330 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6331 (((drive_map
& 0x0f)==0) ? 0 : 2);
6332 n_drives
= (drive_map
==0) ? 0 : ((drive_map
==3) ? 2 : 1);
6334 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6336 SET_DISK_RET_STATUS(0x01);
6337 SET_CF(); /* error occurred */
6343 case 0x00: /* disk controller reset */
6344 BX_DEBUG_INT13_HD("int13_f00\n");
6347 SET_DISK_RET_STATUS(0);
6348 set_diskette_ret_status(0);
6349 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6350 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6351 CLEAR_CF(); /* successful */
6355 case 0x01: /* read disk status */
6356 BX_DEBUG_INT13_HD("int13_f01\n");
6357 status
= read_byte(0x0040, 0x0074);
6359 SET_DISK_RET_STATUS(0);
6360 /* set CF if error status read */
6361 if (status
) SET_CF();
6366 case 0x04: // verify disk sectors
6367 case 0x02: // read disk sectors
6369 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6371 num_sectors
= GET_AL();
6372 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6373 sector
= (GET_CL() & 0x3f);
6377 if (hd_cylinders
> 1024) {
6378 if (hd_cylinders
<= 2048) {
6381 else if (hd_cylinders
<= 4096) {
6384 else if (hd_cylinders
<= 8192) {
6387 else { // hd_cylinders <= 16384
6391 ax
= head
/ hd_heads
;
6392 cyl_mod
= ax
& 0xff;
6394 cylinder
|= cyl_mod
;
6397 if ( (cylinder
>= hd_cylinders
) ||
6398 (sector
> hd_sectors
) ||
6399 (head
>= hd_heads
) ) {
6401 SET_DISK_RET_STATUS(1);
6402 SET_CF(); /* error occurred */
6406 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6407 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6410 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6412 if ( GET_AH() == 0x04 ) {
6414 SET_DISK_RET_STATUS(0);
6419 status
= inb(0x1f7);
6420 if (status
& 0x80) {
6421 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6423 outb(0x01f2, num_sectors
);
6424 /* activate LBA? (tomv) */
6425 if (hd_heads
> 16) {
6426 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6427 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6430 outb(0x01f3, sector
);
6431 outb(0x01f4, cylinder
& 0x00ff);
6432 outb(0x01f5, cylinder
>> 8);
6433 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6438 status
= inb(0x1f7);
6439 if (!(status
& 0x80)) break;
6442 if (status
& 0x01) {
6443 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6444 } else if (!(status
& 0x08)) {
6445 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6446 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6453 sti
;; enable higher priority interrupts
6458 ;; store temp bx in real DI
register
6461 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6464 ;; adjust
if there will be an overrun
6466 jbe i13_f02_no_adjust
6468 sub di
, #0x0200 ; sub 512 bytes from offset
6470 add ax
, #0x0020 ; add 512 to segment
6474 mov cx
, #0x0100 ;; counter (256 words = 512b)
6475 mov dx
, #0x01f0 ;; AT data read port
6478 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6481 ;; store real DI
register back to temp bx
6484 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6490 if (num_sectors
== 0) {
6491 status
= inb(0x1f7);
6492 if ((status
& 0xc9) != 0x40)
6493 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6497 status
= inb(0x1f7);
6498 if ((status
& 0xc9) != 0x48)
6499 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6505 SET_DISK_RET_STATUS(0);
6506 SET_AL(sector_count
);
6507 CLEAR_CF(); /* successful */
6511 case 0x03: /* write disk sectors */
6512 BX_DEBUG_INT13_HD("int13_f03\n");
6513 drive
= GET_ELDL ();
6514 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6516 num_sectors
= GET_AL();
6517 cylinder
= GET_CH();
6518 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6519 sector
= (GET_CL() & 0x3f);
6522 if (hd_cylinders
> 1024) {
6523 if (hd_cylinders
<= 2048) {
6526 else if (hd_cylinders
<= 4096) {
6529 else if (hd_cylinders
<= 8192) {
6532 else { // hd_cylinders <= 16384
6536 ax
= head
/ hd_heads
;
6537 cyl_mod
= ax
& 0xff;
6539 cylinder
|= cyl_mod
;
6542 if ( (cylinder
>= hd_cylinders
) ||
6543 (sector
> hd_sectors
) ||
6544 (head
>= hd_heads
) ) {
6546 SET_DISK_RET_STATUS(1);
6547 SET_CF(); /* error occurred */
6551 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6552 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6555 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6557 status
= inb(0x1f7);
6558 if (status
& 0x80) {
6559 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6561 // should check for Drive Ready Bit also in status reg
6562 outb(0x01f2, num_sectors
);
6564 /* activate LBA? (tomv) */
6565 if (hd_heads
> 16) {
6566 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6567 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6570 outb(0x01f3, sector
);
6571 outb(0x01f4, cylinder
& 0x00ff);
6572 outb(0x01f5, cylinder
>> 8);
6573 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6577 // wait for busy bit to turn off after seeking
6579 status
= inb(0x1f7);
6580 if (!(status
& 0x80)) break;
6583 if (!(status
& 0x08)) {
6584 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6585 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6592 sti
;; enable higher priority interrupts
6597 ;; store temp bx in real SI
register
6600 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6603 ;; adjust
if there will be an overrun
6605 jbe i13_f03_no_adjust
6607 sub si
, #0x0200 ; sub 512 bytes from offset
6609 add ax
, #0x0020 ; add 512 to segment
6613 mov cx
, #0x0100 ;; counter (256 words = 512b)
6614 mov dx
, #0x01f0 ;; AT data read port
6618 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6620 ;; store real SI
register back to temp bx
6623 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6629 if (num_sectors
== 0) {
6630 status
= inb(0x1f7);
6631 if ((status
& 0xe9) != 0x40)
6632 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6636 status
= inb(0x1f7);
6637 if ((status
& 0xc9) != 0x48)
6638 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6644 SET_DISK_RET_STATUS(0);
6645 SET_AL(sector_count
);
6646 CLEAR_CF(); /* successful */
6650 case 0x05: /* format disk track */
6651 BX_DEBUG_INT13_HD("int13_f05\n");
6652 BX_PANIC("format disk track called\n");
6655 SET_DISK_RET_STATUS(0);
6656 CLEAR_CF(); /* successful */
6660 case 0x08: /* read disk drive parameters */
6661 BX_DEBUG_INT13_HD("int13_f08\n");
6663 drive
= GET_ELDL ();
6664 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6668 if (hd_cylinders
<= 1024) {
6669 // hd_cylinders >>= 0;
6672 else if (hd_cylinders
<= 2048) {
6676 else if (hd_cylinders
<= 4096) {
6680 else if (hd_cylinders
<= 8192) {
6684 else { // hd_cylinders <= 16384
6689 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6691 SET_CH(max_cylinder
& 0xff);
6692 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6693 SET_DH(hd_heads
- 1);
6694 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6696 SET_DISK_RET_STATUS(0);
6697 CLEAR_CF(); /* successful */
6702 case 0x09: /* initialize drive parameters */
6703 BX_DEBUG_INT13_HD("int13_f09\n");
6705 SET_DISK_RET_STATUS(0);
6706 CLEAR_CF(); /* successful */
6710 case 0x0a: /* read disk sectors with ECC */
6711 BX_DEBUG_INT13_HD("int13_f0a\n");
6712 case 0x0b: /* write disk sectors with ECC */
6713 BX_DEBUG_INT13_HD("int13_f0b\n");
6714 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6718 case 0x0c: /* seek to specified cylinder */
6719 BX_DEBUG_INT13_HD("int13_f0c\n");
6720 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6722 SET_DISK_RET_STATUS(0);
6723 CLEAR_CF(); /* successful */
6727 case 0x0d: /* alternate disk reset */
6728 BX_DEBUG_INT13_HD("int13_f0d\n");
6730 SET_DISK_RET_STATUS(0);
6731 CLEAR_CF(); /* successful */
6735 case 0x10: /* check drive ready */
6736 BX_DEBUG_INT13_HD("int13_f10\n");
6738 //SET_DISK_RET_STATUS(0);
6739 //CLEAR_CF(); /* successful */
6743 // should look at 40:8E also???
6744 status
= inb(0x01f7);
6745 if ((status
& 0xc0) == 0x40) {
6747 SET_DISK_RET_STATUS(0);
6748 CLEAR_CF(); // drive ready
6753 SET_DISK_RET_STATUS(0xAA);
6754 SET_CF(); // not ready
6759 case 0x11: /* recalibrate */
6760 BX_DEBUG_INT13_HD("int13_f11\n");
6762 SET_DISK_RET_STATUS(0);
6763 CLEAR_CF(); /* successful */
6767 case 0x14: /* controller internal diagnostic */
6768 BX_DEBUG_INT13_HD("int13_f14\n");
6770 SET_DISK_RET_STATUS(0);
6771 CLEAR_CF(); /* successful */
6776 case 0x15: /* read disk drive size */
6778 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6782 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6783 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6784 mul al
, ah
;; ax
= heads
* sectors
6785 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6786 dec bx
;; use (cylinders
- 1) ???
6787 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6788 ;; now we need to move the
32bit result dx
:ax to what the
6789 ;; BIOS wants which is cx
:dx
.
6790 ;; and then into CX
:DX on the stack
6791 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6792 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6795 SET_AH(3); // hard disk accessible
6796 SET_DISK_RET_STATUS(0); // ??? should this be 0
6797 CLEAR_CF(); // successful
6801 case 0x18: // set media type for format
6802 case 0x41: // IBM/MS
6803 case 0x42: // IBM/MS
6804 case 0x43: // IBM/MS
6805 case 0x44: // IBM/MS
6806 case 0x45: // IBM/MS lock/unlock drive
6807 case 0x46: // IBM/MS eject media
6808 case 0x47: // IBM/MS extended seek
6809 case 0x49: // IBM/MS extended media change
6810 case 0x50: // IBM/MS send packet command
6812 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6814 SET_AH(1); // code=invalid function in AH or invalid parameter
6815 SET_DISK_RET_STATUS(1);
6816 SET_CF(); /* unsuccessful */
6821 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6822 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6825 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6827 Bit16u
*hd_cylinders
;
6837 if (drive
== 0x80) {
6838 hd_type
= inb_cmos(0x12) & 0xf0;
6839 if (hd_type
!= 0xf0)
6840 BX_INFO(panic_msg_reg12h
,0);
6841 hd_type
= inb_cmos(0x19); // HD0: extended type
6843 BX_INFO(panic_msg_reg19h
,0,0x19);
6846 hd_type
= inb_cmos(0x12) & 0x0f;
6847 if (hd_type
!= 0x0f)
6848 BX_INFO(panic_msg_reg12h
,1);
6849 hd_type
= inb_cmos(0x1a); // HD1: extended type
6851 BX_INFO(panic_msg_reg19h
,0,0x1a);
6856 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6857 write_word(ss
, hd_cylinders
, cylinders
);
6860 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6862 // sectors per track
6863 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6866 #endif //else BX_USE_ATADRV
6868 #if BX_SUPPORT_FLOPPY
6870 //////////////////////
6871 // FLOPPY functions //
6872 //////////////////////
6874 void floppy_reset_controller()
6880 outb(0x03f2, val8
& ~0x04);
6881 outb(0x03f2, val8
| 0x04);
6883 // Wait for controller to come out of reset
6886 } while ((val8
& 0xc0) != 0x80);
6889 void floppy_prepare_controller(drive
)
6892 Bit8u val8
, dor
, prev_reset
;
6894 // set 40:3e bit 7 to 0
6895 val8
= read_byte(0x0040, 0x003e);
6897 write_byte(0x0040, 0x003e, val8
);
6899 // turn on motor of selected drive, DMA & int enabled, normal operation
6900 prev_reset
= inb(0x03f2) & 0x04;
6909 // reset the disk motor timeout value of INT 08
6910 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6912 // wait for drive readiness
6915 } while ( (val8
& 0xc0) != 0x80 );
6917 if (prev_reset
== 0) {
6918 // turn on interrupts
6922 // wait on 40:3e bit 7 to become 1
6924 val8
= read_byte(0x0040, 0x003e);
6925 } while ( (val8
& 0x80) == 0 );
6930 write_byte(0x0040, 0x003e, val8
);
6935 floppy_media_known(drive
)
6939 Bit16u media_state_offset
;
6941 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6948 media_state_offset
= 0x0090;
6950 media_state_offset
+= 1;
6952 val8
= read_byte(0x0040, media_state_offset
);
6953 val8
= (val8
>> 4) & 0x01;
6957 // check pass, return KNOWN
6962 floppy_media_sense(drive
)
6966 Bit16u media_state_offset
;
6967 Bit8u drive_type
, config_data
, media_state
;
6969 if (floppy_drive_recal(drive
) == 0) {
6973 // for now cheat and get drive type from CMOS,
6974 // assume media is same as drive type
6976 // ** config_data **
6977 // Bitfields for diskette media control:
6978 // Bit(s) Description (Table M0028)
6979 // 7-6 last data rate set by controller
6980 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6981 // 5-4 last diskette drive step rate selected
6982 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6983 // 3-2 {data rate at start of operation}
6986 // ** media_state **
6987 // Bitfields for diskette drive media state:
6988 // Bit(s) Description (Table M0030)
6990 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6991 // 5 double stepping required (e.g. 360kB in 1.2MB)
6992 // 4 media type established
6993 // 3 drive capable of supporting 4MB media
6994 // 2-0 on exit from BIOS, contains
6995 // 000 trying 360kB in 360kB
6996 // 001 trying 360kB in 1.2MB
6997 // 010 trying 1.2MB in 1.2MB
6998 // 011 360kB in 360kB established
6999 // 100 360kB in 1.2MB established
7000 // 101 1.2MB in 1.2MB established
7002 // 111 all other formats/drives
7004 drive_type
= inb_cmos(0x10);
7011 if (drive_type
== 1) {
7013 config_data
= 0x00; // 0000 0000
7014 media_state
= 0x25; // 0010 0101
7017 else if (drive_type
== 2) {
7018 // 1.2 MB 5.25" drive
7019 config_data
= 0x00; // 0000 0000
7020 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
7023 else if (drive_type
== 3) {
7025 config_data
= 0x00; // 0000 0000 ???
7026 media_state
= 0x17; // 0001 0111
7029 else if (drive_type
== 4) {
7030 // 1.44 MB 3.5" drive
7031 config_data
= 0x00; // 0000 0000
7032 media_state
= 0x17; // 0001 0111
7035 else if (drive_type
== 5) {
7036 // 2.88 MB 3.5" drive
7037 config_data
= 0xCC; // 1100 1100
7038 media_state
= 0xD7; // 1101 0111
7041 // Extended floppy size uses special cmos setting
7042 else if (drive_type
== 6) {
7044 config_data
= 0x00; // 0000 0000
7045 media_state
= 0x27; // 0010 0111
7048 else if (drive_type
== 7) {
7050 config_data
= 0x00; // 0000 0000
7051 media_state
= 0x27; // 0010 0111
7054 else if (drive_type
== 8) {
7056 config_data
= 0x00; // 0000 0000
7057 media_state
= 0x27; // 0010 0111
7062 config_data
= 0x00; // 0000 0000
7063 media_state
= 0x00; // 0000 0000
7068 media_state_offset
= 0x90;
7070 media_state_offset
= 0x91;
7071 write_byte(0x0040, 0x008B, config_data
);
7072 write_byte(0x0040, media_state_offset
, media_state
);
7078 floppy_drive_recal(drive
)
7082 Bit16u curr_cyl_offset
;
7084 floppy_prepare_controller(drive
);
7086 // send Recalibrate command (2 bytes) to controller
7087 outb(0x03f5, 0x07); // 07: Recalibrate
7088 outb(0x03f5, drive
); // 0=drive0, 1=drive1
7090 // turn on interrupts
7095 // wait on 40:3e bit 7 to become 1
7097 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7098 } while ( val8
== 0 );
7100 val8
= 0; // separate asm from while() loop
7101 // turn off interrupts
7106 // set 40:3e bit 7 to 0, and calibrated bit
7107 val8
= read_byte(0x0040, 0x003e);
7110 val8
|= 0x02; // Drive 1 calibrated
7111 curr_cyl_offset
= 0x0095;
7113 val8
|= 0x01; // Drive 0 calibrated
7114 curr_cyl_offset
= 0x0094;
7116 write_byte(0x0040, 0x003e, val8
);
7117 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
7123 floppy_drive_exists(drive
)
7128 // check CMOS to see if drive exists
7129 drive_type
= inb_cmos(0x10);
7134 if ( drive_type
== 0 )
7141 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7142 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7144 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
7145 Bit16u base_address
, base_count
, base_es
;
7146 Bit8u page
, mode_register
, val8
, dor
;
7147 Bit8u return_status
[7];
7148 Bit8u drive_type
, num_floppies
, ah
;
7149 Bit16u es
, last_addr
;
7151 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
7156 case 0x00: // diskette controller reset
7157 BX_DEBUG_INT13_FL("floppy f00\n");
7160 SET_AH(1); // invalid param
7161 set_diskette_ret_status(1);
7165 drive_type
= inb_cmos(0x10);
7171 if (drive_type
== 0) {
7172 SET_AH(0x80); // drive not responding
7173 set_diskette_ret_status(0x80);
7178 set_diskette_ret_status(0);
7179 CLEAR_CF(); // successful
7180 set_diskette_current_cyl(drive
, 0); // current cylinder
7183 case 0x01: // Read Diskette Status
7185 val8
= read_byte(0x0000, 0x0441);
7192 case 0x02: // Read Diskette Sectors
7193 case 0x03: // Write Diskette Sectors
7194 case 0x04: // Verify Diskette Sectors
7195 num_sectors
= GET_AL();
7201 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
7202 (num_sectors
== 0) || (num_sectors
> 72)) {
7203 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
7205 set_diskette_ret_status(1);
7206 SET_AL(0); // no sectors read
7207 SET_CF(); // error occurred
7211 // see if drive exists
7212 if (floppy_drive_exists(drive
) == 0) {
7213 SET_AH(0x80); // not responding
7214 set_diskette_ret_status(0x80);
7215 SET_AL(0); // no sectors read
7216 SET_CF(); // error occurred
7220 // see if media in drive, and type is known
7221 if (floppy_media_known(drive
) == 0) {
7222 if (floppy_media_sense(drive
) == 0) {
7223 SET_AH(0x0C); // Media type not found
7224 set_diskette_ret_status(0x0C);
7225 SET_AL(0); // no sectors read
7226 SET_CF(); // error occurred
7232 // Read Diskette Sectors
7234 //-----------------------------------
7235 // set up DMA controller for transfer
7236 //-----------------------------------
7238 // es:bx = pointer to where to place information from diskette
7239 // port 04: DMA-1 base and current address, channel 2
7240 // port 05: DMA-1 base and current count, channel 2
7241 page
= (ES
>> 12); // upper 4 bits
7242 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7243 base_address
= base_es
+ BX
; // lower 16 bits of address
7244 // contributed by ES:BX
7245 if ( base_address
< base_es
) {
7246 // in case of carry, adjust page by 1
7249 base_count
= (num_sectors
* 512) - 1;
7251 // check for 64K boundary overrun
7252 last_addr
= base_address
+ base_count
;
7253 if (last_addr
< base_address
) {
7255 set_diskette_ret_status(0x09);
7256 SET_AL(0); // no sectors read
7257 SET_CF(); // error occurred
7261 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7264 BX_DEBUG_INT13_FL("clear flip-flop\n");
7265 outb(0x000c, 0x00); // clear flip-flop
7266 outb(0x0004, base_address
);
7267 outb(0x0004, base_address
>>8);
7268 BX_DEBUG_INT13_FL("clear flip-flop\n");
7269 outb(0x000c, 0x00); // clear flip-flop
7270 outb(0x0005, base_count
);
7271 outb(0x0005, base_count
>>8);
7273 // port 0b: DMA-1 Mode Register
7274 mode_register
= 0x46; // single mode, increment, autoinit disable,
7275 // transfer type=write, channel 2
7276 BX_DEBUG_INT13_FL("setting mode register\n");
7277 outb(0x000b, mode_register
);
7279 BX_DEBUG_INT13_FL("setting page register\n");
7280 // port 81: DMA-1 Page Register, channel 2
7283 BX_DEBUG_INT13_FL("unmask chan 2\n");
7284 outb(0x000a, 0x02); // unmask channel 2
7286 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7289 //--------------------------------------
7290 // set up floppy controller for transfer
7291 //--------------------------------------
7292 floppy_prepare_controller(drive
);
7294 // send read-normal-data command (9 bytes) to controller
7295 outb(0x03f5, 0xe6); // e6: read normal data
7296 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7297 outb(0x03f5, track
);
7299 outb(0x03f5, sector
);
7300 outb(0x03f5, 2); // 512 byte sector size
7301 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
7302 outb(0x03f5, 0); // Gap length
7303 outb(0x03f5, 0xff); // Gap length
7305 // turn on interrupts
7310 // wait on 40:3e bit 7 to become 1
7312 val8
= read_byte(0x0040, 0x0040);
7314 floppy_reset_controller();
7315 SET_AH(0x80); // drive not ready (timeout)
7316 set_diskette_ret_status(0x80);
7317 SET_AL(0); // no sectors read
7318 SET_CF(); // error occurred
7321 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7322 } while ( val8
== 0 );
7324 val8
= 0; // separate asm from while() loop
7325 // turn off interrupts
7330 // set 40:3e bit 7 to 0
7331 val8
= read_byte(0x0040, 0x003e);
7333 write_byte(0x0040, 0x003e, val8
);
7335 // check port 3f4 for accessibility to status bytes
7337 if ( (val8
& 0xc0) != 0xc0 )
7338 BX_PANIC("int13_diskette: ctrl not ready\n");
7340 // read 7 return status bytes from controller
7341 // using loop index broken, have to unroll...
7342 return_status
[0] = inb(0x3f5);
7343 return_status
[1] = inb(0x3f5);
7344 return_status
[2] = inb(0x3f5);
7345 return_status
[3] = inb(0x3f5);
7346 return_status
[4] = inb(0x3f5);
7347 return_status
[5] = inb(0x3f5);
7348 return_status
[6] = inb(0x3f5);
7349 // record in BIOS Data Area
7350 write_byte(0x0040, 0x0042, return_status
[0]);
7351 write_byte(0x0040, 0x0043, return_status
[1]);
7352 write_byte(0x0040, 0x0044, return_status
[2]);
7353 write_byte(0x0040, 0x0045, return_status
[3]);
7354 write_byte(0x0040, 0x0046, return_status
[4]);
7355 write_byte(0x0040, 0x0047, return_status
[5]);
7356 write_byte(0x0040, 0x0048, return_status
[6]);
7358 if ( (return_status
[0] & 0xc0) != 0 ) {
7360 set_diskette_ret_status(0x20);
7361 SET_AL(0); // no sectors read
7362 SET_CF(); // error occurred
7366 // ??? should track be new val from return_status[3] ?
7367 set_diskette_current_cyl(drive
, track
);
7368 // AL = number of sectors read (same value as passed)
7369 SET_AH(0x00); // success
7370 CLEAR_CF(); // success
7372 } else if (ah
== 0x03) {
7373 // Write Diskette Sectors
7375 //-----------------------------------
7376 // set up DMA controller for transfer
7377 //-----------------------------------
7379 // es:bx = pointer to where to place information from diskette
7380 // port 04: DMA-1 base and current address, channel 2
7381 // port 05: DMA-1 base and current count, channel 2
7382 page
= (ES
>> 12); // upper 4 bits
7383 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7384 base_address
= base_es
+ BX
; // lower 16 bits of address
7385 // contributed by ES:BX
7386 if ( base_address
< base_es
) {
7387 // in case of carry, adjust page by 1
7390 base_count
= (num_sectors
* 512) - 1;
7392 // check for 64K boundary overrun
7393 last_addr
= base_address
+ base_count
;
7394 if (last_addr
< base_address
) {
7396 set_diskette_ret_status(0x09);
7397 SET_AL(0); // no sectors read
7398 SET_CF(); // error occurred
7402 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7405 outb(0x000c, 0x00); // clear flip-flop
7406 outb(0x0004, base_address
);
7407 outb(0x0004, base_address
>>8);
7408 outb(0x000c, 0x00); // clear flip-flop
7409 outb(0x0005, base_count
);
7410 outb(0x0005, base_count
>>8);
7412 // port 0b: DMA-1 Mode Register
7413 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7414 // transfer type=read, channel 2
7415 outb(0x000b, mode_register
);
7417 // port 81: DMA-1 Page Register, channel 2
7420 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7423 //--------------------------------------
7424 // set up floppy controller for transfer
7425 //--------------------------------------
7426 floppy_prepare_controller(drive
);
7428 // send write-normal-data command (9 bytes) to controller
7429 outb(0x03f5, 0xc5); // c5: write normal data
7430 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7431 outb(0x03f5, track
);
7433 outb(0x03f5, sector
);
7434 outb(0x03f5, 2); // 512 byte sector size
7435 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7436 outb(0x03f5, 0); // Gap length
7437 outb(0x03f5, 0xff); // Gap length
7439 // turn on interrupts
7444 // wait on 40:3e bit 7 to become 1
7446 val8
= read_byte(0x0040, 0x0040);
7448 floppy_reset_controller();
7449 SET_AH(0x80); // drive not ready (timeout)
7450 set_diskette_ret_status(0x80);
7451 SET_AL(0); // no sectors written
7452 SET_CF(); // error occurred
7455 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7456 } while ( val8
== 0 );
7458 val8
= 0; // separate asm from while() loop
7459 // turn off interrupts
7464 // set 40:3e bit 7 to 0
7465 val8
= read_byte(0x0040, 0x003e);
7467 write_byte(0x0040, 0x003e, val8
);
7469 // check port 3f4 for accessibility to status bytes
7471 if ( (val8
& 0xc0) != 0xc0 )
7472 BX_PANIC("int13_diskette: ctrl not ready\n");
7474 // read 7 return status bytes from controller
7475 // using loop index broken, have to unroll...
7476 return_status
[0] = inb(0x3f5);
7477 return_status
[1] = inb(0x3f5);
7478 return_status
[2] = inb(0x3f5);
7479 return_status
[3] = inb(0x3f5);
7480 return_status
[4] = inb(0x3f5);
7481 return_status
[5] = inb(0x3f5);
7482 return_status
[6] = inb(0x3f5);
7483 // record in BIOS Data Area
7484 write_byte(0x0040, 0x0042, return_status
[0]);
7485 write_byte(0x0040, 0x0043, return_status
[1]);
7486 write_byte(0x0040, 0x0044, return_status
[2]);
7487 write_byte(0x0040, 0x0045, return_status
[3]);
7488 write_byte(0x0040, 0x0046, return_status
[4]);
7489 write_byte(0x0040, 0x0047, return_status
[5]);
7490 write_byte(0x0040, 0x0048, return_status
[6]);
7492 if ( (return_status
[0] & 0xc0) != 0 ) {
7493 if ( (return_status
[1] & 0x02) != 0 ) {
7494 // diskette not writable.
7495 // AH=status code=0x03 (tried to write on write-protected disk)
7496 // AL=number of sectors written=0
7501 BX_PANIC("int13_diskette_function: read error\n");
7505 // ??? should track be new val from return_status[3] ?
7506 set_diskette_current_cyl(drive
, track
);
7507 // AL = number of sectors read (same value as passed)
7508 SET_AH(0x00); // success
7509 CLEAR_CF(); // success
7511 } else { // if (ah == 0x04)
7512 // Verify Diskette Sectors
7514 // ??? should track be new val from return_status[3] ?
7515 set_diskette_current_cyl(drive
, track
);
7516 // AL = number of sectors verified (same value as passed)
7517 CLEAR_CF(); // success
7518 SET_AH(0x00); // success
7523 case 0x05: // format diskette track
7524 BX_DEBUG_INT13_FL("floppy f05\n");
7526 num_sectors
= GET_AL();
7531 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7532 (num_sectors
== 0) || (num_sectors
> 18)) {
7534 set_diskette_ret_status(1);
7535 SET_CF(); // error occurred
7538 // see if drive exists
7539 if (floppy_drive_exists(drive
) == 0) {
7540 SET_AH(0x80); // drive not responding
7541 set_diskette_ret_status(0x80);
7542 SET_CF(); // error occurred
7546 // see if media in drive, and type is known
7547 if (floppy_media_known(drive
) == 0) {
7548 if (floppy_media_sense(drive
) == 0) {
7549 SET_AH(0x0C); // Media type not found
7550 set_diskette_ret_status(0x0C);
7551 SET_AL(0); // no sectors read
7552 SET_CF(); // error occurred
7557 // set up DMA controller for transfer
7558 page
= (ES
>> 12); // upper 4 bits
7559 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7560 base_address
= base_es
+ BX
; // lower 16 bits of address
7561 // contributed by ES:BX
7562 if ( base_address
< base_es
) {
7563 // in case of carry, adjust page by 1
7566 base_count
= (num_sectors
* 4) - 1;
7568 // check for 64K boundary overrun
7569 last_addr
= base_address
+ base_count
;
7570 if (last_addr
< base_address
) {
7572 set_diskette_ret_status(0x09);
7573 SET_AL(0); // no sectors read
7574 SET_CF(); // error occurred
7579 outb(0x000c, 0x00); // clear flip-flop
7580 outb(0x0004, base_address
);
7581 outb(0x0004, base_address
>>8);
7582 outb(0x000c, 0x00); // clear flip-flop
7583 outb(0x0005, base_count
);
7584 outb(0x0005, base_count
>>8);
7585 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7586 // transfer type=read, channel 2
7587 outb(0x000b, mode_register
);
7588 // port 81: DMA-1 Page Register, channel 2
7592 // set up floppy controller for transfer
7593 floppy_prepare_controller(drive
);
7595 // send format-track command (6 bytes) to controller
7596 outb(0x03f5, 0x4d); // 4d: format track
7597 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7598 outb(0x03f5, 2); // 512 byte sector size
7599 outb(0x03f5, num_sectors
); // number of sectors per track
7600 outb(0x03f5, 0); // Gap length
7601 outb(0x03f5, 0xf6); // Fill byte
7602 // turn on interrupts
7607 // wait on 40:3e bit 7 to become 1
7609 val8
= read_byte(0x0040, 0x0040);
7611 floppy_reset_controller();
7612 SET_AH(0x80); // drive not ready (timeout)
7613 set_diskette_ret_status(0x80);
7614 SET_CF(); // error occurred
7617 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7618 } while ( val8
== 0 );
7620 val8
= 0; // separate asm from while() loop
7621 // turn off interrupts
7625 // set 40:3e bit 7 to 0
7626 val8
= read_byte(0x0040, 0x003e);
7628 write_byte(0x0040, 0x003e, val8
);
7629 // check port 3f4 for accessibility to status bytes
7631 if ( (val8
& 0xc0) != 0xc0 )
7632 BX_PANIC("int13_diskette: ctrl not ready\n");
7634 // read 7 return status bytes from controller
7635 // using loop index broken, have to unroll...
7636 return_status
[0] = inb(0x3f5);
7637 return_status
[1] = inb(0x3f5);
7638 return_status
[2] = inb(0x3f5);
7639 return_status
[3] = inb(0x3f5);
7640 return_status
[4] = inb(0x3f5);
7641 return_status
[5] = inb(0x3f5);
7642 return_status
[6] = inb(0x3f5);
7643 // record in BIOS Data Area
7644 write_byte(0x0040, 0x0042, return_status
[0]);
7645 write_byte(0x0040, 0x0043, return_status
[1]);
7646 write_byte(0x0040, 0x0044, return_status
[2]);
7647 write_byte(0x0040, 0x0045, return_status
[3]);
7648 write_byte(0x0040, 0x0046, return_status
[4]);
7649 write_byte(0x0040, 0x0047, return_status
[5]);
7650 write_byte(0x0040, 0x0048, return_status
[6]);
7652 if ( (return_status
[0] & 0xc0) != 0 ) {
7653 if ( (return_status
[1] & 0x02) != 0 ) {
7654 // diskette not writable.
7655 // AH=status code=0x03 (tried to write on write-protected disk)
7656 // AL=number of sectors written=0
7661 BX_PANIC("int13_diskette_function: write error\n");
7666 set_diskette_ret_status(0);
7667 set_diskette_current_cyl(drive
, 0);
7668 CLEAR_CF(); // successful
7672 case 0x08: // read diskette drive parameters
7673 BX_DEBUG_INT13_FL("floppy f08\n");
7683 SET_DL(num_floppies
);
7688 drive_type
= inb_cmos(0x10);
7690 if (drive_type
& 0xf0)
7692 if (drive_type
& 0x0f)
7704 SET_DL(num_floppies
);
7706 switch (drive_type
) {
7709 SET_DH(0); // max head #
7712 case 1: // 360KB, 5.25"
7713 CX
= 0x2709; // 40 tracks, 9 sectors
7714 SET_DH(1); // max head #
7717 case 2: // 1.2MB, 5.25"
7718 CX
= 0x4f0f; // 80 tracks, 15 sectors
7719 SET_DH(1); // max head #
7722 case 3: // 720KB, 3.5"
7723 CX
= 0x4f09; // 80 tracks, 9 sectors
7724 SET_DH(1); // max head #
7727 case 4: // 1.44MB, 3.5"
7728 CX
= 0x4f12; // 80 tracks, 18 sectors
7729 SET_DH(1); // max head #
7732 case 5: // 2.88MB, 3.5"
7733 CX
= 0x4f24; // 80 tracks, 36 sectors
7734 SET_DH(1); // max head #
7737 case 6: // 160k, 5.25"
7738 CX
= 0x2708; // 40 tracks, 8 sectors
7739 SET_DH(0); // max head #
7742 case 7: // 180k, 5.25"
7743 CX
= 0x2709; // 40 tracks, 9 sectors
7744 SET_DH(0); // max head #
7747 case 8: // 320k, 5.25"
7748 CX
= 0x2708; // 40 tracks, 8 sectors
7749 SET_DH(1); // max head #
7753 BX_PANIC("floppy: int13: bad floppy type\n");
7756 /* set es & di to point to 11 byte diskette param table in ROM */
7760 mov ax
, #diskette_param_table2
7761 mov _int13_diskette_function
.DI
+2[bp
], ax
7762 mov _int13_diskette_function
.ES
+2[bp
], cs
7765 CLEAR_CF(); // success
7766 /* disk status not changed upon success */
7770 case 0x15: // read diskette drive type
7771 BX_DEBUG_INT13_FL("floppy f15\n");
7774 SET_AH(0); // only 2 drives supported
7775 // set_diskette_ret_status here ???
7779 drive_type
= inb_cmos(0x10);
7785 CLEAR_CF(); // successful, not present
7786 if (drive_type
==0) {
7787 SET_AH(0); // drive not present
7790 SET_AH(1); // drive present, does not support change line
7795 case 0x16: // get diskette change line status
7796 BX_DEBUG_INT13_FL("floppy f16\n");
7799 SET_AH(0x01); // invalid drive
7800 set_diskette_ret_status(0x01);
7805 SET_AH(0x06); // change line not supported
7806 set_diskette_ret_status(0x06);
7810 case 0x17: // set diskette type for format(old)
7811 BX_DEBUG_INT13_FL("floppy f17\n");
7812 /* not used for 1.44M floppies */
7813 SET_AH(0x01); // not supported
7814 set_diskette_ret_status(1); /* not supported */
7818 case 0x18: // set diskette type for format(new)
7819 BX_DEBUG_INT13_FL("floppy f18\n");
7820 SET_AH(0x01); // do later
7821 set_diskette_ret_status(1);
7826 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7828 // if ((ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e)) {
7829 SET_AH(0x01); // ???
7830 set_diskette_ret_status(1);
7836 #else // #if BX_SUPPORT_FLOPPY
7838 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7839 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7845 case 0x01: // Read Diskette Status
7847 val8
= read_byte(0x0000, 0x0441);
7856 write_byte(0x0000, 0x0441, 0x01);
7860 #endif // #if BX_SUPPORT_FLOPPY
7863 set_diskette_ret_status(value
)
7866 write_byte(0x0040, 0x0041, value
);
7870 set_diskette_current_cyl(drive
, cyl
)
7875 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7876 write_byte(0x0040, 0x0094+drive
, cyl
);
7880 determine_floppy_media(drive
)
7884 Bit8u val8
, DOR
, ctrl_info
;
7886 ctrl_info
= read_byte(0x0040, 0x008F);
7894 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7897 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7901 if ((ctrl_info
& 0x04) != 0x04) {
7902 // Drive not determined means no drive exists, done.
7907 // check Main Status Register for readiness
7908 val8
= inb(0x03f4) & 0x80; // Main Status Register
7910 BX_PANIC("d_f_m: MRQ bit not set\n");
7914 // existing BDA values
7916 // turn on drive motor
7917 outb(0x03f2, DOR
); // Digital Output Register
7920 BX_PANIC("d_f_m: OK so far\n");
7925 int17_function(regs
, ds
, iret_addr
)
7926 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7927 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7928 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7930 Bit16u addr
,timeout
;
7937 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7938 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7939 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7940 if (regs
.u
.r8
.ah
== 0) {
7941 outb(addr
, regs
.u
.r8
.al
);
7943 outb(addr
+2, val8
| 0x01); // send strobe
7947 outb(addr
+2, val8
& ~0x01);
7948 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7952 if (regs
.u
.r8
.ah
== 1) {
7954 outb(addr
+2, val8
& ~0x04); // send init
7958 outb(addr
+2, val8
| 0x04);
7961 regs
.u
.r8
.ah
= (val8
^ 0x48);
7962 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7963 ClearCF(iret_addr
.flags
);
7965 SetCF(iret_addr
.flags
); // Unsupported
7970 int19_function(seq_nr
)
7973 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7984 // if BX_ELTORITO_BOOT is not defined, old behavior
7985 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7986 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7987 // 0: system boot sequence, first drive C: then A:
7988 // 1: system boot sequence, first drive A: then C:
7989 // else BX_ELTORITO_BOOT is defined
7990 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7991 // CMOS reg 0x3D & 0x0f : 1st boot device
7992 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7993 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7994 // boot device codes:
7995 // 0x00 : not defined
7996 // 0x01 : first floppy
7997 // 0x02 : first harddrive
7998 // 0x03 : first cdrom
7999 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
8000 // else : boot failure
8002 // Get the boot sequence
8003 #if BX_ELTORITO_BOOT
8004 bootdev
= inb_cmos(0x3d);
8005 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
8006 bootdev
>>= 4 * seq_nr
;
8009 /* Read user selected device */
8010 bootfirst
= read_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
);
8011 if (bootfirst
!= 0xFFFF) {
8012 bootdev
= bootfirst
;
8013 /* User selected device not set */
8014 write_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
, 0xFFFF);
8015 /* Reset boot sequence */
8016 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xFFFF);
8017 } else if (bootdev
== 0) BX_PANIC("No bootable device.\n");
8019 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
8022 if (seq_nr
==2) BX_PANIC("No more boot devices.");
8023 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
8024 /* Boot from floppy if the bit is set or it's the second boot */
8030 /* Read the boot device from the IPL table */
8031 if (get_boot_vector(bootdev
, &e
) == 0) {
8032 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
8036 /* Do the loading, and set up vector as a far pointer to the boot
8037 * address, and bootdrv as the boot drive */
8038 print_boot_device(&e
);
8041 case IPL_TYPE_FLOPPY
: /* FDD */
8042 case IPL_TYPE_HARDDISK
: /* HDD */
8044 bootdrv
= (e
.type
== IPL_TYPE_HARDDISK
) ? 0x80 : 0x00;
8056 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
8057 mov ax
, _int19_function
.bootseg
+ 2[bp
]
8058 mov es
, ax
;; segment
8059 xor bx
, bx
;; offset
8060 mov ah
, #0x02 ;; function 2, read diskette sector
8061 mov al
, #0x01 ;; read 1 sector
8062 mov ch
, #0x00 ;; track 0
8063 mov cl
, #0x01 ;; sector 1
8064 mov dh
, #0x00 ;; head 0
8065 int #0x13 ;; read sector
8068 mov _int19_function
.status
+ 2[bp
], ax
8079 print_boot_failure(e
.type
, 1);
8083 /* Always check the signature on a HDD boot sector; on FDD, only do
8084 * the check if the CMOS doesn't tell us to skip it */
8085 if ((e
.type
!= IPL_TYPE_FLOPPY
) || !((inb_cmos(0x38) & 0x01))) {
8086 if (read_word(bootseg
,0x1fe) != 0xaa55) {
8087 print_boot_failure(e
.type
, 0);
8092 /* Canonicalize bootseg:bootip */
8093 bootip
= (bootseg
& 0x0fff) << 4;
8097 #if BX_ELTORITO_BOOT
8098 case IPL_TYPE_CDROM
: /* CD-ROM */
8099 status
= cdrom_boot();
8102 if ( (status
& 0x00ff) !=0 ) {
8103 print_cdromboot_failure(status
);
8104 print_boot_failure(e
.type
, 1);
8108 bootdrv
= (Bit8u
)(status
>>8);
8109 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
8114 case IPL_TYPE_BEV
: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
8115 bootseg
= e
.vector
>> 16;
8116 bootip
= e
.vector
& 0xffff;
8122 /* Debugging info */
8123 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
8125 /* Jump to the boot vector */
8130 ;; Build an iret stack frame that will take us to the boot vector
.
8131 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
8133 mov ax
, _int19_function
.bootseg
+ 0[bp
]
8135 mov ax
, _int19_function
.bootip
+ 0[bp
]
8137 ;; Set the magic number in ax
and the boot drive in dl
.
8139 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
8140 ;; Zero some of the other registers
.
8151 int1a_function(regs
, ds
, iret_addr
)
8152 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8153 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8154 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8158 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
);
8164 switch (regs
.u
.r8
.ah
) {
8165 case 0: // get current clock count
8169 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
8170 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
8171 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
8172 BiosData
->midnight_flag
= 0; // reset flag
8177 ClearCF(iret_addr
.flags
); // OK
8180 case 1: // Set Current Clock Count
8184 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
8185 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
8186 BiosData
->midnight_flag
= 0; // reset flag
8191 ClearCF(iret_addr
.flags
); // OK
8195 case 2: // Read CMOS Time
8196 if (rtc_updating()) {
8197 SetCF(iret_addr
.flags
);
8201 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
8202 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
8203 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
8204 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
8206 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8207 ClearCF(iret_addr
.flags
); // OK
8210 case 3: // Set CMOS Time
8211 // Using a debugger, I notice the following masking/setting
8212 // of bits in Status Register B, by setting Reg B to
8213 // a few values and getting its value after INT 1A was called.
8215 // try#1 try#2 try#3
8216 // before 1111 1101 0111 1101 0000 0000
8217 // after 0110 0010 0110 0010 0000 0010
8219 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8220 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8221 if (rtc_updating()) {
8223 // fall through as if an update were not in progress
8225 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
8226 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
8227 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
8228 // Set Daylight Savings time enabled bit to requested value
8229 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
8230 // (reg B already selected)
8231 outb_cmos(0x0b, val8
);
8233 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8234 ClearCF(iret_addr
.flags
); // OK
8237 case 4: // Read CMOS Date
8239 if (rtc_updating()) {
8240 SetCF(iret_addr
.flags
);
8243 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
8244 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
8245 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
8246 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
8247 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8248 ClearCF(iret_addr
.flags
); // OK
8251 case 5: // Set CMOS Date
8252 // Using a debugger, I notice the following masking/setting
8253 // of bits in Status Register B, by setting Reg B to
8254 // a few values and getting its value after INT 1A was called.
8256 // try#1 try#2 try#3 try#4
8257 // before 1111 1101 0111 1101 0000 0010 0000 0000
8258 // after 0110 1101 0111 1101 0000 0010 0000 0000
8260 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8261 // My assumption: RegB = (RegB & 01111111b)
8262 if (rtc_updating()) {
8264 SetCF(iret_addr
.flags
);
8267 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
8268 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
8269 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
8270 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
8271 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8272 outb_cmos(0x0b, val8
);
8274 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
8275 ClearCF(iret_addr
.flags
); // OK
8278 case 6: // Set Alarm Time in CMOS
8279 // Using a debugger, I notice the following masking/setting
8280 // of bits in Status Register B, by setting Reg B to
8281 // a few values and getting its value after INT 1A was called.
8283 // try#1 try#2 try#3
8284 // before 1101 1111 0101 1111 0000 0000
8285 // after 0110 1111 0111 1111 0010 0000
8287 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8288 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8289 val8
= inb_cmos(0x0b); // Get Status Reg B
8292 // Alarm interrupt enabled already
8293 SetCF(iret_addr
.flags
); // Error: alarm in use
8296 if (rtc_updating()) {
8298 // fall through as if an update were not in progress
8300 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
8301 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
8302 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
8303 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8304 // enable Status Reg B alarm bit, clear halt clock bit
8305 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
8306 ClearCF(iret_addr
.flags
); // OK
8309 case 7: // Turn off Alarm
8310 // Using a debugger, I notice the following masking/setting
8311 // of bits in Status Register B, by setting Reg B to
8312 // a few values and getting its value after INT 1A was called.
8314 // try#1 try#2 try#3 try#4
8315 // before 1111 1101 0111 1101 0010 0000 0010 0010
8316 // after 0100 0101 0101 0101 0000 0000 0000 0010
8318 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8319 // My assumption: RegB = (RegB & 01010111b)
8320 val8
= inb_cmos(0x0b); // Get Status Reg B
8321 // clear clock-halt bit, disable alarm bit
8322 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
8324 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8325 ClearCF(iret_addr
.flags
); // OK
8329 // real mode PCI BIOS functions now handled in assembler code
8330 // this C code handles the error code for information only
8331 if (regs
.u
.r8
.bl
== 0xff) {
8332 BX_INFO("PCI BIOS: PCI not present\n");
8333 } else if (regs
.u
.r8
.bl
== 0x81) {
8334 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8335 } else if (regs
.u
.r8
.bl
== 0x83) {
8336 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8337 } else if (regs
.u
.r8
.bl
== 0x86) {
8338 if (regs
.u
.r8
.al
== 0x02) {
8339 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8341 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
);
8344 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8345 SetCF(iret_addr
.flags
);
8350 SetCF(iret_addr
.flags
); // Unsupported
8355 int70_function(regs
, ds
, iret_addr
)
8356 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8357 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8358 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8360 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8361 Bit8u registerB
= 0, registerC
= 0;
8363 // Check which modes are enabled and have occurred.
8364 registerB
= inb_cmos( 0xB );
8365 registerC
= inb_cmos( 0xC );
8367 if( ( registerB
& 0x60 ) != 0 ) {
8368 if( ( registerC
& 0x20 ) != 0 ) {
8369 // Handle Alarm Interrupt.
8376 if( ( registerC
& 0x40 ) != 0 ) {
8377 // Handle Periodic Interrupt.
8379 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8380 // Wait Interval (Int 15, AH=83) active.
8381 Bit32u time
, toggle
;
8383 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8384 if( time
< 0x3D1 ) {
8386 Bit16u segment
, offset
;
8388 segment
= read_word( 0x40, 0x98 );
8389 offset
= read_word( 0x40, 0x9A );
8390 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8391 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8392 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8394 // Continue waiting.
8396 write_dword( 0x40, 0x9C, time
);
8409 ;------------------------------------------
8410 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8411 ;------------------------------------------
8416 push
#0x00 ;; placeholder for status
8417 push
#0x00 ;; placeholder for X
8418 push
#0x00 ;; placeholder for Y
8419 push
#0x00 ;; placeholder for Z
8420 push
#0x00 ;; placeholder for make_far_call boolean
8421 call _int74_function
8422 pop cx
;; remove make_far_call from stack
8425 ;; make far call to EBDA
:0022
8428 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8430 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8435 add sp
, #8 ;; pop status, x, y, z
8437 pop ds
;; restore DS
8442 ;; This will perform an IRET
, but will retain value of current CF
8443 ;; by altering flags on stack
. Better than RETF
#02.
8448 and BYTE
[bp
+ 0x06], #0xfe
8454 or BYTE
[bp
+ 0x06], #0x01
8459 ;----------------------
8460 ;- INT13h (relocated
) -
8461 ;----------------------
8463 ; int13_relocated is a little bit messed up since I played with it
8464 ; I have to rewrite it
:
8465 ; - call a function that detect which function to call
8466 ; - make all called C function get the same parameters list
8470 #if BX_ELTORITO_BOOT
8471 ;; check
for an eltorito function
8473 jb int13_not_eltorito
8475 ja int13_not_eltorito
8484 jmp _int13_eltorito
;; ELDX
not used
8492 ;; check
if emulation active
8493 call _cdemu_isactive
8495 je int13_cdemu_inactive
8497 ;; check
if access to the emulated drive
8498 call _cdemu_emulated_drive
8501 cmp al
,dl
;; int13 on emulated drive
8516 jmp _int13_cdemu
;; ELDX
not used
8519 and dl
,#0xE0 ;; mask to get device class, including cdroms
8520 cmp al
,dl
;; al is
0x00 or 0x80
8521 jne int13_cdemu_inactive
;; inactive
for device
class
8533 dec dl
;; real drive is dl
- 1
8536 int13_cdemu_inactive
:
8542 #endif // BX_ELTORITO_BOOT
8553 push dx
;; push eltorito value of dx instead of sp
8564 ;; now the
16-bit registers can be restored with
:
8565 ;; pop ds
; pop es
; popa
; iret
8566 ;; arguments passed to functions should be
8567 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8573 jmp _int13_diskette_function
8582 // ebx is modified: BSD 5.2.1 boot loader problem
8583 // someone should figure out which 32 bit register that actually are used
8600 ;; int13_harddisk modifies high word of EAX
8603 call _int13_harddisk
8616 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8624 ;; Get the boot sequence number out of the IPL memory
8626 mov ds
, bx
;; Set segment
8627 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8629 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8630 mov ds
, ax
;; and reset the segment to zero
.
8632 ;; Carry on in the INT
19h handler
, using the
new sequence number
8640 int19_relocated
: ;; Boot function
, relocated
8642 ;; int19 was beginning to be really
complex, so now it
8643 ;; just calls a C function that does the work
8654 ;; Start from the first boot
device (0, in AX
)
8656 mov ds
, bx
;; Set segment to write to the IPL memory
8657 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8658 mov ds
, ax
;; and reset the segment
.
8664 ;; Call the C code
for the next boot device
8665 call _int19_function
8667 ;; Boot failed
: invoke the boot recovery function
8673 int1c_handler
: ;; User Timer Tick
8677 ;----------------------
8678 ;- POST
: Floppy Drive
-
8679 ;----------------------
8685 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8687 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8689 mov
0x0440, al
;; diskette motor timeout counter
: not active
8690 mov
0x0441, al
;; diskette controller status
return code
8692 mov
0x0442, al
;; disk
& diskette controller status
register 0
8693 mov
0x0443, al
;; diskette controller status
register 1
8694 mov
0x0444, al
;; diskette controller status
register 2
8695 mov
0x0445, al
;; diskette controller cylinder number
8696 mov
0x0446, al
;; diskette controller head number
8697 mov
0x0447, al
;; diskette controller sector number
8698 mov
0x0448, al
;; diskette controller bytes written
8700 mov
0x048b, al
;; diskette configuration data
8702 ;; -----------------------------------------------------------------
8703 ;; (048F
) diskette controller information
8705 mov al
, #0x10 ;; get CMOS diskette drive type
8708 mov ah
, al
;; save byte to AH
8711 shr al
, #4 ;; look at top 4 bits for drive 0
8712 jz f0_missing
;; jump
if no drive0
8713 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8716 mov bl
, #0x00 ;; no drive0
8719 mov al
, ah
;; restore from AH
8720 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8721 jz f1_missing
;; jump
if no drive1
8722 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8724 ;; leave high bits in BL zerod
8725 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8726 ;; -----------------------------------------------------------------
8729 mov
0x0490, al
;; diskette
0 media state
8730 mov
0x0491, al
;; diskette
1 media state
8732 ;; diskette
0,1 operational starting state
8733 ;; drive type has
not been determined
,
8734 ;; has no changed detection line
8738 mov
0x0494, al
;; diskette
0 current cylinder
8739 mov
0x0495, al
;; diskette
1 current cylinder
8742 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8744 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8745 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8746 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8751 ;--------------------
8752 ;- POST
: HARD DRIVE
-
8753 ;--------------------
8754 ; relocated here because the primary POST area isnt big enough
.
8757 // INT 76h calls INT 15h function ax=9100
8759 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8765 mov
0x0474, al
/* hard disk status of last operation */
8766 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8767 mov
0x048c, al
/* hard disk status register */
8768 mov
0x048d, al
/* hard disk error register */
8769 mov
0x048e, al
/* hard disk task complete flag */
8771 mov
0x0475, al
/* hard disk number attached */
8773 mov
0x0476, al
/* hard disk control byte */
8774 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8775 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8776 ;; INT
41h
: hard disk
0 configuration pointer
8777 ;; INT
46h
: hard disk
1 configuration pointer
8778 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8779 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8781 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8793 cmp al
, #47 ;; decimal 47 - user definable
8797 ;; CMOS purpose param table offset
8798 ;; 1b cylinders low
0
8799 ;; 1c cylinders high
1
8801 ;; 1e write pre
-comp low
5
8802 ;; 1f write pre
-comp high
6
8803 ;; 20 retries
/bad map
/heads
>8 8
8804 ;; 21 landing zone low C
8805 ;; 22 landing zone high D
8806 ;; 23 sectors
/track E
8811 ;;; Filling EBDA table
for hard disk
0.
8819 mov (0x003d + 0x05), ax
;; write precomp word
8824 mov (0x003d + 0x08), al
;; drive control byte
8833 mov (0x003d + 0x0C), ax
;; landing zone word
8835 mov al
, #0x1c ;; get cylinders word in AX
8837 in al
, #0x71 ;; high byte
8841 in al
, #0x71 ;; low byte
8842 mov bx
, ax
;; BX
= cylinders
8847 mov cl
, al
;; CL
= heads
8852 mov dl
, al
;; DL
= sectors
8855 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8857 hd0_post_physical_chs
:
8858 ;; no logical CHS mapping used
, just physical CHS
8859 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8860 mov (0x003d + 0x00), bx
;; number of physical cylinders
8861 mov (0x003d + 0x02), cl
;; number of physical heads
8862 mov (0x003d + 0x0E), dl
;; number of physical sectors
8865 hd0_post_logical_chs
:
8866 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8867 mov (0x003d + 0x09), bx
;; number of physical cylinders
8868 mov (0x003d + 0x0b), cl
;; number of physical heads
8869 mov (0x003d + 0x04), dl
;; number of physical sectors
8870 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8872 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8875 jnbe hd0_post_above_2048
8876 ;; 1024 < c
<= 2048 cylinders
8879 jmp hd0_post_store_logical
8881 hd0_post_above_2048
:
8883 jnbe hd0_post_above_4096
8884 ;; 2048 < c
<= 4096 cylinders
8887 jmp hd0_post_store_logical
8889 hd0_post_above_4096
:
8891 jnbe hd0_post_above_8192
8892 ;; 4096 < c
<= 8192 cylinders
8895 jmp hd0_post_store_logical
8897 hd0_post_above_8192
:
8898 ;; 8192 < c
<= 16384 cylinders
8902 hd0_post_store_logical
:
8903 mov (0x003d + 0x00), bx
;; number of physical cylinders
8904 mov (0x003d + 0x02), cl
;; number of physical heads
8906 mov cl
, #0x0f ;; repeat count
8907 mov si
, #0x003d ;; offset to disk0 FDPT
8908 mov al
, #0x00 ;; sum
8909 hd0_post_checksum_loop
:
8913 jnz hd0_post_checksum_loop
8914 not al
;; now take
2s complement
8917 ;;; Done filling EBDA table
for hard disk
0.
8921 ;; is there really a second hard disk
? if not, return now
8929 ;; check that the hd type is really
0x0f.
8934 ;; check that the extended type is
47 - user definable
8938 cmp al
, #47 ;; decimal 47 - user definable
8943 ;; CMOS purpose param table offset
8944 ;; 0x24 cylinders low
0
8945 ;; 0x25 cylinders high
1
8947 ;; 0x27 write pre
-comp low
5
8948 ;; 0x28 write pre
-comp high
6
8950 ;; 0x2a landing zone low C
8951 ;; 0x2b landing zone high D
8952 ;; 0x2c sectors
/track E
8953 ;;; Fill EBDA table
for hard disk
1.
8963 mov (0x004d + 0x05), ax
;; write precomp word
8968 mov (0x004d + 0x08), al
;; drive control byte
8977 mov (0x004d + 0x0C), ax
;; landing zone word
8979 mov al
, #0x25 ;; get cylinders word in AX
8981 in al
, #0x71 ;; high byte
8985 in al
, #0x71 ;; low byte
8986 mov bx
, ax
;; BX
= cylinders
8991 mov cl
, al
;; CL
= heads
8996 mov dl
, al
;; DL
= sectors
8999 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
9001 hd1_post_physical_chs
:
9002 ;; no logical CHS mapping used
, just physical CHS
9003 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
9004 mov (0x004d + 0x00), bx
;; number of physical cylinders
9005 mov (0x004d + 0x02), cl
;; number of physical heads
9006 mov (0x004d + 0x0E), dl
;; number of physical sectors
9009 hd1_post_logical_chs
:
9010 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
9011 mov (0x004d + 0x09), bx
;; number of physical cylinders
9012 mov (0x004d + 0x0b), cl
;; number of physical heads
9013 mov (0x004d + 0x04), dl
;; number of physical sectors
9014 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
9016 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
9019 jnbe hd1_post_above_2048
9020 ;; 1024 < c
<= 2048 cylinders
9023 jmp hd1_post_store_logical
9025 hd1_post_above_2048
:
9027 jnbe hd1_post_above_4096
9028 ;; 2048 < c
<= 4096 cylinders
9031 jmp hd1_post_store_logical
9033 hd1_post_above_4096
:
9035 jnbe hd1_post_above_8192
9036 ;; 4096 < c
<= 8192 cylinders
9039 jmp hd1_post_store_logical
9041 hd1_post_above_8192
:
9042 ;; 8192 < c
<= 16384 cylinders
9046 hd1_post_store_logical
:
9047 mov (0x004d + 0x00), bx
;; number of physical cylinders
9048 mov (0x004d + 0x02), cl
;; number of physical heads
9050 mov cl
, #0x0f ;; repeat count
9051 mov si
, #0x004d ;; offset to disk0 FDPT
9052 mov al
, #0x00 ;; sum
9053 hd1_post_checksum_loop
:
9057 jnz hd1_post_checksum_loop
9058 not al
;; now take
2s complement
9061 ;;; Done filling EBDA table
for hard disk
1.
9065 ;--------------------
9066 ;- POST
: EBDA segment
9067 ;--------------------
9068 ; relocated here because the primary POST area isnt big enough
.
9073 mov byte ptr
[0x0], #EBDA_SIZE
9075 xor ax
, ax
; mov EBDA seg into
40E
9077 mov word ptr
[0x40E], #EBDA_SEG
9080 ;--------------------
9081 ;- POST
: EOI
+ jmp via
[0x40:67)
9082 ;--------------------
9083 ; relocated here because the primary POST area isnt big enough
.
9086 out
#0xA0, al ;; slave PIC EOI
9088 out
#0x20, al ;; master PIC EOI
9121 call _s3_resume_panic
9123 ;--------------------
9126 out
#0xA0, al ;; slave PIC EOI
9129 out
#0x20, al ;; master PIC EOI
9132 ;--------------------
9134 ;; in
: AL in BCD format
9135 ;; out
: AL in binary format
, AH will always be
0
9138 and bl
, #0x0f ;; bl has low digit
9139 shr al
, #4 ;; al has high digit
9141 mul al
, bh
;; multiply high digit by
10 (result in AX
)
9142 add al
, bl
;; then add low digit
9145 ;--------------------
9147 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
9148 ;; Timer Ticks Roller
Flag (0x470:byte
)
9149 ;; The Timer Ticks Count needs to be set according to
9150 ;; the current CMOS time
, as
if ticks have been occurring
9151 ;; at
18.2hz since midnight up to
this point
. Calculating
9152 ;; this is a little complicated
. Here are the factors I gather
9153 ;; regarding
this. 14,318,180 hz was the original clock speed
,
9154 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
9155 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
9156 ;; source was divided again by
4 to feed a
1.193Mhz signal to
9157 ;; the timer
. With a maximum
16bit timer count
, this is again
9158 ;; divided down by
65536 to
18.2hz
.
9160 ;; 14,318,180 Hz clock
9161 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
9162 ;; /4 = 1,193,181 Hz fed to timer
9163 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
9164 ;; 1 second
= 18.20650736 ticks
9165 ;; 1 minute
= 1092.390442 ticks
9166 ;; 1 hour
= 65543.42651 ticks
9168 ;; Given the values in the CMOS clock
, one could calculate
9169 ;; the number of ticks by the following
:
9170 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
9171 ;; (BcdToBin(minutes
) * 1092.3904)
9172 ;; (BcdToBin(hours
) * 65543.427)
9173 ;; To get a little more accuracy
, since Im
using integer
9174 ;; arithmatic
, I use
:
9175 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
9176 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
9177 ;; (BcdToBin(hours
) * 65543427) / 1000
9182 xor eax
, eax
;; clear EAX
9185 in al
, #0x71 ;; AL has CMOS seconds in BCD
9186 call BcdToBin
;; EAX now has seconds in binary
9192 mov ecx
, eax
;; ECX will accumulate total ticks
9195 xor eax
, eax
;; clear EAX
9198 in al
, #0x71 ;; AL has CMOS minutes in BCD
9199 call BcdToBin
;; EAX now has minutes in binary
9205 add ecx
, eax
;; add to total ticks
9208 xor eax
, eax
;; clear EAX
9211 in al
, #0x71 ;; AL has CMOS hours in BCD
9212 call BcdToBin
;; EAX now has hours in binary
9218 add ecx
, eax
;; add to total ticks
9220 mov
0x46C, ecx
;; Timer Ticks Count
9222 mov
0x470, al
;; Timer Ticks Rollover Flag
9225 ;--------------------
9227 ;; record completion in BIOS task complete flag
9239 ;--------------------
9244 #include "apmbios.S"
9248 #include "apmbios.S"
9251 #include "apmbios.S"
9255 ;--------------------
9260 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9261 dw bios32_entry_point
, 0xf ;; 32 bit physical address
9262 db
0 ;; revision level
9263 ;; length in paragraphs
and checksum stored in a word to prevent errors
9264 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
9265 & 0xff) << 8) + 0x01
9266 db
0,0,0,0,0 ;; reserved
9271 cmp eax
, #0x49435024 ;; "$PCI"
9273 mov eax
, #0x80000000
9278 #ifdef PCI_FIXED_HOST_BRIDGE
9279 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9282 ;; say ok
if a device is present
9283 cmp eax
, #0xffffffff
9286 mov ebx
, #0x000f0000
9288 mov edx
, #pcibios_protected
9295 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9306 cmp al
, #0x01 ;; installation check
9310 mov edx
, #0x20494350 ;; "PCI "
9313 pci_pro_f02
: ;; find pci device
9321 call pci_pro_select_reg
9335 pci_pro_f03
: ;; find
class code
9341 call pci_pro_select_reg
9346 jne pci_pro_nextdev2
9353 jne pci_pro_devloop2
9356 pci_pro_f08
: ;; read configuration byte
9359 call pci_pro_select_reg
9368 pci_pro_f09
: ;; read configuration word
9371 call pci_pro_select_reg
9380 pci_pro_f0a
: ;; read configuration dword
9383 call pci_pro_select_reg
9390 pci_pro_f0b
: ;; write configuration byte
9393 call pci_pro_select_reg
9402 pci_pro_f0c
: ;; write configuration word
9405 call pci_pro_select_reg
9414 pci_pro_f0d
: ;; write configuration dword
9417 call pci_pro_select_reg
9430 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9440 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9464 mov eax
, #0x80000000
9469 #ifdef PCI_FIXED_HOST_BRIDGE
9470 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9473 ;; say ok
if a device is present
9474 cmp eax
, #0xffffffff
9485 cmp al
, #0x01 ;; installation check
9490 mov edx
, #0x20494350 ;; "PCI "
9492 mov di
, #pcibios_protected
9495 pci_real_f02
: ;; find pci device
9505 call pci_real_select_reg
9509 jne pci_real_nextdev
9516 jne pci_real_devloop
9521 pci_real_f03
: ;; find
class code
9527 call pci_real_select_reg
9532 jne pci_real_nextdev2
9539 jne pci_real_devloop2
9544 pci_real_f08
: ;; read configuration byte
9547 call pci_real_select_reg
9556 pci_real_f09
: ;; read configuration word
9559 call pci_real_select_reg
9568 pci_real_f0a
: ;; read configuration dword
9571 call pci_real_select_reg
9578 pci_real_f0b
: ;; write configuration byte
9581 call pci_real_select_reg
9590 pci_real_f0c
: ;; write configuration word
9593 call pci_real_select_reg
9602 pci_real_f0d
: ;; write configuration dword
9605 call pci_real_select_reg
9612 pci_real_f0e
: ;; get irq routing options
9614 jne pci_real_unknown
9616 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9617 jb pci_real_too_small
9619 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9627 mov si
, #pci_routing_table_structure_start
9635 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9644 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9648 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9666 pci_real_select_reg
:
9680 pci_routing_table_structure
:
9681 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9683 dw
32 + (6 * 16) ;; table size
9684 db
0 ;; PCI interrupt router bus
9685 db
0x08 ;; PCI interrupt router DevFunc
9686 dw
0x0000 ;; PCI exclusive IRQs
9687 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9688 dw
0x122e ;; compatible PCI interrupt router device ID
9689 dw
0,0 ;; Miniport data
9690 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9692 pci_routing_table_structure_start
:
9693 ;; first slot entry PCI
-to
-ISA (embedded
)
9694 db
0 ;; pci bus number
9695 db
0x08 ;; pci device
number (bit
7-3)
9696 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9697 dw
0xdef8 ;; IRQ bitmap INTA
#
9698 db
0x61 ;; link value INTB
#
9699 dw
0xdef8 ;; IRQ bitmap INTB
#
9700 db
0x62 ;; link value INTC
#
9701 dw
0xdef8 ;; IRQ bitmap INTC
#
9702 db
0x63 ;; link value INTD
#
9703 dw
0xdef8 ;; IRQ bitmap INTD
#
9704 db
0 ;; physical
slot (0 = embedded
)
9706 ;; second slot entry
: 1st PCI slot
9707 db
0 ;; pci bus number
9708 db
0x10 ;; pci device
number (bit
7-3)
9709 db
0x61 ;; link value INTA
#
9710 dw
0xdef8 ;; IRQ bitmap INTA
#
9711 db
0x62 ;; link value INTB
#
9712 dw
0xdef8 ;; IRQ bitmap INTB
#
9713 db
0x63 ;; link value INTC
#
9714 dw
0xdef8 ;; IRQ bitmap INTC
#
9715 db
0x60 ;; link value INTD
#
9716 dw
0xdef8 ;; IRQ bitmap INTD
#
9717 db
1 ;; physical
slot (0 = embedded
)
9719 ;; third slot entry
: 2nd PCI slot
9720 db
0 ;; pci bus number
9721 db
0x18 ;; pci device
number (bit
7-3)
9722 db
0x62 ;; link value INTA
#
9723 dw
0xdef8 ;; IRQ bitmap INTA
#
9724 db
0x63 ;; link value INTB
#
9725 dw
0xdef8 ;; IRQ bitmap INTB
#
9726 db
0x60 ;; link value INTC
#
9727 dw
0xdef8 ;; IRQ bitmap INTC
#
9728 db
0x61 ;; link value INTD
#
9729 dw
0xdef8 ;; IRQ bitmap INTD
#
9730 db
2 ;; physical
slot (0 = embedded
)
9732 ;; 4th slot entry
: 3rd PCI slot
9733 db
0 ;; pci bus number
9734 db
0x20 ;; pci device
number (bit
7-3)
9735 db
0x63 ;; link value INTA
#
9736 dw
0xdef8 ;; IRQ bitmap INTA
#
9737 db
0x60 ;; link value INTB
#
9738 dw
0xdef8 ;; IRQ bitmap INTB
#
9739 db
0x61 ;; link value INTC
#
9740 dw
0xdef8 ;; IRQ bitmap INTC
#
9741 db
0x62 ;; link value INTD
#
9742 dw
0xdef8 ;; IRQ bitmap INTD
#
9743 db
3 ;; physical
slot (0 = embedded
)
9745 ;; 5th slot entry
: 4rd PCI slot
9746 db
0 ;; pci bus number
9747 db
0x28 ;; pci device
number (bit
7-3)
9748 db
0x60 ;; link value INTA
#
9749 dw
0xdef8 ;; IRQ bitmap INTA
#
9750 db
0x61 ;; link value INTB
#
9751 dw
0xdef8 ;; IRQ bitmap INTB
#
9752 db
0x62 ;; link value INTC
#
9753 dw
0xdef8 ;; IRQ bitmap INTC
#
9754 db
0x63 ;; link value INTD
#
9755 dw
0xdef8 ;; IRQ bitmap INTD
#
9756 db
4 ;; physical
slot (0 = embedded
)
9758 ;; 6th slot entry
: 5rd PCI slot
9759 db
0 ;; pci bus number
9760 db
0x30 ;; pci device
number (bit
7-3)
9761 db
0x61 ;; link value INTA
#
9762 dw
0xdef8 ;; IRQ bitmap INTA
#
9763 db
0x62 ;; link value INTB
#
9764 dw
0xdef8 ;; IRQ bitmap INTB
#
9765 db
0x63 ;; link value INTC
#
9766 dw
0xdef8 ;; IRQ bitmap INTC
#
9767 db
0x60 ;; link value INTD
#
9768 dw
0xdef8 ;; IRQ bitmap INTD
#
9769 db
5 ;; physical
slot (0 = embedded
)
9771 pci_routing_table_structure_end
:
9777 pcibios_init_sel_reg
:
9789 pcibios_init_iomem_bases
:
9792 mov eax
, #0xc0000000 ;; base for memory init
9794 mov ax
, #0xc000 ;; base for i/o init
9796 mov ax
, #0x0010 ;; start at base address #0
9801 call pcibios_init_sel_reg
9806 mov dl
, #0x04 ;; disable i/o and memory space access
9807 call pcibios_init_sel_reg
9814 call pcibios_init_sel_reg
9820 mov eax
, #0xffffffff
9825 xor eax
, #0xffffffff
9829 add eax
, ecx
;; calculate next free mem base
9830 add eax
, #0x01000000
9831 and eax
, #0xff000000
9845 add ax
, cx
;; calculate next free i
/o base
9853 je enable_iomem_space
9854 mov byte ptr
[bp
-8], al
9855 jmp pci_init_io_loop2
9857 mov dl
, #0x04 ;; enable i/o and memory space access if available
9858 call pcibios_init_sel_reg
9864 mov byte ptr
[bp
-8], #0x10
9867 jne pci_init_io_loop1
9872 pcibios_init_set_elcr
:
9896 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9901 mov si
, #pci_routing_table_structure
9905 call pcibios_init_sel_reg
9908 cmp ax
, [si
+12] ;; check irq router
9911 call pcibios_init_sel_reg
9912 push bx
;; save irq router bus
+ devfunc
9915 out dx
, ax
;; reset PIRQ route control
9922 add si
, #0x20 ;; set pointer to 1st entry
9924 mov ax
, #pci_irq_list
9933 call pcibios_init_sel_reg
9937 jnz pci_test_int_pin
9943 call pcibios_init_sel_reg
9948 dec al
;; determine pirq reg
9957 call pcibios_init_sel_reg
9964 mov bx
, [bp
-2] ;; pci irq list pointer
9969 call pcibios_init_set_elcr
9973 add bl
, [bp
-3] ;; pci function number
9975 call pcibios_init_sel_reg
9982 jnz pci_init_irq_loop2
9985 mov byte ptr
[bp
-3], #0x00
9986 loop pci_init_irq_loop1
9993 #endif // !BX_ROMBIOS32
9994 #endif // BX_PCIBIOS
9998 ;; save a20
and enable it
10004 ;; save SS
:SP to the BDA
10011 lidt
[pmode_IDT_info
]
10013 lgdt
[rombios32_gdt_48
]
10014 ;; set PE bit in CR0
10018 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
10021 dw
0x000f ;; high
16 bit address
10026 ;; init data segments
10036 ;; init the stack pointer to point below EBDA
10042 ;; pass pointer to s3_resume_flag
and s3_resume_vector to rombios32
10046 ;; call rombios32 code
10047 mov eax
, #0x000e0000
10050 ;; return to
16 bit
protected mode first
10057 ;; restore data segment limits to
0xffff
10065 ;; reset PE bit in CR0
10070 ;; far jump to flush CPU queue after transition to real mode
10071 JMP_AP(0xf000, rombios32_real_mode
)
10073 rombios32_real_mode
:
10074 ;; restore IDT to normal real
-mode defaults
10076 lidt
[rmode_IDT_info
]
10084 ;; restore SS
:SP from the BDA
10101 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
10102 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
10103 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
10104 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
10105 #endif // BX_ROMBIOS32
10108 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
10113 and al
, #0xdf ; clear input mode
10123 mov
[bx
+0x408], dx
; Parallel I
/O address
10125 mov
[bx
+0x478], cl
; Parallel printer timeout
10130 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
10149 mov
[bx
+0x400], dx
; Serial I
/O address
10151 mov
[bx
+0x47c], cl
; Serial timeout
10199 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
10200 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
10208 ;; Scan
for existence of valid expansion ROMS
.
10209 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
10210 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
10211 ;; System ROM
: only
0xE0000
10217 ;; 2 ROM length in
512-byte blocks
10218 ;; 3 ROM initialization entry
point (FAR CALL
)
10223 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
10224 cmp
[0], #0xAA55 ;; look for signature
10225 jne rom_scan_increment
10227 jnz rom_scan_increment
10228 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
10230 ;; We want our increment in
512-byte quantities
, rounded to
10231 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
10233 jz block_count_rounded
10234 and al
, #0xfc ;; needs rounding up
10236 block_count_rounded
:
10238 xor bx
, bx
;; Restore DS back to
0000:
10242 ;; Push addr of ROM entry point
10243 push cx
;; Push seg
10244 push
#0x0003 ;; Push offset
10246 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
10247 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
10252 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
10253 db
0xff ;; call_far ss
:[bp
+0]
10256 cli
;; In
case expansion ROM BIOS turns IF on
10257 add sp
, #2 ;; Pop offset value
10258 pop cx
;; Pop seg
value (restore CX
)
10260 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
10261 ;; to init all the ROMs
and then go back
and build an IPL table of
10262 ;; all the bootable devices
, but we can get away with one pass
.
10263 mov ds
, cx
;; ROM base
10264 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
10265 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
10266 cmp ax
, #0x5024 ;; we look for signature "$PnP"
10272 mov ax
, 0x16[bx
] ;; 0x16 is the offset of Boot Connection Vector
10276 ;; Option ROM has BCV
. Run it now
.
10277 push cx
;; Push seg
10278 push ax
;; Push offset
10280 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
10284 /* jump to BCV function entry pointer */
10285 mov bp
, sp
;; Call ROM BCV routine
using seg
:off on stack
10286 db
0xff ;; call_far ss
:[bp
+0]
10289 cli
;; In
case expansion ROM BIOS turns IF on
10290 add sp
, #2 ;; Pop offset value
10291 pop cx
;; Pop seg
value (restore CX
)
10295 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
10296 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
10299 ;; Found a device that thinks it can boot the system
. Record its BEV
and product name string
.
10300 mov di
, 0x10[bx
] ;; Pointer to the product name string
or zero
if none
10301 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
10303 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
10304 cmp bx
, #IPL_TABLE_ENTRIES
10305 je no_bev
;; Get out
if the table is full
10306 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
10307 mov
0[bx
], #IPL_TYPE_BEV ;; This entry is a BEV device
10308 mov
6[bx
], cx
;; Build a far pointer from the segment
...
10309 mov
4[bx
], ax
;; and the offset
10312 mov
0xA[bx
], cx
;; Build a far pointer from the segment
...
10313 mov
8[bx
], di
;; and the offset
10315 shr bx
, #0x4 ;; Turn the offset back into a count
10316 inc bx
;; We have one more entry now
10317 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
10320 pop di
;; Restore DI
10321 pop ax
;; Restore AX
10322 rom_scan_increment
:
10323 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
10324 ;; because the segment selector is shifted left
4 bits
.
10326 pop ax
;; Restore AX
10330 xor ax
, ax
;; Restore DS back to
0000:
10335 mov al
, #0x11 ; send initialisation commands
10350 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10351 #if BX_USE_PS2_MOUSE
10356 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10359 ;; the following area can be used to write dynamically generated tables
10361 bios_table_area_start
:
10363 dd bios_table_area_end
- bios_table_area_start
- 8;
10368 .org
0xe05b ; POST Entry Point
10373 ;; first reset the DMA controllers
10377 ;; then initialize the DMA controllers
10379 out
0xD6, al
; cascade mode of channel
4 enabled
10381 out
0xD4, al
; unmask channel
4
10383 ;; Examine CMOS shutdown status
.
10391 ;; Reset CMOS shutdown status
.
10393 out
0x70, AL
; select CMOS
register Fh
10395 out
0x71, AL
; set shutdown action to normal
10397 ;; Examine CMOS shutdown status
.
10400 ;; 0x00, 0x09, 0x0D+ = normal startup
10408 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
10412 ;; 0x0A = jmp via
[0x40:0x67] jump
10416 ;; 0x0B = iret via
[0x40:0x67]
10420 ;; 0x0C = retf via
[0x40:0x67]
10424 ;; Examine CMOS shutdown status
.
10425 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08 = Unimplemented shutdown status
.
10427 call _shutdown_status_panic
10433 ; 0xb0, 0x20, /* mov al, #0x20 */
10434 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10444 ; case 0: normal startup
10453 ;; Save shutdown status
10459 ;; zero out BIOS data
area (40:00..40:ff
)
10461 mov cx
, #0x0080 ;; 128 words
10467 call _log_bios_start
10469 ;; set all interrupts to
default handler
10470 xor bx
, bx
;; offset index
10471 mov cx
, #0x0100 ;; counter (256 interrupts)
10472 mov ax
, #dummy_iret_handler
10480 loop post_default_ints
10482 ;; set vector
0x79 to zero
10483 ;; this is used by
'gardian angel' protection system
10484 SET_INT_VECTOR(0x79, #0, #0)
10486 ;; base memory in K
40:13 (word
)
10487 mov ax
, #BASE_MEM_IN_K
10491 ;; Manufacturing Test
40:12
10494 ;; Warm Boot Flag
0040:0072
10495 ;; value of
1234h
= skip memory checks
10499 ;; Printer Services vector
10500 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10502 ;; Bootstrap failure vector
10503 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10505 ;; Bootstrap Loader vector
10506 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10508 ;; User Timer Tick vector
10509 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10511 ;; Memory Size Check vector
10512 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10514 ;; Equipment Configuration Check vector
10515 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10518 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10524 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10525 ;; int 1C already points at
dummy_iret_handler (above
)
10526 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10528 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10533 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10534 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10538 mov
0x0417, al
/* keyboard shift flags, set 1 */
10539 mov
0x0418, al
/* keyboard shift flags, set 2 */
10540 mov
0x0419, al
/* keyboard alt-numpad work area */
10541 mov
0x0471, al
/* keyboard ctrl-break flag */
10542 mov
0x0497, al
/* keyboard status flags 4 */
10544 mov
0x0496, al
/* keyboard status flags 3 */
10547 /* keyboard head of buffer pointer */
10551 /* keyboard end of buffer pointer */
10554 /* keyboard pointer to start of buffer */
10558 /* keyboard pointer to end of buffer */
10562 /* init the keyboard */
10563 call _keyboard_init
10565 ;; mov CMOS Equipment Byte to BDA Equipment Word
10574 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10578 mov cl
, #0x14 ; timeout value
10579 mov dx
, #0x378 ; Parallel I/O address, port 1
10580 call detect_parport
10581 mov dx
, #0x278 ; Parallel I/O address, port 2
10582 call detect_parport
10584 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10586 or ax
, bx
; set number of parallel ports
10590 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10591 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10593 mov cl
, #0x0a ; timeout value
10594 mov dx
, #0x03f8 ; Serial I/O address, port 1
10596 mov dx
, #0x02f8 ; Serial I/O address, port 2
10598 mov dx
, #0x03e8 ; Serial I/O address, port 3
10600 mov dx
, #0x02e8 ; Serial I/O address, port 4
10603 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10605 or ax
, bx
; set number of serial port
10609 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10610 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10611 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10612 ;; BIOS DATA AREA
0x4CE ???
10613 call timer_tick_post
10615 ;; PS
/2 mouse setup
10616 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10618 ;; IRQ13 (FPU exception
) setup
10619 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10622 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10627 mov cx
, #0xc000 ;; init vga bios
10631 call _print_bios_banner
10634 call rombios32_init
10637 call pcibios_init_iomem_bases
10638 call pcibios_init_irqs
10639 #endif //BX_PCIBIOS
10645 call floppy_drive_post
10648 ;; Hard Drive setup
10650 call hard_drive_post
10655 ;; ATA
/ATAPI driver setup
10661 #endif // BX_USE_ATADRV
10663 #if BX_ELTORITO_BOOT
10665 ;; eltorito floppy
/harddisk emulation from cd
10669 #endif // BX_ELTORITO_BOOT
10671 call _init_boot_vectors
10673 mov cx
, #0xc800 ;; init option roms
10677 #if BX_ELTORITO_BOOT
10678 call _interactive_bootkey
10679 #endif // BX_ELTORITO_BOOT
10681 sti
;; enable interrupts
10684 .org
0xe2c3 ; NMI Handler Entry Point
10686 ;; FIXME the NMI handler should
not panic
10687 ;; but iret when called from
int75 (fpu exception
)
10688 call _nmi_handler_msg
10692 out
0xf0, al
// clear irq13
10693 call eoi_both_pics
// clear interrupt
10694 int 2 // legacy nmi call
10697 ;-------------------------------------------
10698 ;- INT
13h Fixed Disk Services Entry Point
-
10699 ;-------------------------------------------
10700 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10702 //JMPL(int13_relocated)
10703 jmp int13_relocated
10705 .org
0xe401 ; Fixed Disk Parameter Table
10710 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10713 jmp int19_relocated
10714 ;-------------------------------------------
10715 ;- System BIOS Configuration Data Table
10716 ;-------------------------------------------
10717 .org BIOS_CONFIG_TABLE
10718 db
0x08 ; Table
size (bytes
) -Lo
10719 db
0x00 ; Table
size (bytes
) -Hi
10724 ; b7
: 1=DMA channel
3 used by hard disk
10725 ; b6
: 1=2 interrupt controllers present
10726 ; b5
: 1=RTC present
10727 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10728 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10729 ; b2
: 1=extended BIOS data area used
10730 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10731 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10735 (BX_CALL_INT15_4F
<< 4) | \
10737 (BX_USE_EBDA
<< 2) | \
10741 ; b7
: 1=32-bit DMA supported
10742 ; b6
: 1=int16h
, function
9 supported
10743 ; b5
: 1=int15h
/C6h (get POS data
) supported
10744 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10745 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10746 ; b2
: 1=non
-8042 kb controller
10747 ; b1
: 1=data streaming supported
10761 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10762 ; b3
: SCSI on system board
10763 ; b2
: info panel installed
10764 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10765 ; b0
: SCSI supported in IML
10769 ; b6
: EEPROM present
10770 ; b5
-3: ABIOS
presence (011 = not supported
)
10772 ; b1
: memory split above
16Mb supported
10773 ; b0
: POSTEXT directly supported by POST
10775 ; Feature byte
5 (IBM
)
10776 ; b1
: enhanced mouse
10782 .org
0xe729 ; Baud Rate Generator Table
10787 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10793 call _int14_function
10799 ;----------------------------------------
10800 ;- INT
16h Keyboard Service Entry Point
-
10801 ;----------------------------------------
10817 call _int16_function
10827 and BYTE
[bp
+ 0x06], #0xbf
10835 or BYTE
[bp
+ 0x06], #0x40
10843 int16_wait_for_key
:
10847 jne int16_key_found
10851 /* no key yet, call int 15h, function AX=9002 */
10852 0x50, /* push AX */
10853 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10854 0xcd, 0x15, /* int 15h */
10856 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10858 jmp int16_wait_for_key
10863 call _int16_function
10868 /* notify int16 complete w/ int 15h, function AX=9102 */
10869 0x50, /* push AX */
10870 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10871 0xcd, 0x15, /* int 15h */
10878 ;-------------------------------------------------
10879 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10880 ;-------------------------------------------------
10886 mov al
, #0xAD ;;disable keyboard
10895 in al
, #0x60 ;;read key from keyboard controller
10899 #ifdef BX_CALL_INT15_4F
10900 mov ah
, #0x4f ;; allow for keyboard intercept
10906 ;; check
for extended key
10908 jne int09_check_pause
10911 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10913 mov BYTE
[0x496], al
10916 int09_check_pause
: ;; check
for pause key
10918 jne int09_process_key
10921 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10923 mov BYTE
[0x496], al
10929 call _int09_function
10935 call eoi_master_pic
10938 mov al
, #0xAE ;;enable keyboard
10944 ;----------------------------------------
10945 ;- INT
13h Diskette Service Entry Point
-
10946 ;----------------------------------------
10949 jmp int13_noeltorito
10951 ;---------------------------------------------
10952 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10953 ;---------------------------------------------
10954 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10964 mov al
, #0x08 ; sense interrupt status
10982 xor ax
, ax
;; segment
0000
10984 call eoi_master_pic
10986 or al
, #0x80 ;; diskette interrupt has occurred
10994 .org
0xefc7 ; Diskette Controller Parameter Table
10995 diskette_param_table
:
10996 ;; Since no provisions are made
for multiple drive types
, most
10997 ;; values in
this table are ignored
. I set parameters
for 1.44M
11000 db
0x02 ;; head load time
0000001, DMA used
11012 ;----------------------------------------
11013 ;- INT17h
: Printer Service Entry Point
-
11014 ;----------------------------------------
11021 call _int17_function
11026 diskette_param_table2
:
11027 ;; New diskette parameter table adding
3 parameters from IBM
11028 ;; Since no provisions are made
for multiple drive types
, most
11029 ;; values in
this table are ignored
. I set parameters
for 1.44M
11032 db
0x02 ;; head load time
0000001, DMA used
11042 db
79 ;; maximum track
11043 db
0 ;; data transfer rate
11044 db
4 ;; drive type in cmos
11046 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
11053 .org
0xf065 ; INT
10h Video Support Service Entry Point
11055 ;; dont
do anything
, since the VGA BIOS handles int10h requests
11058 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
11063 .org
0xf841 ; INT
12h Memory Size Service Entry Point
11064 ; ??? different
for Pentium (machine check
)?
11076 .org
0xf84d ; INT
11h Equipment List Service Entry Point
11088 .org
0xf859 ; INT
15h System Services Entry Point
11102 #if BX_USE_PS2_MOUSE
11104 je int15_handler_mouse
11106 call _int15_function
11107 int15_handler_mouse_ret
:
11109 int15_handler32_ret
:
11119 #if BX_USE_PS2_MOUSE
11120 int15_handler_mouse
:
11121 call _int15_function_mouse
11122 jmp int15_handler_mouse_ret
11127 call _int15_function32
11129 jmp int15_handler32_ret
11131 ;; Protected mode IDT descriptor
11133 ;; I just make the limit
0, so the machine will shutdown
11134 ;; if an exception occurs during
protected mode memory
11137 ;; Set base to f0000 to correspond to beginning of BIOS
,
11138 ;; in
case I actually define an IDT later
11142 dw
0x0000 ;; limit
15:00
11143 dw
0x0000 ;; base
15:00
11144 db
0x0f ;; base
23:16
11146 ;; Real mode IDT descriptor
11148 ;; Set to typical real
-mode values
.
11153 dw
0x03ff ;; limit
15:00
11154 dw
0x0000 ;; base
15:00
11155 db
0x00 ;; base
23:16
11161 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
11174 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
11175 mov ds
, ax
; on
16bit
protected mode
.
11176 jmp int1a_callfunction
11183 int1a_callfunction
:
11184 call _int1a_function
11190 ;; int70h
: IRQ8
- CMOS RTC
11197 call _int70_function
11205 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
11213 ;; time to turn off
drive(s
)?
11216 jz int08_floppy_off
11219 jnz int08_floppy_off
11220 ;; turn
motor(s
) off
11229 mov eax
, 0x046c ;; get ticks dword
11232 ;; compare eax to one days worth of timer ticks at
18.2 hz
11233 cmp eax
, #0x001800B0
11234 jb int08_store_ticks
11235 ;; there has been a midnight rollover at
this point
11236 xor eax
, eax
;; zero out counter
11237 inc BYTE
0x0470 ;; increment rollover flag
11240 mov
0x046c, eax
;; store
new ticks dword
11241 ;; chain to user timer tick INT
#0x1c
11243 //;; call_ep [ds:loc]
11244 //CALL_EP( 0x1c << 2 )
11247 call eoi_master_pic
11252 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
11256 .ascii BIOS_COPYRIGHT_STRING
11258 ;------------------------------------------------
11259 ;- IRET Instruction
for Dummy Interrupt Handler
-
11260 ;------------------------------------------------
11261 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
11262 dummy_iret_handler
:
11265 .org
0xff54 ; INT
05h Print Screen Service Entry Point
11269 .org
0xfff0 ; Power
-up Entry Point
11272 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
11273 .ascii BIOS_BUILD_DATE
11275 .org
0xfffe ; System Model ID
11279 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
11282 * This font comes from the fntcol16.zip package (c) by Joseph Gil
11283 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
11284 * This font is public domain
11286 static Bit8u vgafont8
[128*8]=
11288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11289 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
11290 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
11291 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11292 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11293 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
11294 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
11295 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
11296 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
11297 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
11298 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
11299 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
11300 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
11301 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
11302 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
11303 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
11304 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
11305 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
11306 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
11307 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
11308 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
11309 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
11310 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11311 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11312 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11313 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11314 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11315 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11316 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11317 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11318 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11319 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11321 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11322 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11323 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11324 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11325 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11326 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11327 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11328 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11329 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11330 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11331 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11332 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11333 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11334 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11335 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11336 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11337 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11338 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11339 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11340 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11341 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11342 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11343 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11344 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11345 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11346 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11347 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11348 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11349 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11350 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11351 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11352 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11353 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11354 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11355 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11356 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11357 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11358 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11359 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11360 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11361 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11362 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11363 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11364 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11365 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11366 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11367 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11368 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11369 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11370 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11371 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11372 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11373 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11374 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11375 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11376 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11377 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11378 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11379 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11380 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11381 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11382 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11384 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11385 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11386 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11387 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11388 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11389 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11390 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11391 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11392 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11393 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11394 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11395 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11396 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11397 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11398 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11399 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11400 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11401 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11402 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11403 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11404 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11405 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11406 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11407 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11408 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11409 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11410 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11411 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11412 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11413 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11414 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11415 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11420 bios_table_area_end
:
11421 // bcc-generated data will be placed here