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 // Switch to Protected Mode.
4086 // ES:DI points to user-supplied GDT
4087 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4088 // This subfunction does not return!
4090 // turn off interrupts
4095 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4097 // Initialize CS descriptor for BIOS
4098 write_word(ES
, regs
.u
.r16
.si
+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4099 write_word(ES
, regs
.u
.r16
.si
+0x38+2, 0x0000);// base 15:00
4100 write_byte(ES
, regs
.u
.r16
.si
+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4101 write_byte(ES
, regs
.u
.r16
.si
+0x38+5, 0x9b); // access
4102 write_word(ES
, regs
.u
.r16
.si
+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4106 // Compiler generates locals offset info relative to SP.
4107 // Get BX (PIC offsets) from stack.
4110 mov bx
, _int15_function
.BX
[bx
]
4113 mov al
, #0x11 ; send initialisation commands
4127 mov al
, #0xff ; mask all IRQs, user must re-enable
4131 // Load GDT and IDT from supplied data
4137 // set PE bit in CR0
4141 // far jump to flush CPU queue after transition to protected mode
4142 JMP_AP(0x0038, protmode_switch
)
4145 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
4153 // unwind the stack - this will break if calling sequence changes!
4155 add sp
,#4 ; skip return address
4157 pop ax
; skip saved es
4158 pop ax
; skip saved ds
4159 pop ax
; skip saved flags
4161 // return to caller - note that we do not use IRET because
4162 // we cannot enable interrupts
4163 pop cx
; get
return offset
4164 pop ax
; skip
return segment
4166 mov ax
, #0x30 ; ah must be 0 on successful exit
4168 push cx
; re
-create modified ret address on stack
4176 /* Device busy interrupt. Called by Int 16h when no key available */
4180 /* Interrupt complete. Called by Int 16h when key becomes available */
4184 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4186 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4192 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4197 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
4207 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
4209 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4213 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4214 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4216 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4221 #if BX_USE_PS2_MOUSE
4223 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
4224 pusha_regs_t regs
; // REGS pushed via pusha
4225 Bit16u ES
, DS
, FLAGS
;
4227 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4228 Bit8u mouse_flags_1
, mouse_flags_2
;
4229 Bit16u mouse_driver_seg
;
4230 Bit16u mouse_driver_offset
;
4231 Bit8u comm_byte
, prev_command_byte
;
4232 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
4234 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4236 switch (regs
.u
.r8
.ah
) {
4238 // Return Codes status in AH
4239 // =========================
4241 // 01: invalid subfunction (AL > 7)
4242 // 02: invalid input value (out of allowable range)
4243 // 03: interface error
4244 // 04: resend command received from mouse controller,
4245 // device driver should attempt command again
4246 // 05: cannot enable mouse, since no far call has been installed
4247 // 80/86: mouse service not implemented
4249 switch (regs
.u
.r8
.al
) {
4250 case 0: // Disable/Enable Mouse
4251 BX_DEBUG_INT15("case 0:\n");
4252 switch (regs
.u
.r8
.bh
) {
4253 case 0: // Disable Mouse
4254 BX_DEBUG_INT15("case 0: disable mouse\n");
4255 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4256 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
4258 ret
= get_mouse_data(&mouse_data1
);
4259 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
4272 case 1: // Enable Mouse
4273 BX_DEBUG_INT15("case 1: enable mouse\n");
4274 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4275 if ( (mouse_flags_2
& 0x80) == 0 ) {
4276 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4278 regs
.u
.r8
.ah
= 5; // no far call installed
4281 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4282 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
4284 ret
= get_mouse_data(&mouse_data1
);
4285 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
4286 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4296 default: // invalid subfunction
4297 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4299 regs
.u
.r8
.ah
= 1; // invalid subfunction
4304 case 1: // Reset Mouse
4305 case 5: // Initialize Mouse
4306 BX_DEBUG_INT15("case 1 or 5:\n");
4307 if (regs
.u
.r8
.al
== 5) {
4308 if (regs
.u
.r8
.bh
!= 3) {
4310 regs
.u
.r8
.ah
= 0x02; // invalid input
4313 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4314 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
4315 mouse_flags_1
= 0x00;
4316 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4317 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4320 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4321 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
4323 ret
= get_mouse_data(&mouse_data3
);
4324 // if no mouse attached, it will return RESEND
4325 if (mouse_data3
== 0xfe) {
4329 if (mouse_data3
!= 0xfa)
4330 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
4332 ret
= get_mouse_data(&mouse_data1
);
4334 ret
= get_mouse_data(&mouse_data2
);
4336 // turn IRQ12 and packet generation on
4337 enable_mouse_int_and_events();
4340 regs
.u
.r8
.bl
= mouse_data1
;
4341 regs
.u
.r8
.bh
= mouse_data2
;
4353 case 2: // Set Sample Rate
4354 BX_DEBUG_INT15("case 2:\n");
4355 switch (regs
.u
.r8
.bh
) {
4356 case 0: mouse_data1
= 10; break; // 10 reports/sec
4357 case 1: mouse_data1
= 20; break; // 20 reports/sec
4358 case 2: mouse_data1
= 40; break; // 40 reports/sec
4359 case 3: mouse_data1
= 60; break; // 60 reports/sec
4360 case 4: mouse_data1
= 80; break; // 80 reports/sec
4361 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
4362 case 6: mouse_data1
= 200; break; // 200 reports/sec
4363 default: mouse_data1
= 0;
4365 if (mouse_data1
> 0) {
4366 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
4368 ret
= get_mouse_data(&mouse_data2
);
4369 ret
= send_to_mouse_ctrl(mouse_data1
);
4370 ret
= get_mouse_data(&mouse_data2
);
4376 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4381 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4385 case 3: // Set Resolution
4386 BX_DEBUG_INT15("case 3:\n");
4388 // 0 = 25 dpi, 1 count per millimeter
4389 // 1 = 50 dpi, 2 counts per millimeter
4390 // 2 = 100 dpi, 4 counts per millimeter
4391 // 3 = 200 dpi, 8 counts per millimeter
4392 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4393 if (regs
.u
.r8
.bh
< 4) {
4394 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
4396 ret
= get_mouse_data(&mouse_data1
);
4397 if (mouse_data1
!= 0xfa)
4398 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4399 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
4400 ret
= get_mouse_data(&mouse_data1
);
4401 if (mouse_data1
!= 0xfa)
4402 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4408 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4413 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4415 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4418 case 4: // Get Device ID
4419 BX_DEBUG_INT15("case 4:\n");
4420 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4421 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
4423 ret
= get_mouse_data(&mouse_data1
);
4424 ret
= get_mouse_data(&mouse_data2
);
4427 regs
.u
.r8
.bh
= mouse_data2
;
4431 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4435 case 6: // Return Status & Set Scaling Factor...
4436 BX_DEBUG_INT15("case 6:\n");
4437 switch (regs
.u
.r8
.bh
) {
4438 case 0: // Return Status
4439 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4440 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4442 ret
= get_mouse_data(&mouse_data1
);
4443 if (mouse_data1
!= 0xfa)
4444 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4446 ret
= get_mouse_data(&mouse_data1
);
4448 ret
= get_mouse_data(&mouse_data2
);
4450 ret
= get_mouse_data(&mouse_data3
);
4454 regs
.u
.r8
.bl
= mouse_data1
;
4455 regs
.u
.r8
.cl
= mouse_data2
;
4456 regs
.u
.r8
.dl
= mouse_data3
;
4457 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4468 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4471 case 1: // Set Scaling Factor to 1:1
4472 case 2: // Set Scaling Factor to 2:1
4473 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4474 if (regs
.u
.r8
.bh
== 1) {
4475 ret
= send_to_mouse_ctrl(0xE6);
4477 ret
= send_to_mouse_ctrl(0xE7);
4480 get_mouse_data(&mouse_data1
);
4481 ret
= (mouse_data1
!= 0xFA);
4489 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4491 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4495 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4499 case 7: // Set Mouse Handler Address
4500 BX_DEBUG_INT15("case 7:\n");
4501 mouse_driver_seg
= ES
;
4502 mouse_driver_offset
= regs
.u
.r16
.bx
;
4503 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4504 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4505 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4506 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4507 /* remove handler */
4508 if ( (mouse_flags_2
& 0x80) != 0 ) {
4509 mouse_flags_2
&= ~0x80;
4510 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4514 /* install handler */
4515 mouse_flags_2
|= 0x80;
4517 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4523 BX_DEBUG_INT15("case default:\n");
4524 regs
.u
.r8
.ah
= 1; // invalid function
4530 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4531 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4533 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4537 #endif // BX_USE_PS2_MOUSE
4540 void set_e820_range(ES
, DI
, start
, end
, extra_start
, extra_end
, type
)
4549 write_word(ES
, DI
, start
);
4550 write_word(ES
, DI
+2, start
>> 16);
4551 write_word(ES
, DI
+4, extra_start
);
4552 write_word(ES
, DI
+6, 0x00);
4555 extra_end
-= extra_start
;
4556 write_word(ES
, DI
+8, end
);
4557 write_word(ES
, DI
+10, end
>> 16);
4558 write_word(ES
, DI
+12, extra_end
);
4559 write_word(ES
, DI
+14, 0x0000);
4561 write_word(ES
, DI
+16, type
);
4562 write_word(ES
, DI
+18, 0x0);
4566 int15_function32(regs
, ES
, DS
, FLAGS
)
4567 pushad_regs_t regs
; // REGS pushed via pushad
4568 Bit16u ES
, DS
, FLAGS
;
4570 Bit32u extended_memory_size
=0; // 64bits long
4571 Bit32u extra_lowbits_memory_size
=0;
4573 Bit8u extra_highbits_memory_size
=0;
4575 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4577 switch (regs
.u
.r8
.ah
) {
4579 // Wait for CX:DX microseconds. currently using the
4580 // refresh request port 0x61 bit4, toggling every 15usec
4588 ;; Get the count in eax
4591 mov ax
, _int15_function32
.CX
[bx
]
4594 mov ax
, _int15_function32
.DX
[bx
]
4596 ;; convert to numbers of
15usec ticks
4602 ;; wait
for ecx number of refresh requests
4623 switch(regs
.u
.r8
.al
) {
4624 case 0x20: // coded by osmaker aka K.J.
4625 if(regs
.u
.r32
.edx
== 0x534D4150)
4627 extended_memory_size
= inb_cmos(0x35);
4628 extended_memory_size
<<= 8;
4629 extended_memory_size
|= inb_cmos(0x34);
4630 extended_memory_size
*= 64;
4631 // greater than EFF00000???
4632 if(extended_memory_size
> 0x3bc000) {
4633 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4635 extended_memory_size
*= 1024;
4636 extended_memory_size
+= (16L * 1024 * 1024);
4638 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4639 extended_memory_size
= inb_cmos(0x31);
4640 extended_memory_size
<<= 8;
4641 extended_memory_size
|= inb_cmos(0x30);
4642 extended_memory_size
*= 1024;
4643 extended_memory_size
+= (1L * 1024 * 1024);
4646 extra_lowbits_memory_size
= inb_cmos(0x5c);
4647 extra_lowbits_memory_size
<<= 8;
4648 extra_lowbits_memory_size
|= inb_cmos(0x5b);
4649 extra_lowbits_memory_size
*= 64;
4650 extra_lowbits_memory_size
*= 1024;
4651 extra_highbits_memory_size
= inb_cmos(0x5d);
4653 switch(regs
.u
.r16
.bx
)
4656 set_e820_range(ES
, regs
.u
.r16
.di
,
4657 0x0000000L
, 0x0009f000L
, 0, 0, 1);
4661 set_e820_range(ES
, regs
.u
.r16
.di
,
4662 0x0009f000L
, 0x000a0000L
, 0, 0, 2);
4666 set_e820_range(ES
, regs
.u
.r16
.di
,
4667 0x000e8000L
, 0x00100000L
, 0, 0, 2);
4672 set_e820_range(ES
, regs
.u
.r16
.di
,
4674 extended_memory_size
- ACPI_DATA_SIZE
, 0, 0, 1);
4677 set_e820_range(ES
, regs
.u
.r16
.di
,
4679 extended_memory_size
, 0, 0, 1);
4684 set_e820_range(ES
, regs
.u
.r16
.di
,
4685 extended_memory_size
- ACPI_DATA_SIZE
,
4686 extended_memory_size
, 0, 0, 3); // ACPI RAM
4690 /* 256KB BIOS area at the end of 4 GB */
4691 set_e820_range(ES
, regs
.u
.r16
.di
,
4692 0xfffc0000L
, 0x00000000L
, 0, 0, 2);
4693 if (extra_highbits_memory_size
|| extra_lowbits_memory_size
)
4699 /* Maping of memory above 4 GB */
4700 set_e820_range(ES
, regs
.u
.r16
.di
, 0x00000000L
,
4701 extra_lowbits_memory_size
, 1, extra_highbits_memory_size
4705 default: /* AX=E820, DX=534D4150, BX unrecognized */
4706 goto int15_unimplemented
;
4709 regs
.u
.r32
.eax
= 0x534D4150;
4710 regs
.u
.r32
.ecx
= 0x14;
4713 // if DX != 0x534D4150)
4714 goto int15_unimplemented
;
4719 // do we have any reason to fail here ?
4722 // my real system sets ax and bx to 0
4723 // this is confirmed by Ralph Brown list
4724 // but syslinux v1.48 is known to behave
4725 // strangely if ax is set to 0
4726 // regs.u.r16.ax = 0;
4727 // regs.u.r16.bx = 0;
4729 // Get the amount of extended memory (above 1M)
4730 regs
.u
.r8
.cl
= inb_cmos(0x30);
4731 regs
.u
.r8
.ch
= inb_cmos(0x31);
4734 if(regs
.u
.r16
.cx
> 0x3c00)
4736 regs
.u
.r16
.cx
= 0x3c00;
4739 // Get the amount of extended memory above 16M in 64k blocs
4740 regs
.u
.r8
.dl
= inb_cmos(0x34);
4741 regs
.u
.r8
.dh
= inb_cmos(0x35);
4743 // Set configured memory equal to extended memory
4744 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4745 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4747 default: /* AH=0xE8?? but not implemented */
4748 goto int15_unimplemented
;
4751 int15_unimplemented
:
4752 // fall into the default
4754 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4755 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4757 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4763 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4764 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4766 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4767 Bit16u kbd_code
, max
;
4769 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4771 shift_flags
= read_byte(0x0040, 0x17);
4772 led_flags
= read_byte(0x0040, 0x97);
4773 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4778 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4779 if ((inb(0x60) == 0xfa)) {
4781 led_flags
|= ((shift_flags
>> 4) & 0x07);
4782 outb(0x60, led_flags
& 0x07);
4783 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4785 write_byte(0x0040, 0x97, led_flags
);
4793 case 0x00: /* read keyboard input */
4795 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4796 BX_PANIC("KBD: int16h: out of keyboard input\n");
4798 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4799 else if (ascii_code
== 0xE0) ascii_code
= 0;
4800 AX
= (scan_code
<< 8) | ascii_code
;
4803 case 0x01: /* check keyboard status */
4804 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4808 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4809 else if (ascii_code
== 0xE0) ascii_code
= 0;
4810 AX
= (scan_code
<< 8) | ascii_code
;
4814 case 0x02: /* get shift flag status */
4815 shift_flags
= read_byte(0x0040, 0x17);
4816 SET_AL(shift_flags
);
4819 case 0x05: /* store key-stroke into buffer */
4820 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4828 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4829 // bit Bochs Description
4831 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4832 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4833 // 4 1 INT 16/AH=0Ah supported
4834 // 3 0 INT 16/AX=0306h supported
4835 // 2 0 INT 16/AX=0305h supported
4836 // 1 0 INT 16/AX=0304h supported
4837 // 0 0 INT 16/AX=0300h supported
4842 case 0x0A: /* GET KEYBOARD ID */
4848 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4850 if ((inb(0x60) == 0xfa)) {
4853 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4856 kbd_code
|= (inb(0x60) << 8);
4858 } while (--count
>0);
4864 case 0x10: /* read MF-II keyboard input */
4866 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4867 BX_PANIC("KBD: int16h: out of keyboard input\n");
4869 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4870 AX
= (scan_code
<< 8) | ascii_code
;
4873 case 0x11: /* check MF-II keyboard status */
4874 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4878 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4879 AX
= (scan_code
<< 8) | ascii_code
;
4883 case 0x12: /* get extended keyboard status */
4884 shift_flags
= read_byte(0x0040, 0x17);
4885 SET_AL(shift_flags
);
4886 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4887 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4888 SET_AH(shift_flags
);
4889 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4892 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4893 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4896 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4897 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4901 if (GET_AL() == 0x08)
4902 SET_AH(0x02); // unsupported, aka normal keyboard
4905 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4910 dequeue_key(scan_code
, ascii_code
, incr
)
4915 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4920 buffer_start
= 0x001E;
4921 buffer_end
= 0x003E;
4923 buffer_start
= read_word(0x0040, 0x0080);
4924 buffer_end
= read_word(0x0040, 0x0082);
4927 buffer_head
= read_word(0x0040, 0x001a);
4928 buffer_tail
= read_word(0x0040, 0x001c);
4930 if (buffer_head
!= buffer_tail
) {
4932 acode
= read_byte(0x0040, buffer_head
);
4933 scode
= read_byte(0x0040, buffer_head
+1);
4934 write_byte(ss
, ascii_code
, acode
);
4935 write_byte(ss
, scan_code
, scode
);
4939 if (buffer_head
>= buffer_end
)
4940 buffer_head
= buffer_start
;
4941 write_word(0x0040, 0x001a, buffer_head
);
4950 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4953 inhibit_mouse_int_and_events()
4955 Bit8u command_byte
, prev_command_byte
;
4957 // Turn off IRQ generation and aux data line
4958 if ( inb(0x64) & 0x02 )
4959 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4960 outb(0x64, 0x20); // get command byte
4961 while ( (inb(0x64) & 0x01) != 0x01 );
4962 prev_command_byte
= inb(0x60);
4963 command_byte
= prev_command_byte
;
4964 //while ( (inb(0x64) & 0x02) );
4965 if ( inb(0x64) & 0x02 )
4966 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4967 command_byte
&= 0xfd; // turn off IRQ 12 generation
4968 command_byte
|= 0x20; // disable mouse serial clock line
4969 outb(0x64, 0x60); // write command byte
4970 outb(0x60, command_byte
);
4971 return(prev_command_byte
);
4975 enable_mouse_int_and_events()
4979 // Turn on IRQ generation and aux data line
4980 if ( inb(0x64) & 0x02 )
4981 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4982 outb(0x64, 0x20); // get command byte
4983 while ( (inb(0x64) & 0x01) != 0x01 );
4984 command_byte
= inb(0x60);
4985 //while ( (inb(0x64) & 0x02) );
4986 if ( inb(0x64) & 0x02 )
4987 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4988 command_byte
|= 0x02; // turn on IRQ 12 generation
4989 command_byte
&= 0xdf; // enable mouse serial clock line
4990 outb(0x64, 0x60); // write command byte
4991 outb(0x60, command_byte
);
4995 send_to_mouse_ctrl(sendbyte
)
5000 // wait for chance to write to ctrl
5001 if ( inb(0x64) & 0x02 )
5002 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
5004 outb(0x60, sendbyte
);
5010 get_mouse_data(data
)
5016 while ((inb(0x64) & 0x21) != 0x21) { }
5018 response
= inb(0x60);
5021 write_byte(ss
, data
, response
);
5026 set_kbd_command_byte(command_byte
)
5029 if ( inb(0x64) & 0x02 )
5030 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
5033 outb(0x64, 0x60); // write command byte
5034 outb(0x60, command_byte
);
5038 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
5039 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
5041 Bit8u scancode
, asciicode
, shift_flags
;
5042 Bit8u mf2_flags
, mf2_state
;
5045 // DS has been set to F000 before call
5049 scancode
= GET_AL();
5051 if (scancode
== 0) {
5052 BX_INFO("KBD: int09 handler: AL=0\n");
5057 shift_flags
= read_byte(0x0040, 0x17);
5058 mf2_flags
= read_byte(0x0040, 0x18);
5059 mf2_state
= read_byte(0x0040, 0x96);
5063 case 0x3a: /* Caps Lock press */
5064 shift_flags
^= 0x40;
5065 write_byte(0x0040, 0x17, shift_flags
);
5067 write_byte(0x0040, 0x18, mf2_flags
);
5069 case 0xba: /* Caps Lock release */
5071 write_byte(0x0040, 0x18, mf2_flags
);
5074 case 0x2a: /* L Shift press */
5075 shift_flags
|= 0x02;
5076 write_byte(0x0040, 0x17, shift_flags
);
5078 case 0xaa: /* L Shift release */
5079 shift_flags
&= ~0x02;
5080 write_byte(0x0040, 0x17, shift_flags
);
5083 case 0x36: /* R Shift press */
5084 shift_flags
|= 0x01;
5085 write_byte(0x0040, 0x17, shift_flags
);
5087 case 0xb6: /* R Shift release */
5088 shift_flags
&= ~0x01;
5089 write_byte(0x0040, 0x17, shift_flags
);
5092 case 0x1d: /* Ctrl press */
5093 if ((mf2_state
& 0x01) == 0) {
5094 shift_flags
|= 0x04;
5095 write_byte(0x0040, 0x17, shift_flags
);
5096 if (mf2_state
& 0x02) {
5098 write_byte(0x0040, 0x96, mf2_state
);
5101 write_byte(0x0040, 0x18, mf2_flags
);
5105 case 0x9d: /* Ctrl release */
5106 if ((mf2_state
& 0x01) == 0) {
5107 shift_flags
&= ~0x04;
5108 write_byte(0x0040, 0x17, shift_flags
);
5109 if (mf2_state
& 0x02) {
5111 write_byte(0x0040, 0x96, mf2_state
);
5114 write_byte(0x0040, 0x18, mf2_flags
);
5119 case 0x38: /* Alt press */
5120 shift_flags
|= 0x08;
5121 write_byte(0x0040, 0x17, shift_flags
);
5122 if (mf2_state
& 0x02) {
5124 write_byte(0x0040, 0x96, mf2_state
);
5127 write_byte(0x0040, 0x18, mf2_flags
);
5130 case 0xb8: /* Alt release */
5131 shift_flags
&= ~0x08;
5132 write_byte(0x0040, 0x17, shift_flags
);
5133 if (mf2_state
& 0x02) {
5135 write_byte(0x0040, 0x96, mf2_state
);
5138 write_byte(0x0040, 0x18, mf2_flags
);
5142 case 0x45: /* Num Lock press */
5143 if ((mf2_state
& 0x03) == 0) {
5145 write_byte(0x0040, 0x18, mf2_flags
);
5146 shift_flags
^= 0x20;
5147 write_byte(0x0040, 0x17, shift_flags
);
5150 case 0xc5: /* Num Lock release */
5151 if ((mf2_state
& 0x03) == 0) {
5153 write_byte(0x0040, 0x18, mf2_flags
);
5157 case 0x46: /* Scroll Lock press */
5159 write_byte(0x0040, 0x18, mf2_flags
);
5160 shift_flags
^= 0x10;
5161 write_byte(0x0040, 0x17, shift_flags
);
5164 case 0xc6: /* Scroll Lock release */
5166 write_byte(0x0040, 0x18, mf2_flags
);
5170 if (scancode
& 0x80) {
5171 break; /* toss key releases ... */
5173 if (scancode
> MAX_SCAN_CODE
) {
5174 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
5177 if (shift_flags
& 0x08) { /* ALT */
5178 asciicode
= scan_to_scanascii
[scancode
].alt
;
5179 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
5180 } else if (shift_flags
& 0x04) { /* CONTROL */
5181 asciicode
= scan_to_scanascii
[scancode
].control
;
5182 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
5183 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
5184 /* extended keys handling */
5186 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5187 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
5188 /* check if lock state should be ignored
5189 * because a SHIFT key are pressed */
5191 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
5192 asciicode
= scan_to_scanascii
[scancode
].normal
;
5193 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5195 asciicode
= scan_to_scanascii
[scancode
].shift
;
5196 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
5199 /* check if lock is on */
5200 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
5201 asciicode
= scan_to_scanascii
[scancode
].shift
;
5202 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
5204 asciicode
= scan_to_scanascii
[scancode
].normal
;
5205 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5208 if (scancode
==0 && asciicode
==0) {
5209 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5211 enqueue_key(scancode
, asciicode
);
5214 if ((scancode
& 0x7f) != 0x1d) {
5218 write_byte(0x0040, 0x96, mf2_state
);
5222 enqueue_key(scan_code
, ascii_code
)
5223 Bit8u scan_code
, ascii_code
;
5225 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
5228 buffer_start
= 0x001E;
5229 buffer_end
= 0x003E;
5231 buffer_start
= read_word(0x0040, 0x0080);
5232 buffer_end
= read_word(0x0040, 0x0082);
5235 buffer_head
= read_word(0x0040, 0x001A);
5236 buffer_tail
= read_word(0x0040, 0x001C);
5238 temp_tail
= buffer_tail
;
5240 if (buffer_tail
>= buffer_end
)
5241 buffer_tail
= buffer_start
;
5243 if (buffer_tail
== buffer_head
) {
5247 write_byte(0x0040, temp_tail
, ascii_code
);
5248 write_byte(0x0040, temp_tail
+1, scan_code
);
5249 write_word(0x0040, 0x001C, buffer_tail
);
5254 int74_function(make_farcall
, Z
, Y
, X
, status
)
5255 Bit16u make_farcall
, Z
, Y
, X
, status
;
5257 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5258 Bit8u in_byte
, index
, package_count
;
5259 Bit8u mouse_flags_1
, mouse_flags_2
;
5261 BX_DEBUG_INT74("entering int74_function\n");
5264 in_byte
= inb(0x64);
5265 if ((in_byte
& 0x21) != 0x21) {
5269 in_byte
= inb(0x60);
5270 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
5272 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
5273 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
5275 if ((mouse_flags_2
& 0x80) != 0x80) {
5279 package_count
= mouse_flags_2
& 0x07;
5280 index
= mouse_flags_1
& 0x07;
5281 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
5283 if ( (index
+1) >= package_count
) {
5284 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5285 status
= read_byte(ebda_seg
, 0x0028 + 0);
5286 X
= read_byte(ebda_seg
, 0x0028 + 1);
5287 Y
= read_byte(ebda_seg
, 0x0028 + 2);
5290 // check if far call handler installed
5291 if (mouse_flags_2
& 0x80)
5297 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
5300 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5305 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5306 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5308 Bit32u lba_low
, lba_high
;
5309 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5310 Bit16u cylinder
, head
, sector
;
5311 Bit16u segment
, offset
;
5312 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
5314 Bit8u device
, status
;
5316 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5318 write_byte(0x0040, 0x008e, 0); // clear completion flag
5320 // basic check : device has to be defined
5321 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
5322 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5326 // Get the ata channel
5327 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
5329 // basic check : device has to be valid
5330 if (device
>= BX_MAX_ATA_DEVICES
) {
5331 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5337 case 0x00: /* disk controller reset */
5342 case 0x01: /* read disk status */
5343 status
= read_byte(0x0040, 0x0074);
5345 SET_DISK_RET_STATUS(0);
5346 /* set CF if error status read */
5347 if (status
) goto int13_fail_nostatus
;
5348 else goto int13_success_noah
;
5351 case 0x02: // read disk sectors
5352 case 0x03: // write disk sectors
5353 case 0x04: // verify disk sectors
5356 cylinder
= GET_CH();
5357 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5358 sector
= (GET_CL() & 0x3f);
5364 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
5365 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5369 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5370 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5371 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5373 // sanity check on cyl heads, sec
5374 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
) ) {
5375 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
5380 if (GET_AH() == 0x04) goto int13_success
;
5382 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5383 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5385 // if needed, translate lchs to lba, and execute command
5386 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
5387 lba_low
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
5389 sector
= 0; // this forces the command to be lba
5392 if (GET_AH() == 0x02)
5393 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
);
5395 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
);
5397 // Set nb of sector transferred
5398 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
5401 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5403 goto int13_fail_noah
;
5409 case 0x05: /* format disk track */
5410 BX_INFO("format disk track called\n");
5415 case 0x08: /* read disk drive parameters */
5417 // Get logical geometry from table
5418 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5419 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5420 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5421 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5423 nlc
= nlc
- 2; /* 0 based, last sector not used */
5426 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5428 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5430 // FIXME should set ES & DI
5435 case 0x10: /* check drive ready */
5436 // should look at 40:8E also???
5438 // Read the status from controller
5439 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5440 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5445 goto int13_fail_noah
;
5449 case 0x15: /* read disk drive size */
5451 // Get logical geometry from table
5452 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5453 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5454 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5456 // Compute sector count seen by int13
5457 lba_low
= (Bit32u
)(nlc
- 1) * (Bit32u
)nlh
* (Bit32u
)nlspt
;
5459 DX
= lba_low
& 0xffff;
5461 SET_AH(3); // hard disk accessible
5462 goto int13_success_noah
;
5465 case 0x41: // IBM/MS installation check
5466 BX
=0xaa55; // install check
5467 SET_AH(0x30); // EDD 3.0
5468 CX
=0x0007; // ext disk access and edd, removable supported
5469 goto int13_success_noah
;
5472 case 0x42: // IBM/MS extended read
5473 case 0x43: // IBM/MS extended write
5474 case 0x44: // IBM/MS verify
5475 case 0x47: // IBM/MS extended seek
5477 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5478 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5479 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5481 // Get 32 msb lba and check
5482 lba_high
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5483 if (lba_high
> read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
) ) {
5484 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5488 // Get 32 lsb lba and check
5489 lba_low
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5490 if (lba_high
== read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
)
5491 && lba_low
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_low
) ) {
5492 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5496 // If verify or seek
5497 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5500 // Execute the command
5501 if (GET_AH() == 0x42)
5502 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba_low
, lba_high
, segment
, offset
);
5504 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba_low
, lba_high
, segment
, offset
);
5506 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5507 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5510 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5512 goto int13_fail_noah
;
5518 case 0x45: // IBM/MS lock/unlock drive
5519 case 0x49: // IBM/MS extended media change
5520 goto int13_success
; // Always success for HD
5523 case 0x46: // IBM/MS eject media
5524 SET_AH(0xb2); // Volume Not Removable
5525 goto int13_fail_noah
; // Always fail for HD
5528 case 0x48: // IBM/MS get drive parameters
5529 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5531 // Buffer is too small
5539 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5540 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5541 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5542 lba_low
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_low
);
5543 lba_high
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
);
5544 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5546 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5547 if (lba_high
|| (lba_low
/npspt
)/nph
> 0x3fff)
5549 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x00); // geometry is invalid
5550 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0x3fff);
5554 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5555 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5557 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5558 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5559 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba_low
);
5560 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, lba_high
);
5561 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5566 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5567 Bit16u iobase1
, iobase2
, options
;
5569 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5571 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5572 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5575 channel
= device
/ 2;
5576 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5577 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5578 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5579 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5580 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5582 options
= (translation
==ATA_TRANSLATION_NONE
?0:1)<<3; // chs translation
5583 options
|= (1<<4); // lba translation
5584 options
|= (mode
==ATA_MODE_PIO32
?1:0)<<7;
5585 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0)<<9;
5586 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0)<<9;
5588 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5589 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5590 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5591 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5592 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5593 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5594 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5595 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5596 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5597 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5599 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5601 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x10);
5604 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5605 checksum
= ~checksum
;
5606 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5611 Bit8u channel
, iface
, checksum
, i
;
5614 channel
= device
/ 2;
5615 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5616 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5618 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5619 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5620 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5621 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5622 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5624 if (iface
==ATA_IFACE_ISA
) {
5625 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5626 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5627 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5628 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5633 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5634 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5635 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5636 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5638 if (iface
==ATA_IFACE_ISA
) {
5639 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5640 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5641 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5646 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5647 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5648 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5649 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5652 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5653 checksum
= ~checksum
;
5654 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5660 case 0x4e: // // IBM/MS set hardware configuration
5661 // DMA, prefetch, PIO maximum not supported
5674 case 0x09: /* initialize drive parameters */
5675 case 0x0c: /* seek to specified cylinder */
5676 case 0x0d: /* alternate disk reset */
5677 case 0x11: /* recalibrate */
5678 case 0x14: /* controller internal diagnostic */
5679 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5683 case 0x0a: /* read disk sectors with ECC */
5684 case 0x0b: /* write disk sectors with ECC */
5685 case 0x18: // set media type for format
5686 case 0x50: // IBM/MS send packet command
5688 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5694 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5696 SET_DISK_RET_STATUS(GET_AH());
5697 int13_fail_nostatus
:
5698 SET_CF(); // error occurred
5702 SET_AH(0x00); // no error
5704 SET_DISK_RET_STATUS(0x00);
5705 CLEAR_CF(); // no error
5708 // ---------------------------------------------------------------------------
5709 // Start of int13 for cdrom
5710 // ---------------------------------------------------------------------------
5713 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5714 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5716 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5717 Bit8u device
, status
, locks
;
5720 Bit16u count
, segment
, offset
, i
, size
;
5722 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5724 SET_DISK_RET_STATUS(0x00);
5726 /* basic check : device should be 0xE0+ */
5727 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5728 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5732 // Get the ata channel
5733 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5735 /* basic check : device has to be valid */
5736 if (device
>= BX_MAX_ATA_DEVICES
) {
5737 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5743 // all those functions return SUCCESS
5744 case 0x00: /* disk controller reset */
5745 case 0x09: /* initialize drive parameters */
5746 case 0x0c: /* seek to specified cylinder */
5747 case 0x0d: /* alternate disk reset */
5748 case 0x10: /* check drive ready */
5749 case 0x11: /* recalibrate */
5750 case 0x14: /* controller internal diagnostic */
5751 case 0x16: /* detect disk change */
5755 // all those functions return disk write-protected
5756 case 0x03: /* write disk sectors */
5757 case 0x05: /* format disk track */
5758 case 0x43: // IBM/MS extended write
5760 goto int13_fail_noah
;
5763 case 0x01: /* read disk status */
5764 status
= read_byte(0x0040, 0x0074);
5766 SET_DISK_RET_STATUS(0);
5768 /* set CF if error status read */
5769 if (status
) goto int13_fail_nostatus
;
5770 else goto int13_success_noah
;
5773 case 0x15: /* read disk drive size */
5775 goto int13_fail_noah
;
5778 case 0x41: // IBM/MS installation check
5779 BX
=0xaa55; // install check
5780 SET_AH(0x30); // EDD 2.1
5781 CX
=0x0007; // ext disk access, removable and edd
5782 goto int13_success_noah
;
5785 case 0x42: // IBM/MS extended read
5786 case 0x44: // IBM/MS verify sectors
5787 case 0x47: // IBM/MS extended seek
5789 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5790 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5791 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5793 // Can't use 64 bits lba
5794 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5796 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5801 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5803 // If verify or seek
5804 if ((GET_AH() == 0x44) || (GET_AH() == 0x47))
5807 memsetb(get_SS(),atacmd
,0,12);
5808 atacmd
[0]=0x28; // READ command
5809 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5810 atacmd
[8]=(count
& 0x00ff); // Sectors
5811 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5812 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5813 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5814 atacmd
[5]=(lba
& 0x000000ff);
5815 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5817 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5818 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5821 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5823 goto int13_fail_noah
;
5829 case 0x45: // IBM/MS lock/unlock drive
5830 if (GET_AL() > 2) goto int13_fail
;
5832 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5836 if (locks
== 0xff) {
5839 goto int13_fail_noah
;
5841 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5845 if (locks
== 0x00) {
5848 goto int13_fail_noah
;
5850 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5851 SET_AL(locks
==0?0:1);
5854 SET_AL(locks
==0?0:1);
5861 case 0x46: // IBM/MS eject media
5862 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5865 SET_AH(0xb1); // media locked
5866 goto int13_fail_noah
;
5868 // FIXME should handle 0x31 no media in device
5869 // FIXME should handle 0xb5 valid request failed
5871 // Call removable media eject
5878 mov _int13_cdrom
.status
+ 2[bp
], ah
5879 jnc int13_cdrom_rme_end
5880 mov _int13_cdrom
.status
, #1
5881 int13_cdrom_rme_end
:
5886 SET_AH(0xb1); // media locked
5887 goto int13_fail_noah
;
5893 case 0x48: // IBM/MS get drive parameters
5894 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5896 // Buffer is too small
5902 Bit16u cylinders
, heads
, spt
, blksize
;
5904 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5906 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5907 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5908 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5909 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5910 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5911 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5912 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5913 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5918 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5919 Bit16u iobase1
, iobase2
, options
;
5921 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5923 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5924 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5927 channel
= device
/ 2;
5928 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5929 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5930 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5931 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5933 // FIXME atapi device
5934 options
= (1<<4); // lba translation
5935 options
|= (1<<5); // removable device
5936 options
|= (1<<6); // atapi device
5937 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5939 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5940 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5941 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5942 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5943 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5944 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5945 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5946 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5947 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5948 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5949 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5952 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5953 checksum
= ~checksum
;
5954 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5959 Bit8u channel
, iface
, checksum
, i
;
5962 channel
= device
/ 2;
5963 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5964 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5966 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5967 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5968 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5969 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5970 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5972 if (iface
==ATA_IFACE_ISA
) {
5973 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5974 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5975 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5976 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5981 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5982 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5983 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5984 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5986 if (iface
==ATA_IFACE_ISA
) {
5987 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5988 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5989 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5994 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5995 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5996 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5997 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
6000 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
6001 checksum
= ~checksum
;
6002 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
6008 case 0x49: // IBM/MS extended media change
6009 // always send changed ??
6011 goto int13_fail_nostatus
;
6014 case 0x4e: // // IBM/MS set hardware configuration
6015 // DMA, prefetch, PIO maximum not supported
6028 // all those functions return unimplemented
6029 case 0x02: /* read sectors */
6030 case 0x04: /* verify sectors */
6031 case 0x08: /* read disk drive parameters */
6032 case 0x0a: /* read disk sectors with ECC */
6033 case 0x0b: /* write disk sectors with ECC */
6034 case 0x18: /* set media type for format */
6035 case 0x50: // ? - send packet command
6037 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6043 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6045 SET_DISK_RET_STATUS(GET_AH());
6046 int13_fail_nostatus
:
6047 SET_CF(); // error occurred
6051 SET_AH(0x00); // no error
6053 SET_DISK_RET_STATUS(0x00);
6054 CLEAR_CF(); // no error
6057 // ---------------------------------------------------------------------------
6058 // End of int13 for cdrom
6059 // ---------------------------------------------------------------------------
6061 #if BX_ELTORITO_BOOT
6062 // ---------------------------------------------------------------------------
6063 // Start of int13 for eltorito functions
6064 // ---------------------------------------------------------------------------
6067 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6068 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6070 Bit16u ebda_seg
=read_word(0x0040,0x000E);
6072 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6073 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6077 // FIXME ElTorito Various. Should be implemented
6078 case 0x4a: // ElTorito - Initiate disk emu
6079 case 0x4c: // ElTorito - Initiate disk emu and boot
6080 case 0x4d: // ElTorito - Return Boot catalog
6081 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
6085 case 0x4b: // ElTorito - Terminate disk emu
6086 // FIXME ElTorito Hardcoded
6087 write_byte(DS
,SI
+0x00,0x13);
6088 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
6089 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
6090 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
6091 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
6092 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
6093 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
6094 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
6095 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
6096 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
6097 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
6098 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
6100 // If we have to terminate emulation
6101 if(GET_AL() == 0x00) {
6102 // FIXME ElTorito Various. Should be handled accordingly to spec
6103 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
6110 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6116 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6117 SET_DISK_RET_STATUS(GET_AH());
6118 SET_CF(); // error occurred
6122 SET_AH(0x00); // no error
6123 SET_DISK_RET_STATUS(0x00);
6124 CLEAR_CF(); // no error
6127 // ---------------------------------------------------------------------------
6128 // End of int13 for eltorito functions
6129 // ---------------------------------------------------------------------------
6131 // ---------------------------------------------------------------------------
6132 // Start of int13 when emulating a device from the cd
6133 // ---------------------------------------------------------------------------
6136 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6137 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6139 Bit16u ebda_seg
=read_word(0x0040,0x000E);
6140 Bit8u device
, status
;
6141 Bit16u vheads
, vspt
, vcylinders
;
6142 Bit16u head
, sector
, cylinder
, nbsectors
;
6143 Bit32u vlba
, ilba
, slba
, elba
;
6144 Bit16u before
, segment
, offset
;
6147 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6149 /* at this point, we are emulating a floppy/harddisk */
6151 // Recompute the device number
6152 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
6153 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
6155 SET_DISK_RET_STATUS(0x00);
6157 /* basic checks : emulation should be active, dl should equal the emulated drive */
6158 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0) ||
6159 (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
6160 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6166 // all those functions return SUCCESS
6167 case 0x00: /* disk controller reset */
6168 case 0x09: /* initialize drive parameters */
6169 case 0x0c: /* seek to specified cylinder */
6170 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6171 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6172 case 0x11: /* recalibrate */
6173 case 0x14: /* controller internal diagnostic */
6174 case 0x16: /* detect disk change */
6178 // all those functions return disk write-protected
6179 case 0x03: /* write disk sectors */
6180 case 0x05: /* format disk track */
6182 goto int13_fail_noah
;
6185 case 0x01: /* read disk status */
6186 status
=read_byte(0x0040, 0x0074);
6188 SET_DISK_RET_STATUS(0);
6190 /* set CF if error status read */
6191 if (status
) goto int13_fail_nostatus
;
6192 else goto int13_success_noah
;
6195 case 0x02: // read disk sectors
6196 case 0x04: // verify disk sectors
6197 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
6198 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
6199 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
6201 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
6203 sector
= GET_CL() & 0x003f;
6204 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6206 nbsectors
= GET_AL();
6210 // no sector to read ?
6211 if(nbsectors
==0) goto int13_success
;
6213 // sanity checks sco openserver needs this!
6215 || (cylinder
>= vcylinders
)
6216 || (head
>= vheads
)) {
6220 // After controls, verify do nothing
6221 if (GET_AH() == 0x04) goto int13_success
;
6223 segment
= ES
+(BX
/ 16);
6226 // calculate the virtual lba inside the image
6227 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
6229 // In advance so we don't loose the count
6233 slba
= (Bit32u
)vlba
/4;
6234 before
= (Bit16u
)vlba
%4;
6237 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
6239 memsetb(get_SS(),atacmd
,0,12);
6240 atacmd
[0]=0x28; // READ command
6241 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
6242 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
6243 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
6244 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
6245 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
6246 atacmd
[5]=(ilba
+slba
& 0x000000ff);
6247 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
6248 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
6251 goto int13_fail_noah
;
6257 case 0x08: /* read disk drive parameters */
6258 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
6259 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
6260 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
6264 SET_CH(vcylinders
& 0xff);
6265 SET_CL(((vcylinders
>> 2) & 0xc0) | (vspt
& 0x3f));
6267 SET_DL(0x02); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6268 // FIXME ElTorito Harddisk. should send the HD count
6270 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
6271 case 0x01: SET_BL( 0x02 ); break;
6272 case 0x02: SET_BL( 0x04 ); break;
6273 case 0x03: SET_BL( 0x06 ); break;
6279 mov ax
, #diskette_param_table2
6280 mov _int13_cdemu
.DI
+2[bp
], ax
6281 mov _int13_cdemu
.ES
+2[bp
], cs
6287 case 0x15: /* read disk drive size */
6288 // FIXME ElTorito Harddisk. What geometry to send ?
6290 goto int13_success_noah
;
6293 // all those functions return unimplemented
6294 case 0x0a: /* read disk sectors with ECC */
6295 case 0x0b: /* write disk sectors with ECC */
6296 case 0x18: /* set media type for format */
6297 case 0x41: // IBM/MS installation check
6298 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6299 case 0x42: // IBM/MS extended read
6300 case 0x43: // IBM/MS extended write
6301 case 0x44: // IBM/MS verify sectors
6302 case 0x45: // IBM/MS lock/unlock drive
6303 case 0x46: // IBM/MS eject media
6304 case 0x47: // IBM/MS extended seek
6305 case 0x48: // IBM/MS get drive parameters
6306 case 0x49: // IBM/MS extended media change
6307 case 0x4e: // ? - set hardware configuration
6308 case 0x50: // ? - send packet command
6310 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6316 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6318 SET_DISK_RET_STATUS(GET_AH());
6319 int13_fail_nostatus
:
6320 SET_CF(); // error occurred
6324 SET_AH(0x00); // no error
6326 SET_DISK_RET_STATUS(0x00);
6327 CLEAR_CF(); // no error
6330 // ---------------------------------------------------------------------------
6331 // End of int13 when emulating a device from the cd
6332 // ---------------------------------------------------------------------------
6334 #endif // BX_ELTORITO_BOOT
6336 #else //BX_USE_ATADRV
6339 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
6354 mov ax
,4[bp
] // cylinder
6356 mov bl
,6[bp
] // hd_heads
6359 mov bl
,8[bp
] // head
6361 mov bl
,10[bp
] // hd_sectors
6363 mov bl
,12[bp
] // sector
6392 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6393 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6395 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
6399 Bit16u max_cylinder
, cylinder
, total_sectors
;
6400 Bit16u hd_cylinders
;
6401 Bit8u hd_heads
, hd_sectors
;
6408 Bit16u count
, segment
, offset
;
6412 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6414 write_byte(0x0040, 0x008e, 0); // clear completion flag
6416 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6418 /* check how many disks first (cmos reg 0x12), return an error if
6419 drive not present */
6420 drive_map
= inb_cmos(0x12);
6421 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6422 (((drive_map
& 0x0f)==0) ? 0 : 2);
6423 n_drives
= (drive_map
==0) ? 0 : ((drive_map
==3) ? 2 : 1);
6425 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6427 SET_DISK_RET_STATUS(0x01);
6428 SET_CF(); /* error occurred */
6434 case 0x00: /* disk controller reset */
6435 BX_DEBUG_INT13_HD("int13_f00\n");
6438 SET_DISK_RET_STATUS(0);
6439 set_diskette_ret_status(0);
6440 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6441 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6442 CLEAR_CF(); /* successful */
6446 case 0x01: /* read disk status */
6447 BX_DEBUG_INT13_HD("int13_f01\n");
6448 status
= read_byte(0x0040, 0x0074);
6450 SET_DISK_RET_STATUS(0);
6451 /* set CF if error status read */
6452 if (status
) SET_CF();
6457 case 0x04: // verify disk sectors
6458 case 0x02: // read disk sectors
6460 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6462 num_sectors
= GET_AL();
6463 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6464 sector
= (GET_CL() & 0x3f);
6468 if (hd_cylinders
> 1024) {
6469 if (hd_cylinders
<= 2048) {
6472 else if (hd_cylinders
<= 4096) {
6475 else if (hd_cylinders
<= 8192) {
6478 else { // hd_cylinders <= 16384
6482 ax
= head
/ hd_heads
;
6483 cyl_mod
= ax
& 0xff;
6485 cylinder
|= cyl_mod
;
6488 if ( (cylinder
>= hd_cylinders
) ||
6489 (sector
> hd_sectors
) ||
6490 (head
>= hd_heads
) ) {
6492 SET_DISK_RET_STATUS(1);
6493 SET_CF(); /* error occurred */
6497 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6498 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6501 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6503 if ( GET_AH() == 0x04 ) {
6505 SET_DISK_RET_STATUS(0);
6510 status
= inb(0x1f7);
6511 if (status
& 0x80) {
6512 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6514 outb(0x01f2, num_sectors
);
6515 /* activate LBA? (tomv) */
6516 if (hd_heads
> 16) {
6517 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6518 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6521 outb(0x01f3, sector
);
6522 outb(0x01f4, cylinder
& 0x00ff);
6523 outb(0x01f5, cylinder
>> 8);
6524 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6529 status
= inb(0x1f7);
6530 if (!(status
& 0x80)) break;
6533 if (status
& 0x01) {
6534 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6535 } else if (!(status
& 0x08)) {
6536 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6537 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6544 sti
;; enable higher priority interrupts
6549 ;; store temp bx in real DI
register
6552 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6555 ;; adjust
if there will be an overrun
6557 jbe i13_f02_no_adjust
6559 sub di
, #0x0200 ; sub 512 bytes from offset
6561 add ax
, #0x0020 ; add 512 to segment
6565 mov cx
, #0x0100 ;; counter (256 words = 512b)
6566 mov dx
, #0x01f0 ;; AT data read port
6569 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6572 ;; store real DI
register back to temp bx
6575 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6581 if (num_sectors
== 0) {
6582 status
= inb(0x1f7);
6583 if ((status
& 0xc9) != 0x40)
6584 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6588 status
= inb(0x1f7);
6589 if ((status
& 0xc9) != 0x48)
6590 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6596 SET_DISK_RET_STATUS(0);
6597 SET_AL(sector_count
);
6598 CLEAR_CF(); /* successful */
6602 case 0x03: /* write disk sectors */
6603 BX_DEBUG_INT13_HD("int13_f03\n");
6604 drive
= GET_ELDL ();
6605 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6607 num_sectors
= GET_AL();
6608 cylinder
= GET_CH();
6609 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6610 sector
= (GET_CL() & 0x3f);
6613 if (hd_cylinders
> 1024) {
6614 if (hd_cylinders
<= 2048) {
6617 else if (hd_cylinders
<= 4096) {
6620 else if (hd_cylinders
<= 8192) {
6623 else { // hd_cylinders <= 16384
6627 ax
= head
/ hd_heads
;
6628 cyl_mod
= ax
& 0xff;
6630 cylinder
|= cyl_mod
;
6633 if ( (cylinder
>= hd_cylinders
) ||
6634 (sector
> hd_sectors
) ||
6635 (head
>= hd_heads
) ) {
6637 SET_DISK_RET_STATUS(1);
6638 SET_CF(); /* error occurred */
6642 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6643 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6646 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6648 status
= inb(0x1f7);
6649 if (status
& 0x80) {
6650 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6652 // should check for Drive Ready Bit also in status reg
6653 outb(0x01f2, num_sectors
);
6655 /* activate LBA? (tomv) */
6656 if (hd_heads
> 16) {
6657 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6658 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6661 outb(0x01f3, sector
);
6662 outb(0x01f4, cylinder
& 0x00ff);
6663 outb(0x01f5, cylinder
>> 8);
6664 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6668 // wait for busy bit to turn off after seeking
6670 status
= inb(0x1f7);
6671 if (!(status
& 0x80)) break;
6674 if (!(status
& 0x08)) {
6675 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6676 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6683 sti
;; enable higher priority interrupts
6688 ;; store temp bx in real SI
register
6691 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6694 ;; adjust
if there will be an overrun
6696 jbe i13_f03_no_adjust
6698 sub si
, #0x0200 ; sub 512 bytes from offset
6700 add ax
, #0x0020 ; add 512 to segment
6704 mov cx
, #0x0100 ;; counter (256 words = 512b)
6705 mov dx
, #0x01f0 ;; AT data read port
6709 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6711 ;; store real SI
register back to temp bx
6714 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6720 if (num_sectors
== 0) {
6721 status
= inb(0x1f7);
6722 if ((status
& 0xe9) != 0x40)
6723 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6727 status
= inb(0x1f7);
6728 if ((status
& 0xc9) != 0x48)
6729 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6735 SET_DISK_RET_STATUS(0);
6736 SET_AL(sector_count
);
6737 CLEAR_CF(); /* successful */
6741 case 0x05: /* format disk track */
6742 BX_DEBUG_INT13_HD("int13_f05\n");
6743 BX_PANIC("format disk track called\n");
6746 SET_DISK_RET_STATUS(0);
6747 CLEAR_CF(); /* successful */
6751 case 0x08: /* read disk drive parameters */
6752 BX_DEBUG_INT13_HD("int13_f08\n");
6754 drive
= GET_ELDL ();
6755 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6759 if (hd_cylinders
<= 1024) {
6760 // hd_cylinders >>= 0;
6763 else if (hd_cylinders
<= 2048) {
6767 else if (hd_cylinders
<= 4096) {
6771 else if (hd_cylinders
<= 8192) {
6775 else { // hd_cylinders <= 16384
6780 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6782 SET_CH(max_cylinder
& 0xff);
6783 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6784 SET_DH(hd_heads
- 1);
6785 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6787 SET_DISK_RET_STATUS(0);
6788 CLEAR_CF(); /* successful */
6793 case 0x09: /* initialize drive parameters */
6794 BX_DEBUG_INT13_HD("int13_f09\n");
6796 SET_DISK_RET_STATUS(0);
6797 CLEAR_CF(); /* successful */
6801 case 0x0a: /* read disk sectors with ECC */
6802 BX_DEBUG_INT13_HD("int13_f0a\n");
6803 case 0x0b: /* write disk sectors with ECC */
6804 BX_DEBUG_INT13_HD("int13_f0b\n");
6805 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6809 case 0x0c: /* seek to specified cylinder */
6810 BX_DEBUG_INT13_HD("int13_f0c\n");
6811 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6813 SET_DISK_RET_STATUS(0);
6814 CLEAR_CF(); /* successful */
6818 case 0x0d: /* alternate disk reset */
6819 BX_DEBUG_INT13_HD("int13_f0d\n");
6821 SET_DISK_RET_STATUS(0);
6822 CLEAR_CF(); /* successful */
6826 case 0x10: /* check drive ready */
6827 BX_DEBUG_INT13_HD("int13_f10\n");
6829 //SET_DISK_RET_STATUS(0);
6830 //CLEAR_CF(); /* successful */
6834 // should look at 40:8E also???
6835 status
= inb(0x01f7);
6836 if ((status
& 0xc0) == 0x40) {
6838 SET_DISK_RET_STATUS(0);
6839 CLEAR_CF(); // drive ready
6844 SET_DISK_RET_STATUS(0xAA);
6845 SET_CF(); // not ready
6850 case 0x11: /* recalibrate */
6851 BX_DEBUG_INT13_HD("int13_f11\n");
6853 SET_DISK_RET_STATUS(0);
6854 CLEAR_CF(); /* successful */
6858 case 0x14: /* controller internal diagnostic */
6859 BX_DEBUG_INT13_HD("int13_f14\n");
6861 SET_DISK_RET_STATUS(0);
6862 CLEAR_CF(); /* successful */
6867 case 0x15: /* read disk drive size */
6869 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6873 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6874 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6875 mul al
, ah
;; ax
= heads
* sectors
6876 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6877 dec bx
;; use (cylinders
- 1) ???
6878 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6879 ;; now we need to move the
32bit result dx
:ax to what the
6880 ;; BIOS wants which is cx
:dx
.
6881 ;; and then into CX
:DX on the stack
6882 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6883 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6886 SET_AH(3); // hard disk accessible
6887 SET_DISK_RET_STATUS(0); // ??? should this be 0
6888 CLEAR_CF(); // successful
6892 case 0x18: // set media type for format
6893 case 0x41: // IBM/MS
6894 case 0x42: // IBM/MS
6895 case 0x43: // IBM/MS
6896 case 0x44: // IBM/MS
6897 case 0x45: // IBM/MS lock/unlock drive
6898 case 0x46: // IBM/MS eject media
6899 case 0x47: // IBM/MS extended seek
6900 case 0x49: // IBM/MS extended media change
6901 case 0x50: // IBM/MS send packet command
6903 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6905 SET_AH(1); // code=invalid function in AH or invalid parameter
6906 SET_DISK_RET_STATUS(1);
6907 SET_CF(); /* unsuccessful */
6912 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6913 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6916 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6918 Bit16u
*hd_cylinders
;
6928 if (drive
== 0x80) {
6929 hd_type
= inb_cmos(0x12) & 0xf0;
6930 if (hd_type
!= 0xf0)
6931 BX_INFO(panic_msg_reg12h
,0);
6932 hd_type
= inb_cmos(0x19); // HD0: extended type
6934 BX_INFO(panic_msg_reg19h
,0,0x19);
6937 hd_type
= inb_cmos(0x12) & 0x0f;
6938 if (hd_type
!= 0x0f)
6939 BX_INFO(panic_msg_reg12h
,1);
6940 hd_type
= inb_cmos(0x1a); // HD1: extended type
6942 BX_INFO(panic_msg_reg19h
,0,0x1a);
6947 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6948 write_word(ss
, hd_cylinders
, cylinders
);
6951 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6953 // sectors per track
6954 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6957 #endif //else BX_USE_ATADRV
6959 #if BX_SUPPORT_FLOPPY
6961 //////////////////////
6962 // FLOPPY functions //
6963 //////////////////////
6965 void floppy_reset_controller()
6971 outb(0x03f2, val8
& ~0x04);
6972 outb(0x03f2, val8
| 0x04);
6974 // Wait for controller to come out of reset
6977 } while ((val8
& 0xc0) != 0x80);
6980 void floppy_prepare_controller(drive
)
6983 Bit8u val8
, dor
, prev_reset
;
6985 // set 40:3e bit 7 to 0
6986 val8
= read_byte(0x0040, 0x003e);
6988 write_byte(0x0040, 0x003e, val8
);
6990 // turn on motor of selected drive, DMA & int enabled, normal operation
6991 prev_reset
= inb(0x03f2) & 0x04;
7000 // reset the disk motor timeout value of INT 08
7001 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
7003 // wait for drive readiness
7006 } while ( (val8
& 0xc0) != 0x80 );
7008 if (prev_reset
== 0) {
7009 // turn on interrupts
7013 // wait on 40:3e bit 7 to become 1
7015 val8
= read_byte(0x0040, 0x003e);
7016 } while ( (val8
& 0x80) == 0 );
7021 write_byte(0x0040, 0x003e, val8
);
7026 floppy_media_known(drive
)
7030 Bit16u media_state_offset
;
7032 val8
= read_byte(0x0040, 0x003e); // diskette recal status
7039 media_state_offset
= 0x0090;
7041 media_state_offset
+= 1;
7043 val8
= read_byte(0x0040, media_state_offset
);
7044 val8
= (val8
>> 4) & 0x01;
7048 // check pass, return KNOWN
7053 floppy_media_sense(drive
)
7057 Bit16u media_state_offset
;
7058 Bit8u drive_type
, config_data
, media_state
;
7060 if (floppy_drive_recal(drive
) == 0) {
7064 // for now cheat and get drive type from CMOS,
7065 // assume media is same as drive type
7067 // ** config_data **
7068 // Bitfields for diskette media control:
7069 // Bit(s) Description (Table M0028)
7070 // 7-6 last data rate set by controller
7071 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7072 // 5-4 last diskette drive step rate selected
7073 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7074 // 3-2 {data rate at start of operation}
7077 // ** media_state **
7078 // Bitfields for diskette drive media state:
7079 // Bit(s) Description (Table M0030)
7081 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7082 // 5 double stepping required (e.g. 360kB in 1.2MB)
7083 // 4 media type established
7084 // 3 drive capable of supporting 4MB media
7085 // 2-0 on exit from BIOS, contains
7086 // 000 trying 360kB in 360kB
7087 // 001 trying 360kB in 1.2MB
7088 // 010 trying 1.2MB in 1.2MB
7089 // 011 360kB in 360kB established
7090 // 100 360kB in 1.2MB established
7091 // 101 1.2MB in 1.2MB established
7093 // 111 all other formats/drives
7095 drive_type
= inb_cmos(0x10);
7102 if (drive_type
== 1) {
7104 config_data
= 0x00; // 0000 0000
7105 media_state
= 0x25; // 0010 0101
7108 else if (drive_type
== 2) {
7109 // 1.2 MB 5.25" drive
7110 config_data
= 0x00; // 0000 0000
7111 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
7114 else if (drive_type
== 3) {
7116 config_data
= 0x00; // 0000 0000 ???
7117 media_state
= 0x17; // 0001 0111
7120 else if (drive_type
== 4) {
7121 // 1.44 MB 3.5" drive
7122 config_data
= 0x00; // 0000 0000
7123 media_state
= 0x17; // 0001 0111
7126 else if (drive_type
== 5) {
7127 // 2.88 MB 3.5" drive
7128 config_data
= 0xCC; // 1100 1100
7129 media_state
= 0xD7; // 1101 0111
7132 // Extended floppy size uses special cmos setting
7133 else if (drive_type
== 6) {
7135 config_data
= 0x00; // 0000 0000
7136 media_state
= 0x27; // 0010 0111
7139 else if (drive_type
== 7) {
7141 config_data
= 0x00; // 0000 0000
7142 media_state
= 0x27; // 0010 0111
7145 else if (drive_type
== 8) {
7147 config_data
= 0x00; // 0000 0000
7148 media_state
= 0x27; // 0010 0111
7153 config_data
= 0x00; // 0000 0000
7154 media_state
= 0x00; // 0000 0000
7159 media_state_offset
= 0x90;
7161 media_state_offset
= 0x91;
7162 write_byte(0x0040, 0x008B, config_data
);
7163 write_byte(0x0040, media_state_offset
, media_state
);
7169 floppy_drive_recal(drive
)
7173 Bit16u curr_cyl_offset
;
7175 floppy_prepare_controller(drive
);
7177 // send Recalibrate command (2 bytes) to controller
7178 outb(0x03f5, 0x07); // 07: Recalibrate
7179 outb(0x03f5, drive
); // 0=drive0, 1=drive1
7181 // turn on interrupts
7186 // wait on 40:3e bit 7 to become 1
7188 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7189 } while ( val8
== 0 );
7191 val8
= 0; // separate asm from while() loop
7192 // turn off interrupts
7197 // set 40:3e bit 7 to 0, and calibrated bit
7198 val8
= read_byte(0x0040, 0x003e);
7201 val8
|= 0x02; // Drive 1 calibrated
7202 curr_cyl_offset
= 0x0095;
7204 val8
|= 0x01; // Drive 0 calibrated
7205 curr_cyl_offset
= 0x0094;
7207 write_byte(0x0040, 0x003e, val8
);
7208 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
7214 floppy_drive_exists(drive
)
7219 // check CMOS to see if drive exists
7220 drive_type
= inb_cmos(0x10);
7225 if ( drive_type
== 0 )
7232 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7233 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7235 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
7236 Bit16u base_address
, base_count
, base_es
;
7237 Bit8u page
, mode_register
, val8
, dor
;
7238 Bit8u return_status
[7];
7239 Bit8u drive_type
, num_floppies
, ah
;
7240 Bit16u es
, last_addr
;
7242 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
7247 case 0x00: // diskette controller reset
7248 BX_DEBUG_INT13_FL("floppy f00\n");
7251 SET_AH(1); // invalid param
7252 set_diskette_ret_status(1);
7256 drive_type
= inb_cmos(0x10);
7262 if (drive_type
== 0) {
7263 SET_AH(0x80); // drive not responding
7264 set_diskette_ret_status(0x80);
7269 set_diskette_ret_status(0);
7270 CLEAR_CF(); // successful
7271 set_diskette_current_cyl(drive
, 0); // current cylinder
7274 case 0x01: // Read Diskette Status
7276 val8
= read_byte(0x0000, 0x0441);
7283 case 0x02: // Read Diskette Sectors
7284 case 0x03: // Write Diskette Sectors
7285 case 0x04: // Verify Diskette Sectors
7286 num_sectors
= GET_AL();
7292 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
7293 (num_sectors
== 0) || (num_sectors
> 72)) {
7294 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
7296 set_diskette_ret_status(1);
7297 SET_AL(0); // no sectors read
7298 SET_CF(); // error occurred
7302 // see if drive exists
7303 if (floppy_drive_exists(drive
) == 0) {
7304 SET_AH(0x80); // not responding
7305 set_diskette_ret_status(0x80);
7306 SET_AL(0); // no sectors read
7307 SET_CF(); // error occurred
7311 // see if media in drive, and type is known
7312 if (floppy_media_known(drive
) == 0) {
7313 if (floppy_media_sense(drive
) == 0) {
7314 SET_AH(0x0C); // Media type not found
7315 set_diskette_ret_status(0x0C);
7316 SET_AL(0); // no sectors read
7317 SET_CF(); // error occurred
7323 // Read Diskette Sectors
7325 //-----------------------------------
7326 // set up DMA controller for transfer
7327 //-----------------------------------
7329 // es:bx = pointer to where to place information from diskette
7330 // port 04: DMA-1 base and current address, channel 2
7331 // port 05: DMA-1 base and current count, channel 2
7332 page
= (ES
>> 12); // upper 4 bits
7333 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7334 base_address
= base_es
+ BX
; // lower 16 bits of address
7335 // contributed by ES:BX
7336 if ( base_address
< base_es
) {
7337 // in case of carry, adjust page by 1
7340 base_count
= (num_sectors
* 512) - 1;
7342 // check for 64K boundary overrun
7343 last_addr
= base_address
+ base_count
;
7344 if (last_addr
< base_address
) {
7346 set_diskette_ret_status(0x09);
7347 SET_AL(0); // no sectors read
7348 SET_CF(); // error occurred
7352 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7355 BX_DEBUG_INT13_FL("clear flip-flop\n");
7356 outb(0x000c, 0x00); // clear flip-flop
7357 outb(0x0004, base_address
);
7358 outb(0x0004, base_address
>>8);
7359 BX_DEBUG_INT13_FL("clear flip-flop\n");
7360 outb(0x000c, 0x00); // clear flip-flop
7361 outb(0x0005, base_count
);
7362 outb(0x0005, base_count
>>8);
7364 // port 0b: DMA-1 Mode Register
7365 mode_register
= 0x46; // single mode, increment, autoinit disable,
7366 // transfer type=write, channel 2
7367 BX_DEBUG_INT13_FL("setting mode register\n");
7368 outb(0x000b, mode_register
);
7370 BX_DEBUG_INT13_FL("setting page register\n");
7371 // port 81: DMA-1 Page Register, channel 2
7374 BX_DEBUG_INT13_FL("unmask chan 2\n");
7375 outb(0x000a, 0x02); // unmask channel 2
7377 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7380 //--------------------------------------
7381 // set up floppy controller for transfer
7382 //--------------------------------------
7383 floppy_prepare_controller(drive
);
7385 // send read-normal-data command (9 bytes) to controller
7386 outb(0x03f5, 0xe6); // e6: read normal data
7387 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7388 outb(0x03f5, track
);
7390 outb(0x03f5, sector
);
7391 outb(0x03f5, 2); // 512 byte sector size
7392 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
7393 outb(0x03f5, 0); // Gap length
7394 outb(0x03f5, 0xff); // Gap length
7396 // turn on interrupts
7401 // wait on 40:3e bit 7 to become 1
7403 val8
= read_byte(0x0040, 0x0040);
7405 floppy_reset_controller();
7406 SET_AH(0x80); // drive not ready (timeout)
7407 set_diskette_ret_status(0x80);
7408 SET_AL(0); // no sectors read
7409 SET_CF(); // error occurred
7412 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7413 } while ( val8
== 0 );
7415 val8
= 0; // separate asm from while() loop
7416 // turn off interrupts
7421 // set 40:3e bit 7 to 0
7422 val8
= read_byte(0x0040, 0x003e);
7424 write_byte(0x0040, 0x003e, val8
);
7426 // check port 3f4 for accessibility to status bytes
7428 if ( (val8
& 0xc0) != 0xc0 )
7429 BX_PANIC("int13_diskette: ctrl not ready\n");
7431 // read 7 return status bytes from controller
7432 // using loop index broken, have to unroll...
7433 return_status
[0] = inb(0x3f5);
7434 return_status
[1] = inb(0x3f5);
7435 return_status
[2] = inb(0x3f5);
7436 return_status
[3] = inb(0x3f5);
7437 return_status
[4] = inb(0x3f5);
7438 return_status
[5] = inb(0x3f5);
7439 return_status
[6] = inb(0x3f5);
7440 // record in BIOS Data Area
7441 write_byte(0x0040, 0x0042, return_status
[0]);
7442 write_byte(0x0040, 0x0043, return_status
[1]);
7443 write_byte(0x0040, 0x0044, return_status
[2]);
7444 write_byte(0x0040, 0x0045, return_status
[3]);
7445 write_byte(0x0040, 0x0046, return_status
[4]);
7446 write_byte(0x0040, 0x0047, return_status
[5]);
7447 write_byte(0x0040, 0x0048, return_status
[6]);
7449 if ( (return_status
[0] & 0xc0) != 0 ) {
7451 set_diskette_ret_status(0x20);
7452 SET_AL(0); // no sectors read
7453 SET_CF(); // error occurred
7457 // ??? should track be new val from return_status[3] ?
7458 set_diskette_current_cyl(drive
, track
);
7459 // AL = number of sectors read (same value as passed)
7460 SET_AH(0x00); // success
7461 CLEAR_CF(); // success
7463 } else if (ah
== 0x03) {
7464 // Write Diskette Sectors
7466 //-----------------------------------
7467 // set up DMA controller for transfer
7468 //-----------------------------------
7470 // es:bx = pointer to where to place information from diskette
7471 // port 04: DMA-1 base and current address, channel 2
7472 // port 05: DMA-1 base and current count, channel 2
7473 page
= (ES
>> 12); // upper 4 bits
7474 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7475 base_address
= base_es
+ BX
; // lower 16 bits of address
7476 // contributed by ES:BX
7477 if ( base_address
< base_es
) {
7478 // in case of carry, adjust page by 1
7481 base_count
= (num_sectors
* 512) - 1;
7483 // check for 64K boundary overrun
7484 last_addr
= base_address
+ base_count
;
7485 if (last_addr
< base_address
) {
7487 set_diskette_ret_status(0x09);
7488 SET_AL(0); // no sectors read
7489 SET_CF(); // error occurred
7493 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7496 outb(0x000c, 0x00); // clear flip-flop
7497 outb(0x0004, base_address
);
7498 outb(0x0004, base_address
>>8);
7499 outb(0x000c, 0x00); // clear flip-flop
7500 outb(0x0005, base_count
);
7501 outb(0x0005, base_count
>>8);
7503 // port 0b: DMA-1 Mode Register
7504 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7505 // transfer type=read, channel 2
7506 outb(0x000b, mode_register
);
7508 // port 81: DMA-1 Page Register, channel 2
7511 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7514 //--------------------------------------
7515 // set up floppy controller for transfer
7516 //--------------------------------------
7517 floppy_prepare_controller(drive
);
7519 // send write-normal-data command (9 bytes) to controller
7520 outb(0x03f5, 0xc5); // c5: write normal data
7521 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7522 outb(0x03f5, track
);
7524 outb(0x03f5, sector
);
7525 outb(0x03f5, 2); // 512 byte sector size
7526 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7527 outb(0x03f5, 0); // Gap length
7528 outb(0x03f5, 0xff); // Gap length
7530 // turn on interrupts
7535 // wait on 40:3e bit 7 to become 1
7537 val8
= read_byte(0x0040, 0x0040);
7539 floppy_reset_controller();
7540 SET_AH(0x80); // drive not ready (timeout)
7541 set_diskette_ret_status(0x80);
7542 SET_AL(0); // no sectors written
7543 SET_CF(); // error occurred
7546 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7547 } while ( val8
== 0 );
7549 val8
= 0; // separate asm from while() loop
7550 // turn off interrupts
7555 // set 40:3e bit 7 to 0
7556 val8
= read_byte(0x0040, 0x003e);
7558 write_byte(0x0040, 0x003e, val8
);
7560 // check port 3f4 for accessibility to status bytes
7562 if ( (val8
& 0xc0) != 0xc0 )
7563 BX_PANIC("int13_diskette: ctrl not ready\n");
7565 // read 7 return status bytes from controller
7566 // using loop index broken, have to unroll...
7567 return_status
[0] = inb(0x3f5);
7568 return_status
[1] = inb(0x3f5);
7569 return_status
[2] = inb(0x3f5);
7570 return_status
[3] = inb(0x3f5);
7571 return_status
[4] = inb(0x3f5);
7572 return_status
[5] = inb(0x3f5);
7573 return_status
[6] = inb(0x3f5);
7574 // record in BIOS Data Area
7575 write_byte(0x0040, 0x0042, return_status
[0]);
7576 write_byte(0x0040, 0x0043, return_status
[1]);
7577 write_byte(0x0040, 0x0044, return_status
[2]);
7578 write_byte(0x0040, 0x0045, return_status
[3]);
7579 write_byte(0x0040, 0x0046, return_status
[4]);
7580 write_byte(0x0040, 0x0047, return_status
[5]);
7581 write_byte(0x0040, 0x0048, return_status
[6]);
7583 if ( (return_status
[0] & 0xc0) != 0 ) {
7584 if ( (return_status
[1] & 0x02) != 0 ) {
7585 // diskette not writable.
7586 // AH=status code=0x03 (tried to write on write-protected disk)
7587 // AL=number of sectors written=0
7592 BX_PANIC("int13_diskette_function: read error\n");
7596 // ??? should track be new val from return_status[3] ?
7597 set_diskette_current_cyl(drive
, track
);
7598 // AL = number of sectors read (same value as passed)
7599 SET_AH(0x00); // success
7600 CLEAR_CF(); // success
7602 } else { // if (ah == 0x04)
7603 // Verify Diskette Sectors
7605 // ??? should track be new val from return_status[3] ?
7606 set_diskette_current_cyl(drive
, track
);
7607 // AL = number of sectors verified (same value as passed)
7608 CLEAR_CF(); // success
7609 SET_AH(0x00); // success
7614 case 0x05: // format diskette track
7615 BX_DEBUG_INT13_FL("floppy f05\n");
7617 num_sectors
= GET_AL();
7622 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7623 (num_sectors
== 0) || (num_sectors
> 18)) {
7625 set_diskette_ret_status(1);
7626 SET_CF(); // error occurred
7629 // see if drive exists
7630 if (floppy_drive_exists(drive
) == 0) {
7631 SET_AH(0x80); // drive not responding
7632 set_diskette_ret_status(0x80);
7633 SET_CF(); // error occurred
7637 // see if media in drive, and type is known
7638 if (floppy_media_known(drive
) == 0) {
7639 if (floppy_media_sense(drive
) == 0) {
7640 SET_AH(0x0C); // Media type not found
7641 set_diskette_ret_status(0x0C);
7642 SET_AL(0); // no sectors read
7643 SET_CF(); // error occurred
7648 // set up DMA controller for transfer
7649 page
= (ES
>> 12); // upper 4 bits
7650 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7651 base_address
= base_es
+ BX
; // lower 16 bits of address
7652 // contributed by ES:BX
7653 if ( base_address
< base_es
) {
7654 // in case of carry, adjust page by 1
7657 base_count
= (num_sectors
* 4) - 1;
7659 // check for 64K boundary overrun
7660 last_addr
= base_address
+ base_count
;
7661 if (last_addr
< base_address
) {
7663 set_diskette_ret_status(0x09);
7664 SET_AL(0); // no sectors read
7665 SET_CF(); // error occurred
7670 outb(0x000c, 0x00); // clear flip-flop
7671 outb(0x0004, base_address
);
7672 outb(0x0004, base_address
>>8);
7673 outb(0x000c, 0x00); // clear flip-flop
7674 outb(0x0005, base_count
);
7675 outb(0x0005, base_count
>>8);
7676 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7677 // transfer type=read, channel 2
7678 outb(0x000b, mode_register
);
7679 // port 81: DMA-1 Page Register, channel 2
7683 // set up floppy controller for transfer
7684 floppy_prepare_controller(drive
);
7686 // send format-track command (6 bytes) to controller
7687 outb(0x03f5, 0x4d); // 4d: format track
7688 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7689 outb(0x03f5, 2); // 512 byte sector size
7690 outb(0x03f5, num_sectors
); // number of sectors per track
7691 outb(0x03f5, 0); // Gap length
7692 outb(0x03f5, 0xf6); // Fill byte
7693 // turn on interrupts
7698 // wait on 40:3e bit 7 to become 1
7700 val8
= read_byte(0x0040, 0x0040);
7702 floppy_reset_controller();
7703 SET_AH(0x80); // drive not ready (timeout)
7704 set_diskette_ret_status(0x80);
7705 SET_CF(); // error occurred
7708 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7709 } while ( val8
== 0 );
7711 val8
= 0; // separate asm from while() loop
7712 // turn off interrupts
7716 // set 40:3e bit 7 to 0
7717 val8
= read_byte(0x0040, 0x003e);
7719 write_byte(0x0040, 0x003e, val8
);
7720 // check port 3f4 for accessibility to status bytes
7722 if ( (val8
& 0xc0) != 0xc0 )
7723 BX_PANIC("int13_diskette: ctrl not ready\n");
7725 // read 7 return status bytes from controller
7726 // using loop index broken, have to unroll...
7727 return_status
[0] = inb(0x3f5);
7728 return_status
[1] = inb(0x3f5);
7729 return_status
[2] = inb(0x3f5);
7730 return_status
[3] = inb(0x3f5);
7731 return_status
[4] = inb(0x3f5);
7732 return_status
[5] = inb(0x3f5);
7733 return_status
[6] = inb(0x3f5);
7734 // record in BIOS Data Area
7735 write_byte(0x0040, 0x0042, return_status
[0]);
7736 write_byte(0x0040, 0x0043, return_status
[1]);
7737 write_byte(0x0040, 0x0044, return_status
[2]);
7738 write_byte(0x0040, 0x0045, return_status
[3]);
7739 write_byte(0x0040, 0x0046, return_status
[4]);
7740 write_byte(0x0040, 0x0047, return_status
[5]);
7741 write_byte(0x0040, 0x0048, return_status
[6]);
7743 if ( (return_status
[0] & 0xc0) != 0 ) {
7744 if ( (return_status
[1] & 0x02) != 0 ) {
7745 // diskette not writable.
7746 // AH=status code=0x03 (tried to write on write-protected disk)
7747 // AL=number of sectors written=0
7752 BX_PANIC("int13_diskette_function: write error\n");
7757 set_diskette_ret_status(0);
7758 set_diskette_current_cyl(drive
, 0);
7759 CLEAR_CF(); // successful
7763 case 0x08: // read diskette drive parameters
7764 BX_DEBUG_INT13_FL("floppy f08\n");
7774 SET_DL(num_floppies
);
7779 drive_type
= inb_cmos(0x10);
7781 if (drive_type
& 0xf0)
7783 if (drive_type
& 0x0f)
7795 SET_DL(num_floppies
);
7797 switch (drive_type
) {
7800 SET_DH(0); // max head #
7803 case 1: // 360KB, 5.25"
7804 CX
= 0x2709; // 40 tracks, 9 sectors
7805 SET_DH(1); // max head #
7808 case 2: // 1.2MB, 5.25"
7809 CX
= 0x4f0f; // 80 tracks, 15 sectors
7810 SET_DH(1); // max head #
7813 case 3: // 720KB, 3.5"
7814 CX
= 0x4f09; // 80 tracks, 9 sectors
7815 SET_DH(1); // max head #
7818 case 4: // 1.44MB, 3.5"
7819 CX
= 0x4f12; // 80 tracks, 18 sectors
7820 SET_DH(1); // max head #
7823 case 5: // 2.88MB, 3.5"
7824 CX
= 0x4f24; // 80 tracks, 36 sectors
7825 SET_DH(1); // max head #
7828 case 6: // 160k, 5.25"
7829 CX
= 0x2708; // 40 tracks, 8 sectors
7830 SET_DH(0); // max head #
7833 case 7: // 180k, 5.25"
7834 CX
= 0x2709; // 40 tracks, 9 sectors
7835 SET_DH(0); // max head #
7838 case 8: // 320k, 5.25"
7839 CX
= 0x2708; // 40 tracks, 8 sectors
7840 SET_DH(1); // max head #
7844 BX_PANIC("floppy: int13: bad floppy type\n");
7847 /* set es & di to point to 11 byte diskette param table in ROM */
7851 mov ax
, #diskette_param_table2
7852 mov _int13_diskette_function
.DI
+2[bp
], ax
7853 mov _int13_diskette_function
.ES
+2[bp
], cs
7856 CLEAR_CF(); // success
7857 /* disk status not changed upon success */
7861 case 0x15: // read diskette drive type
7862 BX_DEBUG_INT13_FL("floppy f15\n");
7865 SET_AH(0); // only 2 drives supported
7866 // set_diskette_ret_status here ???
7870 drive_type
= inb_cmos(0x10);
7876 CLEAR_CF(); // successful, not present
7877 if (drive_type
==0) {
7878 SET_AH(0); // drive not present
7881 SET_AH(1); // drive present, does not support change line
7886 case 0x16: // get diskette change line status
7887 BX_DEBUG_INT13_FL("floppy f16\n");
7890 SET_AH(0x01); // invalid drive
7891 set_diskette_ret_status(0x01);
7896 SET_AH(0x06); // change line not supported
7897 set_diskette_ret_status(0x06);
7901 case 0x17: // set diskette type for format(old)
7902 BX_DEBUG_INT13_FL("floppy f17\n");
7903 /* not used for 1.44M floppies */
7904 SET_AH(0x01); // not supported
7905 set_diskette_ret_status(1); /* not supported */
7909 case 0x18: // set diskette type for format(new)
7910 BX_DEBUG_INT13_FL("floppy f18\n");
7911 SET_AH(0x01); // do later
7912 set_diskette_ret_status(1);
7917 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7919 // if ((ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e)) {
7920 SET_AH(0x01); // ???
7921 set_diskette_ret_status(1);
7927 #else // #if BX_SUPPORT_FLOPPY
7929 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7930 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7936 case 0x01: // Read Diskette Status
7938 val8
= read_byte(0x0000, 0x0441);
7947 write_byte(0x0000, 0x0441, 0x01);
7951 #endif // #if BX_SUPPORT_FLOPPY
7954 set_diskette_ret_status(value
)
7957 write_byte(0x0040, 0x0041, value
);
7961 set_diskette_current_cyl(drive
, cyl
)
7966 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7967 write_byte(0x0040, 0x0094+drive
, cyl
);
7971 determine_floppy_media(drive
)
7975 Bit8u val8
, DOR
, ctrl_info
;
7977 ctrl_info
= read_byte(0x0040, 0x008F);
7985 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7988 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7992 if ((ctrl_info
& 0x04) != 0x04) {
7993 // Drive not determined means no drive exists, done.
7998 // check Main Status Register for readiness
7999 val8
= inb(0x03f4) & 0x80; // Main Status Register
8001 BX_PANIC("d_f_m: MRQ bit not set\n");
8005 // existing BDA values
8007 // turn on drive motor
8008 outb(0x03f2, DOR
); // Digital Output Register
8011 BX_PANIC("d_f_m: OK so far\n");
8016 int17_function(regs
, ds
, iret_addr
)
8017 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8018 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8019 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8021 Bit16u addr
,timeout
;
8028 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
8029 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
8030 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
8031 if (regs
.u
.r8
.ah
== 0) {
8032 outb(addr
, regs
.u
.r8
.al
);
8034 outb(addr
+2, val8
| 0x01); // send strobe
8038 outb(addr
+2, val8
& ~0x01);
8039 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
8043 if (regs
.u
.r8
.ah
== 1) {
8045 outb(addr
+2, val8
& ~0x04); // send init
8049 outb(addr
+2, val8
| 0x04);
8052 regs
.u
.r8
.ah
= (val8
^ 0x48);
8053 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
8054 ClearCF(iret_addr
.flags
);
8056 SetCF(iret_addr
.flags
); // Unsupported
8061 int19_function(seq_nr
)
8064 Bit16u ebda_seg
=read_word(0x0040,0x000E);
8075 // if BX_ELTORITO_BOOT is not defined, old behavior
8076 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8077 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8078 // 0: system boot sequence, first drive C: then A:
8079 // 1: system boot sequence, first drive A: then C:
8080 // else BX_ELTORITO_BOOT is defined
8081 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8082 // CMOS reg 0x3D & 0x0f : 1st boot device
8083 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8084 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8085 // boot device codes:
8086 // 0x00 : not defined
8087 // 0x01 : first floppy
8088 // 0x02 : first harddrive
8089 // 0x03 : first cdrom
8090 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
8091 // else : boot failure
8093 // Get the boot sequence
8094 #if BX_ELTORITO_BOOT
8095 bootdev
= inb_cmos(0x3d);
8096 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
8097 bootdev
>>= 4 * seq_nr
;
8100 /* Read user selected device */
8101 bootfirst
= read_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
);
8102 if (bootfirst
!= 0xFFFF) {
8103 bootdev
= bootfirst
;
8104 /* User selected device not set */
8105 write_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
, 0xFFFF);
8106 /* Reset boot sequence */
8107 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xFFFF);
8108 } else if (bootdev
== 0) BX_PANIC("No bootable device.\n");
8110 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
8113 if (seq_nr
==2) BX_PANIC("No more boot devices.");
8114 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
8115 /* Boot from floppy if the bit is set or it's the second boot */
8121 /* Read the boot device from the IPL table */
8122 if (get_boot_vector(bootdev
, &e
) == 0) {
8123 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
8127 /* Do the loading, and set up vector as a far pointer to the boot
8128 * address, and bootdrv as the boot drive */
8129 print_boot_device(&e
);
8132 case IPL_TYPE_FLOPPY
: /* FDD */
8133 case IPL_TYPE_HARDDISK
: /* HDD */
8135 bootdrv
= (e
.type
== IPL_TYPE_HARDDISK
) ? 0x80 : 0x00;
8147 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
8148 mov ax
, _int19_function
.bootseg
+ 2[bp
]
8149 mov es
, ax
;; segment
8150 xor bx
, bx
;; offset
8151 mov ah
, #0x02 ;; function 2, read diskette sector
8152 mov al
, #0x01 ;; read 1 sector
8153 mov ch
, #0x00 ;; track 0
8154 mov cl
, #0x01 ;; sector 1
8155 mov dh
, #0x00 ;; head 0
8156 int #0x13 ;; read sector
8159 mov _int19_function
.status
+ 2[bp
], ax
8170 print_boot_failure(e
.type
, 1);
8174 /* Always check the signature on a HDD boot sector; on FDD, only do
8175 * the check if the CMOS doesn't tell us to skip it */
8176 if ((e
.type
!= IPL_TYPE_FLOPPY
) || !((inb_cmos(0x38) & 0x01))) {
8177 if (read_word(bootseg
,0x1fe) != 0xaa55) {
8178 print_boot_failure(e
.type
, 0);
8183 /* Canonicalize bootseg:bootip */
8184 bootip
= (bootseg
& 0x0fff) << 4;
8188 #if BX_ELTORITO_BOOT
8189 case IPL_TYPE_CDROM
: /* CD-ROM */
8190 status
= cdrom_boot();
8193 if ( (status
& 0x00ff) !=0 ) {
8194 print_cdromboot_failure(status
);
8195 print_boot_failure(e
.type
, 1);
8199 bootdrv
= (Bit8u
)(status
>>8);
8200 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
8205 case IPL_TYPE_BEV
: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
8206 bootseg
= e
.vector
>> 16;
8207 bootip
= e
.vector
& 0xffff;
8213 /* Debugging info */
8214 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
8216 /* Jump to the boot vector */
8221 ;; Build an iret stack frame that will take us to the boot vector
.
8222 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
8224 mov ax
, _int19_function
.bootseg
+ 0[bp
]
8226 mov ax
, _int19_function
.bootip
+ 0[bp
]
8228 ;; Set the magic number in ax
and the boot drive in dl
.
8230 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
8231 ;; Zero some of the other registers
.
8242 int1a_function(regs
, ds
, iret_addr
)
8243 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8244 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8245 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8249 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
);
8255 switch (regs
.u
.r8
.ah
) {
8256 case 0: // get current clock count
8260 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
8261 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
8262 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
8263 BiosData
->midnight_flag
= 0; // reset flag
8268 ClearCF(iret_addr
.flags
); // OK
8271 case 1: // Set Current Clock Count
8275 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
8276 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
8277 BiosData
->midnight_flag
= 0; // reset flag
8282 ClearCF(iret_addr
.flags
); // OK
8286 case 2: // Read CMOS Time
8287 if (rtc_updating()) {
8288 SetCF(iret_addr
.flags
);
8292 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
8293 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
8294 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
8295 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
8297 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8298 ClearCF(iret_addr
.flags
); // OK
8301 case 3: // Set CMOS Time
8302 // Using a debugger, I notice the following masking/setting
8303 // of bits in Status Register B, by setting Reg B to
8304 // a few values and getting its value after INT 1A was called.
8306 // try#1 try#2 try#3
8307 // before 1111 1101 0111 1101 0000 0000
8308 // after 0110 0010 0110 0010 0000 0010
8310 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8311 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8312 if (rtc_updating()) {
8314 // fall through as if an update were not in progress
8316 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
8317 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
8318 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
8319 // Set Daylight Savings time enabled bit to requested value
8320 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
8321 // (reg B already selected)
8322 outb_cmos(0x0b, val8
);
8324 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8325 ClearCF(iret_addr
.flags
); // OK
8328 case 4: // Read CMOS Date
8330 if (rtc_updating()) {
8331 SetCF(iret_addr
.flags
);
8334 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
8335 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
8336 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
8337 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
8338 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8339 ClearCF(iret_addr
.flags
); // OK
8342 case 5: // Set CMOS Date
8343 // Using a debugger, I notice the following masking/setting
8344 // of bits in Status Register B, by setting Reg B to
8345 // a few values and getting its value after INT 1A was called.
8347 // try#1 try#2 try#3 try#4
8348 // before 1111 1101 0111 1101 0000 0010 0000 0000
8349 // after 0110 1101 0111 1101 0000 0010 0000 0000
8351 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8352 // My assumption: RegB = (RegB & 01111111b)
8353 if (rtc_updating()) {
8355 SetCF(iret_addr
.flags
);
8358 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
8359 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
8360 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
8361 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
8362 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8363 outb_cmos(0x0b, val8
);
8365 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
8366 ClearCF(iret_addr
.flags
); // OK
8369 case 6: // Set Alarm Time in CMOS
8370 // Using a debugger, I notice the following masking/setting
8371 // of bits in Status Register B, by setting Reg B to
8372 // a few values and getting its value after INT 1A was called.
8374 // try#1 try#2 try#3
8375 // before 1101 1111 0101 1111 0000 0000
8376 // after 0110 1111 0111 1111 0010 0000
8378 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8379 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8380 val8
= inb_cmos(0x0b); // Get Status Reg B
8383 // Alarm interrupt enabled already
8384 SetCF(iret_addr
.flags
); // Error: alarm in use
8387 if (rtc_updating()) {
8389 // fall through as if an update were not in progress
8391 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
8392 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
8393 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
8394 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8395 // enable Status Reg B alarm bit, clear halt clock bit
8396 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
8397 ClearCF(iret_addr
.flags
); // OK
8400 case 7: // Turn off Alarm
8401 // Using a debugger, I notice the following masking/setting
8402 // of bits in Status Register B, by setting Reg B to
8403 // a few values and getting its value after INT 1A was called.
8405 // try#1 try#2 try#3 try#4
8406 // before 1111 1101 0111 1101 0010 0000 0010 0010
8407 // after 0100 0101 0101 0101 0000 0000 0000 0010
8409 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8410 // My assumption: RegB = (RegB & 01010111b)
8411 val8
= inb_cmos(0x0b); // Get Status Reg B
8412 // clear clock-halt bit, disable alarm bit
8413 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
8415 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8416 ClearCF(iret_addr
.flags
); // OK
8420 // real mode PCI BIOS functions now handled in assembler code
8421 // this C code handles the error code for information only
8422 if (regs
.u
.r8
.bl
== 0xff) {
8423 BX_INFO("PCI BIOS: PCI not present\n");
8424 } else if (regs
.u
.r8
.bl
== 0x81) {
8425 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8426 } else if (regs
.u
.r8
.bl
== 0x83) {
8427 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8428 } else if (regs
.u
.r8
.bl
== 0x86) {
8429 if (regs
.u
.r8
.al
== 0x02) {
8430 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8432 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
);
8435 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8436 SetCF(iret_addr
.flags
);
8441 SetCF(iret_addr
.flags
); // Unsupported
8446 int70_function(regs
, ds
, iret_addr
)
8447 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8448 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8449 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8451 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8452 Bit8u registerB
= 0, registerC
= 0;
8454 // Check which modes are enabled and have occurred.
8455 registerB
= inb_cmos( 0xB );
8456 registerC
= inb_cmos( 0xC );
8458 if( ( registerB
& 0x60 ) != 0 ) {
8459 if( ( registerC
& 0x20 ) != 0 ) {
8460 // Handle Alarm Interrupt.
8467 if( ( registerC
& 0x40 ) != 0 ) {
8468 // Handle Periodic Interrupt.
8470 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8471 // Wait Interval (Int 15, AH=83) active.
8472 Bit32u time
, toggle
;
8474 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8475 if( time
< 0x3D1 ) {
8477 Bit16u segment
, offset
;
8479 segment
= read_word( 0x40, 0x98 );
8480 offset
= read_word( 0x40, 0x9A );
8481 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8482 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8483 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8485 // Continue waiting.
8487 write_dword( 0x40, 0x9C, time
);
8500 ;------------------------------------------
8501 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8502 ;------------------------------------------
8507 push
#0x00 ;; placeholder for status
8508 push
#0x00 ;; placeholder for X
8509 push
#0x00 ;; placeholder for Y
8510 push
#0x00 ;; placeholder for Z
8511 push
#0x00 ;; placeholder for make_far_call boolean
8512 call _int74_function
8513 pop cx
;; remove make_far_call from stack
8516 ;; make far call to EBDA
:0022
8519 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8521 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8526 add sp
, #8 ;; pop status, x, y, z
8528 pop ds
;; restore DS
8533 ;; This will perform an IRET
, but will retain value of current CF
8534 ;; by altering flags on stack
. Better than RETF
#02.
8539 and BYTE
[bp
+ 0x06], #0xfe
8545 or BYTE
[bp
+ 0x06], #0x01
8550 ;----------------------
8551 ;- INT13h (relocated
) -
8552 ;----------------------
8554 ; int13_relocated is a little bit messed up since I played with it
8555 ; I have to rewrite it
:
8556 ; - call a function that detect which function to call
8557 ; - make all called C function get the same parameters list
8561 #if BX_ELTORITO_BOOT
8562 ;; check
for an eltorito function
8564 jb int13_not_eltorito
8566 ja int13_not_eltorito
8575 jmp _int13_eltorito
;; ELDX
not used
8583 ;; check
if emulation active
8584 call _cdemu_isactive
8586 je int13_cdemu_inactive
8588 ;; check
if access to the emulated drive
8589 call _cdemu_emulated_drive
8592 cmp al
,dl
;; int13 on emulated drive
8607 jmp _int13_cdemu
;; ELDX
not used
8610 and dl
,#0xE0 ;; mask to get device class, including cdroms
8611 cmp al
,dl
;; al is
0x00 or 0x80
8612 jne int13_cdemu_inactive
;; inactive
for device
class
8624 dec dl
;; real drive is dl
- 1
8627 int13_cdemu_inactive
:
8633 #endif // BX_ELTORITO_BOOT
8644 push dx
;; push eltorito value of dx instead of sp
8655 ;; now the
16-bit registers can be restored with
:
8656 ;; pop ds
; pop es
; popa
; iret
8657 ;; arguments passed to functions should be
8658 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8664 jmp _int13_diskette_function
8673 // ebx is modified: BSD 5.2.1 boot loader problem
8674 // someone should figure out which 32 bit register that actually are used
8691 ;; int13_harddisk modifies high word of EAX
8694 call _int13_harddisk
8707 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8715 ;; Get the boot sequence number out of the IPL memory
8717 mov ds
, bx
;; Set segment
8718 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8720 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8721 mov ds
, ax
;; and reset the segment to zero
.
8723 ;; Carry on in the INT
19h handler
, using the
new sequence number
8731 int19_relocated
: ;; Boot function
, relocated
8733 ;; int19 was beginning to be really
complex, so now it
8734 ;; just calls a C function that does the work
8745 ;; Start from the first boot
device (0, in AX
)
8747 mov ds
, bx
;; Set segment to write to the IPL memory
8748 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8749 mov ds
, ax
;; and reset the segment
.
8755 ;; Call the C code
for the next boot device
8756 call _int19_function
8758 ;; Boot failed
: invoke the boot recovery function
8764 int1c_handler
: ;; User Timer Tick
8768 ;----------------------
8769 ;- POST
: Floppy Drive
-
8770 ;----------------------
8776 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8778 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8780 mov
0x0440, al
;; diskette motor timeout counter
: not active
8781 mov
0x0441, al
;; diskette controller status
return code
8783 mov
0x0442, al
;; disk
& diskette controller status
register 0
8784 mov
0x0443, al
;; diskette controller status
register 1
8785 mov
0x0444, al
;; diskette controller status
register 2
8786 mov
0x0445, al
;; diskette controller cylinder number
8787 mov
0x0446, al
;; diskette controller head number
8788 mov
0x0447, al
;; diskette controller sector number
8789 mov
0x0448, al
;; diskette controller bytes written
8791 mov
0x048b, al
;; diskette configuration data
8793 ;; -----------------------------------------------------------------
8794 ;; (048F
) diskette controller information
8796 mov al
, #0x10 ;; get CMOS diskette drive type
8799 mov ah
, al
;; save byte to AH
8802 shr al
, #4 ;; look at top 4 bits for drive 0
8803 jz f0_missing
;; jump
if no drive0
8804 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8807 mov bl
, #0x00 ;; no drive0
8810 mov al
, ah
;; restore from AH
8811 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8812 jz f1_missing
;; jump
if no drive1
8813 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8815 ;; leave high bits in BL zerod
8816 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8817 ;; -----------------------------------------------------------------
8820 mov
0x0490, al
;; diskette
0 media state
8821 mov
0x0491, al
;; diskette
1 media state
8823 ;; diskette
0,1 operational starting state
8824 ;; drive type has
not been determined
,
8825 ;; has no changed detection line
8829 mov
0x0494, al
;; diskette
0 current cylinder
8830 mov
0x0495, al
;; diskette
1 current cylinder
8833 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8835 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8836 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8837 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8842 ;--------------------
8843 ;- POST
: HARD DRIVE
-
8844 ;--------------------
8845 ; relocated here because the primary POST area isnt big enough
.
8848 // INT 76h calls INT 15h function ax=9100
8850 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8856 mov
0x0474, al
/* hard disk status of last operation */
8857 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8858 mov
0x048c, al
/* hard disk status register */
8859 mov
0x048d, al
/* hard disk error register */
8860 mov
0x048e, al
/* hard disk task complete flag */
8862 mov
0x0475, al
/* hard disk number attached */
8864 mov
0x0476, al
/* hard disk control byte */
8865 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8866 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8867 ;; INT
41h
: hard disk
0 configuration pointer
8868 ;; INT
46h
: hard disk
1 configuration pointer
8869 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8870 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8872 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8884 cmp al
, #47 ;; decimal 47 - user definable
8888 ;; CMOS purpose param table offset
8889 ;; 1b cylinders low
0
8890 ;; 1c cylinders high
1
8892 ;; 1e write pre
-comp low
5
8893 ;; 1f write pre
-comp high
6
8894 ;; 20 retries
/bad map
/heads
>8 8
8895 ;; 21 landing zone low C
8896 ;; 22 landing zone high D
8897 ;; 23 sectors
/track E
8902 ;;; Filling EBDA table
for hard disk
0.
8910 mov (0x003d + 0x05), ax
;; write precomp word
8915 mov (0x003d + 0x08), al
;; drive control byte
8924 mov (0x003d + 0x0C), ax
;; landing zone word
8926 mov al
, #0x1c ;; get cylinders word in AX
8928 in al
, #0x71 ;; high byte
8932 in al
, #0x71 ;; low byte
8933 mov bx
, ax
;; BX
= cylinders
8938 mov cl
, al
;; CL
= heads
8943 mov dl
, al
;; DL
= sectors
8946 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8948 hd0_post_physical_chs
:
8949 ;; no logical CHS mapping used
, just physical CHS
8950 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8951 mov (0x003d + 0x00), bx
;; number of physical cylinders
8952 mov (0x003d + 0x02), cl
;; number of physical heads
8953 mov (0x003d + 0x0E), dl
;; number of physical sectors
8956 hd0_post_logical_chs
:
8957 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8958 mov (0x003d + 0x09), bx
;; number of physical cylinders
8959 mov (0x003d + 0x0b), cl
;; number of physical heads
8960 mov (0x003d + 0x04), dl
;; number of physical sectors
8961 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8963 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8966 jnbe hd0_post_above_2048
8967 ;; 1024 < c
<= 2048 cylinders
8970 jmp hd0_post_store_logical
8972 hd0_post_above_2048
:
8974 jnbe hd0_post_above_4096
8975 ;; 2048 < c
<= 4096 cylinders
8978 jmp hd0_post_store_logical
8980 hd0_post_above_4096
:
8982 jnbe hd0_post_above_8192
8983 ;; 4096 < c
<= 8192 cylinders
8986 jmp hd0_post_store_logical
8988 hd0_post_above_8192
:
8989 ;; 8192 < c
<= 16384 cylinders
8993 hd0_post_store_logical
:
8994 mov (0x003d + 0x00), bx
;; number of physical cylinders
8995 mov (0x003d + 0x02), cl
;; number of physical heads
8997 mov cl
, #0x0f ;; repeat count
8998 mov si
, #0x003d ;; offset to disk0 FDPT
8999 mov al
, #0x00 ;; sum
9000 hd0_post_checksum_loop
:
9004 jnz hd0_post_checksum_loop
9005 not al
;; now take
2s complement
9008 ;;; Done filling EBDA table
for hard disk
0.
9012 ;; is there really a second hard disk
? if not, return now
9020 ;; check that the hd type is really
0x0f.
9025 ;; check that the extended type is
47 - user definable
9029 cmp al
, #47 ;; decimal 47 - user definable
9034 ;; CMOS purpose param table offset
9035 ;; 0x24 cylinders low
0
9036 ;; 0x25 cylinders high
1
9038 ;; 0x27 write pre
-comp low
5
9039 ;; 0x28 write pre
-comp high
6
9041 ;; 0x2a landing zone low C
9042 ;; 0x2b landing zone high D
9043 ;; 0x2c sectors
/track E
9044 ;;; Fill EBDA table
for hard disk
1.
9054 mov (0x004d + 0x05), ax
;; write precomp word
9059 mov (0x004d + 0x08), al
;; drive control byte
9068 mov (0x004d + 0x0C), ax
;; landing zone word
9070 mov al
, #0x25 ;; get cylinders word in AX
9072 in al
, #0x71 ;; high byte
9076 in al
, #0x71 ;; low byte
9077 mov bx
, ax
;; BX
= cylinders
9082 mov cl
, al
;; CL
= heads
9087 mov dl
, al
;; DL
= sectors
9090 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
9092 hd1_post_physical_chs
:
9093 ;; no logical CHS mapping used
, just physical CHS
9094 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
9095 mov (0x004d + 0x00), bx
;; number of physical cylinders
9096 mov (0x004d + 0x02), cl
;; number of physical heads
9097 mov (0x004d + 0x0E), dl
;; number of physical sectors
9100 hd1_post_logical_chs
:
9101 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
9102 mov (0x004d + 0x09), bx
;; number of physical cylinders
9103 mov (0x004d + 0x0b), cl
;; number of physical heads
9104 mov (0x004d + 0x04), dl
;; number of physical sectors
9105 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
9107 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
9110 jnbe hd1_post_above_2048
9111 ;; 1024 < c
<= 2048 cylinders
9114 jmp hd1_post_store_logical
9116 hd1_post_above_2048
:
9118 jnbe hd1_post_above_4096
9119 ;; 2048 < c
<= 4096 cylinders
9122 jmp hd1_post_store_logical
9124 hd1_post_above_4096
:
9126 jnbe hd1_post_above_8192
9127 ;; 4096 < c
<= 8192 cylinders
9130 jmp hd1_post_store_logical
9132 hd1_post_above_8192
:
9133 ;; 8192 < c
<= 16384 cylinders
9137 hd1_post_store_logical
:
9138 mov (0x004d + 0x00), bx
;; number of physical cylinders
9139 mov (0x004d + 0x02), cl
;; number of physical heads
9141 mov cl
, #0x0f ;; repeat count
9142 mov si
, #0x004d ;; offset to disk0 FDPT
9143 mov al
, #0x00 ;; sum
9144 hd1_post_checksum_loop
:
9148 jnz hd1_post_checksum_loop
9149 not al
;; now take
2s complement
9152 ;;; Done filling EBDA table
for hard disk
1.
9156 ;--------------------
9157 ;- POST
: EBDA segment
9158 ;--------------------
9159 ; relocated here because the primary POST area isnt big enough
.
9164 mov byte ptr
[0x0], #EBDA_SIZE
9166 xor ax
, ax
; mov EBDA seg into
40E
9168 mov word ptr
[0x40E], #EBDA_SEG
9171 ;--------------------
9172 ;- POST
: EOI
+ jmp via
[0x40:67)
9173 ;--------------------
9174 ; relocated here because the primary POST area isnt big enough
.
9177 out
#0xA0, al ;; slave PIC EOI
9179 out
#0x20, al ;; master PIC EOI
9212 call _s3_resume_panic
9214 ;--------------------
9217 out
#0xA0, al ;; slave PIC EOI
9220 out
#0x20, al ;; master PIC EOI
9223 ;--------------------
9225 ;; in
: AL in BCD format
9226 ;; out
: AL in binary format
, AH will always be
0
9229 and bl
, #0x0f ;; bl has low digit
9230 shr al
, #4 ;; al has high digit
9232 mul al
, bh
;; multiply high digit by
10 (result in AX
)
9233 add al
, bl
;; then add low digit
9236 ;--------------------
9238 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
9239 ;; Timer Ticks Roller
Flag (0x470:byte
)
9240 ;; The Timer Ticks Count needs to be set according to
9241 ;; the current CMOS time
, as
if ticks have been occurring
9242 ;; at
18.2hz since midnight up to
this point
. Calculating
9243 ;; this is a little complicated
. Here are the factors I gather
9244 ;; regarding
this. 14,318,180 hz was the original clock speed
,
9245 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
9246 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
9247 ;; source was divided again by
4 to feed a
1.193Mhz signal to
9248 ;; the timer
. With a maximum
16bit timer count
, this is again
9249 ;; divided down by
65536 to
18.2hz
.
9251 ;; 14,318,180 Hz clock
9252 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
9253 ;; /4 = 1,193,181 Hz fed to timer
9254 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
9255 ;; 1 second
= 18.20650736 ticks
9256 ;; 1 minute
= 1092.390442 ticks
9257 ;; 1 hour
= 65543.42651 ticks
9259 ;; Given the values in the CMOS clock
, one could calculate
9260 ;; the number of ticks by the following
:
9261 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
9262 ;; (BcdToBin(minutes
) * 1092.3904)
9263 ;; (BcdToBin(hours
) * 65543.427)
9264 ;; To get a little more accuracy
, since Im
using integer
9265 ;; arithmatic
, I use
:
9266 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
9267 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
9268 ;; (BcdToBin(hours
) * 65543427) / 1000
9273 xor eax
, eax
;; clear EAX
9276 in al
, #0x71 ;; AL has CMOS seconds in BCD
9277 call BcdToBin
;; EAX now has seconds in binary
9283 mov ecx
, eax
;; ECX will accumulate total ticks
9286 xor eax
, eax
;; clear EAX
9289 in al
, #0x71 ;; AL has CMOS minutes in BCD
9290 call BcdToBin
;; EAX now has minutes in binary
9296 add ecx
, eax
;; add to total ticks
9299 xor eax
, eax
;; clear EAX
9302 in al
, #0x71 ;; AL has CMOS hours in BCD
9303 call BcdToBin
;; EAX now has hours in binary
9309 add ecx
, eax
;; add to total ticks
9311 mov
0x46C, ecx
;; Timer Ticks Count
9313 mov
0x470, al
;; Timer Ticks Rollover Flag
9316 ;--------------------
9318 ;; record completion in BIOS task complete flag
9330 ;--------------------
9335 #include "apmbios.S"
9339 #include "apmbios.S"
9342 #include "apmbios.S"
9346 ;--------------------
9351 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9352 dw bios32_entry_point
, 0xf ;; 32 bit physical address
9353 db
0 ;; revision level
9354 ;; length in paragraphs
and checksum stored in a word to prevent errors
9355 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
9356 & 0xff) << 8) + 0x01
9357 db
0,0,0,0,0 ;; reserved
9362 cmp eax
, #0x49435024 ;; "$PCI"
9364 mov eax
, #0x80000000
9369 #ifdef PCI_FIXED_HOST_BRIDGE
9370 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9373 ;; say ok
if a device is present
9374 cmp eax
, #0xffffffff
9377 mov ebx
, #0x000f0000
9379 mov edx
, #pcibios_protected
9386 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9397 cmp al
, #0x01 ;; installation check
9401 mov edx
, #0x20494350 ;; "PCI "
9404 pci_pro_f02
: ;; find pci device
9412 call pci_pro_select_reg
9426 pci_pro_f03
: ;; find
class code
9432 call pci_pro_select_reg
9437 jne pci_pro_nextdev2
9444 jne pci_pro_devloop2
9447 pci_pro_f08
: ;; read configuration byte
9450 call pci_pro_select_reg
9459 pci_pro_f09
: ;; read configuration word
9462 call pci_pro_select_reg
9471 pci_pro_f0a
: ;; read configuration dword
9474 call pci_pro_select_reg
9481 pci_pro_f0b
: ;; write configuration byte
9484 call pci_pro_select_reg
9493 pci_pro_f0c
: ;; write configuration word
9496 call pci_pro_select_reg
9505 pci_pro_f0d
: ;; write configuration dword
9508 call pci_pro_select_reg
9521 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9531 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9555 mov eax
, #0x80000000
9560 #ifdef PCI_FIXED_HOST_BRIDGE
9561 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9564 ;; say ok
if a device is present
9565 cmp eax
, #0xffffffff
9576 cmp al
, #0x01 ;; installation check
9581 mov edx
, #0x20494350 ;; "PCI "
9583 mov di
, #pcibios_protected
9586 pci_real_f02
: ;; find pci device
9596 call pci_real_select_reg
9600 jne pci_real_nextdev
9607 jne pci_real_devloop
9612 pci_real_f03
: ;; find
class code
9618 call pci_real_select_reg
9623 jne pci_real_nextdev2
9630 jne pci_real_devloop2
9635 pci_real_f08
: ;; read configuration byte
9638 call pci_real_select_reg
9647 pci_real_f09
: ;; read configuration word
9650 call pci_real_select_reg
9659 pci_real_f0a
: ;; read configuration dword
9662 call pci_real_select_reg
9669 pci_real_f0b
: ;; write configuration byte
9672 call pci_real_select_reg
9681 pci_real_f0c
: ;; write configuration word
9684 call pci_real_select_reg
9693 pci_real_f0d
: ;; write configuration dword
9696 call pci_real_select_reg
9703 pci_real_f0e
: ;; get irq routing options
9705 jne pci_real_unknown
9707 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9708 jb pci_real_too_small
9710 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9718 mov si
, #pci_routing_table_structure_start
9726 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9735 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9739 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9757 pci_real_select_reg
:
9771 pci_routing_table_structure
:
9772 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9774 dw
32 + (6 * 16) ;; table size
9775 db
0 ;; PCI interrupt router bus
9776 db
0x08 ;; PCI interrupt router DevFunc
9777 dw
0x0000 ;; PCI exclusive IRQs
9778 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9779 dw
0x122e ;; compatible PCI interrupt router device ID
9780 dw
0,0 ;; Miniport data
9781 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9783 pci_routing_table_structure_start
:
9784 ;; first slot entry PCI
-to
-ISA (embedded
)
9785 db
0 ;; pci bus number
9786 db
0x08 ;; pci device
number (bit
7-3)
9787 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9788 dw
0xdef8 ;; IRQ bitmap INTA
#
9789 db
0x61 ;; link value INTB
#
9790 dw
0xdef8 ;; IRQ bitmap INTB
#
9791 db
0x62 ;; link value INTC
#
9792 dw
0xdef8 ;; IRQ bitmap INTC
#
9793 db
0x63 ;; link value INTD
#
9794 dw
0xdef8 ;; IRQ bitmap INTD
#
9795 db
0 ;; physical
slot (0 = embedded
)
9797 ;; second slot entry
: 1st PCI slot
9798 db
0 ;; pci bus number
9799 db
0x10 ;; pci device
number (bit
7-3)
9800 db
0x61 ;; link value INTA
#
9801 dw
0xdef8 ;; IRQ bitmap INTA
#
9802 db
0x62 ;; link value INTB
#
9803 dw
0xdef8 ;; IRQ bitmap INTB
#
9804 db
0x63 ;; link value INTC
#
9805 dw
0xdef8 ;; IRQ bitmap INTC
#
9806 db
0x60 ;; link value INTD
#
9807 dw
0xdef8 ;; IRQ bitmap INTD
#
9808 db
1 ;; physical
slot (0 = embedded
)
9810 ;; third slot entry
: 2nd PCI slot
9811 db
0 ;; pci bus number
9812 db
0x18 ;; pci device
number (bit
7-3)
9813 db
0x62 ;; link value INTA
#
9814 dw
0xdef8 ;; IRQ bitmap INTA
#
9815 db
0x63 ;; link value INTB
#
9816 dw
0xdef8 ;; IRQ bitmap INTB
#
9817 db
0x60 ;; link value INTC
#
9818 dw
0xdef8 ;; IRQ bitmap INTC
#
9819 db
0x61 ;; link value INTD
#
9820 dw
0xdef8 ;; IRQ bitmap INTD
#
9821 db
2 ;; physical
slot (0 = embedded
)
9823 ;; 4th slot entry
: 3rd PCI slot
9824 db
0 ;; pci bus number
9825 db
0x20 ;; pci device
number (bit
7-3)
9826 db
0x63 ;; link value INTA
#
9827 dw
0xdef8 ;; IRQ bitmap INTA
#
9828 db
0x60 ;; link value INTB
#
9829 dw
0xdef8 ;; IRQ bitmap INTB
#
9830 db
0x61 ;; link value INTC
#
9831 dw
0xdef8 ;; IRQ bitmap INTC
#
9832 db
0x62 ;; link value INTD
#
9833 dw
0xdef8 ;; IRQ bitmap INTD
#
9834 db
3 ;; physical
slot (0 = embedded
)
9836 ;; 5th slot entry
: 4rd PCI slot
9837 db
0 ;; pci bus number
9838 db
0x28 ;; pci device
number (bit
7-3)
9839 db
0x60 ;; link value INTA
#
9840 dw
0xdef8 ;; IRQ bitmap INTA
#
9841 db
0x61 ;; link value INTB
#
9842 dw
0xdef8 ;; IRQ bitmap INTB
#
9843 db
0x62 ;; link value INTC
#
9844 dw
0xdef8 ;; IRQ bitmap INTC
#
9845 db
0x63 ;; link value INTD
#
9846 dw
0xdef8 ;; IRQ bitmap INTD
#
9847 db
4 ;; physical
slot (0 = embedded
)
9849 ;; 6th slot entry
: 5rd PCI slot
9850 db
0 ;; pci bus number
9851 db
0x30 ;; pci device
number (bit
7-3)
9852 db
0x61 ;; link value INTA
#
9853 dw
0xdef8 ;; IRQ bitmap INTA
#
9854 db
0x62 ;; link value INTB
#
9855 dw
0xdef8 ;; IRQ bitmap INTB
#
9856 db
0x63 ;; link value INTC
#
9857 dw
0xdef8 ;; IRQ bitmap INTC
#
9858 db
0x60 ;; link value INTD
#
9859 dw
0xdef8 ;; IRQ bitmap INTD
#
9860 db
5 ;; physical
slot (0 = embedded
)
9862 pci_routing_table_structure_end
:
9868 pcibios_init_sel_reg
:
9880 pcibios_init_iomem_bases
:
9883 mov eax
, #0xc0000000 ;; base for memory init
9885 mov ax
, #0xc000 ;; base for i/o init
9887 mov ax
, #0x0010 ;; start at base address #0
9892 call pcibios_init_sel_reg
9897 mov dl
, #0x04 ;; disable i/o and memory space access
9898 call pcibios_init_sel_reg
9905 call pcibios_init_sel_reg
9911 mov eax
, #0xffffffff
9916 xor eax
, #0xffffffff
9920 add eax
, ecx
;; calculate next free mem base
9921 add eax
, #0x01000000
9922 and eax
, #0xff000000
9936 add ax
, cx
;; calculate next free i
/o base
9944 je enable_iomem_space
9945 mov byte ptr
[bp
-8], al
9946 jmp pci_init_io_loop2
9948 mov dl
, #0x04 ;; enable i/o and memory space access if available
9949 call pcibios_init_sel_reg
9955 mov byte ptr
[bp
-8], #0x10
9958 jne pci_init_io_loop1
9963 pcibios_init_set_elcr
:
9987 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9992 mov si
, #pci_routing_table_structure
9996 call pcibios_init_sel_reg
9999 cmp ax
, [si
+12] ;; check irq router
10002 call pcibios_init_sel_reg
10003 push bx
;; save irq router bus
+ devfunc
10006 out dx
, ax
;; reset PIRQ route control
10013 add si
, #0x20 ;; set pointer to 1st entry
10015 mov ax
, #pci_irq_list
10019 pci_init_irq_loop1
:
10022 pci_init_irq_loop2
:
10024 call pcibios_init_sel_reg
10028 jnz pci_test_int_pin
10034 call pcibios_init_sel_reg
10039 dec al
;; determine pirq reg
10048 call pcibios_init_sel_reg
10055 mov bx
, [bp
-2] ;; pci irq list pointer
10060 call pcibios_init_set_elcr
10064 add bl
, [bp
-3] ;; pci function number
10066 call pcibios_init_sel_reg
10073 jnz pci_init_irq_loop2
10076 mov byte ptr
[bp
-3], #0x00
10077 loop pci_init_irq_loop1
10084 #endif // !BX_ROMBIOS32
10085 #endif // BX_PCIBIOS
10089 ;; save a20
and enable it
10095 ;; save SS
:SP to the BDA
10102 lidt
[pmode_IDT_info
]
10104 lgdt
[rombios32_gdt_48
]
10105 ;; set PE bit in CR0
10109 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
10112 dw
0x000f ;; high
16 bit address
10117 ;; init data segments
10127 ;; init the stack pointer to point below EBDA
10133 ;; pass pointer to s3_resume_flag
and s3_resume_vector to rombios32
10137 ;; call rombios32 code
10138 mov eax
, #0x000e0000
10141 ;; return to
16 bit
protected mode first
10148 ;; restore data segment limits to
0xffff
10156 ;; reset PE bit in CR0
10161 ;; far jump to flush CPU queue after transition to real mode
10162 JMP_AP(0xf000, rombios32_real_mode
)
10164 rombios32_real_mode
:
10165 ;; restore IDT to normal real
-mode defaults
10167 lidt
[rmode_IDT_info
]
10175 ;; restore SS
:SP from the BDA
10192 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
10193 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
10194 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
10195 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
10196 #endif // BX_ROMBIOS32
10199 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
10204 and al
, #0xdf ; clear input mode
10214 mov
[bx
+0x408], dx
; Parallel I
/O address
10216 mov
[bx
+0x478], cl
; Parallel printer timeout
10221 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
10240 mov
[bx
+0x400], dx
; Serial I
/O address
10242 mov
[bx
+0x47c], cl
; Serial timeout
10290 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
10291 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
10299 ;; Scan
for existence of valid expansion ROMS
.
10300 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
10301 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
10302 ;; System ROM
: only
0xE0000
10308 ;; 2 ROM length in
512-byte blocks
10309 ;; 3 ROM initialization entry
point (FAR CALL
)
10314 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
10315 cmp
[0], #0xAA55 ;; look for signature
10316 jne rom_scan_increment
10318 jnz rom_scan_increment
10319 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
10321 ;; We want our increment in
512-byte quantities
, rounded to
10322 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
10324 jz block_count_rounded
10325 and al
, #0xfc ;; needs rounding up
10327 block_count_rounded
:
10329 xor bx
, bx
;; Restore DS back to
0000:
10333 ;; Push addr of ROM entry point
10334 push cx
;; Push seg
10335 push
#0x0003 ;; Push offset
10337 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
10338 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
10343 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
10344 db
0xff ;; call_far ss
:[bp
+0]
10347 cli
;; In
case expansion ROM BIOS turns IF on
10348 add sp
, #2 ;; Pop offset value
10349 pop cx
;; Pop seg
value (restore CX
)
10351 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
10352 ;; to init all the ROMs
and then go back
and build an IPL table of
10353 ;; all the bootable devices
, but we can get away with one pass
.
10354 mov ds
, cx
;; ROM base
10355 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
10356 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
10357 cmp ax
, #0x5024 ;; we look for signature "$PnP"
10363 mov ax
, 0x16[bx
] ;; 0x16 is the offset of Boot Connection Vector
10367 ;; Option ROM has BCV
. Run it now
.
10368 push cx
;; Push seg
10369 push ax
;; Push offset
10371 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
10375 /* jump to BCV function entry pointer */
10376 mov bp
, sp
;; Call ROM BCV routine
using seg
:off on stack
10377 db
0xff ;; call_far ss
:[bp
+0]
10380 cli
;; In
case expansion ROM BIOS turns IF on
10381 add sp
, #2 ;; Pop offset value
10382 pop cx
;; Pop seg
value (restore CX
)
10386 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
10387 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
10390 ;; Found a device that thinks it can boot the system
. Record its BEV
and product name string
.
10391 mov di
, 0x10[bx
] ;; Pointer to the product name string
or zero
if none
10392 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
10394 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
10395 cmp bx
, #IPL_TABLE_ENTRIES
10396 je no_bev
;; Get out
if the table is full
10397 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
10398 mov
0[bx
], #IPL_TYPE_BEV ;; This entry is a BEV device
10399 mov
6[bx
], cx
;; Build a far pointer from the segment
...
10400 mov
4[bx
], ax
;; and the offset
10403 mov
0xA[bx
], cx
;; Build a far pointer from the segment
...
10404 mov
8[bx
], di
;; and the offset
10406 shr bx
, #0x4 ;; Turn the offset back into a count
10407 inc bx
;; We have one more entry now
10408 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
10411 pop di
;; Restore DI
10412 pop ax
;; Restore AX
10413 rom_scan_increment
:
10414 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
10415 ;; because the segment selector is shifted left
4 bits
.
10417 pop ax
;; Restore AX
10421 xor ax
, ax
;; Restore DS back to
0000:
10426 mov al
, #0x11 ; send initialisation commands
10441 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10442 #if BX_USE_PS2_MOUSE
10447 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10450 ;; the following area can be used to write dynamically generated tables
10452 bios_table_area_start
:
10454 dd bios_table_area_end
- bios_table_area_start
- 8;
10459 .org
0xe05b ; POST Entry Point
10464 ;; first reset the DMA controllers
10468 ;; then initialize the DMA controllers
10470 out
0xD6, al
; cascade mode of channel
4 enabled
10472 out
0xD4, al
; unmask channel
4
10474 ;; Examine CMOS shutdown status
.
10482 ;; Reset CMOS shutdown status
.
10484 out
0x70, AL
; select CMOS
register Fh
10486 out
0x71, AL
; set shutdown action to normal
10488 ;; Examine CMOS shutdown status
.
10491 ;; 0x00, 0x09, 0x0D+ = normal startup
10497 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
10501 ;; 0x0A = jmp via
[0x40:0x67] jump
10505 ;; 0x0B = iret via
[0x40:0x67]
10509 ;; 0x0C = retf via
[0x40:0x67]
10513 ;; Examine CMOS shutdown status
.
10514 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08,0x09 = Unimplemented shutdown status
.
10516 call _shutdown_status_panic
10522 ; 0xb0, 0x20, /* mov al, #0x20 */
10523 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10533 ; case 0: normal startup
10542 ;; Save shutdown status
10548 ;; zero out BIOS data
area (40:00..40:ff
)
10550 mov cx
, #0x0080 ;; 128 words
10556 call _log_bios_start
10558 ;; set all interrupts to
default handler
10559 xor bx
, bx
;; offset index
10560 mov cx
, #0x0100 ;; counter (256 interrupts)
10561 mov ax
, #dummy_iret_handler
10569 loop post_default_ints
10571 ;; set vector
0x79 to zero
10572 ;; this is used by
'gardian angel' protection system
10573 SET_INT_VECTOR(0x79, #0, #0)
10575 ;; base memory in K
40:13 (word
)
10576 mov ax
, #BASE_MEM_IN_K
10580 ;; Manufacturing Test
40:12
10583 ;; Warm Boot Flag
0040:0072
10584 ;; value of
1234h
= skip memory checks
10588 ;; Printer Services vector
10589 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10591 ;; Bootstrap failure vector
10592 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10594 ;; Bootstrap Loader vector
10595 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10597 ;; User Timer Tick vector
10598 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10600 ;; Memory Size Check vector
10601 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10603 ;; Equipment Configuration Check vector
10604 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10607 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10613 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10614 ;; int 1C already points at
dummy_iret_handler (above
)
10615 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10617 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10622 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10623 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10627 mov
0x0417, al
/* keyboard shift flags, set 1 */
10628 mov
0x0418, al
/* keyboard shift flags, set 2 */
10629 mov
0x0419, al
/* keyboard alt-numpad work area */
10630 mov
0x0471, al
/* keyboard ctrl-break flag */
10631 mov
0x0497, al
/* keyboard status flags 4 */
10633 mov
0x0496, al
/* keyboard status flags 3 */
10636 /* keyboard head of buffer pointer */
10640 /* keyboard end of buffer pointer */
10643 /* keyboard pointer to start of buffer */
10647 /* keyboard pointer to end of buffer */
10651 /* init the keyboard */
10652 call _keyboard_init
10654 ;; mov CMOS Equipment Byte to BDA Equipment Word
10663 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10667 mov cl
, #0x14 ; timeout value
10668 mov dx
, #0x378 ; Parallel I/O address, port 1
10669 call detect_parport
10670 mov dx
, #0x278 ; Parallel I/O address, port 2
10671 call detect_parport
10673 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10675 or ax
, bx
; set number of parallel ports
10679 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10680 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10682 mov cl
, #0x0a ; timeout value
10683 mov dx
, #0x03f8 ; Serial I/O address, port 1
10685 mov dx
, #0x02f8 ; Serial I/O address, port 2
10687 mov dx
, #0x03e8 ; Serial I/O address, port 3
10689 mov dx
, #0x02e8 ; Serial I/O address, port 4
10692 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10694 or ax
, bx
; set number of serial port
10698 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10699 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10700 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10701 ;; BIOS DATA AREA
0x4CE ???
10702 call timer_tick_post
10704 ;; PS
/2 mouse setup
10705 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10707 ;; IRQ13 (FPU exception
) setup
10708 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10711 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10716 mov cx
, #0xc000 ;; init vga bios
10720 call _print_bios_banner
10723 call rombios32_init
10726 call pcibios_init_iomem_bases
10727 call pcibios_init_irqs
10728 #endif //BX_PCIBIOS
10734 call floppy_drive_post
10737 ;; Hard Drive setup
10739 call hard_drive_post
10744 ;; ATA
/ATAPI driver setup
10750 #endif // BX_USE_ATADRV
10752 #if BX_ELTORITO_BOOT
10754 ;; eltorito floppy
/harddisk emulation from cd
10758 #endif // BX_ELTORITO_BOOT
10760 call _init_boot_vectors
10762 mov cx
, #0xc800 ;; init option roms
10766 #if BX_ELTORITO_BOOT
10767 call _interactive_bootkey
10768 #endif // BX_ELTORITO_BOOT
10770 sti
;; enable interrupts
10773 .org
0xe2c3 ; NMI Handler Entry Point
10775 ;; FIXME the NMI handler should
not panic
10776 ;; but iret when called from
int75 (fpu exception
)
10777 call _nmi_handler_msg
10781 out
0xf0, al
// clear irq13
10782 call eoi_both_pics
// clear interrupt
10783 int 2 // legacy nmi call
10786 ;-------------------------------------------
10787 ;- INT
13h Fixed Disk Services Entry Point
-
10788 ;-------------------------------------------
10789 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10791 //JMPL(int13_relocated)
10792 jmp int13_relocated
10794 .org
0xe401 ; Fixed Disk Parameter Table
10799 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10802 jmp int19_relocated
10803 ;-------------------------------------------
10804 ;- System BIOS Configuration Data Table
10805 ;-------------------------------------------
10806 .org BIOS_CONFIG_TABLE
10807 db
0x08 ; Table
size (bytes
) -Lo
10808 db
0x00 ; Table
size (bytes
) -Hi
10813 ; b7
: 1=DMA channel
3 used by hard disk
10814 ; b6
: 1=2 interrupt controllers present
10815 ; b5
: 1=RTC present
10816 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10817 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10818 ; b2
: 1=extended BIOS data area used
10819 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10820 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10824 (BX_CALL_INT15_4F
<< 4) | \
10826 (BX_USE_EBDA
<< 2) | \
10830 ; b7
: 1=32-bit DMA supported
10831 ; b6
: 1=int16h
, function
9 supported
10832 ; b5
: 1=int15h
/C6h (get POS data
) supported
10833 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10834 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10835 ; b2
: 1=non
-8042 kb controller
10836 ; b1
: 1=data streaming supported
10850 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10851 ; b3
: SCSI on system board
10852 ; b2
: info panel installed
10853 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10854 ; b0
: SCSI supported in IML
10858 ; b6
: EEPROM present
10859 ; b5
-3: ABIOS
presence (011 = not supported
)
10861 ; b1
: memory split above
16Mb supported
10862 ; b0
: POSTEXT directly supported by POST
10864 ; Feature byte
5 (IBM
)
10865 ; b1
: enhanced mouse
10871 .org
0xe729 ; Baud Rate Generator Table
10876 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10882 call _int14_function
10888 ;----------------------------------------
10889 ;- INT
16h Keyboard Service Entry Point
-
10890 ;----------------------------------------
10906 call _int16_function
10916 and BYTE
[bp
+ 0x06], #0xbf
10924 or BYTE
[bp
+ 0x06], #0x40
10932 int16_wait_for_key
:
10936 jne int16_key_found
10940 /* no key yet, call int 15h, function AX=9002 */
10941 0x50, /* push AX */
10942 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10943 0xcd, 0x15, /* int 15h */
10945 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10947 jmp int16_wait_for_key
10952 call _int16_function
10957 /* notify int16 complete w/ int 15h, function AX=9102 */
10958 0x50, /* push AX */
10959 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10960 0xcd, 0x15, /* int 15h */
10967 ;-------------------------------------------------
10968 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10969 ;-------------------------------------------------
10975 mov al
, #0xAD ;;disable keyboard
10984 in al
, #0x60 ;;read key from keyboard controller
10988 #ifdef BX_CALL_INT15_4F
10989 mov ah
, #0x4f ;; allow for keyboard intercept
10995 ;; check
for extended key
10997 jne int09_check_pause
11000 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
11002 mov BYTE
[0x496], al
11005 int09_check_pause
: ;; check
for pause key
11007 jne int09_process_key
11010 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
11012 mov BYTE
[0x496], al
11018 call _int09_function
11024 call eoi_master_pic
11027 mov al
, #0xAE ;;enable keyboard
11033 ;----------------------------------------
11034 ;- INT
13h Diskette Service Entry Point
-
11035 ;----------------------------------------
11038 jmp int13_noeltorito
11040 ;---------------------------------------------
11041 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
11042 ;---------------------------------------------
11043 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
11053 mov al
, #0x08 ; sense interrupt status
11071 xor ax
, ax
;; segment
0000
11073 call eoi_master_pic
11075 or al
, #0x80 ;; diskette interrupt has occurred
11083 .org
0xefc7 ; Diskette Controller Parameter Table
11084 diskette_param_table
:
11085 ;; Since no provisions are made
for multiple drive types
, most
11086 ;; values in
this table are ignored
. I set parameters
for 1.44M
11089 db
0x02 ;; head load time
0000001, DMA used
11101 ;----------------------------------------
11102 ;- INT17h
: Printer Service Entry Point
-
11103 ;----------------------------------------
11110 call _int17_function
11115 diskette_param_table2
:
11116 ;; New diskette parameter table adding
3 parameters from IBM
11117 ;; Since no provisions are made
for multiple drive types
, most
11118 ;; values in
this table are ignored
. I set parameters
for 1.44M
11121 db
0x02 ;; head load time
0000001, DMA used
11131 db
79 ;; maximum track
11132 db
0 ;; data transfer rate
11133 db
4 ;; drive type in cmos
11135 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
11142 .org
0xf065 ; INT
10h Video Support Service Entry Point
11144 ;; dont
do anything
, since the VGA BIOS handles int10h requests
11147 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
11152 .org
0xf841 ; INT
12h Memory Size Service Entry Point
11153 ; ??? different
for Pentium (machine check
)?
11165 .org
0xf84d ; INT
11h Equipment List Service Entry Point
11177 .org
0xf859 ; INT
15h System Services Entry Point
11191 #if BX_USE_PS2_MOUSE
11193 je int15_handler_mouse
11195 call _int15_function
11196 int15_handler_mouse_ret
:
11198 int15_handler32_ret
:
11208 #if BX_USE_PS2_MOUSE
11209 int15_handler_mouse
:
11210 call _int15_function_mouse
11211 jmp int15_handler_mouse_ret
11216 call _int15_function32
11218 jmp int15_handler32_ret
11220 ;; Protected mode IDT descriptor
11222 ;; I just make the limit
0, so the machine will shutdown
11223 ;; if an exception occurs during
protected mode memory
11226 ;; Set base to f0000 to correspond to beginning of BIOS
,
11227 ;; in
case I actually define an IDT later
11231 dw
0x0000 ;; limit
15:00
11232 dw
0x0000 ;; base
15:00
11233 db
0x0f ;; base
23:16
11235 ;; Real mode IDT descriptor
11237 ;; Set to typical real
-mode values
.
11242 dw
0x03ff ;; limit
15:00
11243 dw
0x0000 ;; base
15:00
11244 db
0x00 ;; base
23:16
11250 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
11263 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
11264 mov ds
, ax
; on
16bit
protected mode
.
11265 jmp int1a_callfunction
11272 int1a_callfunction
:
11273 call _int1a_function
11279 ;; int70h
: IRQ8
- CMOS RTC
11286 call _int70_function
11294 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
11302 ;; time to turn off
drive(s
)?
11305 jz int08_floppy_off
11308 jnz int08_floppy_off
11309 ;; turn
motor(s
) off
11318 mov eax
, 0x046c ;; get ticks dword
11321 ;; compare eax to one days worth of timer ticks at
18.2 hz
11322 cmp eax
, #0x001800B0
11323 jb int08_store_ticks
11324 ;; there has been a midnight rollover at
this point
11325 xor eax
, eax
;; zero out counter
11326 inc BYTE
0x0470 ;; increment rollover flag
11329 mov
0x046c, eax
;; store
new ticks dword
11330 ;; chain to user timer tick INT
#0x1c
11332 //;; call_ep [ds:loc]
11333 //CALL_EP( 0x1c << 2 )
11336 call eoi_master_pic
11341 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
11345 .ascii BIOS_COPYRIGHT_STRING
11347 ;------------------------------------------------
11348 ;- IRET Instruction
for Dummy Interrupt Handler
-
11349 ;------------------------------------------------
11350 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
11351 dummy_iret_handler
:
11354 .org
0xff54 ; INT
05h Print Screen Service Entry Point
11358 .org
0xfff0 ; Power
-up Entry Point
11361 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
11362 .ascii BIOS_BUILD_DATE
11364 .org
0xfffe ; System Model ID
11368 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
11371 * This font comes from the fntcol16.zip package (c) by Joseph Gil
11372 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
11373 * This font is public domain
11375 static Bit8u vgafont8
[128*8]=
11377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11378 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
11379 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
11380 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11381 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11382 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
11383 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
11384 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
11385 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
11386 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
11387 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
11388 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
11389 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
11390 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
11391 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
11392 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
11393 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
11394 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
11395 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
11396 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
11397 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
11398 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
11399 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11400 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11401 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11402 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11403 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11404 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11405 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11406 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11407 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11408 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11410 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11411 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11412 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11413 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11414 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11415 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11416 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11417 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11418 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11419 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11420 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11421 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11422 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11423 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11424 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11425 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11426 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11427 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11428 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11429 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11430 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11431 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11432 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11433 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11434 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11435 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11436 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11437 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11438 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11439 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11440 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11441 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11442 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11443 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11444 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11445 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11446 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11447 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11448 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11449 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11450 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11451 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11452 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11453 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11454 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11455 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11456 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11457 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11458 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11459 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11460 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11461 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11462 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11463 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11464 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11465 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11466 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11467 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11468 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11469 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11470 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11471 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11473 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11474 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11475 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11476 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11477 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11478 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11479 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11480 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11481 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11482 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11483 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11484 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11485 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11486 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11487 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11488 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11489 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11490 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11491 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11492 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11493 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11494 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11495 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11496 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11497 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11498 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11499 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11500 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11501 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11502 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11503 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11504 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11509 bios_table_area_end
:
11510 // bcc-generated data will be placed here