1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.221 2008/12/07 17:32:29 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
128 #define DEBUG_INT13_HD 0
129 #define DEBUG_INT13_CD 0
130 #define DEBUG_INT13_ET 0
131 #define DEBUG_INT13_FL 0
132 #define DEBUG_INT15 0
133 #define DEBUG_INT16 0
134 #define DEBUG_INT1A 0
135 #define DEBUG_INT74 0
139 #define BX_USE_PS2_MOUSE 1
140 #define BX_CALL_INT15_4F 1
141 #define BX_USE_EBDA 1
142 #define BX_SUPPORT_FLOPPY 1
143 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
147 #define BX_USE_ATADRV 1
148 #define BX_ELTORITO_BOOT 1
150 #define BX_MAX_ATA_INTERFACES 4
151 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
153 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
154 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
156 /* model byte 0xFC = AT */
157 #define SYS_MODEL_ID 0xFC
158 #define SYS_SUBMODEL_ID 0x00
159 #define BIOS_REVISION 1
160 #define BIOS_CONFIG_TABLE 0xe6f5
162 #ifndef BIOS_BUILD_DATE
163 # define BIOS_BUILD_DATE "06/23/99"
166 // 1K of base memory used for Extended Bios Data Area (EBDA)
167 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
168 #define EBDA_SEG 0x9FC0
169 #define EBDA_SIZE 1 // In KiB
170 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
172 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
173 #define IPL_SEG 0x9ff0
174 #define IPL_TABLE_OFFSET 0x0000
175 #define IPL_TABLE_ENTRIES 8
176 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
177 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
178 #define IPL_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
696 // ElTorito Device Emulation data
700 Bit8u emulated_drive
;
701 Bit8u controller_index
;
704 Bit16u buffer_segment
;
711 #endif // BX_ELTORITO_BOOT
713 // for access to EBDA area
714 // The EBDA structure should conform to
715 // http://www.frontiernet.net/~fys/rombios.htm document
716 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
717 // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot
718 // device tables are at IPL_SEG
720 unsigned char filler1
[0x3D];
722 // FDPT - Can be splitted in data members if needed
723 unsigned char fdpt0
[0x10];
724 unsigned char fdpt1
[0x10];
726 unsigned char filler2
[0xC4];
732 // El Torito Emulation data
734 #endif // BX_ELTORITO_BOOT
738 #define EbdaData ((ebda_data_t *) 0)
740 // for access to the int13ext structure
751 #define Int13Ext ((int13ext_t *) 0)
753 // Disk Physical Table definition
760 Bit32u sector_count1
;
761 Bit32u sector_count2
;
772 Bit8u device_path
[8];
777 #define Int13DPT ((dpt_t *) 0)
779 #endif // BX_USE_ATADRV
784 Bit16u di
, si
, bp
, sp
;
785 Bit16u bx
, dx
, cx
, ax
;
789 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
797 Bit32u edi
, esi
, ebp
, esp
;
798 Bit32u ebx
, edx
, ecx
, eax
;
801 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
802 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
830 #define SetCF(x) x.u.r8.flagsl |= 0x01
831 #define SetZF(x) x.u.r8.flagsl |= 0x40
832 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
833 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
834 #define GetCF(x) (x.u.r8.flagsl & 0x01)
853 static Bit8u
inb_cmos();
855 static void outb_cmos();
858 static void init_rtc();
859 static bx_bool
rtc_updating();
861 static Bit8u
read_byte();
862 static Bit16u
read_word();
863 static void write_byte();
864 static void write_word();
865 static void bios_printf();
867 static Bit8u
inhibit_mouse_int_and_events();
868 static void enable_mouse_int_and_events();
869 static Bit8u
send_to_mouse_ctrl();
870 static Bit8u
get_mouse_data();
871 static void set_kbd_command_byte();
873 static void int09_function();
874 static void int13_harddisk();
875 static void int13_cdrom();
876 static void int13_cdemu();
877 static void int13_eltorito();
878 static void int13_diskette_function();
879 static void int14_function();
880 static void int15_function();
881 static void int16_function();
882 static void int17_function();
883 static void int19_function();
884 static void int1a_function();
885 static void int70_function();
886 static void int74_function();
887 static Bit16u
get_CS();
888 static Bit16u
get_SS();
889 static unsigned int enqueue_key();
890 static unsigned int dequeue_key();
891 static void get_hd_geometry();
892 static void set_diskette_ret_status();
893 static void set_diskette_current_cyl();
894 static void determine_floppy_media();
895 static bx_bool
floppy_drive_exists();
896 static bx_bool
floppy_drive_recal();
897 static bx_bool
floppy_media_known();
898 static bx_bool
floppy_media_sense();
899 static bx_bool
set_enable_a20();
900 static void debugger_on();
901 static void debugger_off();
902 static void keyboard_init();
903 static void keyboard_panic();
904 static void shutdown_status_panic();
905 static void nmi_handler_msg();
906 static void delay_ticks();
907 static void delay_ticks_and_check_for_keystroke();
909 static void interactive_bootkey();
910 static void print_bios_banner();
911 static void print_boot_device();
912 static void print_boot_failure();
913 static void print_cdromboot_failure();
917 // ATA / ATAPI driver
922 Bit16u
ata_cmd_non_data();
923 Bit16u
ata_cmd_data_in();
924 Bit16u
ata_cmd_data_out();
925 Bit16u
ata_cmd_packet();
927 Bit16u
atapi_get_sense();
928 Bit16u
atapi_is_ready();
929 Bit16u
atapi_is_cdrom();
931 #endif // BX_USE_ATADRV
936 Bit8u
cdemu_isactive();
937 Bit8u
cdemu_emulated_drive();
941 #endif // BX_ELTORITO_BOOT
943 static char bios_cvs_version_string
[] = "$Revision: 1.221 $ $Date: 2008/12/07 17:32:29 $";
945 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
948 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
950 # define BX_DEBUG_ATA(a...)
953 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
955 # define BX_DEBUG_INT13_HD(a...)
958 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
960 # define BX_DEBUG_INT13_CD(a...)
963 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
965 # define BX_DEBUG_INT13_ET(a...)
968 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
970 # define BX_DEBUG_INT13_FL(a...)
973 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
975 # define BX_DEBUG_INT15(a...)
978 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
980 # define BX_DEBUG_INT16(a...)
983 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
985 # define BX_DEBUG_INT1A(a...)
988 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
990 # define BX_DEBUG_INT74(a...)
993 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
994 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
995 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
996 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
997 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
998 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
999 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1000 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1002 #define GET_AL() ( AX & 0x00ff )
1003 #define GET_BL() ( BX & 0x00ff )
1004 #define GET_CL() ( CX & 0x00ff )
1005 #define GET_DL() ( DX & 0x00ff )
1006 #define GET_AH() ( AX >> 8 )
1007 #define GET_BH() ( BX >> 8 )
1008 #define GET_CH() ( CX >> 8 )
1009 #define GET_DH() ( DX >> 8 )
1011 #define GET_ELDL() ( ELDX & 0x00ff )
1012 #define GET_ELDH() ( ELDX >> 8 )
1014 #define SET_CF() FLAGS |= 0x0001
1015 #define CLEAR_CF() FLAGS &= 0xfffe
1016 #define GET_CF() (FLAGS & 0x0001)
1018 #define SET_ZF() FLAGS |= 0x0040
1019 #define CLEAR_ZF() FLAGS &= 0xffbf
1020 #define GET_ZF() (FLAGS & 0x0040)
1022 #define UNSUPPORTED_FUNCTION 0x86
1025 #define MAX_SCAN_CODE 0x58
1033 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1034 { none
, none
, none
, none
, none
},
1035 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1036 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1037 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1038 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1039 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1040 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1041 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1042 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1043 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1044 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1045 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1046 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1047 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1048 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1049 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1050 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1051 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1052 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1053 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1054 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1055 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1056 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1057 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1058 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1059 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1060 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1061 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1062 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1063 { none
, none
, none
, none
, none
}, /* L Ctrl */
1064 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1065 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1066 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1067 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1068 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1069 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1070 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1071 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1072 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1073 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1074 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1075 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1076 { none
, none
, none
, none
, none
}, /* L shift */
1077 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1078 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1079 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1080 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1081 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1082 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1083 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1084 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1085 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1086 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1087 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1088 { none
, none
, none
, none
, none
}, /* R Shift */
1089 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1090 { none
, none
, none
, none
, none
}, /* L Alt */
1091 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1092 { none
, none
, none
, none
, none
}, /* caps lock */
1093 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1094 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1095 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1096 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1097 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1098 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1099 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1100 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1101 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1102 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1103 { none
, none
, none
, none
, none
}, /* Num Lock */
1104 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1105 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1106 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1107 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1108 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1109 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1110 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1111 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1112 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1113 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1114 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1115 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1116 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1117 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1118 { none
, none
, none
, none
, none
},
1119 { none
, none
, none
, none
, none
},
1120 { 0x565c, 0x567c, none
, none
, none
}, /* \| */
1121 { 0x8500, 0x8700, 0x8900, 0x8b00, none
}, /* F11 */
1122 { 0x8600, 0x8800, 0x8a00, 0x8c00, none
}, /* F12 */
1206 outb_cmos(cmos_reg
, val
)
1214 mov al
, 4[bp
] ;; cmos_reg
1216 mov al
, 6[bp
] ;; val
1231 mov al
, 4[bp
] ;; cmos_reg
1242 outb_cmos(0x0a, 0x26);
1243 outb_cmos(0x0b, 0x02);
1251 // This function checks to see if the update-in-progress bit
1252 // is set in CMOS Status Register A. If not, it returns 0.
1253 // If it is set, it tries to wait until there is a transition
1254 // to 0, and will return 0 if such a transition occurs. A 1
1255 // is returned only after timing out. The maximum period
1256 // that this bit should be set is constrained to 244useconds.
1257 // The count I use below guarantees coverage or more than
1258 // this time, with any reasonable IPS setting.
1263 while (--count
!= 0) {
1264 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1267 return(1); // update-in-progress never transitioned to 0
1272 read_byte(seg
, offset
)
1282 mov ax
, 4[bp
] ; segment
1284 mov bx
, 6[bp
] ; offset
1286 ;; al
= return value (byte
)
1295 read_word(seg
, offset
)
1305 mov ax
, 4[bp
] ; segment
1307 mov bx
, 6[bp
] ; offset
1309 ;; ax
= return value (word
)
1318 write_byte(seg
, offset
, data
)
1330 mov ax
, 4[bp
] ; segment
1332 mov bx
, 6[bp
] ; offset
1333 mov al
, 8[bp
] ; data byte
1334 mov
[bx
], al
; write data byte
1344 write_word(seg
, offset
, data
)
1356 mov ax
, 4[bp
] ; segment
1358 mov bx
, 6[bp
] ; offset
1359 mov ax
, 8[bp
] ; data word
1360 mov
[bx
], ax
; write data word
1386 /* serial debug port*/
1387 #define BX_DEBUG_PORT 0x03f8
1390 #define UART_RBR 0x00
1391 #define UART_THR 0x00
1394 #define UART_IER 0x01
1395 #define UART_IIR 0x02
1396 #define UART_FCR 0x02
1397 #define UART_LCR 0x03
1398 #define UART_MCR 0x04
1399 #define UART_DLL 0x00
1400 #define UART_DLM 0x01
1403 #define UART_LSR 0x05
1404 #define UART_MSR 0x06
1405 #define UART_SCR 0x07
1407 int uart_can_tx_byte(base_port
)
1410 return inb(base_port
+ UART_LSR
) & 0x20;
1413 void uart_wait_to_tx_byte(base_port
)
1416 while (!uart_can_tx_byte(base_port
));
1419 void uart_wait_until_sent(base_port
)
1422 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1425 void uart_tx_byte(base_port
, data
)
1429 uart_wait_to_tx_byte(base_port
);
1430 outb(base_port
+ UART_THR
, data
);
1431 uart_wait_until_sent(base_port
);
1460 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1461 uart_tx_byte(BX_DEBUG_PORT
, c
);
1463 #if BX_VIRTUAL_PORTS
1464 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1465 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1467 if (action
& BIOS_PRINTF_SCREEN
) {
1468 if (c
== '\n') wrch('\r');
1474 put_int(action
, val
, width
, neg
)
1479 short nval
= val
/ 10;
1481 put_int(action
, nval
, width
- 1, neg
);
1483 while (--width
> 0) send(action
, ' ');
1484 if (neg
) send(action
, '-');
1486 send(action
, val
- (nval
* 10) + '0');
1490 put_uint(action
, val
, width
, neg
)
1496 unsigned short nval
= val
/ 10;
1498 put_uint(action
, nval
, width
- 1, neg
);
1500 while (--width
> 0) send(action
, ' ');
1501 if (neg
) send(action
, '-');
1503 send(action
, val
- (nval
* 10) + '0');
1507 put_luint(action
, val
, width
, neg
)
1513 unsigned long nval
= val
/ 10;
1515 put_luint(action
, nval
, width
- 1, neg
);
1517 while (--width
> 0) send(action
, ' ');
1518 if (neg
) send(action
, '-');
1520 send(action
, val
- (nval
* 10) + '0');
1523 void put_str(action
, segment
, offset
)
1530 while (c
= read_byte(segment
, offset
)) {
1540 long ticks_to_wait
, delta
;
1541 Bit32u prev_ticks
, t
;
1544 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
1545 * We also have to be careful about interrupt storms.
1551 ticks_to_wait
= ticks
;
1552 prev_ticks
= read_dword(0x0, 0x46c);
1558 t
= read_dword(0x0, 0x46c);
1561 delta
= t
- prev_ticks
; /* The temp var is required or bcc screws up. */
1562 ticks_to_wait
-= delta
;
1564 else if (t
< prev_ticks
)
1566 ticks_to_wait
-= t
; /* wrapped */
1570 } while (ticks_to_wait
> 0);
1578 check_for_keystroke()
1603 delay_ticks_and_check_for_keystroke(ticks
, count
)
1604 Bit16u ticks
, count
;
1607 for (i
= 1; i
<= count
; i
++) {
1609 if (check_for_keystroke())
1614 //--------------------------------------------------------------------------
1616 // A compact variable argument printf function.
1618 // Supports %[format_width][length]format
1619 // where format can be x,X,u,d,s,S,c
1620 // and the optional length modifier is l (ell)
1621 //--------------------------------------------------------------------------
1623 bios_printf(action
, s
)
1627 Bit8u c
, format_char
;
1631 Bit16u arg_seg
, arg
, nibble
, hibyte
, shift_count
, format_width
, hexadd
;
1639 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1640 #if BX_VIRTUAL_PORTS
1641 outb(PANIC_PORT2
, 0x00);
1643 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1646 while (c
= read_byte(get_CS(), s
)) {
1651 else if (in_format
) {
1652 if ( (c
>='0') && (c
<='9') ) {
1653 format_width
= (format_width
* 10) + (c
- '0');
1656 arg_ptr
++; // increment to next arg
1657 arg
= read_word(arg_seg
, arg_ptr
);
1658 if (c
== 'x' || c
== 'X') {
1659 if (format_width
== 0)
1665 for (i
=format_width
-1; i
>=0; i
--) {
1666 nibble
= (arg
>> (4 * i
)) & 0x000f;
1667 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1670 else if (c
== 'u') {
1671 put_uint(action
, arg
, format_width
, 0);
1673 else if (c
== 'l') {
1675 c
= read_byte(get_CS(), s
); /* is it ld,lx,lu? */
1676 arg_ptr
++; /* increment to next arg */
1677 hibyte
= read_word(arg_seg
, arg_ptr
);
1679 if (hibyte
& 0x8000)
1680 put_luint(action
, 0L-(((Bit32u
) hibyte
<< 16) | arg
), format_width
-1, 1);
1682 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1684 else if (c
== 'u') {
1685 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1687 else if (c
== 'x' || c
== 'X')
1689 if (format_width
== 0)
1695 for (i
=format_width
-1; i
>=0; i
--) {
1696 nibble
= ((((Bit32u
) hibyte
<<16) | arg
) >> (4 * i
)) & 0x000f;
1697 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+hexadd
));
1701 else if (c
== 'd') {
1703 put_int(action
, -arg
, format_width
- 1, 1);
1705 put_int(action
, arg
, format_width
, 0);
1707 else if (c
== 's') {
1708 put_str(action
, get_CS(), arg
);
1710 else if (c
== 'S') {
1713 arg
= read_word(arg_seg
, arg_ptr
);
1714 put_str(action
, hibyte
, arg
);
1716 else if (c
== 'c') {
1720 BX_PANIC("bios_printf: unknown format\n");
1730 if (action
& BIOS_PRINTF_HALT
) {
1731 // freeze in a busy loop.
1741 //--------------------------------------------------------------------------
1743 //--------------------------------------------------------------------------
1744 // this file is based on LinuxBIOS implementation of keyboard.c
1745 // could convert to #asm to gain space
1751 /* ------------------- Flush buffers ------------------------*/
1752 /* Wait until buffer is empty */
1754 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1756 /* flush incoming keys */
1760 if (inb(0x64) & 0x01) {
1766 // Due to timer issues, and if the IPS setting is > 15000000,
1767 // the incoming keys might not be flushed here. That will
1768 // cause a panic a few lines below. See sourceforge bug report :
1769 // [ 642031 ] FATAL: Keyboard RESET error:993
1771 /* ------------------- controller side ----------------------*/
1772 /* send cmd = 0xAA, self test 8042 */
1775 /* Wait until buffer is empty */
1777 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1778 if (max
==0x0) keyboard_panic(00);
1782 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1783 if (max
==0x0) keyboard_panic(01);
1785 /* read self-test result, 0x55 should be returned from 0x60 */
1786 if ((inb(0x60) != 0x55)){
1787 keyboard_panic(991);
1790 /* send cmd = 0xAB, keyboard interface test */
1793 /* Wait until buffer is empty */
1795 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1796 if (max
==0x0) keyboard_panic(10);
1800 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1801 if (max
==0x0) keyboard_panic(11);
1803 /* read keyboard interface test result, */
1804 /* 0x00 should be returned form 0x60 */
1805 if ((inb(0x60) != 0x00)) {
1806 keyboard_panic(992);
1809 /* Enable Keyboard clock */
1813 /* ------------------- keyboard side ------------------------*/
1814 /* reset kerboard and self test (keyboard side) */
1817 /* Wait until buffer is empty */
1819 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1820 if (max
==0x0) keyboard_panic(20);
1824 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1825 if (max
==0x0) keyboard_panic(21);
1827 /* keyboard should return ACK */
1828 if ((inb(0x60) != 0xfa)) {
1829 keyboard_panic(993);
1834 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1835 if (max
==0x0) keyboard_panic(31);
1837 if ((inb(0x60) != 0xaa)) {
1838 keyboard_panic(994);
1841 /* Disable keyboard */
1844 /* Wait until buffer is empty */
1846 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1847 if (max
==0x0) keyboard_panic(40);
1851 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1852 if (max
==0x0) keyboard_panic(41);
1854 /* keyboard should return ACK */
1855 if ((inb(0x60) != 0xfa)) {
1856 keyboard_panic(995);
1859 /* Write Keyboard Mode */
1862 /* Wait until buffer is empty */
1864 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1865 if (max
==0x0) keyboard_panic(50);
1867 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1870 /* Wait until buffer is empty */
1872 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1873 if (max
==0x0) keyboard_panic(60);
1875 /* Enable keyboard */
1878 /* Wait until buffer is empty */
1880 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1881 if (max
==0x0) keyboard_panic(70);
1885 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1886 if (max
==0x0) keyboard_panic(70);
1888 /* keyboard should return ACK */
1889 if ((inb(0x60) != 0xfa)) {
1890 keyboard_panic(996);
1896 //--------------------------------------------------------------------------
1898 //--------------------------------------------------------------------------
1900 keyboard_panic(status
)
1903 // If you're getting a 993 keyboard panic here,
1904 // please see the comment in keyboard_init
1906 BX_PANIC("Keyboard error:%u\n",status
);
1909 //--------------------------------------------------------------------------
1910 // shutdown_status_panic
1911 // called when the shutdown statsu is not implemented, displays the status
1912 //--------------------------------------------------------------------------
1914 shutdown_status_panic(status
)
1917 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1920 void s3_resume_panic()
1922 BX_PANIC("Returned from s3_resume.\n");
1925 //--------------------------------------------------------------------------
1926 // print_bios_banner
1927 // displays a the bios version
1928 //--------------------------------------------------------------------------
1932 printf(BX_APPNAME
" BIOS - build: %s\n%s\nOptions: ",
1933 BIOS_BUILD_DATE
, bios_cvs_version_string
);
1941 #if BX_ELTORITO_BOOT
1950 //--------------------------------------------------------------------------
1951 // BIOS Boot Specification 1.0.1 compatibility
1953 // Very basic support for the BIOS Boot Specification, which allows expansion
1954 // ROMs to register themselves as boot devices, instead of just stealing the
1955 // INT 19h boot vector.
1957 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1958 // one; we just lie to the option ROMs to make them behave correctly.
1959 // We also don't support letting option ROMs register as bootable disk
1960 // drives (BCVs), only as bootable devices (BEVs).
1962 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1963 //--------------------------------------------------------------------------
1965 static char drivetypes
[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1972 Bit16u ss
= get_SS();
1974 /* Clear out the IPL table. */
1975 memsetb(IPL_SEG
, IPL_TABLE_OFFSET
, 0, IPL_SIZE
);
1977 /* User selected device not set */
1978 write_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
, 0xFFFF);
1981 e
.type
= IPL_TYPE_FLOPPY
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1982 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1986 e
.type
= IPL_TYPE_HARDDISK
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1987 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1990 #if BX_ELTORITO_BOOT
1992 e
.type
= IPL_TYPE_CDROM
; e
.flags
= 0; e
.vector
= 0; e
.description
= 0; e
.reserved
= 0;
1993 memcpyb(IPL_SEG
, IPL_TABLE_OFFSET
+ count
* sizeof (e
), ss
, &e
, sizeof (e
));
1997 /* Remember how many devices we have */
1998 write_word(IPL_SEG
, IPL_COUNT_OFFSET
, count
);
1999 /* Not tried booting anything yet */
2000 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xffff);
2004 get_boot_vector(i
, e
)
2005 Bit16u i
; ipl_entry_t
*e
;
2008 Bit16u ss
= get_SS();
2009 /* Get the count of boot devices, and refuse to overrun the array */
2010 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
2011 if (i
>= count
) return 0;
2012 /* OK to read this device */
2013 memcpyb(ss
, e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (*e
), sizeof (*e
));
2017 #if BX_ELTORITO_BOOT
2019 interactive_bootkey()
2023 char description
[33];
2026 Bit16u ss
= get_SS();
2027 Bit16u valid_choice
= 0;
2029 while (check_for_keystroke())
2032 printf("Press F12 for boot menu.\n\n");
2034 delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */
2035 if (check_for_keystroke())
2037 scan_code
= get_keystroke();
2038 if (scan_code
== 0x86) /* F12 */
2040 while (check_for_keystroke())
2043 printf("Select boot device:\n\n");
2045 count
= read_word(IPL_SEG
, IPL_COUNT_OFFSET
);
2046 for (i
= 0; i
< count
; i
++)
2048 memcpyb(ss
, &e
, IPL_SEG
, IPL_TABLE_OFFSET
+ i
* sizeof (e
), sizeof (e
));
2049 printf("%d. ", i
+1);
2052 case IPL_TYPE_FLOPPY
:
2053 case IPL_TYPE_HARDDISK
:
2054 case IPL_TYPE_CDROM
:
2055 printf("%s\n", drivetypes
[e
.type
]);
2058 printf("%s", drivetypes
[4]);
2059 if (e
.description
!= 0)
2061 memcpyb(ss
, &description
, (Bit16u
)(e
.description
>> 16), (Bit16u
)(e
.description
& 0xffff), 32);
2062 description
[32] = 0;
2063 printf(" [%S]", ss
, description
);
2071 while (!valid_choice
) {
2072 scan_code
= get_keystroke();
2073 if (scan_code
== 0x01 || scan_code
== 0x58) /* ESC or F12 */
2077 else if (scan_code
<= count
)
2081 /* Set user selected device */
2082 write_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
, scan_code
);
2089 #endif // BX_ELTORITO_BOOT
2091 //--------------------------------------------------------------------------
2092 // print_boot_device
2093 // displays the boot device
2094 //--------------------------------------------------------------------------
2097 print_boot_device(e
)
2101 char description
[33];
2102 Bit16u ss
= get_SS();
2104 /* NIC appears as type 0x80 */
2105 if (type
== IPL_TYPE_BEV
) type
= 0x4;
2106 if (type
== 0 || type
> 0x4) BX_PANIC("Bad drive type\n");
2107 printf("Booting from %s", drivetypes
[type
]);
2108 /* print product string if BEV */
2109 if (type
== 4 && e
->description
!= 0) {
2110 /* first 32 bytes are significant */
2111 memcpyb(ss
, &description
, (Bit16u
)(e
->description
>> 16), (Bit16u
)(e
->description
& 0xffff), 32);
2112 /* terminate string */
2113 description
[32] = 0;
2114 printf(" [%S]", ss
, description
);
2119 //--------------------------------------------------------------------------
2120 // print_boot_failure
2121 // displays the reason why boot failed
2122 //--------------------------------------------------------------------------
2124 print_boot_failure(type
, reason
)
2125 Bit16u type
; Bit8u reason
;
2127 if (type
== 0 || type
> 0x3) BX_PANIC("Bad drive type\n");
2129 printf("Boot failed");
2131 /* Report the reason too */
2133 printf(": not a bootable disk");
2135 printf(": could not read the boot disk");
2140 //--------------------------------------------------------------------------
2141 // print_cdromboot_failure
2142 // displays the reason why boot failed
2143 //--------------------------------------------------------------------------
2145 print_cdromboot_failure( code
)
2148 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
2156 BX_PANIC("NMI Handler called\n");
2162 BX_PANIC("INT18: BOOT FAILURE\n");
2169 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
2171 BX_INFO("%s\n", bios_cvs_version_string
);
2180 // Use PS2 System Control port A to set A20 enable
2182 // get current setting first
2185 // change A20 status
2187 outb(0x92, oldval
| 0x02);
2189 outb(0x92, oldval
& 0xfd);
2191 return((oldval
& 0x02) != 0);
2209 Bit32u s3_wakeup_vector
;
2210 Bit8u s3_resume_flag
;
2212 s3_resume_flag
= read_byte(0x40, 0xb0);
2213 s3_wakeup_vector
= read_dword(0x40, 0xb2);
2215 BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag
, s3_wakeup_vector
);
2216 if (s3_resume_flag
!= 0xFE || !s3_wakeup_vector
)
2219 write_byte(0x40, 0xb0, 0);
2221 /* setup wakeup vector */
2222 write_word(0x40, 0xb6, (s3_wakeup_vector
& 0xF)); /* IP */
2223 write_word(0x40, 0xb8, (s3_wakeup_vector
>> 4)); /* CS */
2225 BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector
>> 4),
2226 (s3_wakeup_vector
& 0xF));
2235 // ---------------------------------------------------------------------------
2236 // Start of ATA/ATAPI Driver
2237 // ---------------------------------------------------------------------------
2239 // Global defines -- ATA register and register bits.
2240 // command block & control block regs
2241 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2242 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2243 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2244 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2245 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2246 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2247 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2248 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2249 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2250 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2251 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2252 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2253 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2255 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2256 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2257 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2258 #define ATA_CB_ER_MC 0x20 // ATA media change
2259 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2260 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2261 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2262 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2263 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2265 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2266 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2267 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2268 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2269 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2271 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2272 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2273 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2274 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2275 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2277 // bits 7-4 of the device/head (CB_DH) reg
2278 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2279 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2280 #define ATA_CB_DH_LBA 0x40 // use LBA
2282 // status reg (CB_STAT and CB_ASTAT) bits
2283 #define ATA_CB_STAT_BSY 0x80 // busy
2284 #define ATA_CB_STAT_RDY 0x40 // ready
2285 #define ATA_CB_STAT_DF 0x20 // device fault
2286 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2287 #define ATA_CB_STAT_SKC 0x10 // seek complete
2288 #define ATA_CB_STAT_SERV 0x10 // service
2289 #define ATA_CB_STAT_DRQ 0x08 // data request
2290 #define ATA_CB_STAT_CORR 0x04 // corrected
2291 #define ATA_CB_STAT_IDX 0x02 // index
2292 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2293 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2295 // device control reg (CB_DC) bits
2296 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2297 #define ATA_CB_DC_SRST 0x04 // soft reset
2298 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2300 // Most mandtory and optional ATA commands (from ATA-3),
2301 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2302 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2303 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2304 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2305 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2306 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2307 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2308 #define ATA_CMD_DEVICE_RESET 0x08
2309 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2310 #define ATA_CMD_FLUSH_CACHE 0xE7
2311 #define ATA_CMD_FORMAT_TRACK 0x50
2312 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2313 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2314 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2315 #define ATA_CMD_IDLE1 0xE3
2316 #define ATA_CMD_IDLE2 0x97
2317 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2318 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2319 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2320 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2321 #define ATA_CMD_NOP 0x00
2322 #define ATA_CMD_PACKET 0xA0
2323 #define ATA_CMD_READ_BUFFER 0xE4
2324 #define ATA_CMD_READ_DMA 0xC8
2325 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2326 #define ATA_CMD_READ_MULTIPLE 0xC4
2327 #define ATA_CMD_READ_SECTORS 0x20
2328 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2329 #define ATA_CMD_RECALIBRATE 0x10
2330 #define ATA_CMD_REQUEST_SENSE 0x03
2331 #define ATA_CMD_SEEK 0x70
2332 #define ATA_CMD_SET_FEATURES 0xEF
2333 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2334 #define ATA_CMD_SLEEP1 0xE6
2335 #define ATA_CMD_SLEEP2 0x99
2336 #define ATA_CMD_STANDBY1 0xE2
2337 #define ATA_CMD_STANDBY2 0x96
2338 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2339 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2340 #define ATA_CMD_WRITE_BUFFER 0xE8
2341 #define ATA_CMD_WRITE_DMA 0xCA
2342 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2343 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2344 #define ATA_CMD_WRITE_SECTORS 0x30
2345 #define ATA_CMD_WRITE_VERIFY 0x3C
2347 #define ATA_IFACE_NONE 0x00
2348 #define ATA_IFACE_ISA 0x00
2349 #define ATA_IFACE_PCI 0x01
2351 #define ATA_TYPE_NONE 0x00
2352 #define ATA_TYPE_UNKNOWN 0x01
2353 #define ATA_TYPE_ATA 0x02
2354 #define ATA_TYPE_ATAPI 0x03
2356 #define ATA_DEVICE_NONE 0x00
2357 #define ATA_DEVICE_HD 0xFF
2358 #define ATA_DEVICE_CDROM 0x05
2360 #define ATA_MODE_NONE 0x00
2361 #define ATA_MODE_PIO16 0x00
2362 #define ATA_MODE_PIO32 0x01
2363 #define ATA_MODE_ISADMA 0x02
2364 #define ATA_MODE_PCIDMA 0x03
2365 #define ATA_MODE_USEIRQ 0x10
2367 #define ATA_TRANSLATION_NONE 0
2368 #define ATA_TRANSLATION_LBA 1
2369 #define ATA_TRANSLATION_LARGE 2
2370 #define ATA_TRANSLATION_RECHS 3
2372 #define ATA_DATA_NO 0x00
2373 #define ATA_DATA_IN 0x01
2374 #define ATA_DATA_OUT 0x02
2376 // ---------------------------------------------------------------------------
2377 // ATA/ATAPI driver : initialization
2378 // ---------------------------------------------------------------------------
2381 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2382 Bit8u channel
, device
;
2384 // Channels info init.
2385 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2386 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2387 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2388 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2389 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2392 // Devices info init.
2393 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2394 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2395 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2396 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2397 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2398 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2399 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2400 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2401 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2402 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2403 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2404 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2405 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2406 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2408 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
,0L);
2409 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_high
,0L);
2412 // hdidmap and cdidmap init.
2413 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2414 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2415 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2418 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2419 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2425 #define NOT_BSY_DRQ 3
2426 #define NOT_BSY_NOT_DRQ 4
2427 #define NOT_BSY_RDY 5
2429 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
2432 static int await_ide(when_done
,base
,timeout
)
2437 Bit32u time
=0,last
=0;
2440 status
= inb(base
+ ATA_CB_STAT
); // for the times you're supposed to throw one away
2442 status
= inb(base
+ATA_CB_STAT
);
2444 if (when_done
== BSY
)
2445 result
= status
& ATA_CB_STAT_BSY
;
2446 else if (when_done
== NOT_BSY
)
2447 result
= !(status
& ATA_CB_STAT_BSY
);
2448 else if (when_done
== NOT_BSY_DRQ
)
2449 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_DRQ
);
2450 else if (when_done
== NOT_BSY_NOT_DRQ
)
2451 result
= !(status
& ATA_CB_STAT_BSY
) && !(status
& ATA_CB_STAT_DRQ
);
2452 else if (when_done
== NOT_BSY_RDY
)
2453 result
= !(status
& ATA_CB_STAT_BSY
) && (status
& ATA_CB_STAT_RDY
);
2454 else if (when_done
== TIMEOUT
)
2457 if (result
) return 0;
2458 if (time
>>16 != last
) // mod 2048 each 16 ms
2461 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
);
2463 if (status
& ATA_CB_STAT_ERR
)
2465 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
);
2468 if ((timeout
== 0) || ((time
>>11) > timeout
)) break;
2470 BX_INFO("IDE time out\n");
2474 // ---------------------------------------------------------------------------
2475 // ATA/ATAPI driver : device detection
2476 // ---------------------------------------------------------------------------
2480 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2481 Bit8u hdcount
, cdcount
, device
, type
;
2482 Bit8u buffer
[0x0200];
2484 #if BX_MAX_ATA_INTERFACES > 0
2485 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2486 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2487 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2488 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2490 #if BX_MAX_ATA_INTERFACES > 1
2491 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2492 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2493 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2494 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2496 #if BX_MAX_ATA_INTERFACES > 2
2497 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2498 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2499 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2500 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2502 #if BX_MAX_ATA_INTERFACES > 3
2503 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2504 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2505 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2506 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2508 #if BX_MAX_ATA_INTERFACES > 4
2509 #error Please fill the ATA interface informations
2515 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2516 Bit16u iobase1
, iobase2
;
2517 Bit8u channel
, slave
, shift
;
2518 Bit8u sc
, sn
, cl
, ch
, st
;
2520 channel
= device
/ 2;
2523 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2524 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2526 // Disable interrupts
2527 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2530 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2531 outb(iobase1
+ATA_CB_SC
, 0x55);
2532 outb(iobase1
+ATA_CB_SN
, 0xaa);
2533 outb(iobase1
+ATA_CB_SC
, 0xaa);
2534 outb(iobase1
+ATA_CB_SN
, 0x55);
2535 outb(iobase1
+ATA_CB_SC
, 0x55);
2536 outb(iobase1
+ATA_CB_SN
, 0xaa);
2538 // If we found something
2539 sc
= inb(iobase1
+ATA_CB_SC
);
2540 sn
= inb(iobase1
+ATA_CB_SN
);
2542 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2543 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2545 // reset the channel
2548 // check for ATA or ATAPI
2549 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2550 sc
= inb(iobase1
+ATA_CB_SC
);
2551 sn
= inb(iobase1
+ATA_CB_SN
);
2552 if ((sc
==0x01) && (sn
==0x01)) {
2553 cl
= inb(iobase1
+ATA_CB_CL
);
2554 ch
= inb(iobase1
+ATA_CB_CH
);
2555 st
= inb(iobase1
+ATA_CB_STAT
);
2557 if ((cl
==0x14) && (ch
==0xeb)) {
2558 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2559 } else if ((cl
==0x00) && (ch
==0x00) && (st
!=0x00)) {
2560 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2561 } else if ((cl
==0xff) && (ch
==0xff)) {
2562 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2567 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2569 // Now we send a IDENTIFY command to ATA device
2570 if(type
== ATA_TYPE_ATA
) {
2571 Bit32u sectors_low
, sectors_high
;
2572 Bit16u cylinders
, heads
, spt
, blksize
;
2573 Bit8u translation
, removable
, mode
;
2575 //Temporary values to do the transfer
2576 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2577 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2579 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer
) !=0 )
2580 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2582 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2583 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2584 blksize
= read_word(get_SS(),buffer
+10);
2586 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2587 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2588 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2590 if (read_word(get_SS(),buffer
+(83*2)) & (1 << 10)) { // word 83 - lba48 support
2591 sectors_low
= read_dword(get_SS(),buffer
+(100*2)); // word 100 and word 101
2592 sectors_high
= read_dword(get_SS(),buffer
+(102*2)); // word 102 and word 103
2594 sectors_low
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2598 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2599 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2600 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2601 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2602 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2603 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2604 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2605 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
, sectors_low
);
2606 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_high
, sectors_high
);
2607 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2609 translation
= inb_cmos(0x39 + channel
/2);
2610 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2611 translation
&= 0x03;
2613 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2615 switch (translation
) {
2616 case ATA_TRANSLATION_NONE
:
2619 case ATA_TRANSLATION_LBA
:
2622 case ATA_TRANSLATION_LARGE
:
2625 case ATA_TRANSLATION_RECHS
:
2629 switch (translation
) {
2630 case ATA_TRANSLATION_NONE
:
2632 case ATA_TRANSLATION_LBA
:
2635 heads
= sectors_low
/ 1024;
2636 if (heads
>128) heads
= 255;
2637 else if (heads
>64) heads
= 128;
2638 else if (heads
>32) heads
= 64;
2639 else if (heads
>16) heads
= 32;
2641 cylinders
= sectors_low
/ heads
;
2643 case ATA_TRANSLATION_RECHS
:
2644 // Take care not to overflow
2646 if(cylinders
>61439) cylinders
=61439;
2648 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2650 // then go through the large bitshift process
2651 case ATA_TRANSLATION_LARGE
:
2652 while(cylinders
> 1024) {
2656 // If we max out the head count
2657 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");
2744 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2745 if (sizeinmb
< (1UL<<16))
2746 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version
, (Bit16u
)sizeinmb
);
2748 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version
, (Bit16u
)(sizeinmb
>>10));
2750 case ATA_TYPE_ATAPI
:
2751 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2752 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2753 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2754 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2756 printf(" ATAPI-%d Device\n",version
);
2758 case ATA_TYPE_UNKNOWN
:
2759 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2765 // Store the devices counts
2766 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2767 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2768 write_byte(0x40,0x75, hdcount
);
2772 // FIXME : should use bios=cmos|auto|disable bits
2773 // FIXME : should know about translation bits
2774 // FIXME : move hard_drive_post here
2778 // ---------------------------------------------------------------------------
2779 // ATA/ATAPI driver : software reset
2780 // ---------------------------------------------------------------------------
2782 // 8.2.1 Software reset - Device 0
2784 void ata_reset(device
)
2787 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2788 Bit16u iobase1
, iobase2
;
2789 Bit8u channel
, slave
, sn
, sc
;
2793 channel
= device
/ 2;
2796 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2797 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2801 // 8.2.1 (a) -- set SRST in DC
2802 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2804 // 8.2.1 (b) -- wait for BSY
2805 await_ide(BSY
, iobase1
, 20);
2807 // 8.2.1 (f) -- clear SRST
2808 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2810 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2811 if (type
!= ATA_TYPE_NONE
) {
2813 // 8.2.1 (g) -- check for sc==sn==0x01
2815 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2816 sc
= inb(iobase1
+ATA_CB_SC
);
2817 sn
= inb(iobase1
+ATA_CB_SN
);
2819 if ( (sc
==0x01) && (sn
==0x01) ) {
2820 if (type
== ATA_TYPE_ATA
) //ATA
2821 await_ide(NOT_BSY_RDY
, iobase1
, IDE_TIMEOUT
);
2823 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2826 // 8.2.1 (h) -- wait for not BSY
2827 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2830 // Enable interrupts
2831 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2834 // ---------------------------------------------------------------------------
2835 // ATA/ATAPI driver : execute a non data command
2836 // ---------------------------------------------------------------------------
2838 Bit16u
ata_cmd_non_data()
2841 // ---------------------------------------------------------------------------
2842 // ATA/ATAPI driver : execute a data-in command
2843 // ---------------------------------------------------------------------------
2848 // 3 : expected DRQ=1
2849 // 4 : no sectors left to read/verify
2850 // 5 : more sectors to read/verify
2851 // 6 : no sectors left to write
2852 // 7 : more sectors to write
2853 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
)
2854 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2855 Bit32u lba_low
, lba_high
;
2857 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2858 Bit16u iobase1
, iobase2
, blksize
;
2859 Bit8u channel
, slave
;
2860 Bit8u status
, current
, mode
;
2862 channel
= device
/ 2;
2865 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2866 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2867 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2868 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2869 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2872 // Reset count of transferred data
2873 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2874 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2877 status
= inb(iobase1
+ ATA_CB_STAT
);
2878 if (status
& ATA_CB_STAT_BSY
) return 1;
2880 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2882 // sector will be 0 only on lba access. Convert to lba-chs
2884 if ((count
>= 1 << 8) || lba_high
|| (lba_low
+ count
>= 1UL << 28)) {
2885 outb(iobase1
+ ATA_CB_FR
, 0x00);
2886 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
2887 outb(iobase1
+ ATA_CB_SN
, lba_low
>> 24);
2888 outb(iobase1
+ ATA_CB_CL
, lba_high
& 0xff);
2889 outb(iobase1
+ ATA_CB_CH
, lba_high
>> 8);
2891 count
&= (1UL << 8) - 1;
2892 lba_low
&= (1UL << 24) - 1;
2894 sector
= (Bit16u
) (lba_low
& 0x000000ffL
);
2895 cylinder
= (Bit16u
) ((lba_low
>>8) & 0x0000ffffL
);
2896 head
= ((Bit16u
) ((lba_low
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
2899 outb(iobase1
+ ATA_CB_FR
, 0x00);
2900 outb(iobase1
+ ATA_CB_SC
, count
);
2901 outb(iobase1
+ ATA_CB_SN
, sector
);
2902 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2903 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2904 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2905 outb(iobase1
+ ATA_CB_CMD
, command
);
2907 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
2908 status
= inb(iobase1
+ ATA_CB_STAT
);
2910 if (status
& ATA_CB_STAT_ERR
) {
2911 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2913 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2914 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2918 // FIXME : move seg/off translation here
2921 sti
;; enable higher priority interrupts
2929 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2930 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2931 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2933 ;; adjust
if there will be an overrun
. 2K max sector size
2935 jbe ata_in_no_adjust
2938 sub di
, #0x0800 ;; sub 2 kbytes from offset
2939 add ax
, #0x0080 ;; add 2 Kbytes to segment
2942 mov es
, ax
;; segment in es
2944 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2946 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2947 cmp ah
, #ATA_MODE_PIO32
2952 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2957 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2960 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2961 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2966 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2968 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
2969 status
= inb(iobase1
+ ATA_CB_STAT
);
2971 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2972 != ATA_CB_STAT_RDY
) {
2973 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2979 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2980 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2981 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2987 // Enable interrupts
2988 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2992 // ---------------------------------------------------------------------------
2993 // ATA/ATAPI driver : execute a data-out command
2994 // ---------------------------------------------------------------------------
2999 // 3 : expected DRQ=1
3000 // 4 : no sectors left to read/verify
3001 // 5 : more sectors to read/verify
3002 // 6 : no sectors left to write
3003 // 7 : more sectors to write
3004 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
)
3005 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
3006 Bit32u lba_low
, lba_high
;
3008 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3009 Bit16u iobase1
, iobase2
, blksize
;
3010 Bit8u channel
, slave
;
3011 Bit8u status
, current
, mode
;
3013 channel
= device
/ 2;
3016 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
3017 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
3018 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
3019 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3020 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
3023 // Reset count of transferred data
3024 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
3025 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
3028 status
= inb(iobase1
+ ATA_CB_STAT
);
3029 if (status
& ATA_CB_STAT_BSY
) return 1;
3031 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
3033 // sector will be 0 only on lba access. Convert to lba-chs
3035 if ((count
>= 1 << 8) || lba_high
|| (lba_low
+ count
>= 1UL << 28)) {
3036 outb(iobase1
+ ATA_CB_FR
, 0x00);
3037 outb(iobase1
+ ATA_CB_SC
, (count
>> 8) & 0xff);
3038 outb(iobase1
+ ATA_CB_SN
, lba_low
>> 24);
3039 outb(iobase1
+ ATA_CB_CL
, lba_high
& 0xff);
3040 outb(iobase1
+ ATA_CB_CH
, lba_high
>> 8);
3042 count
&= (1UL << 8) - 1;
3043 lba_low
&= (1UL << 24) - 1;
3045 sector
= (Bit16u
) (lba_low
& 0x000000ffL
);
3046 cylinder
= (Bit16u
) ((lba_low
>>8) & 0x0000ffffL
);
3047 head
= ((Bit16u
) ((lba_low
>>24) & 0x0000000fL
)) | ATA_CB_DH_LBA
;
3050 outb(iobase1
+ ATA_CB_FR
, 0x00);
3051 outb(iobase1
+ ATA_CB_SC
, count
);
3052 outb(iobase1
+ ATA_CB_SN
, sector
);
3053 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
3054 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
3055 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
3056 outb(iobase1
+ ATA_CB_CMD
, command
);
3058 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3059 status
= inb(iobase1
+ ATA_CB_STAT
);
3061 if (status
& ATA_CB_STAT_ERR
) {
3062 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3064 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
3065 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
3069 // FIXME : move seg/off translation here
3072 sti
;; enable higher priority interrupts
3080 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
3081 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
3082 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
3084 ;; adjust
if there will be an overrun
. 2K max sector size
3086 jbe ata_out_no_adjust
3089 sub si
, #0x0800 ;; sub 2 kbytes from offset
3090 add ax
, #0x0080 ;; add 2 Kbytes to segment
3093 mov es
, ax
;; segment in es
3095 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
3097 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
3098 cmp ah
, #ATA_MODE_PIO32
3104 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
3110 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
3113 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
3114 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
3119 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
3121 status
= inb(iobase1
+ ATA_CB_STAT
);
3123 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3124 != ATA_CB_STAT_RDY
) {
3125 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
3131 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3132 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
3133 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
3139 // Enable interrupts
3140 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3144 // ---------------------------------------------------------------------------
3145 // ATA/ATAPI driver : execute a packet command
3146 // ---------------------------------------------------------------------------
3149 // 1 : error in parameters
3153 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
3155 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
3159 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3160 Bit16u iobase1
, iobase2
;
3161 Bit16u lcount
, lbefore
, lafter
, count
;
3162 Bit8u channel
, slave
;
3163 Bit8u status
, mode
, lmode
;
3164 Bit32u total
, transfer
;
3166 channel
= device
/ 2;
3169 // Data out is not supported yet
3170 if (inout
== ATA_DATA_OUT
) {
3171 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3175 // The header length must be even
3177 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
3181 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
3182 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
3183 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
3186 if (cmdlen
< 12) cmdlen
=12;
3187 if (cmdlen
> 12) cmdlen
=16;
3190 // Reset count of transferred data
3191 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
3192 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
3194 status
= inb(iobase1
+ ATA_CB_STAT
);
3195 if (status
& ATA_CB_STAT_BSY
) return 2;
3197 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
3198 outb(iobase1
+ ATA_CB_FR
, 0x00);
3199 outb(iobase1
+ ATA_CB_SC
, 0x00);
3200 outb(iobase1
+ ATA_CB_SN
, 0x00);
3201 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
3202 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
3203 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
3204 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
3206 // Device should ok to receive command
3207 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3208 status
= inb(iobase1
+ ATA_CB_STAT
);
3210 if (status
& ATA_CB_STAT_ERR
) {
3211 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
3213 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
3214 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
3218 // Normalize address
3219 cmdseg
+= (cmdoff
/ 16);
3222 // Send command to device
3224 sti
;; enable higher priority interrupts
3229 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
3230 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
3231 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
3232 mov es
, ax
;; segment in es
3234 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
3238 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
3243 if (inout
== ATA_DATA_NO
) {
3244 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3245 status
= inb(iobase1
+ ATA_CB_STAT
);
3252 if (loops
== 0) {//first time through
3253 status
= inb(iobase2
+ ATA_CB_ASTAT
);
3254 await_ide(NOT_BSY_DRQ
, iobase1
, IDE_TIMEOUT
);
3257 await_ide(NOT_BSY
, iobase1
, IDE_TIMEOUT
);
3260 status
= inb(iobase1
+ ATA_CB_STAT
);
3261 sc
= inb(iobase1
+ ATA_CB_SC
);
3263 // Check if command completed
3264 if(((inb(iobase1
+ ATA_CB_SC
)&0x7)==0x3) &&
3265 ((status
& (ATA_CB_STAT_RDY
| ATA_CB_STAT_ERR
)) == ATA_CB_STAT_RDY
)) break;
3267 if (status
& ATA_CB_STAT_ERR
) {
3268 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
3272 // Normalize address
3273 bufseg
+= (bufoff
/ 16);
3276 // Get the byte count
3277 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
3279 // adjust to read what we want
3292 lafter
=lcount
-length
;
3304 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
3305 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
3307 // If counts not dividable by 4, use 16bits mode
3309 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
3310 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
3311 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
3313 // adds an extra byte if count are odd. before is always even
3314 if (lcount
& 0x01) {
3316 if ((lafter
> 0) && (lafter
& 0x01)) {
3321 if (lmode
== ATA_MODE_PIO32
) {
3322 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
3325 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
3334 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
3336 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
3337 jcxz ata_packet_no_before
3339 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3340 cmp ah
, #ATA_MODE_PIO32
3341 je ata_packet_in_before_32
3343 ata_packet_in_before_16
:
3345 loop ata_packet_in_before_16
3346 jmp ata_packet_no_before
3348 ata_packet_in_before_32
:
3350 ata_packet_in_before_32_loop
:
3352 loop ata_packet_in_before_32_loop
3355 ata_packet_no_before
:
3356 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3357 jcxz ata_packet_after
3359 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3360 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3363 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3364 cmp ah
, #ATA_MODE_PIO32
3369 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3370 jmp ata_packet_after
3374 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3377 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3378 jcxz ata_packet_done
3380 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3381 cmp ah
, #ATA_MODE_PIO32
3382 je ata_packet_in_after_32
3384 ata_packet_in_after_16
:
3386 loop ata_packet_in_after_16
3389 ata_packet_in_after_32
:
3391 ata_packet_in_after_32_loop
:
3393 loop ata_packet_in_after_32_loop
3400 // Compute new buffer address
3403 // Save transferred bytes count
3405 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3409 // Final check, device must be ready
3410 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3411 != ATA_CB_STAT_RDY
) {
3412 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3416 // Enable interrupts
3417 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3421 // ---------------------------------------------------------------------------
3422 // End of ATA/ATAPI Driver
3423 // ---------------------------------------------------------------------------
3425 // ---------------------------------------------------------------------------
3426 // Start of ATA/ATAPI generic functions
3427 // ---------------------------------------------------------------------------
3430 atapi_get_sense(device
, seg
, asc
, ascq
)
3437 memsetb(get_SS(),atacmd
,0,12);
3440 atacmd
[0]=ATA_CMD_REQUEST_SENSE
;
3441 atacmd
[4]=sizeof(buffer
);
3442 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 18L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3445 write_byte(seg
,asc
,buffer
[12]);
3446 write_byte(seg
,ascq
,buffer
[13]);
3452 atapi_is_ready(device
)
3459 Bit32u timeout
; //measured in ms
3463 Bit16u ebda_seg
= read_word(0x0040,0x000E);
3464 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
) {
3465 printf("not implemented for non-ATAPI device\n");
3469 BX_DEBUG_ATA("ata_detect_medium: begin\n");
3470 memsetb(get_SS(),packet
, 0, sizeof packet
);
3471 packet
[0] = 0x25; /* READ CAPACITY */
3473 /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
3474 * is reported by the device. If the device reports "IN PROGRESS",
3475 * 30 seconds is added. */
3479 while (time
< timeout
) {
3480 if (ata_cmd_packet(device
, sizeof(packet
), get_SS(), packet
, 0, 8L, ATA_DATA_IN
, get_SS(), buf
) == 0)
3483 if (atapi_get_sense(device
, get_SS(), &asc
, &ascq
) == 0) {
3484 if (asc
== 0x3a) { /* MEDIUM NOT PRESENT */
3485 BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
3489 if (asc
== 0x04 && ascq
== 0x01 && !in_progress
) {
3490 /* IN PROGRESS OF BECOMING READY */
3491 printf("Waiting for device to detect medium... ");
3492 /* Allow 30 seconds more */
3499 BX_DEBUG_ATA("read capacity failed\n");
3503 block_len
= (Bit32u
) buf
[4] << 24
3504 | (Bit32u
) buf
[5] << 16
3505 | (Bit32u
) buf
[6] << 8
3506 | (Bit32u
) buf
[7] << 0;
3507 BX_DEBUG_ATA("block_len=%u\n", block_len
);
3509 if (block_len
!= 2048 && block_len
!= 512)
3511 printf("Unsupported sector size %u\n", block_len
);
3514 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, block_len
);
3516 sectors
= (Bit32u
) buf
[0] << 24
3517 | (Bit32u
) buf
[1] << 16
3518 | (Bit32u
) buf
[2] << 8
3519 | (Bit32u
) buf
[3] << 0;
3521 BX_DEBUG_ATA("sectors=%u\n", sectors
);
3522 if (block_len
== 2048)
3523 sectors
<<= 2; /* # of sectors in 512-byte "soft" sector */
3524 if (sectors
!= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
))
3525 printf("%dMB medium detected\n", sectors
>>(20-9));
3526 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors_low
, sectors
);
3531 atapi_is_cdrom(device
)
3534 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3536 if (device
>= BX_MAX_ATA_DEVICES
)
3539 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3542 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3548 // ---------------------------------------------------------------------------
3549 // End of ATA/ATAPI generic functions
3550 // ---------------------------------------------------------------------------
3552 #endif // BX_USE_ATADRV
3554 #if BX_ELTORITO_BOOT
3556 // ---------------------------------------------------------------------------
3557 // Start of El-Torito boot functions
3558 // ---------------------------------------------------------------------------
3563 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3565 // the only important data is this one for now
3566 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3572 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3574 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3578 cdemu_emulated_drive()
3580 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3582 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3585 static char isotag
[6]="CD001";
3586 static char eltorito
[24]="EL TORITO SPECIFICATION";
3588 // Returns ah: emulated drive, al: error code
3593 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3594 Bit8u atacmd
[12], buffer
[2048];
3596 Bit16u boot_segment
, nbsectors
, i
, error
;
3599 // Find out the first cdrom
3600 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3601 if (atapi_is_cdrom(device
)) break;
3605 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3607 if(error
= atapi_is_ready(device
) != 0)
3608 BX_INFO("ata_is_ready returned %d\n",error
);
3610 // Read the Boot Record Volume Descriptor
3611 memsetb(get_SS(),atacmd
,0,12);
3612 atacmd
[0]=0x28; // READ command
3613 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3614 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3615 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3616 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3617 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3618 atacmd
[5]=(0x11 & 0x000000ff);
3619 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3623 if(buffer
[0]!=0)return 4;
3625 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3628 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3630 // ok, now we calculate the Boot catalog address
3631 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3633 // And we read the Boot Catalog
3634 memsetb(get_SS(),atacmd
,0,12);
3635 atacmd
[0]=0x28; // READ command
3636 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3637 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3638 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3639 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3640 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3641 atacmd
[5]=(lba
& 0x000000ff);
3642 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3646 if(buffer
[0x00]!=0x01)return 8; // Header
3647 if(buffer
[0x01]!=0x00)return 9; // Platform
3648 if(buffer
[0x1E]!=0x55)return 10; // key 1
3649 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3651 // Initial/Default Entry
3652 if(buffer
[0x20]!=0x88)return 11; // Bootable
3654 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3655 if(buffer
[0x21]==0){
3656 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3657 // Win2000 cd boot needs to know it booted from cd
3658 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3660 else if(buffer
[0x21]<4)
3661 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3663 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3665 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3666 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3668 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3669 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3671 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3672 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3674 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3675 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3677 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3678 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3680 // And we read the image in memory
3681 memsetb(get_SS(),atacmd
,0,12);
3682 atacmd
[0]=0x28; // READ command
3683 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3684 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3685 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3686 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3687 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3688 atacmd
[5]=(lba
& 0x000000ff);
3689 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3692 // Remember the media type
3693 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3694 case 0x01: // 1.2M floppy
3695 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3696 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3697 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3699 case 0x02: // 1.44M floppy
3700 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3701 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3702 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3704 case 0x03: // 2.88M floppy
3705 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3706 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3707 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3709 case 0x04: // Harddrive
3710 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3711 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3712 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3713 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3717 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3718 // Increase bios installed hardware number of devices
3719 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3720 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3722 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3726 // everything is ok, so from now on, the emulation is active
3727 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3728 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3730 // return the boot drive + no error
3731 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3734 // ---------------------------------------------------------------------------
3735 // End of El-Torito boot functions
3736 // ---------------------------------------------------------------------------
3737 #endif // BX_ELTORITO_BOOT
3740 int14_function(regs
, ds
, iret_addr
)
3741 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3742 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3743 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3745 Bit16u addr
,timer
,val16
;
3752 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3753 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3754 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3755 switch (regs
.u
.r8
.ah
) {
3757 outb(addr
+3, inb(addr
+3) | 0x80);
3758 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3762 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3763 outb(addr
, val16
& 0xFF);
3764 outb(addr
+1, val16
>> 8);
3766 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3767 regs
.u
.r8
.ah
= inb(addr
+5);
3768 regs
.u
.r8
.al
= inb(addr
+6);
3769 ClearCF(iret_addr
.flags
);
3772 timer
= read_word(0x0040, 0x006C);
3773 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3774 val16
= read_word(0x0040, 0x006C);
3775 if (val16
!= timer
) {
3780 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3781 regs
.u
.r8
.ah
= inb(addr
+5);
3782 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3783 ClearCF(iret_addr
.flags
);
3786 timer
= read_word(0x0040, 0x006C);
3787 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3788 val16
= read_word(0x0040, 0x006C);
3789 if (val16
!= timer
) {
3796 regs
.u
.r8
.al
= inb(addr
);
3798 regs
.u
.r8
.ah
= inb(addr
+5);
3800 ClearCF(iret_addr
.flags
);
3803 regs
.u
.r8
.ah
= inb(addr
+5);
3804 regs
.u
.r8
.al
= inb(addr
+6);
3805 ClearCF(iret_addr
.flags
);
3808 SetCF(iret_addr
.flags
); // Unsupported
3811 SetCF(iret_addr
.flags
); // Unsupported
3816 int15_function(regs
, ES
, DS
, FLAGS
)
3817 pusha_regs_t regs
; // REGS pushed via pusha
3818 Bit16u ES
, DS
, FLAGS
;
3820 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3821 bx_bool prev_a20_enable
;
3830 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3832 switch (regs
.u
.r8
.ah
) {
3833 case 0x24: /* A20 Control */
3834 switch (regs
.u
.r8
.al
) {
3846 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3856 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3858 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3864 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3868 /* keyboard intercept */
3870 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3877 case 0x52: // removable media eject
3879 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3883 if( regs
.u
.r8
.al
== 0 ) {
3884 // Set Interval requested.
3885 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3886 // Interval not already set.
3887 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3888 write_word( 0x40, 0x98, ES
); // Byte location, segment
3889 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3890 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3891 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3893 irqDisable
= inb( 0xA1 );
3894 outb( 0xA1, irqDisable
& 0xFE );
3895 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3896 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3898 // Interval already set.
3899 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3901 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3903 } else if( regs
.u
.r8
.al
== 1 ) {
3904 // Clear Interval requested
3905 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3907 bRegister
= inb_cmos( 0xB );
3908 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3910 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3912 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3921 # error "Int15 function 87h not supported on < 80386"
3923 // +++ should probably have descriptor checks
3924 // +++ should have exception handlers
3926 // turn off interrupts
3931 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3933 // 128K max of transfer on 386+ ???
3934 // source == destination ???
3936 // ES:SI points to descriptor table
3937 // offset use initially comments
3938 // ==============================================
3939 // 00..07 Unused zeros Null descriptor
3940 // 08..0f GDT zeros filled in by BIOS
3941 // 10..17 source ssssssss source of data
3942 // 18..1f dest dddddddd destination of data
3943 // 20..27 CS zeros filled in by BIOS
3944 // 28..2f SS zeros filled in by BIOS
3951 // check for access rights of source & dest here
3953 // Initialize GDT descriptor
3954 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3955 base23_16
= ES
>> 12;
3956 if (base15_00
< (ES
<<4))
3958 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3959 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3960 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3961 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3962 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3964 // Initialize CS descriptor
3965 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3966 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3967 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3968 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3969 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3971 // Initialize SS descriptor
3973 base15_00
= ss
<< 4;
3974 base23_16
= ss
>> 12;
3975 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3976 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3977 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3978 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3979 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3983 // Compile generates locals offset info relative to SP.
3984 // Get CX (word count) from stack.
3987 mov cx
, _int15_function
.CX
[bx
]
3989 // since we need to set SS:SP, save them to the BDA
3990 // for future restore
4000 lidt
[pmode_IDT_info
]
4001 ;; perhaps
do something with IDT here
4003 ;; set PE bit in CR0
4007 ;; far jump to flush CPU queue after transition to
protected mode
4008 JMP_AP(0x0020, protected_mode
)
4011 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
4012 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4014 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4016 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4022 movsw
;; move CX words from DS
:SI to ES
:DI
4024 ;; make sure DS
and ES limits are
64KB
4029 ;; reset PG bit in CR0
???
4034 ;; far jump to flush CPU queue after transition to real mode
4035 JMP_AP(0xf000, real_mode
)
4038 ;; restore IDT to normal real
-mode defaults
4040 lidt
[rmode_IDT_info
]
4042 // restore SS:SP from the BDA
4050 set_enable_a20(prev_a20_enable
);
4052 // turn back on interrupts
4063 // Get the amount of extended memory (above 1M)
4065 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4068 regs
.u
.r8
.al
= inb_cmos(0x30);
4069 regs
.u
.r8
.ah
= inb_cmos(0x31);
4071 // According to Ralf Brown's interrupt the limit should be 15M,
4072 // but real machines mostly return max. 63M.
4073 if(regs
.u
.r16
.ax
> 0xffc0)
4074 regs
.u
.r16
.ax
= 0xffc0;
4081 /* Device busy interrupt. Called by Int 16h when no key available */
4085 /* Interrupt complete. Called by Int 16h when key becomes available */
4089 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4091 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4097 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4102 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
4112 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
4114 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4118 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4119 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4121 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4126 #if BX_USE_PS2_MOUSE
4128 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
4129 pusha_regs_t regs
; // REGS pushed via pusha
4130 Bit16u ES
, DS
, FLAGS
;
4132 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4133 Bit8u mouse_flags_1
, mouse_flags_2
;
4134 Bit16u mouse_driver_seg
;
4135 Bit16u mouse_driver_offset
;
4136 Bit8u comm_byte
, prev_command_byte
;
4137 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
4139 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4141 switch (regs
.u
.r8
.ah
) {
4143 // Return Codes status in AH
4144 // =========================
4146 // 01: invalid subfunction (AL > 7)
4147 // 02: invalid input value (out of allowable range)
4148 // 03: interface error
4149 // 04: resend command received from mouse controller,
4150 // device driver should attempt command again
4151 // 05: cannot enable mouse, since no far call has been installed
4152 // 80/86: mouse service not implemented
4154 switch (regs
.u
.r8
.al
) {
4155 case 0: // Disable/Enable Mouse
4156 BX_DEBUG_INT15("case 0:\n");
4157 switch (regs
.u
.r8
.bh
) {
4158 case 0: // Disable Mouse
4159 BX_DEBUG_INT15("case 0: disable mouse\n");
4160 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4161 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
4163 ret
= get_mouse_data(&mouse_data1
);
4164 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
4177 case 1: // Enable Mouse
4178 BX_DEBUG_INT15("case 1: enable mouse\n");
4179 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4180 if ( (mouse_flags_2
& 0x80) == 0 ) {
4181 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4183 regs
.u
.r8
.ah
= 5; // no far call installed
4186 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4187 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
4189 ret
= get_mouse_data(&mouse_data1
);
4190 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
4191 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4201 default: // invalid subfunction
4202 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4204 regs
.u
.r8
.ah
= 1; // invalid subfunction
4209 case 1: // Reset Mouse
4210 case 5: // Initialize Mouse
4211 BX_DEBUG_INT15("case 1 or 5:\n");
4212 if (regs
.u
.r8
.al
== 5) {
4213 if (regs
.u
.r8
.bh
!= 3) {
4215 regs
.u
.r8
.ah
= 0x02; // invalid input
4218 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4219 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
4220 mouse_flags_1
= 0x00;
4221 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4222 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4225 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4226 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
4228 ret
= get_mouse_data(&mouse_data3
);
4229 // if no mouse attached, it will return RESEND
4230 if (mouse_data3
== 0xfe) {
4234 if (mouse_data3
!= 0xfa)
4235 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
4237 ret
= get_mouse_data(&mouse_data1
);
4239 ret
= get_mouse_data(&mouse_data2
);
4241 // turn IRQ12 and packet generation on
4242 enable_mouse_int_and_events();
4245 regs
.u
.r8
.bl
= mouse_data1
;
4246 regs
.u
.r8
.bh
= mouse_data2
;
4258 case 2: // Set Sample Rate
4259 BX_DEBUG_INT15("case 2:\n");
4260 switch (regs
.u
.r8
.bh
) {
4261 case 0: mouse_data1
= 10; break; // 10 reports/sec
4262 case 1: mouse_data1
= 20; break; // 20 reports/sec
4263 case 2: mouse_data1
= 40; break; // 40 reports/sec
4264 case 3: mouse_data1
= 60; break; // 60 reports/sec
4265 case 4: mouse_data1
= 80; break; // 80 reports/sec
4266 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
4267 case 6: mouse_data1
= 200; break; // 200 reports/sec
4268 default: mouse_data1
= 0;
4270 if (mouse_data1
> 0) {
4271 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
4273 ret
= get_mouse_data(&mouse_data2
);
4274 ret
= send_to_mouse_ctrl(mouse_data1
);
4275 ret
= get_mouse_data(&mouse_data2
);
4281 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4286 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4290 case 3: // Set Resolution
4291 BX_DEBUG_INT15("case 3:\n");
4293 // 0 = 25 dpi, 1 count per millimeter
4294 // 1 = 50 dpi, 2 counts per millimeter
4295 // 2 = 100 dpi, 4 counts per millimeter
4296 // 3 = 200 dpi, 8 counts per millimeter
4297 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4298 if (regs
.u
.r8
.bh
< 4) {
4299 ret
= send_to_mouse_ctrl(0xE8); // set resolution command
4301 ret
= get_mouse_data(&mouse_data1
);
4302 if (mouse_data1
!= 0xfa)
4303 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4304 ret
= send_to_mouse_ctrl(regs
.u
.r8
.bh
);
4305 ret
= get_mouse_data(&mouse_data1
);
4306 if (mouse_data1
!= 0xfa)
4307 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4313 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4318 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4320 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4323 case 4: // Get Device ID
4324 BX_DEBUG_INT15("case 4:\n");
4325 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4326 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
4328 ret
= get_mouse_data(&mouse_data1
);
4329 ret
= get_mouse_data(&mouse_data2
);
4332 regs
.u
.r8
.bh
= mouse_data2
;
4336 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4340 case 6: // Return Status & Set Scaling Factor...
4341 BX_DEBUG_INT15("case 6:\n");
4342 switch (regs
.u
.r8
.bh
) {
4343 case 0: // Return Status
4344 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4345 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
4347 ret
= get_mouse_data(&mouse_data1
);
4348 if (mouse_data1
!= 0xfa)
4349 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
4351 ret
= get_mouse_data(&mouse_data1
);
4353 ret
= get_mouse_data(&mouse_data2
);
4355 ret
= get_mouse_data(&mouse_data3
);
4359 regs
.u
.r8
.bl
= mouse_data1
;
4360 regs
.u
.r8
.cl
= mouse_data2
;
4361 regs
.u
.r8
.dl
= mouse_data3
;
4362 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4373 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4376 case 1: // Set Scaling Factor to 1:1
4377 case 2: // Set Scaling Factor to 2:1
4378 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4379 if (regs
.u
.r8
.bh
== 1) {
4380 ret
= send_to_mouse_ctrl(0xE6);
4382 ret
= send_to_mouse_ctrl(0xE7);
4385 get_mouse_data(&mouse_data1
);
4386 ret
= (mouse_data1
!= 0xFA);
4394 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4396 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
4400 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
4404 case 7: // Set Mouse Handler Address
4405 BX_DEBUG_INT15("case 7:\n");
4406 mouse_driver_seg
= ES
;
4407 mouse_driver_offset
= regs
.u
.r16
.bx
;
4408 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
4409 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
4410 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4411 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
4412 /* remove handler */
4413 if ( (mouse_flags_2
& 0x80) != 0 ) {
4414 mouse_flags_2
&= ~0x80;
4415 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4419 /* install handler */
4420 mouse_flags_2
|= 0x80;
4422 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4428 BX_DEBUG_INT15("case default:\n");
4429 regs
.u
.r8
.ah
= 1; // invalid function
4435 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4436 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4438 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4442 #endif // BX_USE_PS2_MOUSE
4445 void set_e820_range(ES
, DI
, start
, end
, type
)
4452 write_word(ES
, DI
, start
);
4453 write_word(ES
, DI
+2, start
>> 16);
4454 write_word(ES
, DI
+4, 0x00);
4455 write_word(ES
, DI
+6, 0x00);
4458 write_word(ES
, DI
+8, end
);
4459 write_word(ES
, DI
+10, end
>> 16);
4460 write_word(ES
, DI
+12, 0x0000);
4461 write_word(ES
, DI
+14, 0x0000);
4463 write_word(ES
, DI
+16, type
);
4464 write_word(ES
, DI
+18, 0x0);
4468 int15_function32(regs
, ES
, DS
, FLAGS
)
4469 pushad_regs_t regs
; // REGS pushed via pushad
4470 Bit16u ES
, DS
, FLAGS
;
4472 Bit32u extended_memory_size
=0; // 64bits long
4475 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4477 switch (regs
.u
.r8
.ah
) {
4479 // Wait for CX:DX microseconds. currently using the
4480 // refresh request port 0x61 bit4, toggling every 15usec
4488 ;; Get the count in eax
4491 mov ax
, _int15_function32
.CX
[bx
]
4494 mov ax
, _int15_function32
.DX
[bx
]
4496 ;; convert to numbers of
15usec ticks
4502 ;; wait
for ecx number of refresh requests
4523 switch(regs
.u
.r8
.al
)
4525 case 0x20: // coded by osmaker aka K.J.
4526 if(regs
.u
.r32
.edx
== 0x534D4150)
4528 extended_memory_size
= inb_cmos(0x35);
4529 extended_memory_size
<<= 8;
4530 extended_memory_size
|= inb_cmos(0x34);
4531 extended_memory_size
*= 64;
4532 // greater than EFF00000???
4533 if(extended_memory_size
> 0x3bc000) {
4534 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4536 extended_memory_size
*= 1024;
4537 extended_memory_size
+= (16L * 1024 * 1024);
4539 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4540 extended_memory_size
= inb_cmos(0x31);
4541 extended_memory_size
<<= 8;
4542 extended_memory_size
|= inb_cmos(0x30);
4543 extended_memory_size
*= 1024;
4544 extended_memory_size
+= (1L * 1024 * 1024);
4547 switch(regs
.u
.r16
.bx
)
4550 set_e820_range(ES
, regs
.u
.r16
.di
,
4551 0x0000000L
, 0x0009f000L
, 1);
4553 regs
.u
.r32
.eax
= 0x534D4150;
4554 regs
.u
.r32
.ecx
= 0x14;
4559 set_e820_range(ES
, regs
.u
.r16
.di
,
4560 0x0009f000L
, 0x000a0000L
, 2);
4562 regs
.u
.r32
.eax
= 0x534D4150;
4563 regs
.u
.r32
.ecx
= 0x14;
4568 set_e820_range(ES
, regs
.u
.r16
.di
,
4569 0x000e8000L
, 0x00100000L
, 2);
4571 regs
.u
.r32
.eax
= 0x534D4150;
4572 regs
.u
.r32
.ecx
= 0x14;
4578 set_e820_range(ES
, regs
.u
.r16
.di
,
4580 extended_memory_size
- ACPI_DATA_SIZE
, 1);
4583 set_e820_range(ES
, regs
.u
.r16
.di
,
4585 extended_memory_size
, 1);
4588 regs
.u
.r32
.eax
= 0x534D4150;
4589 regs
.u
.r32
.ecx
= 0x14;
4594 set_e820_range(ES
, regs
.u
.r16
.di
,
4595 extended_memory_size
- ACPI_DATA_SIZE
,
4596 extended_memory_size
, 3); // ACPI RAM
4598 regs
.u
.r32
.eax
= 0x534D4150;
4599 regs
.u
.r32
.ecx
= 0x14;
4604 /* 256KB BIOS area at the end of 4 GB */
4605 set_e820_range(ES
, regs
.u
.r16
.di
,
4606 0xfffc0000L
, 0x00000000L
, 2);
4608 regs
.u
.r32
.eax
= 0x534D4150;
4609 regs
.u
.r32
.ecx
= 0x14;
4612 default: /* AX=E820, DX=534D4150, BX unrecognized */
4613 goto int15_unimplemented
;
4617 // if DX != 0x534D4150)
4618 goto int15_unimplemented
;
4623 // do we have any reason to fail here ?
4626 // my real system sets ax and bx to 0
4627 // this is confirmed by Ralph Brown list
4628 // but syslinux v1.48 is known to behave
4629 // strangely if ax is set to 0
4630 // regs.u.r16.ax = 0;
4631 // regs.u.r16.bx = 0;
4633 // Get the amount of extended memory (above 1M)
4634 regs
.u
.r8
.cl
= inb_cmos(0x30);
4635 regs
.u
.r8
.ch
= inb_cmos(0x31);
4638 if(regs
.u
.r16
.cx
> 0x3c00)
4640 regs
.u
.r16
.cx
= 0x3c00;
4643 // Get the amount of extended memory above 16M in 64k blocs
4644 regs
.u
.r8
.dl
= inb_cmos(0x34);
4645 regs
.u
.r8
.dh
= inb_cmos(0x35);
4647 // Set configured memory equal to extended memory
4648 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4649 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4651 default: /* AH=0xE8?? but not implemented */
4652 goto int15_unimplemented
;
4655 int15_unimplemented
:
4656 // fall into the default
4658 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4659 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4661 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4667 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4668 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4670 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4671 Bit16u kbd_code
, max
;
4673 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4675 shift_flags
= read_byte(0x0040, 0x17);
4676 led_flags
= read_byte(0x0040, 0x97);
4677 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4682 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4683 if ((inb(0x60) == 0xfa)) {
4685 led_flags
|= ((shift_flags
>> 4) & 0x07);
4686 outb(0x60, led_flags
& 0x07);
4687 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4689 write_byte(0x0040, 0x97, led_flags
);
4697 case 0x00: /* read keyboard input */
4699 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4700 BX_PANIC("KBD: int16h: out of keyboard input\n");
4702 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4703 else if (ascii_code
== 0xE0) ascii_code
= 0;
4704 AX
= (scan_code
<< 8) | ascii_code
;
4707 case 0x01: /* check keyboard status */
4708 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4712 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4713 else if (ascii_code
== 0xE0) ascii_code
= 0;
4714 AX
= (scan_code
<< 8) | ascii_code
;
4718 case 0x02: /* get shift flag status */
4719 shift_flags
= read_byte(0x0040, 0x17);
4720 SET_AL(shift_flags
);
4723 case 0x05: /* store key-stroke into buffer */
4724 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4732 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4733 // bit Bochs Description
4735 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4736 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4737 // 4 1 INT 16/AH=0Ah supported
4738 // 3 0 INT 16/AX=0306h supported
4739 // 2 0 INT 16/AX=0305h supported
4740 // 1 0 INT 16/AX=0304h supported
4741 // 0 0 INT 16/AX=0300h supported
4746 case 0x0A: /* GET KEYBOARD ID */
4752 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4754 if ((inb(0x60) == 0xfa)) {
4757 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4760 kbd_code
|= (inb(0x60) << 8);
4762 } while (--count
>0);
4768 case 0x10: /* read MF-II keyboard input */
4770 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4771 BX_PANIC("KBD: int16h: out of keyboard input\n");
4773 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4774 AX
= (scan_code
<< 8) | ascii_code
;
4777 case 0x11: /* check MF-II keyboard status */
4778 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4782 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4783 AX
= (scan_code
<< 8) | ascii_code
;
4787 case 0x12: /* get extended keyboard status */
4788 shift_flags
= read_byte(0x0040, 0x17);
4789 SET_AL(shift_flags
);
4790 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4791 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4792 SET_AH(shift_flags
);
4793 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4796 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4797 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4800 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4801 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4805 if (GET_AL() == 0x08)
4806 SET_AH(0x02); // unsupported, aka normal keyboard
4809 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4814 dequeue_key(scan_code
, ascii_code
, incr
)
4819 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4824 buffer_start
= 0x001E;
4825 buffer_end
= 0x003E;
4827 buffer_start
= read_word(0x0040, 0x0080);
4828 buffer_end
= read_word(0x0040, 0x0082);
4831 buffer_head
= read_word(0x0040, 0x001a);
4832 buffer_tail
= read_word(0x0040, 0x001c);
4834 if (buffer_head
!= buffer_tail
) {
4836 acode
= read_byte(0x0040, buffer_head
);
4837 scode
= read_byte(0x0040, buffer_head
+1);
4838 write_byte(ss
, ascii_code
, acode
);
4839 write_byte(ss
, scan_code
, scode
);
4843 if (buffer_head
>= buffer_end
)
4844 buffer_head
= buffer_start
;
4845 write_word(0x0040, 0x001a, buffer_head
);
4854 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4857 inhibit_mouse_int_and_events()
4859 Bit8u command_byte
, prev_command_byte
;
4861 // Turn off IRQ generation and aux data line
4862 if ( inb(0x64) & 0x02 )
4863 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4864 outb(0x64, 0x20); // get command byte
4865 while ( (inb(0x64) & 0x01) != 0x01 );
4866 prev_command_byte
= inb(0x60);
4867 command_byte
= prev_command_byte
;
4868 //while ( (inb(0x64) & 0x02) );
4869 if ( inb(0x64) & 0x02 )
4870 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4871 command_byte
&= 0xfd; // turn off IRQ 12 generation
4872 command_byte
|= 0x20; // disable mouse serial clock line
4873 outb(0x64, 0x60); // write command byte
4874 outb(0x60, command_byte
);
4875 return(prev_command_byte
);
4879 enable_mouse_int_and_events()
4883 // Turn on IRQ generation and aux data line
4884 if ( inb(0x64) & 0x02 )
4885 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4886 outb(0x64, 0x20); // get command byte
4887 while ( (inb(0x64) & 0x01) != 0x01 );
4888 command_byte
= inb(0x60);
4889 //while ( (inb(0x64) & 0x02) );
4890 if ( inb(0x64) & 0x02 )
4891 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4892 command_byte
|= 0x02; // turn on IRQ 12 generation
4893 command_byte
&= 0xdf; // enable mouse serial clock line
4894 outb(0x64, 0x60); // write command byte
4895 outb(0x60, command_byte
);
4899 send_to_mouse_ctrl(sendbyte
)
4904 // wait for chance to write to ctrl
4905 if ( inb(0x64) & 0x02 )
4906 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4908 outb(0x60, sendbyte
);
4914 get_mouse_data(data
)
4920 while ( (inb(0x64) & 0x21) != 0x21 ) {
4923 response
= inb(0x60);
4926 write_byte(ss
, data
, response
);
4931 set_kbd_command_byte(command_byte
)
4934 if ( inb(0x64) & 0x02 )
4935 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4938 outb(0x64, 0x60); // write command byte
4939 outb(0x60, command_byte
);
4943 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4944 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4946 Bit8u scancode
, asciicode
, shift_flags
;
4947 Bit8u mf2_flags
, mf2_state
;
4950 // DS has been set to F000 before call
4954 scancode
= GET_AL();
4956 if (scancode
== 0) {
4957 BX_INFO("KBD: int09 handler: AL=0\n");
4962 shift_flags
= read_byte(0x0040, 0x17);
4963 mf2_flags
= read_byte(0x0040, 0x18);
4964 mf2_state
= read_byte(0x0040, 0x96);
4968 case 0x3a: /* Caps Lock press */
4969 shift_flags
^= 0x40;
4970 write_byte(0x0040, 0x17, shift_flags
);
4972 write_byte(0x0040, 0x18, mf2_flags
);
4974 case 0xba: /* Caps Lock release */
4976 write_byte(0x0040, 0x18, mf2_flags
);
4979 case 0x2a: /* L Shift press */
4980 shift_flags
|= 0x02;
4981 write_byte(0x0040, 0x17, shift_flags
);
4983 case 0xaa: /* L Shift release */
4984 shift_flags
&= ~0x02;
4985 write_byte(0x0040, 0x17, shift_flags
);
4988 case 0x36: /* R Shift press */
4989 shift_flags
|= 0x01;
4990 write_byte(0x0040, 0x17, shift_flags
);
4992 case 0xb6: /* R Shift release */
4993 shift_flags
&= ~0x01;
4994 write_byte(0x0040, 0x17, shift_flags
);
4997 case 0x1d: /* Ctrl press */
4998 if ((mf2_state
& 0x01) == 0) {
4999 shift_flags
|= 0x04;
5000 write_byte(0x0040, 0x17, shift_flags
);
5001 if (mf2_state
& 0x02) {
5003 write_byte(0x0040, 0x96, mf2_state
);
5006 write_byte(0x0040, 0x18, mf2_flags
);
5010 case 0x9d: /* Ctrl release */
5011 if ((mf2_state
& 0x01) == 0) {
5012 shift_flags
&= ~0x04;
5013 write_byte(0x0040, 0x17, shift_flags
);
5014 if (mf2_state
& 0x02) {
5016 write_byte(0x0040, 0x96, mf2_state
);
5019 write_byte(0x0040, 0x18, mf2_flags
);
5024 case 0x38: /* Alt press */
5025 shift_flags
|= 0x08;
5026 write_byte(0x0040, 0x17, shift_flags
);
5027 if (mf2_state
& 0x02) {
5029 write_byte(0x0040, 0x96, mf2_state
);
5032 write_byte(0x0040, 0x18, mf2_flags
);
5035 case 0xb8: /* Alt release */
5036 shift_flags
&= ~0x08;
5037 write_byte(0x0040, 0x17, shift_flags
);
5038 if (mf2_state
& 0x02) {
5040 write_byte(0x0040, 0x96, mf2_state
);
5043 write_byte(0x0040, 0x18, mf2_flags
);
5047 case 0x45: /* Num Lock press */
5048 if ((mf2_state
& 0x03) == 0) {
5050 write_byte(0x0040, 0x18, mf2_flags
);
5051 shift_flags
^= 0x20;
5052 write_byte(0x0040, 0x17, shift_flags
);
5055 case 0xc5: /* Num Lock release */
5056 if ((mf2_state
& 0x03) == 0) {
5058 write_byte(0x0040, 0x18, mf2_flags
);
5062 case 0x46: /* Scroll Lock press */
5064 write_byte(0x0040, 0x18, mf2_flags
);
5065 shift_flags
^= 0x10;
5066 write_byte(0x0040, 0x17, shift_flags
);
5069 case 0xc6: /* Scroll Lock release */
5071 write_byte(0x0040, 0x18, mf2_flags
);
5075 if (scancode
& 0x80) {
5076 break; /* toss key releases ... */
5078 if (scancode
> MAX_SCAN_CODE
) {
5079 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
5082 if (shift_flags
& 0x08) { /* ALT */
5083 asciicode
= scan_to_scanascii
[scancode
].alt
;
5084 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
5085 } else if (shift_flags
& 0x04) { /* CONTROL */
5086 asciicode
= scan_to_scanascii
[scancode
].control
;
5087 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
5088 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
5089 /* extended keys handling */
5091 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5092 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
5093 /* check if lock state should be ignored
5094 * because a SHIFT key are pressed */
5096 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
5097 asciicode
= scan_to_scanascii
[scancode
].normal
;
5098 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5100 asciicode
= scan_to_scanascii
[scancode
].shift
;
5101 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
5104 /* check if lock is on */
5105 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
5106 asciicode
= scan_to_scanascii
[scancode
].shift
;
5107 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
5109 asciicode
= scan_to_scanascii
[scancode
].normal
;
5110 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
5113 if (scancode
==0 && asciicode
==0) {
5114 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5116 enqueue_key(scancode
, asciicode
);
5119 if ((scancode
& 0x7f) != 0x1d) {
5123 write_byte(0x0040, 0x96, mf2_state
);
5127 enqueue_key(scan_code
, ascii_code
)
5128 Bit8u scan_code
, ascii_code
;
5130 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
5133 buffer_start
= 0x001E;
5134 buffer_end
= 0x003E;
5136 buffer_start
= read_word(0x0040, 0x0080);
5137 buffer_end
= read_word(0x0040, 0x0082);
5140 buffer_head
= read_word(0x0040, 0x001A);
5141 buffer_tail
= read_word(0x0040, 0x001C);
5143 temp_tail
= buffer_tail
;
5145 if (buffer_tail
>= buffer_end
)
5146 buffer_tail
= buffer_start
;
5148 if (buffer_tail
== buffer_head
) {
5152 write_byte(0x0040, temp_tail
, ascii_code
);
5153 write_byte(0x0040, temp_tail
+1, scan_code
);
5154 write_word(0x0040, 0x001C, buffer_tail
);
5160 int74_function(make_farcall
, Z
, Y
, X
, status
)
5161 Bit16u make_farcall
, Z
, Y
, X
, status
;
5163 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5164 Bit8u in_byte
, index
, package_count
;
5165 Bit8u mouse_flags_1
, mouse_flags_2
;
5167 BX_DEBUG_INT74("entering int74_function\n");
5170 in_byte
= inb(0x64);
5171 if ( (in_byte
& 0x21) != 0x21 ) {
5174 in_byte
= inb(0x60);
5175 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
5177 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
5178 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
5180 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
5184 package_count
= mouse_flags_2
& 0x07;
5185 index
= mouse_flags_1
& 0x07;
5186 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
5188 if ( (index
+1) >= package_count
) {
5189 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5190 status
= read_byte(ebda_seg
, 0x0028 + 0);
5191 X
= read_byte(ebda_seg
, 0x0028 + 1);
5192 Y
= read_byte(ebda_seg
, 0x0028 + 2);
5195 // check if far call handler installed
5196 if (mouse_flags_2
& 0x80)
5202 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
5205 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5210 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5211 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5213 Bit32u lba_low
, lba_high
;
5214 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5215 Bit16u cylinder
, head
, sector
;
5216 Bit16u segment
, offset
;
5217 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
5219 Bit8u device
, status
;
5221 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5223 write_byte(0x0040, 0x008e, 0); // clear completion flag
5225 // basic check : device has to be defined
5226 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
5227 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5231 // Get the ata channel
5232 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
5234 // basic check : device has to be valid
5235 if (device
>= BX_MAX_ATA_DEVICES
) {
5236 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5242 case 0x00: /* disk controller reset */
5247 case 0x01: /* read disk status */
5248 status
= read_byte(0x0040, 0x0074);
5250 SET_DISK_RET_STATUS(0);
5251 /* set CF if error status read */
5252 if (status
) goto int13_fail_nostatus
;
5253 else goto int13_success_noah
;
5256 case 0x02: // read disk sectors
5257 case 0x03: // write disk sectors
5258 case 0x04: // verify disk sectors
5261 cylinder
= GET_CH();
5262 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5263 sector
= (GET_CL() & 0x3f);
5269 if ((count
> 128) || (count
== 0) || (sector
== 0)) {
5270 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5274 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5275 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5276 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5278 // sanity check on cyl heads, sec
5279 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
5280 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
5285 if ( GET_AH() == 0x04 ) goto int13_success
;
5287 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5288 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5290 // if needed, translate lchs to lba, and execute command
5291 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
5292 lba_low
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
5294 sector
= 0; // this forces the command to be lba
5297 if ( GET_AH() == 0x02 )
5298 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
);
5300 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba_low
, lba_high
, segment
, offset
);
5302 // Set nb of sector transferred
5303 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
5306 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5308 goto int13_fail_noah
;
5314 case 0x05: /* format disk track */
5315 BX_INFO("format disk track called\n");
5320 case 0x08: /* read disk drive parameters */
5322 // Get logical geometry from table
5323 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5324 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5325 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5326 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
5328 nlc
= nlc
- 2; /* 0 based , last sector not used */
5331 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
5333 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
5335 // FIXME should set ES & DI
5340 case 0x10: /* check drive ready */
5341 // should look at 40:8E also???
5343 // Read the status from controller
5344 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
5345 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
5350 goto int13_fail_noah
;
5354 case 0x15: /* read disk drive size */
5356 // Get logical geometry from table
5357 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
5358 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
5359 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
5361 // Compute sector count seen by int13
5362 lba_low
= (Bit32u
)(nlc
- 1) * (Bit32u
)nlh
* (Bit32u
)nlspt
;
5364 DX
= lba_low
& 0xffff;
5366 SET_AH(3); // hard disk accessible
5367 goto int13_success_noah
;
5370 case 0x41: // IBM/MS installation check
5371 BX
=0xaa55; // install check
5372 SET_AH(0x30); // EDD 3.0
5373 CX
=0x0007; // ext disk access and edd, removable supported
5374 goto int13_success_noah
;
5377 case 0x42: // IBM/MS extended read
5378 case 0x43: // IBM/MS extended write
5379 case 0x44: // IBM/MS verify
5380 case 0x47: // IBM/MS extended seek
5382 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5383 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5384 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5386 // Get 32 msb lba and check
5387 lba_high
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5388 if (lba_high
> read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
) ) {
5389 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5393 // Get 32 lsb lba and check
5394 lba_low
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5395 if (lba_high
== read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
)
5396 && lba_low
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_low
) ) {
5397 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5401 // If verify or seek
5402 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5405 // Execute the command
5406 if ( GET_AH() == 0x42 )
5407 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba_low
, lba_high
, segment
, offset
);
5409 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba_low
, lba_high
, segment
, offset
);
5411 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
5412 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5415 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
5417 goto int13_fail_noah
;
5423 case 0x45: // IBM/MS lock/unlock drive
5424 case 0x49: // IBM/MS extended media change
5425 goto int13_success
; // Always success for HD
5428 case 0x46: // IBM/MS eject media
5429 SET_AH(0xb2); // Volume Not Removable
5430 goto int13_fail_noah
; // Always fail for HD
5433 case 0x48: // IBM/MS get drive parameters
5434 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
5436 // Buffer is too small
5444 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5445 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5446 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5447 lba_low
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_low
);
5448 lba_high
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors_high
);
5449 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5451 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5452 if (lba_high
|| (lba_low
/npspt
)/nph
> 0x3fff)
5454 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x00); // geometry is invalid
5455 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0x3fff);
5459 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5460 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5462 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5463 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5464 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba_low
);
5465 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, lba_high
);
5466 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5471 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5472 Bit16u iobase1
, iobase2
, options
;
5474 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5476 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5477 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5480 channel
= device
/ 2;
5481 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5482 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5483 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5484 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5485 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5487 options
= (translation
==ATA_TRANSLATION_NONE
?0:1)<<3; // chs translation
5488 options
|= (1<<4); // lba translation
5489 options
|= (mode
==ATA_MODE_PIO32
?1:0)<<7;
5490 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0)<<9;
5491 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0)<<9;
5493 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5494 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5495 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5496 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5497 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5498 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5499 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5500 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5501 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5502 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5504 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5506 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x10);
5509 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5510 checksum
= ~checksum
;
5511 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5516 Bit8u channel
, iface
, checksum
, i
;
5519 channel
= device
/ 2;
5520 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5521 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5523 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5524 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5525 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5526 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5527 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5529 if (iface
==ATA_IFACE_ISA
) {
5530 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5531 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5532 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5533 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5538 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5539 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5540 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5541 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5543 if (iface
==ATA_IFACE_ISA
) {
5544 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5545 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5546 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5551 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5552 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5553 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5554 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5557 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5558 checksum
= ~checksum
;
5559 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5565 case 0x4e: // // IBM/MS set hardware configuration
5566 // DMA, prefetch, PIO maximum not supported
5579 case 0x09: /* initialize drive parameters */
5580 case 0x0c: /* seek to specified cylinder */
5581 case 0x0d: /* alternate disk reset */
5582 case 0x11: /* recalibrate */
5583 case 0x14: /* controller internal diagnostic */
5584 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5588 case 0x0a: /* read disk sectors with ECC */
5589 case 0x0b: /* write disk sectors with ECC */
5590 case 0x18: // set media type for format
5591 case 0x50: // IBM/MS send packet command
5593 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5599 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5601 SET_DISK_RET_STATUS(GET_AH());
5602 int13_fail_nostatus
:
5603 SET_CF(); // error occurred
5607 SET_AH(0x00); // no error
5609 SET_DISK_RET_STATUS(0x00);
5610 CLEAR_CF(); // no error
5614 // ---------------------------------------------------------------------------
5615 // Start of int13 for cdrom
5616 // ---------------------------------------------------------------------------
5619 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5620 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5622 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5623 Bit8u device
, status
, locks
;
5626 Bit16u count
, segment
, offset
, i
, size
;
5628 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5630 SET_DISK_RET_STATUS(0x00);
5632 /* basic check : device should be 0xE0+ */
5633 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5634 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5638 // Get the ata channel
5639 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5641 /* basic check : device has to be valid */
5642 if (device
>= BX_MAX_ATA_DEVICES
) {
5643 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5649 // all those functions return SUCCESS
5650 case 0x00: /* disk controller reset */
5651 case 0x09: /* initialize drive parameters */
5652 case 0x0c: /* seek to specified cylinder */
5653 case 0x0d: /* alternate disk reset */
5654 case 0x10: /* check drive ready */
5655 case 0x11: /* recalibrate */
5656 case 0x14: /* controller internal diagnostic */
5657 case 0x16: /* detect disk change */
5661 // all those functions return disk write-protected
5662 case 0x03: /* write disk sectors */
5663 case 0x05: /* format disk track */
5664 case 0x43: // IBM/MS extended write
5666 goto int13_fail_noah
;
5669 case 0x01: /* read disk status */
5670 status
= read_byte(0x0040, 0x0074);
5672 SET_DISK_RET_STATUS(0);
5674 /* set CF if error status read */
5675 if (status
) goto int13_fail_nostatus
;
5676 else goto int13_success_noah
;
5679 case 0x15: /* read disk drive size */
5681 goto int13_fail_noah
;
5684 case 0x41: // IBM/MS installation check
5685 BX
=0xaa55; // install check
5686 SET_AH(0x30); // EDD 2.1
5687 CX
=0x0007; // ext disk access, removable and edd
5688 goto int13_success_noah
;
5691 case 0x42: // IBM/MS extended read
5692 case 0x44: // IBM/MS verify sectors
5693 case 0x47: // IBM/MS extended seek
5695 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5696 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5697 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5699 // Can't use 64 bits lba
5700 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5702 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5707 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5709 // If verify or seek
5710 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5713 memsetb(get_SS(),atacmd
,0,12);
5714 atacmd
[0]=0x28; // READ command
5715 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5716 atacmd
[8]=(count
& 0x00ff); // Sectors
5717 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5718 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5719 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5720 atacmd
[5]=(lba
& 0x000000ff);
5721 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5723 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5724 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5727 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5729 goto int13_fail_noah
;
5735 case 0x45: // IBM/MS lock/unlock drive
5736 if (GET_AL() > 2) goto int13_fail
;
5738 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5742 if (locks
== 0xff) {
5745 goto int13_fail_noah
;
5747 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5751 if (locks
== 0x00) {
5754 goto int13_fail_noah
;
5756 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5757 SET_AL(locks
==0?0:1);
5760 SET_AL(locks
==0?0:1);
5766 case 0x46: // IBM/MS eject media
5767 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5770 SET_AH(0xb1); // media locked
5771 goto int13_fail_noah
;
5773 // FIXME should handle 0x31 no media in device
5774 // FIXME should handle 0xb5 valid request failed
5776 // Call removable media eject
5783 mov _int13_cdrom
.status
+ 2[bp
], ah
5784 jnc int13_cdrom_rme_end
5785 mov _int13_cdrom
.status
, #1
5786 int13_cdrom_rme_end
:
5791 SET_AH(0xb1); // media locked
5792 goto int13_fail_noah
;
5798 case 0x48: // IBM/MS get drive parameters
5799 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5801 // Buffer is too small
5807 Bit16u cylinders
, heads
, spt
, blksize
;
5809 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5811 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5812 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5813 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5814 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5815 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5816 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5817 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5818 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5823 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5824 Bit16u iobase1
, iobase2
, options
;
5826 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5828 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5829 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5832 channel
= device
/ 2;
5833 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5834 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5835 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5836 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5838 // FIXME atapi device
5839 options
= (1<<4); // lba translation
5840 options
|= (1<<5); // removable device
5841 options
|= (1<<6); // atapi device
5842 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5844 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5845 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
+ ATA_CB_DC
);
5846 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5847 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5848 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5849 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5850 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5851 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5852 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5853 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5854 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5857 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, ((Bit8u
*)(&EbdaData
->ata
.dpte
)) + i
);
5858 checksum
= ~checksum
;
5859 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5864 Bit8u channel
, iface
, checksum
, i
;
5867 channel
= device
/ 2;
5868 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5869 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5871 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5872 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5873 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5874 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5875 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5877 if (iface
==ATA_IFACE_ISA
) {
5878 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5879 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5880 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5881 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5886 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5887 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5888 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5889 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5891 if (iface
==ATA_IFACE_ISA
) {
5892 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5893 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5894 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5899 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5900 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5901 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5902 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5905 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5906 checksum
= ~checksum
;
5907 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5913 case 0x49: // IBM/MS extended media change
5914 // always send changed ??
5916 goto int13_fail_nostatus
;
5919 case 0x4e: // // IBM/MS set hardware configuration
5920 // DMA, prefetch, PIO maximum not supported
5933 // all those functions return unimplemented
5934 case 0x02: /* read sectors */
5935 case 0x04: /* verify sectors */
5936 case 0x08: /* read disk drive parameters */
5937 case 0x0a: /* read disk sectors with ECC */
5938 case 0x0b: /* write disk sectors with ECC */
5939 case 0x18: /* set media type for format */
5940 case 0x50: // ? - send packet command
5942 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5948 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5950 SET_DISK_RET_STATUS(GET_AH());
5951 int13_fail_nostatus
:
5952 SET_CF(); // error occurred
5956 SET_AH(0x00); // no error
5958 SET_DISK_RET_STATUS(0x00);
5959 CLEAR_CF(); // no error
5963 // ---------------------------------------------------------------------------
5964 // End of int13 for cdrom
5965 // ---------------------------------------------------------------------------
5967 #if BX_ELTORITO_BOOT
5968 // ---------------------------------------------------------------------------
5969 // Start of int13 for eltorito functions
5970 // ---------------------------------------------------------------------------
5973 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5974 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5976 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5978 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5979 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5983 // FIXME ElTorito Various. Should be implemented
5984 case 0x4a: // ElTorito - Initiate disk emu
5985 case 0x4c: // ElTorito - Initiate disk emu and boot
5986 case 0x4d: // ElTorito - Return Boot catalog
5987 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5991 case 0x4b: // ElTorito - Terminate disk emu
5992 // FIXME ElTorito Hardcoded
5993 write_byte(DS
,SI
+0x00,0x13);
5994 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5995 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5996 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5997 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5998 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5999 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
6000 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
6001 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
6002 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
6003 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
6004 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
6006 // If we have to terminate emulation
6007 if(GET_AL() == 0x00) {
6008 // FIXME ElTorito Various. Should be handled accordingly to spec
6009 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
6016 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6022 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6023 SET_DISK_RET_STATUS(GET_AH());
6024 SET_CF(); // error occurred
6028 SET_AH(0x00); // no error
6029 SET_DISK_RET_STATUS(0x00);
6030 CLEAR_CF(); // no error
6034 // ---------------------------------------------------------------------------
6035 // End of int13 for eltorito functions
6036 // ---------------------------------------------------------------------------
6038 // ---------------------------------------------------------------------------
6039 // Start of int13 when emulating a device from the cd
6040 // ---------------------------------------------------------------------------
6043 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6044 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6046 Bit16u ebda_seg
=read_word(0x0040,0x000E);
6047 Bit8u device
, status
;
6048 Bit16u vheads
, vspt
, vcylinders
;
6049 Bit16u head
, sector
, cylinder
, nbsectors
;
6050 Bit32u vlba
, ilba
, slba
, elba
;
6051 Bit16u before
, segment
, offset
;
6054 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6056 /* at this point, we are emulating a floppy/harddisk */
6058 // Recompute the device number
6059 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
6060 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
6062 SET_DISK_RET_STATUS(0x00);
6064 /* basic checks : emulation should be active, dl should equal the emulated drive */
6065 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
6066 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
6067 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6073 // all those functions return SUCCESS
6074 case 0x00: /* disk controller reset */
6075 case 0x09: /* initialize drive parameters */
6076 case 0x0c: /* seek to specified cylinder */
6077 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6078 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6079 case 0x11: /* recalibrate */
6080 case 0x14: /* controller internal diagnostic */
6081 case 0x16: /* detect disk change */
6085 // all those functions return disk write-protected
6086 case 0x03: /* write disk sectors */
6087 case 0x05: /* format disk track */
6089 goto int13_fail_noah
;
6092 case 0x01: /* read disk status */
6093 status
=read_byte(0x0040, 0x0074);
6095 SET_DISK_RET_STATUS(0);
6097 /* set CF if error status read */
6098 if (status
) goto int13_fail_nostatus
;
6099 else goto int13_success_noah
;
6102 case 0x02: // read disk sectors
6103 case 0x04: // verify disk sectors
6104 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
6105 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
6106 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
6108 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
6110 sector
= GET_CL() & 0x003f;
6111 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6113 nbsectors
= GET_AL();
6117 // no sector to read ?
6118 if(nbsectors
==0) goto int13_success
;
6120 // sanity checks sco openserver needs this!
6122 || (cylinder
>= vcylinders
)
6123 || (head
>= vheads
)) {
6127 // After controls, verify do nothing
6128 if (GET_AH() == 0x04) goto int13_success
;
6130 segment
= ES
+(BX
/ 16);
6133 // calculate the virtual lba inside the image
6134 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
6136 // In advance so we don't loose the count
6140 slba
= (Bit32u
)vlba
/4;
6141 before
= (Bit16u
)vlba
%4;
6144 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
6146 memsetb(get_SS(),atacmd
,0,12);
6147 atacmd
[0]=0x28; // READ command
6148 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
6149 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
6150 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
6151 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
6152 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
6153 atacmd
[5]=(ilba
+slba
& 0x000000ff);
6154 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
6155 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
6158 goto int13_fail_noah
;
6164 case 0x08: /* read disk drive parameters */
6165 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
6166 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
6167 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
6171 SET_CH( vcylinders
& 0xff );
6172 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
6174 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6175 // FIXME ElTorito Harddisk. should send the HD count
6177 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
6178 case 0x01: SET_BL( 0x02 ); break;
6179 case 0x02: SET_BL( 0x04 ); break;
6180 case 0x03: SET_BL( 0x06 ); break;
6186 mov ax
, #diskette_param_table2
6187 mov _int13_cdemu
.DI
+2[bp
], ax
6188 mov _int13_cdemu
.ES
+2[bp
], cs
6194 case 0x15: /* read disk drive size */
6195 // FIXME ElTorito Harddisk. What geometry to send ?
6197 goto int13_success_noah
;
6200 // all those functions return unimplemented
6201 case 0x0a: /* read disk sectors with ECC */
6202 case 0x0b: /* write disk sectors with ECC */
6203 case 0x18: /* set media type for format */
6204 case 0x41: // IBM/MS installation check
6205 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6206 case 0x42: // IBM/MS extended read
6207 case 0x43: // IBM/MS extended write
6208 case 0x44: // IBM/MS verify sectors
6209 case 0x45: // IBM/MS lock/unlock drive
6210 case 0x46: // IBM/MS eject media
6211 case 0x47: // IBM/MS extended seek
6212 case 0x48: // IBM/MS get drive parameters
6213 case 0x49: // IBM/MS extended media change
6214 case 0x4e: // ? - set hardware configuration
6215 case 0x50: // ? - send packet command
6217 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6223 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6225 SET_DISK_RET_STATUS(GET_AH());
6226 int13_fail_nostatus
:
6227 SET_CF(); // error occurred
6231 SET_AH(0x00); // no error
6233 SET_DISK_RET_STATUS(0x00);
6234 CLEAR_CF(); // no error
6238 // ---------------------------------------------------------------------------
6239 // End of int13 when emulating a device from the cd
6240 // ---------------------------------------------------------------------------
6242 #endif // BX_ELTORITO_BOOT
6244 #else //BX_USE_ATADRV
6247 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
6262 mov ax
,4[bp
] // cylinder
6264 mov bl
,6[bp
] // hd_heads
6267 mov bl
,8[bp
] // head
6269 mov bl
,10[bp
] // hd_sectors
6271 mov bl
,12[bp
] // sector
6300 int13_harddisk(EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6301 Bit16u EHAX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6303 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
6307 Bit16u max_cylinder
, cylinder
, total_sectors
;
6308 Bit16u hd_cylinders
;
6309 Bit8u hd_heads
, hd_sectors
;
6316 Bit16u count
, segment
, offset
;
6320 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6322 write_byte(0x0040, 0x008e, 0); // clear completion flag
6324 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6326 /* check how many disks first (cmos reg 0x12), return an error if
6327 drive not present */
6328 drive_map
= inb_cmos(0x12);
6329 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
6330 (((drive_map
& 0x0f)==0) ? 0 : 2);
6331 n_drives
= (drive_map
==0) ? 0 :
6332 ((drive_map
==3) ? 2 : 1);
6334 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6336 SET_DISK_RET_STATUS(0x01);
6337 SET_CF(); /* error occurred */
6343 case 0x00: /* disk controller reset */
6344 BX_DEBUG_INT13_HD("int13_f00\n");
6347 SET_DISK_RET_STATUS(0);
6348 set_diskette_ret_status(0);
6349 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6350 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6351 CLEAR_CF(); /* successful */
6355 case 0x01: /* read disk status */
6356 BX_DEBUG_INT13_HD("int13_f01\n");
6357 status
= read_byte(0x0040, 0x0074);
6359 SET_DISK_RET_STATUS(0);
6360 /* set CF if error status read */
6361 if (status
) SET_CF();
6366 case 0x04: // verify disk sectors
6367 case 0x02: // read disk sectors
6369 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6371 num_sectors
= GET_AL();
6372 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
6373 sector
= (GET_CL() & 0x3f);
6377 if (hd_cylinders
> 1024) {
6378 if (hd_cylinders
<= 2048) {
6381 else if (hd_cylinders
<= 4096) {
6384 else if (hd_cylinders
<= 8192) {
6387 else { // hd_cylinders <= 16384
6391 ax
= head
/ hd_heads
;
6392 cyl_mod
= ax
& 0xff;
6394 cylinder
|= cyl_mod
;
6397 if ( (cylinder
>= hd_cylinders
) ||
6398 (sector
> hd_sectors
) ||
6399 (head
>= hd_heads
) ) {
6401 SET_DISK_RET_STATUS(1);
6402 SET_CF(); /* error occurred */
6406 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6407 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6410 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6412 if ( GET_AH() == 0x04 ) {
6414 SET_DISK_RET_STATUS(0);
6419 status
= inb(0x1f7);
6420 if (status
& 0x80) {
6421 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6423 outb(0x01f2, num_sectors
);
6424 /* activate LBA? (tomv) */
6425 if (hd_heads
> 16) {
6426 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
6427 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
6430 outb(0x01f3, sector
);
6431 outb(0x01f4, cylinder
& 0x00ff);
6432 outb(0x01f5, cylinder
>> 8);
6433 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
6438 status
= inb(0x1f7);
6439 if ( !(status
& 0x80) ) break;
6442 if (status
& 0x01) {
6443 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6444 } else if ( !(status
& 0x08) ) {
6445 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6446 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6453 sti
;; enable higher priority interrupts
6458 ;; store temp bx in real DI
register
6461 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6464 ;; adjust
if there will be an overrun
6466 jbe i13_f02_no_adjust
6468 sub di
, #0x0200 ; sub 512 bytes from offset
6470 add ax
, #0x0020 ; add 512 to segment
6474 mov cx
, #0x0100 ;; counter (256 words = 512b)
6475 mov dx
, #0x01f0 ;; AT data read port
6478 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6481 ;; store real DI
register back to temp bx
6484 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6490 if (num_sectors
== 0) {
6491 status
= inb(0x1f7);
6492 if ( (status
& 0xc9) != 0x40 )
6493 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6497 status
= inb(0x1f7);
6498 if ( (status
& 0xc9) != 0x48 )
6499 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6505 SET_DISK_RET_STATUS(0);
6506 SET_AL(sector_count
);
6507 CLEAR_CF(); /* successful */
6512 case 0x03: /* write disk sectors */
6513 BX_DEBUG_INT13_HD("int13_f03\n");
6514 drive
= GET_ELDL ();
6515 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6517 num_sectors
= GET_AL();
6518 cylinder
= GET_CH();
6519 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6520 sector
= (GET_CL() & 0x3f);
6523 if (hd_cylinders
> 1024) {
6524 if (hd_cylinders
<= 2048) {
6527 else if (hd_cylinders
<= 4096) {
6530 else if (hd_cylinders
<= 8192) {
6533 else { // hd_cylinders <= 16384
6537 ax
= head
/ hd_heads
;
6538 cyl_mod
= ax
& 0xff;
6540 cylinder
|= cyl_mod
;
6543 if ( (cylinder
>= hd_cylinders
) ||
6544 (sector
> hd_sectors
) ||
6545 (head
>= hd_heads
) ) {
6547 SET_DISK_RET_STATUS(1);
6548 SET_CF(); /* error occurred */
6552 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6553 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6556 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6558 status
= inb(0x1f7);
6559 if (status
& 0x80) {
6560 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6562 // should check for Drive Ready Bit also in status reg
6563 outb(0x01f2, num_sectors
);
6565 /* activate LBA? (tomv) */
6566 if (hd_heads
> 16) {
6567 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6568 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6571 outb(0x01f3, sector
);
6572 outb(0x01f4, cylinder
& 0x00ff);
6573 outb(0x01f5, cylinder
>> 8);
6574 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6578 // wait for busy bit to turn off after seeking
6580 status
= inb(0x1f7);
6581 if ( !(status
& 0x80) ) break;
6584 if ( !(status
& 0x08) ) {
6585 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6586 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6593 sti
;; enable higher priority interrupts
6598 ;; store temp bx in real SI
register
6601 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6604 ;; adjust
if there will be an overrun
6606 jbe i13_f03_no_adjust
6608 sub si
, #0x0200 ; sub 512 bytes from offset
6610 add ax
, #0x0020 ; add 512 to segment
6614 mov cx
, #0x0100 ;; counter (256 words = 512b)
6615 mov dx
, #0x01f0 ;; AT data read port
6619 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6621 ;; store real SI
register back to temp bx
6624 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6630 if (num_sectors
== 0) {
6631 status
= inb(0x1f7);
6632 if ( (status
& 0xe9) != 0x40 )
6633 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6637 status
= inb(0x1f7);
6638 if ( (status
& 0xc9) != 0x48 )
6639 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6645 SET_DISK_RET_STATUS(0);
6646 SET_AL(sector_count
);
6647 CLEAR_CF(); /* successful */
6651 case 0x05: /* format disk track */
6652 BX_DEBUG_INT13_HD("int13_f05\n");
6653 BX_PANIC("format disk track called\n");
6656 SET_DISK_RET_STATUS(0);
6657 CLEAR_CF(); /* successful */
6661 case 0x08: /* read disk drive parameters */
6662 BX_DEBUG_INT13_HD("int13_f08\n");
6664 drive
= GET_ELDL ();
6665 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6669 if (hd_cylinders
<= 1024) {
6670 // hd_cylinders >>= 0;
6673 else if (hd_cylinders
<= 2048) {
6677 else if (hd_cylinders
<= 4096) {
6681 else if (hd_cylinders
<= 8192) {
6685 else { // hd_cylinders <= 16384
6690 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6692 SET_CH(max_cylinder
& 0xff);
6693 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6694 SET_DH(hd_heads
- 1);
6695 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6697 SET_DISK_RET_STATUS(0);
6698 CLEAR_CF(); /* successful */
6703 case 0x09: /* initialize drive parameters */
6704 BX_DEBUG_INT13_HD("int13_f09\n");
6706 SET_DISK_RET_STATUS(0);
6707 CLEAR_CF(); /* successful */
6711 case 0x0a: /* read disk sectors with ECC */
6712 BX_DEBUG_INT13_HD("int13_f0a\n");
6713 case 0x0b: /* write disk sectors with ECC */
6714 BX_DEBUG_INT13_HD("int13_f0b\n");
6715 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6719 case 0x0c: /* seek to specified cylinder */
6720 BX_DEBUG_INT13_HD("int13_f0c\n");
6721 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6723 SET_DISK_RET_STATUS(0);
6724 CLEAR_CF(); /* successful */
6728 case 0x0d: /* alternate disk reset */
6729 BX_DEBUG_INT13_HD("int13_f0d\n");
6731 SET_DISK_RET_STATUS(0);
6732 CLEAR_CF(); /* successful */
6736 case 0x10: /* check drive ready */
6737 BX_DEBUG_INT13_HD("int13_f10\n");
6739 //SET_DISK_RET_STATUS(0);
6740 //CLEAR_CF(); /* successful */
6744 // should look at 40:8E also???
6745 status
= inb(0x01f7);
6746 if ( (status
& 0xc0) == 0x40 ) {
6748 SET_DISK_RET_STATUS(0);
6749 CLEAR_CF(); // drive ready
6754 SET_DISK_RET_STATUS(0xAA);
6755 SET_CF(); // not ready
6760 case 0x11: /* recalibrate */
6761 BX_DEBUG_INT13_HD("int13_f11\n");
6763 SET_DISK_RET_STATUS(0);
6764 CLEAR_CF(); /* successful */
6768 case 0x14: /* controller internal diagnostic */
6769 BX_DEBUG_INT13_HD("int13_f14\n");
6771 SET_DISK_RET_STATUS(0);
6772 CLEAR_CF(); /* successful */
6777 case 0x15: /* read disk drive size */
6779 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6783 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6784 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6785 mul al
, ah
;; ax
= heads
* sectors
6786 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6787 dec bx
;; use (cylinders
- 1) ???
6788 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6789 ;; now we need to move the
32bit result dx
:ax to what the
6790 ;; BIOS wants which is cx
:dx
.
6791 ;; and then into CX
:DX on the stack
6792 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6793 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6796 SET_AH(3); // hard disk accessible
6797 SET_DISK_RET_STATUS(0); // ??? should this be 0
6798 CLEAR_CF(); // successful
6802 case 0x18: // set media type for format
6803 case 0x41: // IBM/MS
6804 case 0x42: // IBM/MS
6805 case 0x43: // IBM/MS
6806 case 0x44: // IBM/MS
6807 case 0x45: // IBM/MS lock/unlock drive
6808 case 0x46: // IBM/MS eject media
6809 case 0x47: // IBM/MS extended seek
6810 case 0x49: // IBM/MS extended media change
6811 case 0x50: // IBM/MS send packet command
6813 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6815 SET_AH(1); // code=invalid function in AH or invalid parameter
6816 SET_DISK_RET_STATUS(1);
6817 SET_CF(); /* unsuccessful */
6823 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6824 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6827 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6829 Bit16u
*hd_cylinders
;
6839 if (drive
== 0x80) {
6840 hd_type
= inb_cmos(0x12) & 0xf0;
6841 if (hd_type
!= 0xf0)
6842 BX_INFO(panic_msg_reg12h
,0);
6843 hd_type
= inb_cmos(0x19); // HD0: extended type
6845 BX_INFO(panic_msg_reg19h
,0,0x19);
6848 hd_type
= inb_cmos(0x12) & 0x0f;
6849 if (hd_type
!= 0x0f)
6850 BX_INFO(panic_msg_reg12h
,1);
6851 hd_type
= inb_cmos(0x1a); // HD1: extended type
6853 BX_INFO(panic_msg_reg19h
,0,0x1a);
6858 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6859 write_word(ss
, hd_cylinders
, cylinders
);
6862 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6864 // sectors per track
6865 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6868 #endif //else BX_USE_ATADRV
6870 #if BX_SUPPORT_FLOPPY
6872 //////////////////////
6873 // FLOPPY functions //
6874 //////////////////////
6876 void floppy_reset_controller()
6882 outb(0x03f2, val8
& ~0x04);
6883 outb(0x03f2, val8
| 0x04);
6885 // Wait for controller to come out of reset
6888 } while ( (val8
& 0xc0) != 0x80 );
6891 void floppy_prepare_controller(drive
)
6894 Bit8u val8
, dor
, prev_reset
;
6896 // set 40:3e bit 7 to 0
6897 val8
= read_byte(0x0040, 0x003e);
6899 write_byte(0x0040, 0x003e, val8
);
6901 // turn on motor of selected drive, DMA & int enabled, normal operation
6902 prev_reset
= inb(0x03f2) & 0x04;
6911 // reset the disk motor timeout value of INT 08
6912 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6914 // wait for drive readiness
6917 } while ( (val8
& 0xc0) != 0x80 );
6919 if (prev_reset
== 0) {
6920 // turn on interrupts
6924 // wait on 40:3e bit 7 to become 1
6926 val8
= read_byte(0x0040, 0x003e);
6927 } while ( (val8
& 0x80) == 0 );
6932 write_byte(0x0040, 0x003e, val8
);
6937 floppy_media_known(drive
)
6941 Bit16u media_state_offset
;
6943 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6950 media_state_offset
= 0x0090;
6952 media_state_offset
+= 1;
6954 val8
= read_byte(0x0040, media_state_offset
);
6955 val8
= (val8
>> 4) & 0x01;
6959 // check pass, return KNOWN
6964 floppy_media_sense(drive
)
6968 Bit16u media_state_offset
;
6969 Bit8u drive_type
, config_data
, media_state
;
6971 if (floppy_drive_recal(drive
) == 0) {
6975 // for now cheat and get drive type from CMOS,
6976 // assume media is same as drive type
6978 // ** config_data **
6979 // Bitfields for diskette media control:
6980 // Bit(s) Description (Table M0028)
6981 // 7-6 last data rate set by controller
6982 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6983 // 5-4 last diskette drive step rate selected
6984 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6985 // 3-2 {data rate at start of operation}
6988 // ** media_state **
6989 // Bitfields for diskette drive media state:
6990 // Bit(s) Description (Table M0030)
6992 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6993 // 5 double stepping required (e.g. 360kB in 1.2MB)
6994 // 4 media type established
6995 // 3 drive capable of supporting 4MB media
6996 // 2-0 on exit from BIOS, contains
6997 // 000 trying 360kB in 360kB
6998 // 001 trying 360kB in 1.2MB
6999 // 010 trying 1.2MB in 1.2MB
7000 // 011 360kB in 360kB established
7001 // 100 360kB in 1.2MB established
7002 // 101 1.2MB in 1.2MB established
7004 // 111 all other formats/drives
7006 drive_type
= inb_cmos(0x10);
7011 if ( drive_type
== 1 ) {
7013 config_data
= 0x00; // 0000 0000
7014 media_state
= 0x25; // 0010 0101
7017 else if ( drive_type
== 2 ) {
7018 // 1.2 MB 5.25" drive
7019 config_data
= 0x00; // 0000 0000
7020 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
7023 else if ( drive_type
== 3 ) {
7025 config_data
= 0x00; // 0000 0000 ???
7026 media_state
= 0x17; // 0001 0111
7029 else if ( drive_type
== 4 ) {
7030 // 1.44 MB 3.5" drive
7031 config_data
= 0x00; // 0000 0000
7032 media_state
= 0x17; // 0001 0111
7035 else if ( drive_type
== 5 ) {
7036 // 2.88 MB 3.5" drive
7037 config_data
= 0xCC; // 1100 1100
7038 media_state
= 0xD7; // 1101 0111
7042 // Extended floppy size uses special cmos setting
7043 else if ( drive_type
== 6 ) {
7045 config_data
= 0x00; // 0000 0000
7046 media_state
= 0x27; // 0010 0111
7049 else if ( drive_type
== 7 ) {
7051 config_data
= 0x00; // 0000 0000
7052 media_state
= 0x27; // 0010 0111
7055 else if ( drive_type
== 8 ) {
7057 config_data
= 0x00; // 0000 0000
7058 media_state
= 0x27; // 0010 0111
7064 config_data
= 0x00; // 0000 0000
7065 media_state
= 0x00; // 0000 0000
7070 media_state_offset
= 0x90;
7072 media_state_offset
= 0x91;
7073 write_byte(0x0040, 0x008B, config_data
);
7074 write_byte(0x0040, media_state_offset
, media_state
);
7080 floppy_drive_recal(drive
)
7084 Bit16u curr_cyl_offset
;
7086 floppy_prepare_controller(drive
);
7088 // send Recalibrate command (2 bytes) to controller
7089 outb(0x03f5, 0x07); // 07: Recalibrate
7090 outb(0x03f5, drive
); // 0=drive0, 1=drive1
7092 // turn on interrupts
7097 // wait on 40:3e bit 7 to become 1
7099 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7100 } while ( val8
== 0 );
7102 val8
= 0; // separate asm from while() loop
7103 // turn off interrupts
7108 // set 40:3e bit 7 to 0, and calibrated bit
7109 val8
= read_byte(0x0040, 0x003e);
7112 val8
|= 0x02; // Drive 1 calibrated
7113 curr_cyl_offset
= 0x0095;
7115 val8
|= 0x01; // Drive 0 calibrated
7116 curr_cyl_offset
= 0x0094;
7118 write_byte(0x0040, 0x003e, val8
);
7119 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
7127 floppy_drive_exists(drive
)
7132 // check CMOS to see if drive exists
7133 drive_type
= inb_cmos(0x10);
7138 if ( drive_type
== 0 )
7145 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7146 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7148 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
7149 Bit16u base_address
, base_count
, base_es
;
7150 Bit8u page
, mode_register
, val8
, dor
;
7151 Bit8u return_status
[7];
7152 Bit8u drive_type
, num_floppies
, ah
;
7153 Bit16u es
, last_addr
;
7155 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
7160 case 0x00: // diskette controller reset
7161 BX_DEBUG_INT13_FL("floppy f00\n");
7164 SET_AH(1); // invalid param
7165 set_diskette_ret_status(1);
7169 drive_type
= inb_cmos(0x10);
7175 if (drive_type
== 0) {
7176 SET_AH(0x80); // drive not responding
7177 set_diskette_ret_status(0x80);
7182 set_diskette_ret_status(0);
7183 CLEAR_CF(); // successful
7184 set_diskette_current_cyl(drive
, 0); // current cylinder
7187 case 0x01: // Read Diskette Status
7189 val8
= read_byte(0x0000, 0x0441);
7196 case 0x02: // Read Diskette Sectors
7197 case 0x03: // Write Diskette Sectors
7198 case 0x04: // Verify Diskette Sectors
7199 num_sectors
= GET_AL();
7205 if ((drive
> 1) || (head
> 1) || (sector
== 0) ||
7206 (num_sectors
== 0) || (num_sectors
> 72)) {
7207 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
7209 set_diskette_ret_status(1);
7210 SET_AL(0); // no sectors read
7211 SET_CF(); // error occurred
7215 // see if drive exists
7216 if (floppy_drive_exists(drive
) == 0) {
7217 SET_AH(0x80); // not responding
7218 set_diskette_ret_status(0x80);
7219 SET_AL(0); // no sectors read
7220 SET_CF(); // error occurred
7224 // see if media in drive, and type is known
7225 if (floppy_media_known(drive
) == 0) {
7226 if (floppy_media_sense(drive
) == 0) {
7227 SET_AH(0x0C); // Media type not found
7228 set_diskette_ret_status(0x0C);
7229 SET_AL(0); // no sectors read
7230 SET_CF(); // error occurred
7236 // Read Diskette Sectors
7238 //-----------------------------------
7239 // set up DMA controller for transfer
7240 //-----------------------------------
7242 // es:bx = pointer to where to place information from diskette
7243 // port 04: DMA-1 base and current address, channel 2
7244 // port 05: DMA-1 base and current count, channel 2
7245 page
= (ES
>> 12); // upper 4 bits
7246 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7247 base_address
= base_es
+ BX
; // lower 16 bits of address
7248 // contributed by ES:BX
7249 if ( base_address
< base_es
) {
7250 // in case of carry, adjust page by 1
7253 base_count
= (num_sectors
* 512) - 1;
7255 // check for 64K boundary overrun
7256 last_addr
= base_address
+ base_count
;
7257 if (last_addr
< base_address
) {
7259 set_diskette_ret_status(0x09);
7260 SET_AL(0); // no sectors read
7261 SET_CF(); // error occurred
7265 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7268 BX_DEBUG_INT13_FL("clear flip-flop\n");
7269 outb(0x000c, 0x00); // clear flip-flop
7270 outb(0x0004, base_address
);
7271 outb(0x0004, base_address
>>8);
7272 BX_DEBUG_INT13_FL("clear flip-flop\n");
7273 outb(0x000c, 0x00); // clear flip-flop
7274 outb(0x0005, base_count
);
7275 outb(0x0005, base_count
>>8);
7277 // port 0b: DMA-1 Mode Register
7278 mode_register
= 0x46; // single mode, increment, autoinit disable,
7279 // transfer type=write, channel 2
7280 BX_DEBUG_INT13_FL("setting mode register\n");
7281 outb(0x000b, mode_register
);
7283 BX_DEBUG_INT13_FL("setting page register\n");
7284 // port 81: DMA-1 Page Register, channel 2
7287 BX_DEBUG_INT13_FL("unmask chan 2\n");
7288 outb(0x000a, 0x02); // unmask channel 2
7290 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7293 //--------------------------------------
7294 // set up floppy controller for transfer
7295 //--------------------------------------
7296 floppy_prepare_controller(drive
);
7298 // send read-normal-data command (9 bytes) to controller
7299 outb(0x03f5, 0xe6); // e6: read normal data
7300 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7301 outb(0x03f5, track
);
7303 outb(0x03f5, sector
);
7304 outb(0x03f5, 2); // 512 byte sector size
7305 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
7306 outb(0x03f5, 0); // Gap length
7307 outb(0x03f5, 0xff); // Gap length
7309 // turn on interrupts
7314 // wait on 40:3e bit 7 to become 1
7316 val8
= read_byte(0x0040, 0x0040);
7318 floppy_reset_controller();
7319 SET_AH(0x80); // drive not ready (timeout)
7320 set_diskette_ret_status(0x80);
7321 SET_AL(0); // no sectors read
7322 SET_CF(); // error occurred
7325 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7326 } while ( val8
== 0 );
7328 val8
= 0; // separate asm from while() loop
7329 // turn off interrupts
7334 // set 40:3e bit 7 to 0
7335 val8
= read_byte(0x0040, 0x003e);
7337 write_byte(0x0040, 0x003e, val8
);
7339 // check port 3f4 for accessibility to status bytes
7341 if ( (val8
& 0xc0) != 0xc0 )
7342 BX_PANIC("int13_diskette: ctrl not ready\n");
7344 // read 7 return status bytes from controller
7345 // using loop index broken, have to unroll...
7346 return_status
[0] = inb(0x3f5);
7347 return_status
[1] = inb(0x3f5);
7348 return_status
[2] = inb(0x3f5);
7349 return_status
[3] = inb(0x3f5);
7350 return_status
[4] = inb(0x3f5);
7351 return_status
[5] = inb(0x3f5);
7352 return_status
[6] = inb(0x3f5);
7353 // record in BIOS Data Area
7354 write_byte(0x0040, 0x0042, return_status
[0]);
7355 write_byte(0x0040, 0x0043, return_status
[1]);
7356 write_byte(0x0040, 0x0044, return_status
[2]);
7357 write_byte(0x0040, 0x0045, return_status
[3]);
7358 write_byte(0x0040, 0x0046, return_status
[4]);
7359 write_byte(0x0040, 0x0047, return_status
[5]);
7360 write_byte(0x0040, 0x0048, return_status
[6]);
7362 if ( (return_status
[0] & 0xc0) != 0 ) {
7364 set_diskette_ret_status(0x20);
7365 SET_AL(0); // no sectors read
7366 SET_CF(); // error occurred
7370 // ??? should track be new val from return_status[3] ?
7371 set_diskette_current_cyl(drive
, track
);
7372 // AL = number of sectors read (same value as passed)
7373 SET_AH(0x00); // success
7374 CLEAR_CF(); // success
7376 } else if (ah
== 0x03) {
7377 // Write Diskette Sectors
7379 //-----------------------------------
7380 // set up DMA controller for transfer
7381 //-----------------------------------
7383 // es:bx = pointer to where to place information from diskette
7384 // port 04: DMA-1 base and current address, channel 2
7385 // port 05: DMA-1 base and current count, channel 2
7386 page
= (ES
>> 12); // upper 4 bits
7387 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7388 base_address
= base_es
+ BX
; // lower 16 bits of address
7389 // contributed by ES:BX
7390 if ( base_address
< base_es
) {
7391 // in case of carry, adjust page by 1
7394 base_count
= (num_sectors
* 512) - 1;
7396 // check for 64K boundary overrun
7397 last_addr
= base_address
+ base_count
;
7398 if (last_addr
< base_address
) {
7400 set_diskette_ret_status(0x09);
7401 SET_AL(0); // no sectors read
7402 SET_CF(); // error occurred
7406 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7409 outb(0x000c, 0x00); // clear flip-flop
7410 outb(0x0004, base_address
);
7411 outb(0x0004, base_address
>>8);
7412 outb(0x000c, 0x00); // clear flip-flop
7413 outb(0x0005, base_count
);
7414 outb(0x0005, base_count
>>8);
7416 // port 0b: DMA-1 Mode Register
7417 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7418 // transfer type=read, channel 2
7419 outb(0x000b, mode_register
);
7421 // port 81: DMA-1 Page Register, channel 2
7424 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7427 //--------------------------------------
7428 // set up floppy controller for transfer
7429 //--------------------------------------
7430 floppy_prepare_controller(drive
);
7432 // send write-normal-data command (9 bytes) to controller
7433 outb(0x03f5, 0xc5); // c5: write normal data
7434 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7435 outb(0x03f5, track
);
7437 outb(0x03f5, sector
);
7438 outb(0x03f5, 2); // 512 byte sector size
7439 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
7440 outb(0x03f5, 0); // Gap length
7441 outb(0x03f5, 0xff); // Gap length
7443 // turn on interrupts
7448 // wait on 40:3e bit 7 to become 1
7450 val8
= read_byte(0x0040, 0x0040);
7452 floppy_reset_controller();
7453 SET_AH(0x80); // drive not ready (timeout)
7454 set_diskette_ret_status(0x80);
7455 SET_AL(0); // no sectors written
7456 SET_CF(); // error occurred
7459 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7460 } while ( val8
== 0 );
7462 val8
= 0; // separate asm from while() loop
7463 // turn off interrupts
7468 // set 40:3e bit 7 to 0
7469 val8
= read_byte(0x0040, 0x003e);
7471 write_byte(0x0040, 0x003e, val8
);
7473 // check port 3f4 for accessibility to status bytes
7475 if ( (val8
& 0xc0) != 0xc0 )
7476 BX_PANIC("int13_diskette: ctrl not ready\n");
7478 // read 7 return status bytes from controller
7479 // using loop index broken, have to unroll...
7480 return_status
[0] = inb(0x3f5);
7481 return_status
[1] = inb(0x3f5);
7482 return_status
[2] = inb(0x3f5);
7483 return_status
[3] = inb(0x3f5);
7484 return_status
[4] = inb(0x3f5);
7485 return_status
[5] = inb(0x3f5);
7486 return_status
[6] = inb(0x3f5);
7487 // record in BIOS Data Area
7488 write_byte(0x0040, 0x0042, return_status
[0]);
7489 write_byte(0x0040, 0x0043, return_status
[1]);
7490 write_byte(0x0040, 0x0044, return_status
[2]);
7491 write_byte(0x0040, 0x0045, return_status
[3]);
7492 write_byte(0x0040, 0x0046, return_status
[4]);
7493 write_byte(0x0040, 0x0047, return_status
[5]);
7494 write_byte(0x0040, 0x0048, return_status
[6]);
7496 if ( (return_status
[0] & 0xc0) != 0 ) {
7497 if ( (return_status
[1] & 0x02) != 0 ) {
7498 // diskette not writable.
7499 // AH=status code=0x03 (tried to write on write-protected disk)
7500 // AL=number of sectors written=0
7505 BX_PANIC("int13_diskette_function: read error\n");
7509 // ??? should track be new val from return_status[3] ?
7510 set_diskette_current_cyl(drive
, track
);
7511 // AL = number of sectors read (same value as passed)
7512 SET_AH(0x00); // success
7513 CLEAR_CF(); // success
7515 } else { // if (ah == 0x04)
7516 // Verify Diskette Sectors
7518 // ??? should track be new val from return_status[3] ?
7519 set_diskette_current_cyl(drive
, track
);
7520 // AL = number of sectors verified (same value as passed)
7521 CLEAR_CF(); // success
7522 SET_AH(0x00); // success
7527 case 0x05: // format diskette track
7528 BX_DEBUG_INT13_FL("floppy f05\n");
7530 num_sectors
= GET_AL();
7535 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7536 (num_sectors
== 0) || (num_sectors
> 18)) {
7538 set_diskette_ret_status(1);
7539 SET_CF(); // error occurred
7542 // see if drive exists
7543 if (floppy_drive_exists(drive
) == 0) {
7544 SET_AH(0x80); // drive not responding
7545 set_diskette_ret_status(0x80);
7546 SET_CF(); // error occurred
7550 // see if media in drive, and type is known
7551 if (floppy_media_known(drive
) == 0) {
7552 if (floppy_media_sense(drive
) == 0) {
7553 SET_AH(0x0C); // Media type not found
7554 set_diskette_ret_status(0x0C);
7555 SET_AL(0); // no sectors read
7556 SET_CF(); // error occurred
7561 // set up DMA controller for transfer
7562 page
= (ES
>> 12); // upper 4 bits
7563 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7564 base_address
= base_es
+ BX
; // lower 16 bits of address
7565 // contributed by ES:BX
7566 if ( base_address
< base_es
) {
7567 // in case of carry, adjust page by 1
7570 base_count
= (num_sectors
* 4) - 1;
7572 // check for 64K boundary overrun
7573 last_addr
= base_address
+ base_count
;
7574 if (last_addr
< base_address
) {
7576 set_diskette_ret_status(0x09);
7577 SET_AL(0); // no sectors read
7578 SET_CF(); // error occurred
7583 outb(0x000c, 0x00); // clear flip-flop
7584 outb(0x0004, base_address
);
7585 outb(0x0004, base_address
>>8);
7586 outb(0x000c, 0x00); // clear flip-flop
7587 outb(0x0005, base_count
);
7588 outb(0x0005, base_count
>>8);
7589 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7590 // transfer type=read, channel 2
7591 outb(0x000b, mode_register
);
7592 // port 81: DMA-1 Page Register, channel 2
7596 // set up floppy controller for transfer
7597 floppy_prepare_controller(drive
);
7599 // send format-track command (6 bytes) to controller
7600 outb(0x03f5, 0x4d); // 4d: format track
7601 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7602 outb(0x03f5, 2); // 512 byte sector size
7603 outb(0x03f5, num_sectors
); // number of sectors per track
7604 outb(0x03f5, 0); // Gap length
7605 outb(0x03f5, 0xf6); // Fill byte
7606 // turn on interrupts
7611 // wait on 40:3e bit 7 to become 1
7613 val8
= read_byte(0x0040, 0x0040);
7615 floppy_reset_controller();
7616 SET_AH(0x80); // drive not ready (timeout)
7617 set_diskette_ret_status(0x80);
7618 SET_CF(); // error occurred
7621 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7622 } while ( val8
== 0 );
7624 val8
= 0; // separate asm from while() loop
7625 // turn off interrupts
7629 // set 40:3e bit 7 to 0
7630 val8
= read_byte(0x0040, 0x003e);
7632 write_byte(0x0040, 0x003e, val8
);
7633 // check port 3f4 for accessibility to status bytes
7635 if ( (val8
& 0xc0) != 0xc0 )
7636 BX_PANIC("int13_diskette: ctrl not ready\n");
7638 // read 7 return status bytes from controller
7639 // using loop index broken, have to unroll...
7640 return_status
[0] = inb(0x3f5);
7641 return_status
[1] = inb(0x3f5);
7642 return_status
[2] = inb(0x3f5);
7643 return_status
[3] = inb(0x3f5);
7644 return_status
[4] = inb(0x3f5);
7645 return_status
[5] = inb(0x3f5);
7646 return_status
[6] = inb(0x3f5);
7647 // record in BIOS Data Area
7648 write_byte(0x0040, 0x0042, return_status
[0]);
7649 write_byte(0x0040, 0x0043, return_status
[1]);
7650 write_byte(0x0040, 0x0044, return_status
[2]);
7651 write_byte(0x0040, 0x0045, return_status
[3]);
7652 write_byte(0x0040, 0x0046, return_status
[4]);
7653 write_byte(0x0040, 0x0047, return_status
[5]);
7654 write_byte(0x0040, 0x0048, return_status
[6]);
7656 if ( (return_status
[0] & 0xc0) != 0 ) {
7657 if ( (return_status
[1] & 0x02) != 0 ) {
7658 // diskette not writable.
7659 // AH=status code=0x03 (tried to write on write-protected disk)
7660 // AL=number of sectors written=0
7665 BX_PANIC("int13_diskette_function: write error\n");
7670 set_diskette_ret_status(0);
7671 set_diskette_current_cyl(drive
, 0);
7672 CLEAR_CF(); // successful
7676 case 0x08: // read diskette drive parameters
7677 BX_DEBUG_INT13_FL("floppy f08\n");
7687 SET_DL(num_floppies
);
7692 drive_type
= inb_cmos(0x10);
7694 if (drive_type
& 0xf0)
7696 if (drive_type
& 0x0f)
7708 SET_DL(num_floppies
);
7710 switch (drive_type
) {
7713 SET_DH(0); // max head #
7716 case 1: // 360KB, 5.25"
7717 CX
= 0x2709; // 40 tracks, 9 sectors
7718 SET_DH(1); // max head #
7721 case 2: // 1.2MB, 5.25"
7722 CX
= 0x4f0f; // 80 tracks, 15 sectors
7723 SET_DH(1); // max head #
7726 case 3: // 720KB, 3.5"
7727 CX
= 0x4f09; // 80 tracks, 9 sectors
7728 SET_DH(1); // max head #
7731 case 4: // 1.44MB, 3.5"
7732 CX
= 0x4f12; // 80 tracks, 18 sectors
7733 SET_DH(1); // max head #
7736 case 5: // 2.88MB, 3.5"
7737 CX
= 0x4f24; // 80 tracks, 36 sectors
7738 SET_DH(1); // max head #
7741 case 6: // 160k, 5.25"
7742 CX
= 0x2708; // 40 tracks, 8 sectors
7743 SET_DH(0); // max head #
7746 case 7: // 180k, 5.25"
7747 CX
= 0x2709; // 40 tracks, 9 sectors
7748 SET_DH(0); // max head #
7751 case 8: // 320k, 5.25"
7752 CX
= 0x2708; // 40 tracks, 8 sectors
7753 SET_DH(1); // max head #
7757 BX_PANIC("floppy: int13: bad floppy type\n");
7760 /* set es & di to point to 11 byte diskette param table in ROM */
7764 mov ax
, #diskette_param_table2
7765 mov _int13_diskette_function
.DI
+2[bp
], ax
7766 mov _int13_diskette_function
.ES
+2[bp
], cs
7769 CLEAR_CF(); // success
7770 /* disk status not changed upon success */
7774 case 0x15: // read diskette drive type
7775 BX_DEBUG_INT13_FL("floppy f15\n");
7778 SET_AH(0); // only 2 drives supported
7779 // set_diskette_ret_status here ???
7783 drive_type
= inb_cmos(0x10);
7789 CLEAR_CF(); // successful, not present
7790 if (drive_type
==0) {
7791 SET_AH(0); // drive not present
7794 SET_AH(1); // drive present, does not support change line
7799 case 0x16: // get diskette change line status
7800 BX_DEBUG_INT13_FL("floppy f16\n");
7803 SET_AH(0x01); // invalid drive
7804 set_diskette_ret_status(0x01);
7809 SET_AH(0x06); // change line not supported
7810 set_diskette_ret_status(0x06);
7814 case 0x17: // set diskette type for format(old)
7815 BX_DEBUG_INT13_FL("floppy f17\n");
7816 /* not used for 1.44M floppies */
7817 SET_AH(0x01); // not supported
7818 set_diskette_ret_status(1); /* not supported */
7822 case 0x18: // set diskette type for format(new)
7823 BX_DEBUG_INT13_FL("floppy f18\n");
7824 SET_AH(0x01); // do later
7825 set_diskette_ret_status(1);
7830 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7832 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7833 SET_AH(0x01); // ???
7834 set_diskette_ret_status(1);
7840 #else // #if BX_SUPPORT_FLOPPY
7842 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7843 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7847 switch ( GET_AH() ) {
7849 case 0x01: // Read Diskette Status
7851 val8
= read_byte(0x0000, 0x0441);
7860 write_byte(0x0000, 0x0441, 0x01);
7864 #endif // #if BX_SUPPORT_FLOPPY
7867 set_diskette_ret_status(value
)
7870 write_byte(0x0040, 0x0041, value
);
7874 set_diskette_current_cyl(drive
, cyl
)
7879 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7880 write_byte(0x0040, 0x0094+drive
, cyl
);
7884 determine_floppy_media(drive
)
7888 Bit8u val8
, DOR
, ctrl_info
;
7890 ctrl_info
= read_byte(0x0040, 0x008F);
7898 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7901 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7905 if ( (ctrl_info
& 0x04) != 0x04 ) {
7906 // Drive not determined means no drive exists, done.
7911 // check Main Status Register for readiness
7912 val8
= inb(0x03f4) & 0x80; // Main Status Register
7914 BX_PANIC("d_f_m: MRQ bit not set\n");
7918 // existing BDA values
7920 // turn on drive motor
7921 outb(0x03f2, DOR
); // Digital Output Register
7924 BX_PANIC("d_f_m: OK so far\n");
7929 int17_function(regs
, ds
, iret_addr
)
7930 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7931 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7932 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7934 Bit16u addr
,timeout
;
7941 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7942 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7943 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7944 if (regs
.u
.r8
.ah
== 0) {
7945 outb(addr
, regs
.u
.r8
.al
);
7947 outb(addr
+2, val8
| 0x01); // send strobe
7951 outb(addr
+2, val8
& ~0x01);
7952 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7956 if (regs
.u
.r8
.ah
== 1) {
7958 outb(addr
+2, val8
& ~0x04); // send init
7962 outb(addr
+2, val8
| 0x04);
7965 regs
.u
.r8
.ah
= (val8
^ 0x48);
7966 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7967 ClearCF(iret_addr
.flags
);
7969 SetCF(iret_addr
.flags
); // Unsupported
7974 int19_function(seq_nr
)
7977 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7988 // if BX_ELTORITO_BOOT is not defined, old behavior
7989 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7990 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7991 // 0: system boot sequence, first drive C: then A:
7992 // 1: system boot sequence, first drive A: then C:
7993 // else BX_ELTORITO_BOOT is defined
7994 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7995 // CMOS reg 0x3D & 0x0f : 1st boot device
7996 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7997 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7998 // boot device codes:
7999 // 0x00 : not defined
8000 // 0x01 : first floppy
8001 // 0x02 : first harddrive
8002 // 0x03 : first cdrom
8003 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
8004 // else : boot failure
8006 // Get the boot sequence
8007 #if BX_ELTORITO_BOOT
8008 bootdev
= inb_cmos(0x3d);
8009 bootdev
|= ((inb_cmos(0x38) & 0xf0) << 4);
8010 bootdev
>>= 4 * seq_nr
;
8013 /* Read user selected device */
8014 bootfirst
= read_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
);
8015 if (bootfirst
!= 0xFFFF) {
8016 bootdev
= bootfirst
;
8017 /* User selected device not set */
8018 write_word(IPL_SEG
, IPL_BOOTFIRST_OFFSET
, 0xFFFF);
8019 /* Reset boot sequence */
8020 write_word(IPL_SEG
, IPL_SEQUENCE_OFFSET
, 0xFFFF);
8021 } else if (bootdev
== 0) BX_PANIC("No bootable device.\n");
8023 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
8026 if (seq_nr
==2) BX_PANIC("No more boot devices.");
8027 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr
== 1))
8028 /* Boot from floppy if the bit is set or it's the second boot */
8034 /* Read the boot device from the IPL table */
8035 if (get_boot_vector(bootdev
, &e
) == 0) {
8036 BX_INFO("Invalid boot device (0x%x)\n", bootdev
);
8040 /* Do the loading, and set up vector as a far pointer to the boot
8041 * address, and bootdrv as the boot drive */
8042 print_boot_device(&e
);
8045 case IPL_TYPE_FLOPPY
: /* FDD */
8046 case IPL_TYPE_HARDDISK
: /* HDD */
8048 bootdrv
= (e
.type
== IPL_TYPE_HARDDISK
) ? 0x80 : 0x00;
8060 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
8061 mov ax
, _int19_function
.bootseg
+ 2[bp
]
8062 mov es
, ax
;; segment
8063 xor bx
, bx
;; offset
8064 mov ah
, #0x02 ;; function 2, read diskette sector
8065 mov al
, #0x01 ;; read 1 sector
8066 mov ch
, #0x00 ;; track 0
8067 mov cl
, #0x01 ;; sector 1
8068 mov dh
, #0x00 ;; head 0
8069 int #0x13 ;; read sector
8072 mov _int19_function
.status
+ 2[bp
], ax
8083 print_boot_failure(e
.type
, 1);
8087 /* Always check the signature on a HDD boot sector; on FDD, only do
8088 * the check if the CMOS doesn't tell us to skip it */
8089 if ((e
.type
!= IPL_TYPE_FLOPPY
) || !((inb_cmos(0x38) & 0x01))) {
8090 if (read_word(bootseg
,0x1fe) != 0xaa55) {
8091 print_boot_failure(e
.type
, 0);
8096 /* Canonicalize bootseg:bootip */
8097 bootip
= (bootseg
& 0x0fff) << 4;
8101 #if BX_ELTORITO_BOOT
8102 case IPL_TYPE_CDROM
: /* CD-ROM */
8103 status
= cdrom_boot();
8106 if ( (status
& 0x00ff) !=0 ) {
8107 print_cdromboot_failure(status
);
8108 print_boot_failure(e
.type
, 1);
8112 bootdrv
= (Bit8u
)(status
>>8);
8113 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
8118 case IPL_TYPE_BEV
: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
8119 bootseg
= e
.vector
>> 16;
8120 bootip
= e
.vector
& 0xffff;
8126 /* Debugging info */
8127 BX_INFO("Booting from %x:%x\n", bootseg
, bootip
);
8129 /* Jump to the boot vector */
8134 ;; Build an iret stack frame that will take us to the boot vector
.
8135 ;; iret pops ip
, then cs
, then flags
, so push them in the opposite order
.
8137 mov ax
, _int19_function
.bootseg
+ 0[bp
]
8139 mov ax
, _int19_function
.bootip
+ 0[bp
]
8141 ;; Set the magic number in ax
and the boot drive in dl
.
8143 mov dl
, _int19_function
.bootdrv
+ 0[bp
]
8144 ;; Zero some of the other registers
.
8155 int1a_function(regs
, ds
, iret_addr
)
8156 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8157 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8158 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8162 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
);
8168 switch (regs
.u
.r8
.ah
) {
8169 case 0: // get current clock count
8173 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
8174 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
8175 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
8176 BiosData
->midnight_flag
= 0; // reset flag
8181 ClearCF(iret_addr
.flags
); // OK
8184 case 1: // Set Current Clock Count
8188 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
8189 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
8190 BiosData
->midnight_flag
= 0; // reset flag
8195 ClearCF(iret_addr
.flags
); // OK
8199 case 2: // Read CMOS Time
8200 if (rtc_updating()) {
8201 SetCF(iret_addr
.flags
);
8205 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
8206 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
8207 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
8208 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
8210 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8211 ClearCF(iret_addr
.flags
); // OK
8214 case 3: // Set CMOS Time
8215 // Using a debugger, I notice the following masking/setting
8216 // of bits in Status Register B, by setting Reg B to
8217 // a few values and getting its value after INT 1A was called.
8219 // try#1 try#2 try#3
8220 // before 1111 1101 0111 1101 0000 0000
8221 // after 0110 0010 0110 0010 0000 0010
8223 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8224 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8225 if (rtc_updating()) {
8227 // fall through as if an update were not in progress
8229 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
8230 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
8231 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
8232 // Set Daylight Savings time enabled bit to requested value
8233 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
8234 // (reg B already selected)
8235 outb_cmos(0x0b, val8
);
8237 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8238 ClearCF(iret_addr
.flags
); // OK
8241 case 4: // Read CMOS Date
8243 if (rtc_updating()) {
8244 SetCF(iret_addr
.flags
);
8247 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
8248 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
8249 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
8250 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
8251 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
8252 ClearCF(iret_addr
.flags
); // OK
8255 case 5: // Set CMOS Date
8256 // Using a debugger, I notice the following masking/setting
8257 // of bits in Status Register B, by setting Reg B to
8258 // a few values and getting its value after INT 1A was called.
8260 // try#1 try#2 try#3 try#4
8261 // before 1111 1101 0111 1101 0000 0010 0000 0000
8262 // after 0110 1101 0111 1101 0000 0010 0000 0000
8264 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8265 // My assumption: RegB = (RegB & 01111111b)
8266 if (rtc_updating()) {
8268 SetCF(iret_addr
.flags
);
8271 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
8272 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
8273 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
8274 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
8275 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8276 outb_cmos(0x0b, val8
);
8278 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
8279 ClearCF(iret_addr
.flags
); // OK
8282 case 6: // Set Alarm Time in CMOS
8283 // Using a debugger, I notice the following masking/setting
8284 // of bits in Status Register B, by setting Reg B to
8285 // a few values and getting its value after INT 1A was called.
8287 // try#1 try#2 try#3
8288 // before 1101 1111 0101 1111 0000 0000
8289 // after 0110 1111 0111 1111 0010 0000
8291 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8292 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8293 val8
= inb_cmos(0x0b); // Get Status Reg B
8296 // Alarm interrupt enabled already
8297 SetCF(iret_addr
.flags
); // Error: alarm in use
8300 if (rtc_updating()) {
8302 // fall through as if an update were not in progress
8304 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
8305 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
8306 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
8307 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8308 // enable Status Reg B alarm bit, clear halt clock bit
8309 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
8310 ClearCF(iret_addr
.flags
); // OK
8313 case 7: // Turn off Alarm
8314 // Using a debugger, I notice the following masking/setting
8315 // of bits in Status Register B, by setting Reg B to
8316 // a few values and getting its value after INT 1A was called.
8318 // try#1 try#2 try#3 try#4
8319 // before 1111 1101 0111 1101 0010 0000 0010 0010
8320 // after 0100 0101 0101 0101 0000 0000 0000 0010
8322 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8323 // My assumption: RegB = (RegB & 01010111b)
8324 val8
= inb_cmos(0x0b); // Get Status Reg B
8325 // clear clock-halt bit, disable alarm bit
8326 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
8328 regs
.u
.r8
.al
= val8
; // val last written to Reg B
8329 ClearCF(iret_addr
.flags
); // OK
8333 // real mode PCI BIOS functions now handled in assembler code
8334 // this C code handles the error code for information only
8335 if (regs
.u
.r8
.bl
== 0xff) {
8336 BX_INFO("PCI BIOS: PCI not present\n");
8337 } else if (regs
.u
.r8
.bl
== 0x81) {
8338 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
8339 } else if (regs
.u
.r8
.bl
== 0x83) {
8340 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
8341 } else if (regs
.u
.r8
.bl
== 0x86) {
8342 if (regs
.u
.r8
.al
== 0x02) {
8343 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
8345 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
);
8348 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
8349 SetCF(iret_addr
.flags
);
8354 SetCF(iret_addr
.flags
); // Unsupported
8359 int70_function(regs
, ds
, iret_addr
)
8360 pusha_regs_t regs
; // regs pushed from PUSHA instruction
8361 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
8362 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
8364 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8365 Bit8u registerB
= 0, registerC
= 0;
8367 // Check which modes are enabled and have occurred.
8368 registerB
= inb_cmos( 0xB );
8369 registerC
= inb_cmos( 0xC );
8371 if( ( registerB
& 0x60 ) != 0 ) {
8372 if( ( registerC
& 0x20 ) != 0 ) {
8373 // Handle Alarm Interrupt.
8380 if( ( registerC
& 0x40 ) != 0 ) {
8381 // Handle Periodic Interrupt.
8383 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8384 // Wait Interval (Int 15, AH=83) active.
8385 Bit32u time
, toggle
;
8387 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
8388 if( time
< 0x3D1 ) {
8390 Bit16u segment
, offset
;
8392 segment
= read_word( 0x40, 0x98 );
8393 offset
= read_word( 0x40, 0x9A );
8394 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8395 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
8396 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
8398 // Continue waiting.
8400 write_dword( 0x40, 0x9C, time
);
8413 ;------------------------------------------
8414 ;- INT74h
: PS
/2 mouse hardware interrupt
-
8415 ;------------------------------------------
8420 push
#0x00 ;; placeholder for status
8421 push
#0x00 ;; placeholder for X
8422 push
#0x00 ;; placeholder for Y
8423 push
#0x00 ;; placeholder for Z
8424 push
#0x00 ;; placeholder for make_far_call boolean
8425 call _int74_function
8426 pop cx
;; remove make_far_call from stack
8429 ;; make far call to EBDA
:0022
8432 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
8434 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8439 add sp
, #8 ;; pop status, x, y, z
8441 pop ds
;; restore DS
8446 ;; This will perform an IRET
, but will retain value of current CF
8447 ;; by altering flags on stack
. Better than RETF
#02.
8452 and BYTE
[bp
+ 0x06], #0xfe
8458 or BYTE
[bp
+ 0x06], #0x01
8463 ;----------------------
8464 ;- INT13h (relocated
) -
8465 ;----------------------
8467 ; int13_relocated is a little bit messed up since I played with it
8468 ; I have to rewrite it
:
8469 ; - call a function that detect which function to call
8470 ; - make all called C function get the same parameters list
8474 #if BX_ELTORITO_BOOT
8475 ;; check
for an eltorito function
8477 jb int13_not_eltorito
8479 ja int13_not_eltorito
8488 jmp _int13_eltorito
;; ELDX
not used
8496 ;; check
if emulation active
8497 call _cdemu_isactive
8499 je int13_cdemu_inactive
8501 ;; check
if access to the emulated drive
8502 call _cdemu_emulated_drive
8505 cmp al
,dl
;; int13 on emulated drive
8520 jmp _int13_cdemu
;; ELDX
not used
8523 and dl
,#0xE0 ;; mask to get device class, including cdroms
8524 cmp al
,dl
;; al is
0x00 or 0x80
8525 jne int13_cdemu_inactive
;; inactive
for device
class
8537 dec dl
;; real drive is dl
- 1
8540 int13_cdemu_inactive
:
8546 #endif // BX_ELTORITO_BOOT
8557 push dx
;; push eltorito value of dx instead of sp
8568 ;; now the
16-bit registers can be restored with
:
8569 ;; pop ds
; pop es
; popa
; iret
8570 ;; arguments passed to functions should be
8571 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8577 jmp _int13_diskette_function
8586 // ebx is modified: BSD 5.2.1 boot loader problem
8587 // someone should figure out which 32 bit register that actually are used
8604 ;; int13_harddisk modifies high word of EAX
8607 call _int13_harddisk
8620 int18_handler
: ;; Boot Failure recovery
: try the next device
.
8628 ;; Get the boot sequence number out of the IPL memory
8630 mov ds
, bx
;; Set segment
8631 mov bx
, IPL_SEQUENCE_OFFSET
;; BX is now the sequence number
8633 mov IPL_SEQUENCE_OFFSET
, bx
;; Write it back
8634 mov ds
, ax
;; and reset the segment to zero
.
8636 ;; Carry on in the INT
19h handler
, using the
new sequence number
8644 int19_relocated
: ;; Boot function
, relocated
8646 ;; int19 was beginning to be really
complex, so now it
8647 ;; just calls a C function that does the work
8658 ;; Start from the first boot
device (0, in AX
)
8660 mov ds
, bx
;; Set segment to write to the IPL memory
8661 mov IPL_SEQUENCE_OFFSET
, ax
;; Save the sequence number
8662 mov ds
, ax
;; and reset the segment
.
8668 ;; Call the C code
for the next boot device
8669 call _int19_function
8671 ;; Boot failed
: invoke the boot recovery function
8677 int1c_handler
: ;; User Timer Tick
8681 ;----------------------
8682 ;- POST
: Floppy Drive
-
8683 ;----------------------
8689 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8691 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8693 mov
0x0440, al
;; diskette motor timeout counter
: not active
8694 mov
0x0441, al
;; diskette controller status
return code
8696 mov
0x0442, al
;; disk
& diskette controller status
register 0
8697 mov
0x0443, al
;; diskette controller status
register 1
8698 mov
0x0444, al
;; diskette controller status
register 2
8699 mov
0x0445, al
;; diskette controller cylinder number
8700 mov
0x0446, al
;; diskette controller head number
8701 mov
0x0447, al
;; diskette controller sector number
8702 mov
0x0448, al
;; diskette controller bytes written
8704 mov
0x048b, al
;; diskette configuration data
8706 ;; -----------------------------------------------------------------
8707 ;; (048F
) diskette controller information
8709 mov al
, #0x10 ;; get CMOS diskette drive type
8712 mov ah
, al
;; save byte to AH
8715 shr al
, #4 ;; look at top 4 bits for drive 0
8716 jz f0_missing
;; jump
if no drive0
8717 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8720 mov bl
, #0x00 ;; no drive0
8723 mov al
, ah
;; restore from AH
8724 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8725 jz f1_missing
;; jump
if no drive1
8726 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8728 ;; leave high bits in BL zerod
8729 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8730 ;; -----------------------------------------------------------------
8733 mov
0x0490, al
;; diskette
0 media state
8734 mov
0x0491, al
;; diskette
1 media state
8736 ;; diskette
0,1 operational starting state
8737 ;; drive type has
not been determined
,
8738 ;; has no changed detection line
8742 mov
0x0494, al
;; diskette
0 current cylinder
8743 mov
0x0495, al
;; diskette
1 current cylinder
8746 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8748 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8749 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8750 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8755 ;--------------------
8756 ;- POST
: HARD DRIVE
-
8757 ;--------------------
8758 ; relocated here because the primary POST area isnt big enough
.
8761 // INT 76h calls INT 15h function ax=9100
8763 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8769 mov
0x0474, al
/* hard disk status of last operation */
8770 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8771 mov
0x048c, al
/* hard disk status register */
8772 mov
0x048d, al
/* hard disk error register */
8773 mov
0x048e, al
/* hard disk task complete flag */
8775 mov
0x0475, al
/* hard disk number attached */
8777 mov
0x0476, al
/* hard disk control byte */
8778 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8779 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8780 ;; INT
41h
: hard disk
0 configuration pointer
8781 ;; INT
46h
: hard disk
1 configuration pointer
8782 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8783 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8785 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8797 cmp al
, #47 ;; decimal 47 - user definable
8801 ;; CMOS purpose param table offset
8802 ;; 1b cylinders low
0
8803 ;; 1c cylinders high
1
8805 ;; 1e write pre
-comp low
5
8806 ;; 1f write pre
-comp high
6
8807 ;; 20 retries
/bad map
/heads
>8 8
8808 ;; 21 landing zone low C
8809 ;; 22 landing zone high D
8810 ;; 23 sectors
/track E
8815 ;;; Filling EBDA table
for hard disk
0.
8823 mov (0x003d + 0x05), ax
;; write precomp word
8828 mov (0x003d + 0x08), al
;; drive control byte
8837 mov (0x003d + 0x0C), ax
;; landing zone word
8839 mov al
, #0x1c ;; get cylinders word in AX
8841 in al
, #0x71 ;; high byte
8845 in al
, #0x71 ;; low byte
8846 mov bx
, ax
;; BX
= cylinders
8851 mov cl
, al
;; CL
= heads
8856 mov dl
, al
;; DL
= sectors
8859 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8861 hd0_post_physical_chs
:
8862 ;; no logical CHS mapping used
, just physical CHS
8863 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8864 mov (0x003d + 0x00), bx
;; number of physical cylinders
8865 mov (0x003d + 0x02), cl
;; number of physical heads
8866 mov (0x003d + 0x0E), dl
;; number of physical sectors
8869 hd0_post_logical_chs
:
8870 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8871 mov (0x003d + 0x09), bx
;; number of physical cylinders
8872 mov (0x003d + 0x0b), cl
;; number of physical heads
8873 mov (0x003d + 0x04), dl
;; number of physical sectors
8874 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8876 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8879 jnbe hd0_post_above_2048
8880 ;; 1024 < c
<= 2048 cylinders
8883 jmp hd0_post_store_logical
8885 hd0_post_above_2048
:
8887 jnbe hd0_post_above_4096
8888 ;; 2048 < c
<= 4096 cylinders
8891 jmp hd0_post_store_logical
8893 hd0_post_above_4096
:
8895 jnbe hd0_post_above_8192
8896 ;; 4096 < c
<= 8192 cylinders
8899 jmp hd0_post_store_logical
8901 hd0_post_above_8192
:
8902 ;; 8192 < c
<= 16384 cylinders
8906 hd0_post_store_logical
:
8907 mov (0x003d + 0x00), bx
;; number of physical cylinders
8908 mov (0x003d + 0x02), cl
;; number of physical heads
8910 mov cl
, #0x0f ;; repeat count
8911 mov si
, #0x003d ;; offset to disk0 FDPT
8912 mov al
, #0x00 ;; sum
8913 hd0_post_checksum_loop
:
8917 jnz hd0_post_checksum_loop
8918 not al
;; now take
2s complement
8921 ;;; Done filling EBDA table
for hard disk
0.
8925 ;; is there really a second hard disk
? if not, return now
8933 ;; check that the hd type is really
0x0f.
8938 ;; check that the extended type is
47 - user definable
8942 cmp al
, #47 ;; decimal 47 - user definable
8947 ;; CMOS purpose param table offset
8948 ;; 0x24 cylinders low
0
8949 ;; 0x25 cylinders high
1
8951 ;; 0x27 write pre
-comp low
5
8952 ;; 0x28 write pre
-comp high
6
8954 ;; 0x2a landing zone low C
8955 ;; 0x2b landing zone high D
8956 ;; 0x2c sectors
/track E
8957 ;;; Fill EBDA table
for hard disk
1.
8967 mov (0x004d + 0x05), ax
;; write precomp word
8972 mov (0x004d + 0x08), al
;; drive control byte
8981 mov (0x004d + 0x0C), ax
;; landing zone word
8983 mov al
, #0x25 ;; get cylinders word in AX
8985 in al
, #0x71 ;; high byte
8989 in al
, #0x71 ;; low byte
8990 mov bx
, ax
;; BX
= cylinders
8995 mov cl
, al
;; CL
= heads
9000 mov dl
, al
;; DL
= sectors
9003 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
9005 hd1_post_physical_chs
:
9006 ;; no logical CHS mapping used
, just physical CHS
9007 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
9008 mov (0x004d + 0x00), bx
;; number of physical cylinders
9009 mov (0x004d + 0x02), cl
;; number of physical heads
9010 mov (0x004d + 0x0E), dl
;; number of physical sectors
9013 hd1_post_logical_chs
:
9014 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
9015 mov (0x004d + 0x09), bx
;; number of physical cylinders
9016 mov (0x004d + 0x0b), cl
;; number of physical heads
9017 mov (0x004d + 0x04), dl
;; number of physical sectors
9018 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
9020 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
9023 jnbe hd1_post_above_2048
9024 ;; 1024 < c
<= 2048 cylinders
9027 jmp hd1_post_store_logical
9029 hd1_post_above_2048
:
9031 jnbe hd1_post_above_4096
9032 ;; 2048 < c
<= 4096 cylinders
9035 jmp hd1_post_store_logical
9037 hd1_post_above_4096
:
9039 jnbe hd1_post_above_8192
9040 ;; 4096 < c
<= 8192 cylinders
9043 jmp hd1_post_store_logical
9045 hd1_post_above_8192
:
9046 ;; 8192 < c
<= 16384 cylinders
9050 hd1_post_store_logical
:
9051 mov (0x004d + 0x00), bx
;; number of physical cylinders
9052 mov (0x004d + 0x02), cl
;; number of physical heads
9054 mov cl
, #0x0f ;; repeat count
9055 mov si
, #0x004d ;; offset to disk0 FDPT
9056 mov al
, #0x00 ;; sum
9057 hd1_post_checksum_loop
:
9061 jnz hd1_post_checksum_loop
9062 not al
;; now take
2s complement
9065 ;;; Done filling EBDA table
for hard disk
1.
9069 ;--------------------
9070 ;- POST
: EBDA segment
9071 ;--------------------
9072 ; relocated here because the primary POST area isnt big enough
.
9077 mov byte ptr
[0x0], #EBDA_SIZE
9079 xor ax
, ax
; mov EBDA seg into
40E
9081 mov word ptr
[0x40E], #EBDA_SEG
9084 ;--------------------
9085 ;- POST
: EOI
+ jmp via
[0x40:67)
9086 ;--------------------
9087 ; relocated here because the primary POST area isnt big enough
.
9090 out
#0xA0, al ;; slave PIC EOI
9092 out
#0x20, al ;; master PIC EOI
9124 call _s3_resume_panic
9126 ;--------------------
9129 out
#0xA0, al ;; slave PIC EOI
9132 out
#0x20, al ;; master PIC EOI
9135 ;--------------------
9137 ;; in
: AL in BCD format
9138 ;; out
: AL in binary format
, AH will always be
0
9141 and bl
, #0x0f ;; bl has low digit
9142 shr al
, #4 ;; al has high digit
9144 mul al
, bh
;; multiply high digit by
10 (result in AX
)
9145 add al
, bl
;; then add low digit
9148 ;--------------------
9150 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
9151 ;; Timer Ticks Roller
Flag (0x470:byte
)
9152 ;; The Timer Ticks Count needs to be set according to
9153 ;; the current CMOS time
, as
if ticks have been occurring
9154 ;; at
18.2hz since midnight up to
this point
. Calculating
9155 ;; this is a little complicated
. Here are the factors I gather
9156 ;; regarding
this. 14,318,180 hz was the original clock speed
,
9157 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
9158 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
9159 ;; source was divided again by
4 to feed a
1.193Mhz signal to
9160 ;; the timer
. With a maximum
16bit timer count
, this is again
9161 ;; divided down by
65536 to
18.2hz
.
9163 ;; 14,318,180 Hz clock
9164 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
9165 ;; /4 = 1,193,181 Hz fed to timer
9166 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
9167 ;; 1 second
= 18.20650736 ticks
9168 ;; 1 minute
= 1092.390442 ticks
9169 ;; 1 hour
= 65543.42651 ticks
9171 ;; Given the values in the CMOS clock
, one could calculate
9172 ;; the number of ticks by the following
:
9173 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
9174 ;; (BcdToBin(minutes
) * 1092.3904)
9175 ;; (BcdToBin(hours
) * 65543.427)
9176 ;; To get a little more accuracy
, since Im
using integer
9177 ;; arithmatic
, I use
:
9178 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
9179 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
9180 ;; (BcdToBin(hours
) * 65543427) / 1000
9185 xor eax
, eax
;; clear EAX
9188 in al
, #0x71 ;; AL has CMOS seconds in BCD
9189 call BcdToBin
;; EAX now has seconds in binary
9195 mov ecx
, eax
;; ECX will accumulate total ticks
9198 xor eax
, eax
;; clear EAX
9201 in al
, #0x71 ;; AL has CMOS minutes in BCD
9202 call BcdToBin
;; EAX now has minutes in binary
9208 add ecx
, eax
;; add to total ticks
9211 xor eax
, eax
;; clear EAX
9214 in al
, #0x71 ;; AL has CMOS hours in BCD
9215 call BcdToBin
;; EAX now has hours in binary
9221 add ecx
, eax
;; add to total ticks
9223 mov
0x46C, ecx
;; Timer Ticks Count
9225 mov
0x470, al
;; Timer Ticks Rollover Flag
9228 ;--------------------
9230 ;; record completion in BIOS task complete flag
9242 ;--------------------
9247 #include "apmbios.S"
9251 #include "apmbios.S"
9254 #include "apmbios.S"
9258 ;--------------------
9263 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9264 dw bios32_entry_point
, 0xf ;; 32 bit physical address
9265 db
0 ;; revision level
9266 ;; length in paragraphs
and checksum stored in a word to prevent errors
9267 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
9268 & 0xff) << 8) + 0x01
9269 db
0,0,0,0,0 ;; reserved
9274 cmp eax
, #0x49435024 ;; "$PCI"
9276 mov eax
, #0x80000000
9281 #ifdef PCI_FIXED_HOST_BRIDGE
9282 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9285 ;; say ok
if a device is present
9286 cmp eax
, #0xffffffff
9289 mov ebx
, #0x000f0000
9291 mov edx
, #pcibios_protected
9298 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9309 cmp al
, #0x01 ;; installation check
9313 mov edx
, #0x20494350 ;; "PCI "
9316 pci_pro_f02
: ;; find pci device
9324 call pci_pro_select_reg
9338 pci_pro_f03
: ;; find
class code
9344 call pci_pro_select_reg
9349 jne pci_pro_nextdev2
9356 jne pci_pro_devloop2
9359 pci_pro_f08
: ;; read configuration byte
9362 call pci_pro_select_reg
9371 pci_pro_f09
: ;; read configuration word
9374 call pci_pro_select_reg
9383 pci_pro_f0a
: ;; read configuration dword
9386 call pci_pro_select_reg
9393 pci_pro_f0b
: ;; write configuration byte
9396 call pci_pro_select_reg
9405 pci_pro_f0c
: ;; write configuration word
9408 call pci_pro_select_reg
9417 pci_pro_f0d
: ;; write configuration dword
9420 call pci_pro_select_reg
9433 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9443 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
9467 mov eax
, #0x80000000
9472 #ifdef PCI_FIXED_HOST_BRIDGE
9473 cmp eax
, #PCI_FIXED_HOST_BRIDGE
9476 ;; say ok
if a device is present
9477 cmp eax
, #0xffffffff
9488 cmp al
, #0x01 ;; installation check
9493 mov edx
, #0x20494350 ;; "PCI "
9495 mov di
, #pcibios_protected
9498 pci_real_f02
: ;; find pci device
9508 call pci_real_select_reg
9512 jne pci_real_nextdev
9519 jne pci_real_devloop
9524 pci_real_f03
: ;; find
class code
9530 call pci_real_select_reg
9535 jne pci_real_nextdev2
9542 jne pci_real_devloop2
9547 pci_real_f08
: ;; read configuration byte
9550 call pci_real_select_reg
9559 pci_real_f09
: ;; read configuration word
9562 call pci_real_select_reg
9571 pci_real_f0a
: ;; read configuration dword
9574 call pci_real_select_reg
9581 pci_real_f0b
: ;; write configuration byte
9584 call pci_real_select_reg
9593 pci_real_f0c
: ;; write configuration word
9596 call pci_real_select_reg
9605 pci_real_f0d
: ;; write configuration dword
9608 call pci_real_select_reg
9615 pci_real_f0e
: ;; get irq routing options
9617 jne pci_real_unknown
9619 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9620 jb pci_real_too_small
9622 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9630 mov si
, #pci_routing_table_structure_start
9638 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9647 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9651 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9669 pci_real_select_reg
:
9683 pci_routing_table_structure
:
9684 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9686 dw
32 + (6 * 16) ;; table size
9687 db
0 ;; PCI interrupt router bus
9688 db
0x08 ;; PCI interrupt router DevFunc
9689 dw
0x0000 ;; PCI exclusive IRQs
9690 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9691 dw
0x122e ;; compatible PCI interrupt router device ID
9692 dw
0,0 ;; Miniport data
9693 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9695 pci_routing_table_structure_start
:
9696 ;; first slot entry PCI
-to
-ISA (embedded
)
9697 db
0 ;; pci bus number
9698 db
0x08 ;; pci device
number (bit
7-3)
9699 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9700 dw
0xdef8 ;; IRQ bitmap INTA
#
9701 db
0x61 ;; link value INTB
#
9702 dw
0xdef8 ;; IRQ bitmap INTB
#
9703 db
0x62 ;; link value INTC
#
9704 dw
0xdef8 ;; IRQ bitmap INTC
#
9705 db
0x63 ;; link value INTD
#
9706 dw
0xdef8 ;; IRQ bitmap INTD
#
9707 db
0 ;; physical
slot (0 = embedded
)
9709 ;; second slot entry
: 1st PCI slot
9710 db
0 ;; pci bus number
9711 db
0x10 ;; pci device
number (bit
7-3)
9712 db
0x61 ;; link value INTA
#
9713 dw
0xdef8 ;; IRQ bitmap INTA
#
9714 db
0x62 ;; link value INTB
#
9715 dw
0xdef8 ;; IRQ bitmap INTB
#
9716 db
0x63 ;; link value INTC
#
9717 dw
0xdef8 ;; IRQ bitmap INTC
#
9718 db
0x60 ;; link value INTD
#
9719 dw
0xdef8 ;; IRQ bitmap INTD
#
9720 db
1 ;; physical
slot (0 = embedded
)
9722 ;; third slot entry
: 2nd PCI slot
9723 db
0 ;; pci bus number
9724 db
0x18 ;; pci device
number (bit
7-3)
9725 db
0x62 ;; link value INTA
#
9726 dw
0xdef8 ;; IRQ bitmap INTA
#
9727 db
0x63 ;; link value INTB
#
9728 dw
0xdef8 ;; IRQ bitmap INTB
#
9729 db
0x60 ;; link value INTC
#
9730 dw
0xdef8 ;; IRQ bitmap INTC
#
9731 db
0x61 ;; link value INTD
#
9732 dw
0xdef8 ;; IRQ bitmap INTD
#
9733 db
2 ;; physical
slot (0 = embedded
)
9735 ;; 4th slot entry
: 3rd PCI slot
9736 db
0 ;; pci bus number
9737 db
0x20 ;; pci device
number (bit
7-3)
9738 db
0x63 ;; link value INTA
#
9739 dw
0xdef8 ;; IRQ bitmap INTA
#
9740 db
0x60 ;; link value INTB
#
9741 dw
0xdef8 ;; IRQ bitmap INTB
#
9742 db
0x61 ;; link value INTC
#
9743 dw
0xdef8 ;; IRQ bitmap INTC
#
9744 db
0x62 ;; link value INTD
#
9745 dw
0xdef8 ;; IRQ bitmap INTD
#
9746 db
3 ;; physical
slot (0 = embedded
)
9748 ;; 5th slot entry
: 4rd PCI slot
9749 db
0 ;; pci bus number
9750 db
0x28 ;; pci device
number (bit
7-3)
9751 db
0x60 ;; link value INTA
#
9752 dw
0xdef8 ;; IRQ bitmap INTA
#
9753 db
0x61 ;; link value INTB
#
9754 dw
0xdef8 ;; IRQ bitmap INTB
#
9755 db
0x62 ;; link value INTC
#
9756 dw
0xdef8 ;; IRQ bitmap INTC
#
9757 db
0x63 ;; link value INTD
#
9758 dw
0xdef8 ;; IRQ bitmap INTD
#
9759 db
4 ;; physical
slot (0 = embedded
)
9761 ;; 6th slot entry
: 5rd PCI slot
9762 db
0 ;; pci bus number
9763 db
0x30 ;; pci device
number (bit
7-3)
9764 db
0x61 ;; link value INTA
#
9765 dw
0xdef8 ;; IRQ bitmap INTA
#
9766 db
0x62 ;; link value INTB
#
9767 dw
0xdef8 ;; IRQ bitmap INTB
#
9768 db
0x63 ;; link value INTC
#
9769 dw
0xdef8 ;; IRQ bitmap INTC
#
9770 db
0x60 ;; link value INTD
#
9771 dw
0xdef8 ;; IRQ bitmap INTD
#
9772 db
5 ;; physical
slot (0 = embedded
)
9774 pci_routing_table_structure_end
:
9780 pcibios_init_sel_reg
:
9792 pcibios_init_iomem_bases
:
9795 mov eax
, #0xe0000000 ;; base for memory init
9797 mov ax
, #0xc000 ;; base for i/o init
9799 mov ax
, #0x0010 ;; start at base address #0
9804 call pcibios_init_sel_reg
9809 mov dl
, #0x04 ;; disable i/o and memory space access
9810 call pcibios_init_sel_reg
9817 call pcibios_init_sel_reg
9823 mov eax
, #0xffffffff
9828 xor eax
, #0xffffffff
9832 add eax
, ecx
;; calculate next free mem base
9833 add eax
, #0x01000000
9834 and eax
, #0xff000000
9848 add ax
, cx
;; calculate next free i
/o base
9856 je enable_iomem_space
9857 mov byte ptr
[bp
-8], al
9858 jmp pci_init_io_loop2
9860 mov dl
, #0x04 ;; enable i/o and memory space access if available
9861 call pcibios_init_sel_reg
9867 mov byte ptr
[bp
-8], #0x10
9870 jne pci_init_io_loop1
9875 pcibios_init_set_elcr
:
9899 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9904 mov si
, #pci_routing_table_structure
9908 call pcibios_init_sel_reg
9911 cmp eax
, [si
+12] ;; check irq router
9914 call pcibios_init_sel_reg
9915 push bx
;; save irq router bus
+ devfunc
9918 out dx
, ax
;; reset PIRQ route control
9925 add si
, #0x20 ;; set pointer to 1st entry
9927 mov ax
, #pci_irq_list
9936 call pcibios_init_sel_reg
9940 jnz pci_test_int_pin
9946 call pcibios_init_sel_reg
9951 dec al
;; determine pirq reg
9960 call pcibios_init_sel_reg
9967 mov bx
, [bp
-2] ;; pci irq list pointer
9972 call pcibios_init_set_elcr
9976 add bl
, [bp
-3] ;; pci function number
9978 call pcibios_init_sel_reg
9985 jnz pci_init_irq_loop2
9988 mov byte ptr
[bp
-3], #0x00
9989 loop pci_init_irq_loop1
9996 #endif // !BX_ROMBIOS32
9997 #endif // BX_PCIBIOS
10001 ;; save a20
and enable it
10007 ;; save SS
:SP to the BDA
10014 lidt
[pmode_IDT_info
]
10016 lgdt
[rombios32_gdt_48
]
10017 ;; set PE bit in CR0
10021 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
10024 dw
0x000f ;; high
16 bit address
10029 ;; init data segments
10039 ;; init the stack pointer to point below EBDA
10045 ;; pass pointer to s3_resume_flag
and s3_resume_vector to rombios32
10049 ;; call rombios32 code
10050 mov eax
, #0x000e0000
10053 ;; return to
16 bit
protected mode first
10060 ;; restore data segment limits to
0xffff
10068 ;; reset PE bit in CR0
10073 ;; far jump to flush CPU queue after transition to real mode
10074 JMP_AP(0xf000, rombios32_real_mode
)
10076 rombios32_real_mode
:
10077 ;; restore IDT to normal real
-mode defaults
10079 lidt
[rmode_IDT_info
]
10087 ;; restore SS
:SP from the BDA
10104 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
10105 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
10106 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
10107 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
10108 #endif // BX_ROMBIOS32
10111 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
10116 and al
, #0xdf ; clear input mode
10126 mov
[bx
+0x408], dx
; Parallel I
/O address
10128 mov
[bx
+0x478], cl
; Parallel printer timeout
10133 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
10152 mov
[bx
+0x400], dx
; Serial I
/O address
10154 mov
[bx
+0x47c], cl
; Serial timeout
10181 ;; We need a copy of
this string
, but we are
not actually a PnP BIOS
,
10182 ;; so make sure it is
*not* aligned
, so OSes will
not see it
if they scan
.
10190 ;; Scan
for existence of valid expansion ROMS
.
10191 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
10192 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
10193 ;; System ROM
: only
0xE0000
10199 ;; 2 ROM length in
512-byte blocks
10200 ;; 3 ROM initialization entry
point (FAR CALL
)
10205 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
10206 cmp
[0], #0xAA55 ;; look for signature
10207 jne rom_scan_increment
10209 jnz rom_scan_increment
10210 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
10212 ;; We want our increment in
512-byte quantities
, rounded to
10213 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
10215 jz block_count_rounded
10216 and al
, #0xfc ;; needs rounding up
10218 block_count_rounded
:
10220 xor bx
, bx
;; Restore DS back to
0000:
10224 ;; Push addr of ROM entry point
10225 push cx
;; Push seg
10226 push
#0x0003 ;; Push offset
10228 ;; Point ES
:DI at
"$PnP", which tells the ROM that we are a PnP BIOS
.
10229 ;; That should stop it grabbing INT
19h
; we will use its BEV instead
.
10234 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
10235 db
0xff ;; call_far ss
:[bp
+0]
10238 cli
;; In
case expansion ROM BIOS turns IF on
10239 add sp
, #2 ;; Pop offset value
10240 pop cx
;; Pop seg
value (restore CX
)
10242 ;; Look at the ROM
's PnP Expansion header. Properly, we're supposed
10243 ;; to init all the ROMs
and then go back
and build an IPL table of
10244 ;; all the bootable devices
, but we can get away with one pass
.
10245 mov ds
, cx
;; ROM base
10246 mov bx
, 0x001a ;; 0x1A is the offset into ROM header that contains
...
10247 mov ax
, [bx
] ;; the offset of PnP expansion header
, where
...
10248 cmp ax
, #0x5024 ;; we look for signature "$PnP"
10253 mov ax
, 0x1a[bx
] ;; 0x1A is also the offset into the expansion header of
...
10254 cmp ax
, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
10257 ;; Found a device that thinks it can boot the system
. Record its BEV
and product name string
.
10258 mov di
, 0x10[bx
] ;; Pointer to the product name string
or zero
if none
10259 mov bx
, #IPL_SEG ;; Go to the segment where the IPL table lives
10261 mov bx
, IPL_COUNT_OFFSET
;; Read the number of entries so far
10262 cmp bx
, #IPL_TABLE_ENTRIES
10263 je no_bev
;; Get out
if the table is full
10264 shl bx
, #0x4 ;; Turn count into offset (entries are 16 bytes)
10265 mov
0[bx
], #IPL_TYPE_BEV ;; This entry is a BEV device
10266 mov
6[bx
], cx
;; Build a far pointer from the segment
...
10267 mov
4[bx
], ax
;; and the offset
10270 mov
0xA[bx
], cx
;; Build a far pointer from the segment
...
10271 mov
8[bx
], di
;; and the offset
10273 shr bx
, #0x4 ;; Turn the offset back into a count
10274 inc bx
;; We have one more entry now
10275 mov IPL_COUNT_OFFSET
, bx
;; Remember that
.
10278 pop di
;; Restore DI
10279 pop ax
;; Restore AX
10280 rom_scan_increment
:
10281 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
10282 ;; because the segment selector is shifted left
4 bits
.
10284 pop ax
;; Restore AX
10288 xor ax
, ax
;; Restore DS back to
0000:
10293 mov al
, #0x11 ; send initialisation commands
10308 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
10309 #if BX_USE_PS2_MOUSE
10314 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
10317 ;; the following area can be used to write dynamically generated tables
10319 bios_table_area_start
:
10321 dd bios_table_area_end
- bios_table_area_start
- 8;
10326 .org
0xe05b ; POST Entry Point
10331 ;; first reset the DMA controllers
10335 ;; then initialize the DMA controllers
10337 out
0xD6, al
; cascade mode of channel
4 enabled
10339 out
0xD4, al
; unmask channel
4
10341 ;; Examine CMOS shutdown status
.
10349 ;; Reset CMOS shutdown status
.
10351 out
0x70, AL
; select CMOS
register Fh
10353 out
0x71, AL
; set shutdown action to normal
10355 ;; Examine CMOS shutdown status
.
10358 ;; 0x00, 0x09, 0x0D+ = normal startup
10366 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
10370 ;; 0x0A = jmp via
[0x40:0x67] jump
10374 ;; 0x0B = iret via
[0x40:0x67]
10378 ;; 0x0C = retf via
[0x40:0x67]
10382 ;; Examine CMOS shutdown status
.
10383 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08 = Unimplemented shutdown status
.
10385 call _shutdown_status_panic
10391 ; 0xb0, 0x20, /* mov al, #0x20 */
10392 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10402 ; case 0: normal startup
10411 ;; Save shutdown status
10417 ;; zero out BIOS data
area (40:00..40:ff
)
10419 mov cx
, #0x0080 ;; 128 words
10425 call _log_bios_start
10427 ;; set all interrupts to
default handler
10428 xor bx
, bx
;; offset index
10429 mov cx
, #0x0100 ;; counter (256 interrupts)
10430 mov ax
, #dummy_iret_handler
10438 loop post_default_ints
10440 ;; set vector
0x79 to zero
10441 ;; this is used by
'gardian angel' protection system
10442 SET_INT_VECTOR(0x79, #0, #0)
10444 ;; base memory in K
40:13 (word
)
10445 mov ax
, #BASE_MEM_IN_K
10449 ;; Manufacturing Test
40:12
10452 ;; Warm Boot Flag
0040:0072
10453 ;; value of
1234h
= skip memory checks
10457 ;; Printer Services vector
10458 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10460 ;; Bootstrap failure vector
10461 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10463 ;; Bootstrap Loader vector
10464 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10466 ;; User Timer Tick vector
10467 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10469 ;; Memory Size Check vector
10470 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10472 ;; Equipment Configuration Check vector
10473 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10476 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10482 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10483 ;; int 1C already points at
dummy_iret_handler (above
)
10484 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
10486 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
10491 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10492 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10496 mov
0x0417, al
/* keyboard shift flags, set 1 */
10497 mov
0x0418, al
/* keyboard shift flags, set 2 */
10498 mov
0x0419, al
/* keyboard alt-numpad work area */
10499 mov
0x0471, al
/* keyboard ctrl-break flag */
10500 mov
0x0497, al
/* keyboard status flags 4 */
10502 mov
0x0496, al
/* keyboard status flags 3 */
10505 /* keyboard head of buffer pointer */
10509 /* keyboard end of buffer pointer */
10512 /* keyboard pointer to start of buffer */
10516 /* keyboard pointer to end of buffer */
10520 /* init the keyboard */
10521 call _keyboard_init
10523 ;; mov CMOS Equipment Byte to BDA Equipment Word
10532 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10536 mov cl
, #0x14 ; timeout value
10537 mov dx
, #0x378 ; Parallel I/O address, port 1
10538 call detect_parport
10539 mov dx
, #0x278 ; Parallel I/O address, port 2
10540 call detect_parport
10542 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
10544 or ax
, bx
; set number of parallel ports
10548 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10549 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10551 mov cl
, #0x0a ; timeout value
10552 mov dx
, #0x03f8 ; Serial I/O address, port 1
10554 mov dx
, #0x02f8 ; Serial I/O address, port 2
10556 mov dx
, #0x03e8 ; Serial I/O address, port 3
10558 mov dx
, #0x02e8 ; Serial I/O address, port 4
10561 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
10563 or ax
, bx
; set number of serial port
10567 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10568 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10569 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10570 ;; BIOS DATA AREA
0x4CE ???
10571 call timer_tick_post
10573 ;; PS
/2 mouse setup
10574 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10576 ;; IRQ13 (FPU exception
) setup
10577 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10580 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10585 mov cx
, #0xc000 ;; init vga bios
10589 call _print_bios_banner
10592 call rombios32_init
10595 call pcibios_init_iomem_bases
10596 call pcibios_init_irqs
10597 #endif //BX_PCIBIOS
10603 call floppy_drive_post
10606 ;; Hard Drive setup
10608 call hard_drive_post
10613 ;; ATA
/ATAPI driver setup
10619 #endif // BX_USE_ATADRV
10621 #if BX_ELTORITO_BOOT
10623 ;; eltorito floppy
/harddisk emulation from cd
10627 #endif // BX_ELTORITO_BOOT
10629 call _init_boot_vectors
10631 mov cx
, #0xc800 ;; init option roms
10635 #if BX_ELTORITO_BOOT
10636 call _interactive_bootkey
10637 #endif // BX_ELTORITO_BOOT
10639 sti
;; enable interrupts
10642 .org
0xe2c3 ; NMI Handler Entry Point
10644 ;; FIXME the NMI handler should
not panic
10645 ;; but iret when called from
int75 (fpu exception
)
10646 call _nmi_handler_msg
10650 out
0xf0, al
// clear irq13
10651 call eoi_both_pics
// clear interrupt
10652 int 2 // legacy nmi call
10655 ;-------------------------------------------
10656 ;- INT
13h Fixed Disk Services Entry Point
-
10657 ;-------------------------------------------
10658 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10660 //JMPL(int13_relocated)
10661 jmp int13_relocated
10663 .org
0xe401 ; Fixed Disk Parameter Table
10668 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10671 jmp int19_relocated
10672 ;-------------------------------------------
10673 ;- System BIOS Configuration Data Table
10674 ;-------------------------------------------
10675 .org BIOS_CONFIG_TABLE
10676 db
0x08 ; Table
size (bytes
) -Lo
10677 db
0x00 ; Table
size (bytes
) -Hi
10682 ; b7
: 1=DMA channel
3 used by hard disk
10683 ; b6
: 1=2 interrupt controllers present
10684 ; b5
: 1=RTC present
10685 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10686 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10687 ; b2
: 1=extended BIOS data area used
10688 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10689 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10693 (BX_CALL_INT15_4F
<< 4) | \
10695 (BX_USE_EBDA
<< 2) | \
10699 ; b7
: 1=32-bit DMA supported
10700 ; b6
: 1=int16h
, function
9 supported
10701 ; b5
: 1=int15h
/C6h (get POS data
) supported
10702 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10703 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10704 ; b2
: 1=non
-8042 kb controller
10705 ; b1
: 1=data streaming supported
10719 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10720 ; b3
: SCSI on system board
10721 ; b2
: info panel installed
10722 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10723 ; b0
: SCSI supported in IML
10727 ; b6
: EEPROM present
10728 ; b5
-3: ABIOS
presence (011 = not supported
)
10730 ; b1
: memory split above
16Mb supported
10731 ; b0
: POSTEXT directly supported by POST
10733 ; Feature byte
5 (IBM
)
10734 ; b1
: enhanced mouse
10740 .org
0xe729 ; Baud Rate Generator Table
10745 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10751 call _int14_function
10757 ;----------------------------------------
10758 ;- INT
16h Keyboard Service Entry Point
-
10759 ;----------------------------------------
10775 call _int16_function
10785 and BYTE
[bp
+ 0x06], #0xbf
10793 or BYTE
[bp
+ 0x06], #0x40
10801 int16_wait_for_key
:
10805 jne int16_key_found
10809 /* no key yet, call int 15h, function AX=9002 */
10810 0x50, /* push AX */
10811 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10812 0xcd, 0x15, /* int 15h */
10814 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10816 jmp int16_wait_for_key
10821 call _int16_function
10826 /* notify int16 complete w/ int 15h, function AX=9102 */
10827 0x50, /* push AX */
10828 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10829 0xcd, 0x15, /* int 15h */
10836 ;-------------------------------------------------
10837 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10838 ;-------------------------------------------------
10844 mov al
, #0xAD ;;disable keyboard
10853 in al
, #0x60 ;;read key from keyboard controller
10857 #ifdef BX_CALL_INT15_4F
10858 mov ah
, #0x4f ;; allow for keyboard intercept
10864 ;; check
for extended key
10866 jne int09_check_pause
10869 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10871 mov BYTE
[0x496], al
10874 int09_check_pause
: ;; check
for pause key
10876 jne int09_process_key
10879 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10881 mov BYTE
[0x496], al
10887 call _int09_function
10893 call eoi_master_pic
10896 mov al
, #0xAE ;;enable keyboard
10902 ;----------------------------------------
10903 ;- INT
13h Diskette Service Entry Point
-
10904 ;----------------------------------------
10907 jmp int13_noeltorito
10909 ;---------------------------------------------
10910 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10911 ;---------------------------------------------
10912 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10922 mov al
, #0x08 ; sense interrupt status
10940 xor ax
, ax
;; segment
0000
10942 call eoi_master_pic
10944 or al
, #0x80 ;; diskette interrupt has occurred
10952 .org
0xefc7 ; Diskette Controller Parameter Table
10953 diskette_param_table
:
10954 ;; Since no provisions are made
for multiple drive types
, most
10955 ;; values in
this table are ignored
. I set parameters
for 1.44M
10958 db
0x02 ;; head load time
0000001, DMA used
10970 ;----------------------------------------
10971 ;- INT17h
: Printer Service Entry Point
-
10972 ;----------------------------------------
10979 call _int17_function
10984 diskette_param_table2
:
10985 ;; New diskette parameter table adding
3 parameters from IBM
10986 ;; Since no provisions are made
for multiple drive types
, most
10987 ;; values in
this table are ignored
. I set parameters
for 1.44M
10990 db
0x02 ;; head load time
0000001, DMA used
11000 db
79 ;; maximum track
11001 db
0 ;; data transfer rate
11002 db
4 ;; drive type in cmos
11004 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
11011 .org
0xf065 ; INT
10h Video Support Service Entry Point
11013 ;; dont
do anything
, since the VGA BIOS handles int10h requests
11016 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
11021 .org
0xf841 ; INT
12h Memory Size Service Entry Point
11022 ; ??? different
for Pentium (machine check
)?
11034 .org
0xf84d ; INT
11h Equipment List Service Entry Point
11046 .org
0xf859 ; INT
15h System Services Entry Point
11060 #if BX_USE_PS2_MOUSE
11062 je int15_handler_mouse
11064 call _int15_function
11065 int15_handler_mouse_ret
:
11067 int15_handler32_ret
:
11077 #if BX_USE_PS2_MOUSE
11078 int15_handler_mouse
:
11079 call _int15_function_mouse
11080 jmp int15_handler_mouse_ret
11085 call _int15_function32
11087 jmp int15_handler32_ret
11089 ;; Protected mode IDT descriptor
11091 ;; I just make the limit
0, so the machine will shutdown
11092 ;; if an exception occurs during
protected mode memory
11095 ;; Set base to f0000 to correspond to beginning of BIOS
,
11096 ;; in
case I actually define an IDT later
11100 dw
0x0000 ;; limit
15:00
11101 dw
0x0000 ;; base
15:00
11102 db
0x0f ;; base
23:16
11104 ;; Real mode IDT descriptor
11106 ;; Set to typical real
-mode values
.
11111 dw
0x03ff ;; limit
15:00
11112 dw
0x0000 ;; base
15:00
11113 db
0x00 ;; base
23:16
11119 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
11132 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
11133 mov ds
, ax
; on
16bit
protected mode
.
11134 jmp int1a_callfunction
11141 int1a_callfunction
:
11142 call _int1a_function
11148 ;; int70h
: IRQ8
- CMOS RTC
11155 call _int70_function
11163 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
11171 ;; time to turn off
drive(s
)?
11174 jz int08_floppy_off
11177 jnz int08_floppy_off
11178 ;; turn
motor(s
) off
11187 mov eax
, 0x046c ;; get ticks dword
11190 ;; compare eax to one days worth of timer ticks at
18.2 hz
11191 cmp eax
, #0x001800B0
11192 jb int08_store_ticks
11193 ;; there has been a midnight rollover at
this point
11194 xor eax
, eax
;; zero out counter
11195 inc BYTE
0x0470 ;; increment rollover flag
11198 mov
0x046c, eax
;; store
new ticks dword
11199 ;; chain to user timer tick INT
#0x1c
11201 //;; call_ep [ds:loc]
11202 //CALL_EP( 0x1c << 2 )
11205 call eoi_master_pic
11210 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
11214 .ascii BIOS_COPYRIGHT_STRING
11216 ;------------------------------------------------
11217 ;- IRET Instruction
for Dummy Interrupt Handler
-
11218 ;------------------------------------------------
11219 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
11220 dummy_iret_handler
:
11223 .org
0xff54 ; INT
05h Print Screen Service Entry Point
11227 .org
0xfff0 ; Power
-up Entry Point
11230 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
11231 .ascii BIOS_BUILD_DATE
11233 .org
0xfffe ; System Model ID
11237 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
11240 * This font comes from the fntcol16.zip package (c) by Joseph Gil
11241 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
11242 * This font is public domain
11244 static Bit8u vgafont8
[128*8]=
11246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11247 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
11248 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
11249 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11250 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11251 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
11252 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
11253 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
11254 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
11255 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
11256 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
11257 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
11258 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
11259 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
11260 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
11261 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
11262 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
11263 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
11264 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
11265 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
11266 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
11267 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
11268 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11269 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11270 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11271 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11272 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11273 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11274 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11275 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11276 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11277 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11279 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11280 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11281 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11282 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11283 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11284 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11285 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11286 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11287 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11288 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11289 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11290 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11291 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11292 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11293 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11294 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11295 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11296 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11297 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11298 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11299 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11300 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11301 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11302 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11303 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11304 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11305 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11306 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11307 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11308 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11309 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11310 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11311 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11312 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11313 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11314 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11315 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11316 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11317 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11318 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11319 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11320 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11321 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11322 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11323 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11324 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11325 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11326 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11327 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11328 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11329 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11330 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11331 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11332 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11333 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11334 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11335 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11336 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11337 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11338 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11339 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11340 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11342 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11343 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11344 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11345 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11346 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11347 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11348 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11349 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11350 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11351 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11352 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11353 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11354 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11355 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11356 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11357 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11358 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11359 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11360 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11361 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11362 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11363 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11364 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11365 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11366 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11367 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11368 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11369 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11370 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11371 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11372 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11373 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11378 bios_table_area_end
:
11379 // bcc-generated data will be placed here