1 /////////////////////////////////////////////////////////////////////////
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex x86 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)
125 #define DEBUG_ROMBIOS 0
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 // Define the application NAME
174 # define BX_APPNAME "Plex86"
176 # define BX_APPNAME "Bochs"
180 #if BX_USE_ATADRV && BX_CPU<3
181 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
183 #if BX_USE_ATADRV && !BX_USE_EBDA
184 # error ATA/ATAPI Driver can only be used if EBDA is available
186 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
187 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
189 #if BX_PCIBIOS && BX_CPU<3
190 # error PCI BIOS can only be used with 386+ cpu
192 #if BX_APM && BX_CPU<3
193 # error APM BIOS can only be used with 386+ cpu
196 #ifndef BX_SMP_PROCESSORS
197 #define BX_SMP_PROCESSORS 1
198 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
201 #define PANIC_PORT 0x400
202 #define PANIC_PORT2 0x401
203 #define INFO_PORT 0x402
204 #define DEBUG_PORT 0x403
206 // define this if you want to make PCIBIOS working on a specific bridge only
207 // undef enables PCIBIOS when at least one PCI device is found
208 // i440FX is emulated by Bochs and QEMU
209 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
212 // #$20 is hex 20 = 32
213 // #0x20 is hex 20 = 32
220 // all hex literals should be prefixed with '0x'
221 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
222 // no mov SEG-REG, #value, must mov register into seg-reg
223 // grep -i "mov[ ]*.s" rombios.c
225 // This is for compiling with gcc2 and gcc3
226 #define ASM_START #asm
227 #define ASM_END #endasm
241 ;; the HALT macro is called with the line number of the HALT call
.
242 ;; The line number is then sent to the PANIC_PORT
, causing Bochs
/Plex
243 ;; to print a BX_PANIC message
. This will normally halt the simulation
244 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
245 ;; However
, users can choose to make panics non
-fatal
and continue.
272 typedef unsigned char Bit8u
;
273 typedef unsigned short Bit16u
;
274 typedef unsigned short bx_bool
;
275 typedef unsigned long Bit32u
;
279 void memsetb(seg
,offset
,value
,count
);
280 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
281 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
283 // memset of count bytes
285 memsetb(seg
,offset
,value
,count
)
300 mov cx
, 10[bp
] ; count
303 mov ax
, 4[bp
] ; segment
305 mov ax
, 6[bp
] ; offset
307 mov al
, 8[bp
] ; value
323 // memcpy of count bytes
325 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
343 mov cx
, 12[bp
] ; count
346 mov ax
, 4[bp
] ; dsegment
348 mov ax
, 6[bp
] ; doffset
350 mov ax
, 8[bp
] ; ssegment
352 mov ax
, 10[bp
] ; soffset
370 // memcpy of count dword
372 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
390 mov cx
, 12[bp
] ; count
393 mov ax
, 4[bp
] ; dsegment
395 mov ax
, 6[bp
] ; doffset
397 mov ax
, 8[bp
] ; ssegment
399 mov ax
, 10[bp
] ; soffset
417 #endif //BX_USE_ATADRV
419 // read_dword and write_dword functions
420 static Bit32u
read_dword();
421 static void write_dword();
424 read_dword(seg
, offset
)
434 mov ax
, 4[bp
] ; segment
436 mov bx
, 6[bp
] ; offset
441 ;; ax
= return value (word
)
442 ;; dx
= return value (word
)
451 write_dword(seg
, offset
, data
)
463 mov ax
, 4[bp
] ; segment
465 mov bx
, 6[bp
] ; offset
466 mov ax
, 8[bp
] ; data word
467 mov
[bx
], ax
; write data word
470 mov ax
, 10[bp
] ; data word
471 mov
[bx
], ax
; write data word
480 // Bit32u (unsigned long) and long helper functions
509 cmp eax
, dword ptr
[di
]
528 mul eax
, dword ptr
[di
]
624 // for access to RAM area which is used by interrupt vectors
625 // and BIOS Data Area
628 unsigned char filler1
[0x400];
629 unsigned char filler2
[0x6c];
635 #define BiosData ((bios_data_t *) 0)
639 Bit16u heads
; // # heads
640 Bit16u cylinders
; // # cylinders
641 Bit16u spt
; // # sectors / track
661 Bit8u iface
; // ISA or PCI
662 Bit16u iobase1
; // IO Base 1
663 Bit16u iobase2
; // IO Base 2
668 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
669 Bit8u device
; // Detected type of attached devices (hd/cd/none)
670 Bit8u removable
; // Removable device flag
671 Bit8u lock
; // Locks for removable devices
672 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
673 Bit8u mode
; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
674 Bit16u blksize
; // block size
676 Bit8u translation
; // type of translation
677 chs_t lchs
; // Logical CHS
678 chs_t pchs
; // Physical CHS
680 Bit32u sectors
; // Total sectors count
685 ata_channel_t channels
[BX_MAX_ATA_INTERFACES
];
688 ata_device_t devices
[BX_MAX_ATA_DEVICES
];
690 // map between (bios hd id - 0x80) and ata channels
691 Bit8u hdcount
, hdidmap
[BX_MAX_ATA_DEVICES
];
693 // map between (bios cd id - 0xE0) and ata channels
694 Bit8u cdcount
, cdidmap
[BX_MAX_ATA_DEVICES
];
696 // Buffer for DPTE table
699 // Count of transferred sectors and bytes
706 // ElTorito Device Emulation data
710 Bit8u emulated_drive
;
711 Bit8u controller_index
;
714 Bit16u buffer_segment
;
721 #endif // BX_ELTORITO_BOOT
723 // for access to EBDA area
724 // The EBDA structure should conform to
725 // http://www.frontiernet.net/~fys/rombios.htm document
726 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
728 unsigned char filler1
[0x3D];
730 // FDPT - Can be splitted in data members if needed
731 unsigned char fdpt0
[0x10];
732 unsigned char fdpt1
[0x10];
734 unsigned char filler2
[0xC4];
740 // El Torito Emulation data
742 #endif // BX_ELTORITO_BOOT
746 #define EbdaData ((ebda_data_t *) 0)
748 // for access to the int13ext structure
759 #define Int13Ext ((int13ext_t *) 0)
761 // Disk Physical Table definition
768 Bit32u sector_count1
;
769 Bit32u sector_count2
;
780 Bit8u device_path
[8];
785 #define Int13DPT ((dpt_t *) 0)
787 #endif // BX_USE_ATADRV
792 Bit16u di
, si
, bp
, sp
;
793 Bit16u bx
, dx
, cx
, ax
;
797 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
805 Bit32u edi
, esi
, ebp
, esp
;
806 Bit32u ebx
, edx
, ecx
, eax
;
809 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
810 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
838 #define SetCF(x) x.u.r8.flagsl |= 0x01
839 #define SetZF(x) x.u.r8.flagsl |= 0x40
840 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
841 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
842 #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 Bit32u
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_DS();
889 //static void set_DS();
890 static Bit16u
get_SS();
891 static unsigned int enqueue_key();
892 static unsigned int dequeue_key();
893 static void get_hd_geometry();
894 static void set_diskette_ret_status();
895 static void set_diskette_current_cyl();
896 static void determine_floppy_media();
897 static bx_bool
floppy_drive_exists();
898 static bx_bool
floppy_drive_recal();
899 static bx_bool
floppy_media_known();
900 static bx_bool
floppy_media_sense();
901 static bx_bool
set_enable_a20();
902 static void debugger_on();
903 static void debugger_off();
904 static void keyboard_init();
905 static void keyboard_panic();
906 static void shutdown_status_panic();
907 static void nmi_handler_msg();
909 static void print_bios_banner();
910 static void print_boot_device();
911 static void print_boot_failure();
912 static void print_cdromboot_failure();
916 // ATA / ATAPI driver
921 Bit16u
ata_cmd_non_data();
922 Bit16u
ata_cmd_data_in();
923 Bit16u
ata_cmd_data_out();
924 Bit16u
ata_cmd_packet();
926 Bit16u
atapi_get_sense();
927 Bit16u
atapi_is_ready();
928 Bit16u
atapi_is_cdrom();
930 #endif // BX_USE_ATADRV
935 Bit8u
cdemu_isactive();
936 Bit8u
cdemu_emulated_drive();
940 #endif // BX_ELTORITO_BOOT
942 static char bios_cvs_version_string
[] = "$Revision$";
943 static char bios_date_string
[] = "$Date$";
945 static char CVSID
[] = "$Id$";
947 /* Offset to skip the CVS $Id: prefix */
948 #define bios_version_string (CVSID + 4)
949 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
951 #define BIOS_PRINTF_HALT 1
952 #define BIOS_PRINTF_SCREEN 2
953 #define BIOS_PRINTF_INFO 4
954 #define BIOS_PRINTF_DEBUG 8
955 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
956 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
958 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
960 // Defines the output macros.
961 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
962 // per-device basis. Debug info are sent only in debug mode
964 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
966 # define BX_DEBUG(format, p...)
968 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
969 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
972 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
974 # define BX_DEBUG_ATA(a...)
977 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
979 # define BX_DEBUG_INT13_HD(a...)
982 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
984 # define BX_DEBUG_INT13_CD(a...)
987 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
989 # define BX_DEBUG_INT13_ET(a...)
992 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
994 # define BX_DEBUG_INT13_FL(a...)
997 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
999 # define BX_DEBUG_INT15(a...)
1002 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1004 # define BX_DEBUG_INT16(a...)
1007 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1009 # define BX_DEBUG_INT1A(a...)
1012 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1014 # define BX_DEBUG_INT74(a...)
1017 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1018 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1019 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1020 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1021 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1022 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1023 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1024 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1026 #define GET_AL() ( AX & 0x00ff )
1027 #define GET_BL() ( BX & 0x00ff )
1028 #define GET_CL() ( CX & 0x00ff )
1029 #define GET_DL() ( DX & 0x00ff )
1030 #define GET_AH() ( AX >> 8 )
1031 #define GET_BH() ( BX >> 8 )
1032 #define GET_CH() ( CX >> 8 )
1033 #define GET_DH() ( DX >> 8 )
1035 #define GET_ELDL() ( ELDX & 0x00ff )
1036 #define GET_ELDH() ( ELDX >> 8 )
1038 #define SET_CF() FLAGS |= 0x0001
1039 #define CLEAR_CF() FLAGS &= 0xfffe
1040 #define GET_CF() (FLAGS & 0x0001)
1042 #define SET_ZF() FLAGS |= 0x0040
1043 #define CLEAR_ZF() FLAGS &= 0xffbf
1044 #define GET_ZF() (FLAGS & 0x0040)
1046 #define UNSUPPORTED_FUNCTION 0x86
1049 #define MAX_SCAN_CODE 0x58
1057 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1058 { none
, none
, none
, none
, none
},
1059 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1060 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1061 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1062 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1063 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1064 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1065 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1066 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1067 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1068 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1069 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1070 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1071 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1072 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1073 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1074 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1075 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1076 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1077 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1078 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1079 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1080 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1081 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1082 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1083 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1084 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1085 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1086 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1087 { none
, none
, none
, none
, none
}, /* L Ctrl */
1088 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1089 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1090 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1091 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1092 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1093 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1094 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1095 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1096 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1097 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1098 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1099 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1100 { none
, none
, none
, none
, none
}, /* L shift */
1101 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1102 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1103 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1104 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1105 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1106 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1107 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1108 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1109 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1110 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1111 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1112 { none
, none
, none
, none
, none
}, /* R Shift */
1113 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1114 { none
, none
, none
, none
, none
}, /* L Alt */
1115 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1116 { none
, none
, none
, none
, none
}, /* caps lock */
1117 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1118 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1119 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1120 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1121 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1122 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1123 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1124 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1125 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1126 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1127 { none
, none
, none
, none
, none
}, /* Num Lock */
1128 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1129 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1130 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1131 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1132 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1133 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1134 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1135 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1136 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1137 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1138 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1139 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1140 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1141 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1142 { none
, none
, none
, none
, none
},
1143 { none
, none
, none
, none
, none
},
1144 { none
, none
, none
, none
, none
},
1145 { 0x5700, 0x5700, none
, none
, none
}, /* F11 */
1146 { 0x5800, 0x5800, none
, none
, none
} /* F12 */
1230 outb_cmos(cmos_reg
, val
)
1238 mov al
, 4[bp
] ;; cmos_reg
1240 mov al
, 6[bp
] ;; val
1255 mov al
, 4[bp
] ;; cmos_reg
1266 outb_cmos(0x0a, 0x26);
1267 outb_cmos(0x0b, 0x02);
1275 // This function checks to see if the update-in-progress bit
1276 // is set in CMOS Status Register A. If not, it returns 0.
1277 // If it is set, it tries to wait until there is a transition
1278 // to 0, and will return 0 if such a transition occurs. A 1
1279 // is returned only after timing out. The maximum period
1280 // that this bit should be set is constrained to 244useconds.
1281 // The count I use below guarantees coverage or more than
1282 // this time, with any reasonable IPS setting.
1287 while (--count
!= 0) {
1288 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1291 return(1); // update-in-progress never transitioned to 0
1296 read_byte(seg
, offset
)
1306 mov ax
, 4[bp
] ; segment
1308 mov bx
, 6[bp
] ; offset
1310 ;; al
= return value (byte
)
1319 read_word(seg
, offset
)
1329 mov ax
, 4[bp
] ; segment
1331 mov bx
, 6[bp
] ; offset
1333 ;; ax
= return value (word
)
1342 write_byte(seg
, offset
, data
)
1354 mov ax
, 4[bp
] ; segment
1356 mov bx
, 6[bp
] ; offset
1357 mov al
, 8[bp
] ; data byte
1358 mov
[bx
], al
; write data byte
1368 write_word(seg
, offset
, data
)
1380 mov ax
, 4[bp
] ; segment
1382 mov bx
, 6[bp
] ; offset
1383 mov ax
, 8[bp
] ; data word
1384 mov
[bx
], ax
; write data word
1410 //set_DS(ds_selector)
1411 // Bit16u ds_selector;
1418 // mov ax, 4[bp] ; ds_selector
1435 /* serial debug port*/
1436 #define BX_DEBUG_PORT 0x03f8
1439 #define UART_RBR 0x00
1440 #define UART_THR 0x00
1443 #define UART_IER 0x01
1444 #define UART_IIR 0x02
1445 #define UART_FCR 0x02
1446 #define UART_LCR 0x03
1447 #define UART_MCR 0x04
1448 #define UART_DLL 0x00
1449 #define UART_DLM 0x01
1452 #define UART_LSR 0x05
1453 #define UART_MSR 0x06
1454 #define UART_SCR 0x07
1456 int uart_can_tx_byte(base_port
)
1459 return inb(base_port
+ UART_LSR
) & 0x20;
1462 void uart_wait_to_tx_byte(base_port
)
1465 while (!uart_can_tx_byte(base_port
));
1468 void uart_wait_until_sent(base_port
)
1471 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1474 void uart_tx_byte(base_port
, data
)
1478 uart_wait_to_tx_byte(base_port
);
1479 outb(base_port
+ UART_THR
, data
);
1480 uart_wait_until_sent(base_port
);
1509 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1510 uart_tx_byte(BX_DEBUG_PORT
, c
);
1512 #if BX_VIRTUAL_PORTS
1513 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1514 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1516 if (action
& BIOS_PRINTF_SCREEN
) {
1517 if (c
== '\n') wrch('\r');
1523 put_int(action
, val
, width
, neg
)
1528 short nval
= val
/ 10;
1530 put_int(action
, nval
, width
- 1, neg
);
1532 while (--width
> 0) send(action
, ' ');
1533 if (neg
) send(action
, '-');
1535 send(action
, val
- (nval
* 10) + '0');
1539 put_uint(action
, val
, width
, neg
)
1545 unsigned short nval
= val
/ 10;
1547 put_uint(action
, nval
, width
- 1, neg
);
1549 while (--width
> 0) send(action
, ' ');
1550 if (neg
) send(action
, '-');
1552 send(action
, val
- (nval
* 10) + '0');
1555 //--------------------------------------------------------------------------
1557 // A compact variable argument printf function which prints its output via
1558 // an I/O port so that it can be logged by Bochs/Plex.
1559 // Currently, only %x is supported (or %02x, %04x, etc).
1561 // Supports %[format_width][format]
1562 // where format can be d,x,c,s
1563 //--------------------------------------------------------------------------
1565 bios_printf(action
, s
)
1569 Bit8u c
, format_char
;
1573 Bit16u arg_seg
, arg
, nibble
, shift_count
, format_width
;
1581 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1582 #if BX_VIRTUAL_PORTS
1583 outb(PANIC_PORT2
, 0x00);
1585 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1588 while (c
= read_byte(get_CS(), s
)) {
1593 else if (in_format
) {
1594 if ( (c
>='0') && (c
<='9') ) {
1595 format_width
= (format_width
* 10) + (c
- '0');
1598 arg_ptr
++; // increment to next arg
1599 arg
= read_word(arg_seg
, arg_ptr
);
1601 if (format_width
== 0)
1603 for (i
=format_width
-1; i
>=0; i
--) {
1604 nibble
= (arg
>> (4 * i
)) & 0x000f;
1605 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+'A'));
1608 else if (c
== 'u') {
1609 put_uint(action
, arg
, format_width
, 0);
1611 else if (c
== 'd') {
1613 put_int(action
, -arg
, format_width
- 1, 1);
1615 put_int(action
, arg
, format_width
, 0);
1617 else if (c
== 's') {
1618 bios_printf(action
& (~BIOS_PRINTF_HALT
), arg
);
1620 else if (c
== 'c') {
1624 BX_PANIC("bios_printf: unknown format\n");
1634 if (action
& BIOS_PRINTF_HALT
) {
1635 // freeze in a busy loop.
1645 //--------------------------------------------------------------------------
1647 //--------------------------------------------------------------------------
1648 // this file is based on LinuxBIOS implementation of keyboard.c
1649 // could convert to #asm to gain space
1655 /* ------------------- Flush buffers ------------------------*/
1656 /* Wait until buffer is empty */
1658 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1660 /* flush incoming keys */
1664 if (inb(0x64) & 0x01) {
1670 // Due to timer issues, and if the IPS setting is > 15000000,
1671 // the incoming keys might not be flushed here. That will
1672 // cause a panic a few lines below. See sourceforge bug report :
1673 // [ 642031 ] FATAL: Keyboard RESET error:993
1675 /* ------------------- controller side ----------------------*/
1676 /* send cmd = 0xAA, self test 8042 */
1679 /* Wait until buffer is empty */
1681 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1682 if (max
==0x0) keyboard_panic(00);
1686 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1687 if (max
==0x0) keyboard_panic(01);
1689 /* read self-test result, 0x55 should be returned from 0x60 */
1690 if ((inb(0x60) != 0x55)){
1691 keyboard_panic(991);
1694 /* send cmd = 0xAB, keyboard interface test */
1697 /* Wait until buffer is empty */
1699 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1700 if (max
==0x0) keyboard_panic(10);
1704 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1705 if (max
==0x0) keyboard_panic(11);
1707 /* read keyboard interface test result, */
1708 /* 0x00 should be returned form 0x60 */
1709 if ((inb(0x60) != 0x00)) {
1710 keyboard_panic(992);
1713 /* Enable Keyboard clock */
1717 /* ------------------- keyboard side ------------------------*/
1718 /* reset kerboard and self test (keyboard side) */
1721 /* Wait until buffer is empty */
1723 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1724 if (max
==0x0) keyboard_panic(20);
1728 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1729 if (max
==0x0) keyboard_panic(21);
1731 /* keyboard should return ACK */
1732 if ((inb(0x60) != 0xfa)) {
1733 keyboard_panic(993);
1738 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1739 if (max
==0x0) keyboard_panic(31);
1741 if ((inb(0x60) != 0xaa)) {
1742 keyboard_panic(994);
1745 /* Disable keyboard */
1748 /* Wait until buffer is empty */
1750 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1751 if (max
==0x0) keyboard_panic(40);
1755 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1756 if (max
==0x0) keyboard_panic(41);
1758 /* keyboard should return ACK */
1759 if ((inb(0x60) != 0xfa)) {
1760 keyboard_panic(995);
1763 /* Write Keyboard Mode */
1766 /* Wait until buffer is empty */
1768 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1769 if (max
==0x0) keyboard_panic(50);
1771 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1774 /* Wait until buffer is empty */
1776 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1777 if (max
==0x0) keyboard_panic(60);
1779 /* Enable keyboard */
1782 /* Wait until buffer is empty */
1784 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1785 if (max
==0x0) keyboard_panic(70);
1789 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1790 if (max
==0x0) keyboard_panic(70);
1792 /* keyboard should return ACK */
1793 if ((inb(0x60) != 0xfa)) {
1794 keyboard_panic(996);
1800 //--------------------------------------------------------------------------
1802 //--------------------------------------------------------------------------
1804 keyboard_panic(status
)
1807 // If you're getting a 993 keyboard panic here,
1808 // please see the comment in keyboard_init
1810 BX_PANIC("Keyboard error:%u\n",status
);
1813 //--------------------------------------------------------------------------
1814 // shutdown_status_panic
1815 // called when the shutdown statsu is not implemented, displays the status
1816 //--------------------------------------------------------------------------
1818 shutdown_status_panic(status
)
1821 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1824 //--------------------------------------------------------------------------
1825 // print_bios_banner
1826 // displays a the bios version
1827 //--------------------------------------------------------------------------
1831 printf(BX_APPNAME
" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS
, BX_SMP_PROCESSORS
>1?"s":"");
1832 printf("%s %s\n", bios_cvs_version_string
, bios_date_string
);
1836 //--------------------------------------------------------------------------
1837 // print_boot_device
1838 // displays the boot device
1839 //--------------------------------------------------------------------------
1841 static char drivetypes
[][10]={"Floppy","Hard Disk","CD-Rom"};
1844 print_boot_device(cdboot
, drive
)
1845 Bit8u cdboot
; Bit16u drive
;
1849 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1850 // drive contains real/emulated boot drive
1852 if(cdboot
)i
=2; // CD-Rom
1853 else if((drive
&0x0080)==0x00)i
=0; // Floppy
1854 else if((drive
&0x0080)==0x80)i
=1; // Hard drive
1857 printf("Booting from %s...\n",drivetypes
[i
]);
1860 //--------------------------------------------------------------------------
1861 // print_boot_failure
1862 // displays the reason why boot failed
1863 //--------------------------------------------------------------------------
1865 print_boot_failure(cdboot
, drive
, reason
, lastdrive
)
1866 Bit8u cdboot
; Bit8u drive
; Bit8u lastdrive
;
1868 Bit16u drivenum
= drive
&0x7f;
1870 // cdboot: 1 if boot from cd, 0 otherwise
1871 // drive : drive number
1872 // reason: 0 signature check failed, 1 read error
1873 // lastdrive: 1 boot drive is the last one in boot sequence
1876 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s failed\n",drivetypes
[2]);
1877 else if (drive
& 0x80)
1878 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[1],drivenum
);
1880 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[0],drivenum
);
1884 BX_PANIC("Not a bootable disk\n");
1886 BX_PANIC("Could not read the boot disk\n");
1890 //--------------------------------------------------------------------------
1891 // print_cdromboot_failure
1892 // displays the reason why boot failed
1893 //--------------------------------------------------------------------------
1895 print_cdromboot_failure( code
)
1898 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1906 BX_PANIC("NMI Handler called\n");
1912 BX_PANIC("INT18: BOOT FAILURE\n");
1919 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
1921 BX_INFO("%s\n", bios_version_string
);
1930 // Use PS2 System Control port A to set A20 enable
1932 // get current setting first
1935 // change A20 status
1937 outb(0x92, oldval
| 0x02);
1939 outb(0x92, oldval
& 0xfd);
1941 return((oldval
& 0x02) != 0);
1958 // ---------------------------------------------------------------------------
1959 // Start of ATA/ATAPI Driver
1960 // ---------------------------------------------------------------------------
1962 // Global defines -- ATA register and register bits.
1963 // command block & control block regs
1964 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1965 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1966 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1967 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1968 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1969 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1970 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1971 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1972 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1973 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1974 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1975 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1976 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1978 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1979 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1980 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1981 #define ATA_CB_ER_MC 0x20 // ATA media change
1982 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1983 #define ATA_CB_ER_MCR 0x08 // ATA media change request
1984 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
1985 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
1986 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
1988 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
1989 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
1990 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
1991 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
1992 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
1994 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
1995 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
1996 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
1997 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
1998 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2000 // bits 7-4 of the device/head (CB_DH) reg
2001 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2002 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2004 // status reg (CB_STAT and CB_ASTAT) bits
2005 #define ATA_CB_STAT_BSY 0x80 // busy
2006 #define ATA_CB_STAT_RDY 0x40 // ready
2007 #define ATA_CB_STAT_DF 0x20 // device fault
2008 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2009 #define ATA_CB_STAT_SKC 0x10 // seek complete
2010 #define ATA_CB_STAT_SERV 0x10 // service
2011 #define ATA_CB_STAT_DRQ 0x08 // data request
2012 #define ATA_CB_STAT_CORR 0x04 // corrected
2013 #define ATA_CB_STAT_IDX 0x02 // index
2014 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2015 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2017 // device control reg (CB_DC) bits
2018 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2019 #define ATA_CB_DC_SRST 0x04 // soft reset
2020 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2022 // Most mandtory and optional ATA commands (from ATA-3),
2023 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2024 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2025 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2026 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2027 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2028 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2029 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2030 #define ATA_CMD_DEVICE_RESET 0x08
2031 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2032 #define ATA_CMD_FLUSH_CACHE 0xE7
2033 #define ATA_CMD_FORMAT_TRACK 0x50
2034 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2035 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2036 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2037 #define ATA_CMD_IDLE1 0xE3
2038 #define ATA_CMD_IDLE2 0x97
2039 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2040 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2041 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2042 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2043 #define ATA_CMD_NOP 0x00
2044 #define ATA_CMD_PACKET 0xA0
2045 #define ATA_CMD_READ_BUFFER 0xE4
2046 #define ATA_CMD_READ_DMA 0xC8
2047 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2048 #define ATA_CMD_READ_MULTIPLE 0xC4
2049 #define ATA_CMD_READ_SECTORS 0x20
2050 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2051 #define ATA_CMD_RECALIBRATE 0x10
2052 #define ATA_CMD_SEEK 0x70
2053 #define ATA_CMD_SET_FEATURES 0xEF
2054 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2055 #define ATA_CMD_SLEEP1 0xE6
2056 #define ATA_CMD_SLEEP2 0x99
2057 #define ATA_CMD_STANDBY1 0xE2
2058 #define ATA_CMD_STANDBY2 0x96
2059 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2060 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2061 #define ATA_CMD_WRITE_BUFFER 0xE8
2062 #define ATA_CMD_WRITE_DMA 0xCA
2063 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2064 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2065 #define ATA_CMD_WRITE_SECTORS 0x30
2066 #define ATA_CMD_WRITE_VERIFY 0x3C
2068 #define ATA_IFACE_NONE 0x00
2069 #define ATA_IFACE_ISA 0x00
2070 #define ATA_IFACE_PCI 0x01
2072 #define ATA_TYPE_NONE 0x00
2073 #define ATA_TYPE_UNKNOWN 0x01
2074 #define ATA_TYPE_ATA 0x02
2075 #define ATA_TYPE_ATAPI 0x03
2077 #define ATA_DEVICE_NONE 0x00
2078 #define ATA_DEVICE_HD 0xFF
2079 #define ATA_DEVICE_CDROM 0x05
2081 #define ATA_MODE_NONE 0x00
2082 #define ATA_MODE_PIO16 0x00
2083 #define ATA_MODE_PIO32 0x01
2084 #define ATA_MODE_ISADMA 0x02
2085 #define ATA_MODE_PCIDMA 0x03
2086 #define ATA_MODE_USEIRQ 0x10
2088 #define ATA_TRANSLATION_NONE 0
2089 #define ATA_TRANSLATION_LBA 1
2090 #define ATA_TRANSLATION_LARGE 2
2091 #define ATA_TRANSLATION_RECHS 3
2093 #define ATA_DATA_NO 0x00
2094 #define ATA_DATA_IN 0x01
2095 #define ATA_DATA_OUT 0x02
2097 // ---------------------------------------------------------------------------
2098 // ATA/ATAPI driver : initialization
2099 // ---------------------------------------------------------------------------
2102 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2103 Bit8u channel
, device
;
2105 // Channels info init.
2106 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2107 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2108 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2109 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2110 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2113 // Devices info init.
2114 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2115 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2116 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2117 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2118 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2119 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2120 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2121 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2122 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2123 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2124 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2125 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2126 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2127 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2129 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2132 // hdidmap and cdidmap init.
2133 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2134 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2135 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2138 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2139 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2142 // ---------------------------------------------------------------------------
2143 // ATA/ATAPI driver : device detection
2144 // ---------------------------------------------------------------------------
2148 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2149 Bit8u hdcount
, cdcount
, device
, type
;
2150 Bit8u buffer
[0x0200];
2152 #if BX_MAX_ATA_INTERFACES > 0
2153 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2154 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2155 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2156 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2158 #if BX_MAX_ATA_INTERFACES > 1
2159 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2160 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2161 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2162 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2164 #if BX_MAX_ATA_INTERFACES > 2
2165 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2166 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2167 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2168 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2170 #if BX_MAX_ATA_INTERFACES > 3
2171 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2172 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2173 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2174 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2176 #if BX_MAX_ATA_INTERFACES > 4
2177 #error Please fill the ATA interface informations
2183 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2184 Bit16u iobase1
, iobase2
;
2185 Bit8u channel
, slave
, shift
;
2186 Bit8u sc
, sn
, cl
, ch
, st
;
2188 channel
= device
/ 2;
2191 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2192 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2194 // Disable interrupts
2195 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2198 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2199 outb(iobase1
+ATA_CB_SC
, 0x55);
2200 outb(iobase1
+ATA_CB_SN
, 0xaa);
2201 outb(iobase1
+ATA_CB_SC
, 0xaa);
2202 outb(iobase1
+ATA_CB_SN
, 0x55);
2203 outb(iobase1
+ATA_CB_SC
, 0x55);
2204 outb(iobase1
+ATA_CB_SN
, 0xaa);
2206 // If we found something
2207 sc
= inb(iobase1
+ATA_CB_SC
);
2208 sn
= inb(iobase1
+ATA_CB_SN
);
2210 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2211 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2213 // reset the channel
2216 // check for ATA or ATAPI
2217 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2218 sc
= inb(iobase1
+ATA_CB_SC
);
2219 sn
= inb(iobase1
+ATA_CB_SN
);
2220 if ( (sc
==0x01) && (sn
==0x01) ) {
2221 cl
= inb(iobase1
+ATA_CB_CL
);
2222 ch
= inb(iobase1
+ATA_CB_CH
);
2223 st
= inb(iobase1
+ATA_CB_STAT
);
2225 if ( (cl
==0x14) && (ch
==0xeb) ) {
2226 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2228 else if ( (cl
==0x00) && (ch
==0x00) && (st
!=0x00) ) {
2229 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2234 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2236 // Now we send a IDENTIFY command to ATA device
2237 if(type
== ATA_TYPE_ATA
) {
2239 Bit16u cylinders
, heads
, spt
, blksize
;
2240 Bit8u translation
, removable
, mode
;
2242 //Temporary values to do the transfer
2243 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2244 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2246 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2247 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2249 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2250 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2251 blksize
= read_word(get_SS(),buffer
+10);
2253 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2254 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2255 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2257 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2259 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2260 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2261 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2262 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2263 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2264 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2265 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2266 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2267 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2269 translation
= inb_cmos(0x39 + channel
/2);
2270 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2271 translation
&= 0x03;
2273 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2275 switch (translation
) {
2276 case ATA_TRANSLATION_NONE
:
2279 case ATA_TRANSLATION_LBA
:
2282 case ATA_TRANSLATION_LARGE
:
2285 case ATA_TRANSLATION_RECHS
:
2289 switch (translation
) {
2290 case ATA_TRANSLATION_NONE
:
2292 case ATA_TRANSLATION_LBA
:
2295 heads
= sectors
/ 1024;
2296 if (heads
>128) heads
= 255;
2297 else if (heads
>64) heads
= 128;
2298 else if (heads
>32) heads
= 64;
2299 else if (heads
>16) heads
= 32;
2301 cylinders
= sectors
/ heads
;
2303 case ATA_TRANSLATION_RECHS
:
2304 // Take care not to overflow
2306 if(cylinders
>61439) cylinders
=61439;
2308 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2310 // then go through the large bitshift process
2311 case ATA_TRANSLATION_LARGE
:
2312 while(cylinders
> 1024) {
2316 // If we max out the head count
2317 if (heads
> 127) break;
2321 // clip to 1024 cylinders in lchs
2322 if (cylinders
> 1024) cylinders
=1024;
2323 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2325 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2326 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2327 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2330 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2334 // Now we send a IDENTIFY command to ATAPI device
2335 if(type
== ATA_TYPE_ATAPI
) {
2337 Bit8u type
, removable
, mode
;
2340 //Temporary values to do the transfer
2341 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2342 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2344 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2345 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2347 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2348 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2349 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2352 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2353 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2354 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2355 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2358 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2365 Bit8u c
, i
, version
, model
[41];
2369 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2371 case ATA_TYPE_ATAPI
:
2372 // Read ATA/ATAPI version
2373 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2374 for(version
=15;version
>0;version
--) {
2375 if((ataversion
&(1<<version
))!=0)
2381 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2382 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2386 write_byte(get_SS(),model
+40,0x00);
2388 if(read_byte(get_SS(),model
+i
)==0x20)
2389 write_byte(get_SS(),model
+i
,0x00);
2397 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2398 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2399 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version
,(Bit16u
)sizeinmb
);
2401 case ATA_TYPE_ATAPI
:
2402 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2403 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2404 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2405 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2407 printf(" ATAPI-%d Device\n",version
);
2409 case ATA_TYPE_UNKNOWN
:
2410 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2416 // Store the devices counts
2417 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2418 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2419 write_byte(0x40,0x75, hdcount
);
2423 // FIXME : should use bios=cmos|auto|disable bits
2424 // FIXME : should know about translation bits
2425 // FIXME : move hard_drive_post here
2429 // ---------------------------------------------------------------------------
2430 // ATA/ATAPI driver : software reset
2431 // ---------------------------------------------------------------------------
2433 // 8.2.1 Software reset - Device 0
2435 void ata_reset(device
)
2438 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2439 Bit16u iobase1
, iobase2
;
2440 Bit8u channel
, slave
, sn
, sc
;
2443 channel
= device
/ 2;
2446 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2447 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2451 // 8.2.1 (a) -- set SRST in DC
2452 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2454 // 8.2.1 (b) -- wait for BSY
2457 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2458 if ((status
& ATA_CB_STAT_BSY
) != 0) break;
2461 // 8.2.1 (f) -- clear SRST
2462 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2464 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_NONE
) {
2466 // 8.2.1 (g) -- check for sc==sn==0x01
2468 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2469 sc
= inb(iobase1
+ATA_CB_SC
);
2470 sn
= inb(iobase1
+ATA_CB_SN
);
2472 if ( (sc
==0x01) && (sn
==0x01) ) {
2474 // 8.2.1 (h) -- wait for not BSY
2477 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2478 if ((status
& ATA_CB_STAT_BSY
) == 0) break;
2483 // 8.2.1 (i) -- wait for DRDY
2486 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2487 if ((status
& ATA_CB_STAT_RDY
) != 0) break;
2490 // Enable interrupts
2491 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2494 // ---------------------------------------------------------------------------
2495 // ATA/ATAPI driver : execute a non data command
2496 // ---------------------------------------------------------------------------
2498 Bit16u
ata_cmd_non_data()
2501 // ---------------------------------------------------------------------------
2502 // ATA/ATAPI driver : execute a data-in command
2503 // ---------------------------------------------------------------------------
2508 // 3 : expected DRQ=1
2509 // 4 : no sectors left to read/verify
2510 // 5 : more sectors to read/verify
2511 // 6 : no sectors left to write
2512 // 7 : more sectors to write
2513 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2514 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2517 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2518 Bit16u iobase1
, iobase2
, blksize
;
2519 Bit8u channel
, slave
;
2520 Bit8u status
, current
, mode
;
2522 channel
= device
/ 2;
2525 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2526 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2527 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2528 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2529 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2532 // sector will be 0 only on lba access. Convert to lba-chs
2534 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2536 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2538 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2541 // Reset count of transferred data
2542 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2543 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2546 status
= inb(iobase1
+ ATA_CB_STAT
);
2547 if (status
& ATA_CB_STAT_BSY
) return 1;
2549 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2550 outb(iobase1
+ ATA_CB_FR
, 0x00);
2551 outb(iobase1
+ ATA_CB_SC
, count
);
2552 outb(iobase1
+ ATA_CB_SN
, sector
);
2553 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2554 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2555 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2556 outb(iobase1
+ ATA_CB_CMD
, command
);
2559 status
= inb(iobase1
+ ATA_CB_STAT
);
2560 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2563 if (status
& ATA_CB_STAT_ERR
) {
2564 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2566 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2567 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2571 // FIXME : move seg/off translation here
2574 sti
;; enable higher priority interrupts
2582 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2583 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2584 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2586 ;; adjust
if there will be an overrun
. 2K max sector size
2588 jbe ata_in_no_adjust
2591 sub di
, #0x0800 ;; sub 2 kbytes from offset
2592 add ax
, #0x0080 ;; add 2 Kbytes to segment
2595 mov es
, ax
;; segment in es
2597 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2599 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2600 cmp ah
, #ATA_MODE_PIO32
2605 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2610 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2613 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2614 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2619 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2621 status
= inb(iobase1
+ ATA_CB_STAT
);
2623 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2624 != ATA_CB_STAT_RDY
) {
2625 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2631 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2632 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2633 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2639 // Enable interrupts
2640 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2644 // ---------------------------------------------------------------------------
2645 // ATA/ATAPI driver : execute a data-out command
2646 // ---------------------------------------------------------------------------
2651 // 3 : expected DRQ=1
2652 // 4 : no sectors left to read/verify
2653 // 5 : more sectors to read/verify
2654 // 6 : no sectors left to write
2655 // 7 : more sectors to write
2656 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2657 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2660 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2661 Bit16u iobase1
, iobase2
, blksize
;
2662 Bit8u channel
, slave
;
2663 Bit8u status
, current
, mode
;
2665 channel
= device
/ 2;
2668 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2669 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2670 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2671 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2672 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2675 // sector will be 0 only on lba access. Convert to lba-chs
2677 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2679 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2681 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2684 // Reset count of transferred data
2685 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2686 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2689 status
= inb(iobase1
+ ATA_CB_STAT
);
2690 if (status
& ATA_CB_STAT_BSY
) return 1;
2692 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2693 outb(iobase1
+ ATA_CB_FR
, 0x00);
2694 outb(iobase1
+ ATA_CB_SC
, count
);
2695 outb(iobase1
+ ATA_CB_SN
, sector
);
2696 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2697 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2698 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2699 outb(iobase1
+ ATA_CB_CMD
, command
);
2702 status
= inb(iobase1
+ ATA_CB_STAT
);
2703 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2706 if (status
& ATA_CB_STAT_ERR
) {
2707 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2709 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2710 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2714 // FIXME : move seg/off translation here
2717 sti
;; enable higher priority interrupts
2725 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2726 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2727 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2729 ;; adjust
if there will be an overrun
. 2K max sector size
2731 jbe ata_out_no_adjust
2734 sub si
, #0x0800 ;; sub 2 kbytes from offset
2735 add ax
, #0x0080 ;; add 2 Kbytes to segment
2738 mov es
, ax
;; segment in es
2740 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2742 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2743 cmp ah
, #ATA_MODE_PIO32
2749 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2755 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2758 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2759 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2764 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2766 status
= inb(iobase1
+ ATA_CB_STAT
);
2768 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2769 != ATA_CB_STAT_RDY
) {
2770 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2776 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2777 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2778 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2784 // Enable interrupts
2785 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2789 // ---------------------------------------------------------------------------
2790 // ATA/ATAPI driver : execute a packet command
2791 // ---------------------------------------------------------------------------
2794 // 1 : error in parameters
2798 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2800 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2804 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2805 Bit16u iobase1
, iobase2
;
2806 Bit16u lcount
, lbefore
, lafter
, count
;
2807 Bit8u channel
, slave
;
2808 Bit8u status
, mode
, lmode
;
2809 Bit32u total
, transfer
;
2811 channel
= device
/ 2;
2814 // Data out is not supported yet
2815 if (inout
== ATA_DATA_OUT
) {
2816 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2820 // The header length must be even
2822 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2826 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2827 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2828 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2831 if (cmdlen
< 12) cmdlen
=12;
2832 if (cmdlen
> 12) cmdlen
=16;
2835 // Reset count of transferred data
2836 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2837 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2839 status
= inb(iobase1
+ ATA_CB_STAT
);
2840 if (status
& ATA_CB_STAT_BSY
) return 2;
2842 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2843 // outb(iobase1 + ATA_CB_FR, 0x00);
2844 // outb(iobase1 + ATA_CB_SC, 0x00);
2845 // outb(iobase1 + ATA_CB_SN, 0x00);
2846 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2847 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2848 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2849 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2851 // Device should ok to receive command
2853 status
= inb(iobase1
+ ATA_CB_STAT
);
2854 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2857 if (status
& ATA_CB_STAT_ERR
) {
2858 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2860 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2861 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2865 // Normalize address
2866 cmdseg
+= (cmdoff
/ 16);
2869 // Send command to device
2871 sti
;; enable higher priority interrupts
2876 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
2877 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
2878 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
2879 mov es
, ax
;; segment in es
2881 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
2885 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2890 if (inout
== ATA_DATA_NO
) {
2891 status
= inb(iobase1
+ ATA_CB_STAT
);
2896 status
= inb(iobase1
+ ATA_CB_STAT
);
2898 // Check if command completed
2899 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_DRQ
) ) ==0 ) break;
2901 if (status
& ATA_CB_STAT_ERR
) {
2902 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
2906 // Device must be ready to send data
2907 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2908 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2909 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status
);
2913 // Normalize address
2914 bufseg
+= (bufoff
/ 16);
2917 // Get the byte count
2918 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
2920 // adjust to read what we want
2933 lafter
=lcount
-length
;
2945 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
2946 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
2948 // If counts not dividable by 4, use 16bits mode
2950 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
2951 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
2952 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
2954 // adds an extra byte if count are odd. before is always even
2955 if (lcount
& 0x01) {
2957 if ((lafter
> 0) && (lafter
& 0x01)) {
2962 if (lmode
== ATA_MODE_PIO32
) {
2963 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
2966 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
2975 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
2977 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
2978 jcxz ata_packet_no_before
2980 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
2981 cmp ah
, #ATA_MODE_PIO32
2982 je ata_packet_in_before_32
2984 ata_packet_in_before_16
:
2986 loop ata_packet_in_before_16
2987 jmp ata_packet_no_before
2989 ata_packet_in_before_32
:
2991 ata_packet_in_before_32_loop
:
2993 loop ata_packet_in_before_32_loop
2996 ata_packet_no_before
:
2997 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
2998 jcxz ata_packet_after
3000 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3001 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3004 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3005 cmp ah
, #ATA_MODE_PIO32
3010 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3011 jmp ata_packet_after
3015 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3018 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3019 jcxz ata_packet_done
3021 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3022 cmp ah
, #ATA_MODE_PIO32
3023 je ata_packet_in_after_32
3025 ata_packet_in_after_16
:
3027 loop ata_packet_in_after_16
3030 ata_packet_in_after_32
:
3032 ata_packet_in_after_32_loop
:
3034 loop ata_packet_in_after_32_loop
3041 // Compute new buffer address
3044 // Save transferred bytes count
3046 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3050 // Final check, device must be ready
3051 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3052 != ATA_CB_STAT_RDY
) {
3053 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3057 // Enable interrupts
3058 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3062 // ---------------------------------------------------------------------------
3063 // End of ATA/ATAPI Driver
3064 // ---------------------------------------------------------------------------
3066 // ---------------------------------------------------------------------------
3067 // Start of ATA/ATAPI generic functions
3068 // ---------------------------------------------------------------------------
3071 atapi_get_sense(device
)
3078 memsetb(get_SS(),atacmd
,0,12);
3083 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 16L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3086 if ((buffer
[0] & 0x7e) == 0x70) {
3087 return (((Bit16u
)buffer
[2]&0x0f)*0x100)+buffer
[12];
3094 atapi_is_ready(device
)
3100 memsetb(get_SS(),atacmd
,0,12);
3103 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3106 if (atapi_get_sense(device
) !=0 ) {
3107 memsetb(get_SS(),atacmd
,0,12);
3109 // try to send Test Unit Ready again
3110 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3113 return atapi_get_sense(device
);
3119 atapi_is_cdrom(device
)
3122 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3124 if (device
>= BX_MAX_ATA_DEVICES
)
3127 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3130 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3136 // ---------------------------------------------------------------------------
3137 // End of ATA/ATAPI generic functions
3138 // ---------------------------------------------------------------------------
3140 #endif // BX_USE_ATADRV
3142 #if BX_ELTORITO_BOOT
3144 // ---------------------------------------------------------------------------
3145 // Start of El-Torito boot functions
3146 // ---------------------------------------------------------------------------
3151 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3153 // the only important data is this one for now
3154 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3160 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3162 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3166 cdemu_emulated_drive()
3168 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3170 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3173 static char isotag
[6]="CD001";
3174 static char eltorito
[24]="EL TORITO SPECIFICATION";
3176 // Returns ah: emulated drive, al: error code
3181 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3182 Bit8u atacmd
[12], buffer
[2048];
3184 Bit16u boot_segment
, nbsectors
, i
, error
;
3187 // Find out the first cdrom
3188 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3189 if (atapi_is_cdrom(device
)) break;
3193 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3195 // Read the Boot Record Volume Descriptor
3196 memsetb(get_SS(),atacmd
,0,12);
3197 atacmd
[0]=0x28; // READ command
3198 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3199 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3200 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3201 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3202 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3203 atacmd
[5]=(0x11 & 0x000000ff);
3204 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3208 if(buffer
[0]!=0)return 4;
3210 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3213 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3215 // ok, now we calculate the Boot catalog address
3216 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3218 // And we read the Boot Catalog
3219 memsetb(get_SS(),atacmd
,0,12);
3220 atacmd
[0]=0x28; // READ command
3221 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3222 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3223 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3224 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3225 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3226 atacmd
[5]=(lba
& 0x000000ff);
3227 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3231 if(buffer
[0x00]!=0x01)return 8; // Header
3232 if(buffer
[0x01]!=0x00)return 9; // Platform
3233 if(buffer
[0x1E]!=0x55)return 10; // key 1
3234 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3236 // Initial/Default Entry
3237 if(buffer
[0x20]!=0x88)return 11; // Bootable
3239 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3240 if(buffer
[0x21]==0){
3241 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3242 // Win2000 cd boot needs to know it booted from cd
3243 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3245 else if(buffer
[0x21]<4)
3246 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3248 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3250 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3251 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3253 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3254 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3256 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3257 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3259 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3260 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3262 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3263 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3265 // And we read the image in memory
3266 memsetb(get_SS(),atacmd
,0,12);
3267 atacmd
[0]=0x28; // READ command
3268 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3269 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3270 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3271 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3272 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3273 atacmd
[5]=(lba
& 0x000000ff);
3274 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3277 // Remember the media type
3278 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3279 case 0x01: // 1.2M floppy
3280 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3281 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3282 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3284 case 0x02: // 1.44M floppy
3285 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3286 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3287 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3289 case 0x03: // 2.88M floppy
3290 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3291 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3292 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3294 case 0x04: // Harddrive
3295 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3296 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3297 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3298 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3302 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3303 // Increase bios installed hardware number of devices
3304 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3305 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3307 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3311 // everything is ok, so from now on, the emulation is active
3312 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3313 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3315 // return the boot drive + no error
3316 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3319 // ---------------------------------------------------------------------------
3320 // End of El-Torito boot functions
3321 // ---------------------------------------------------------------------------
3322 #endif // BX_ELTORITO_BOOT
3325 int14_function(regs
, ds
, iret_addr
)
3326 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3327 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3328 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3330 Bit16u addr
,timer
,val16
;
3337 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3338 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3339 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3340 switch (regs
.u
.r8
.ah
) {
3342 outb(addr
+3, inb(addr
+3) | 0x80);
3343 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3347 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3348 outb(addr
, val16
& 0xFF);
3349 outb(addr
+1, val16
>> 8);
3351 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3352 regs
.u
.r8
.ah
= inb(addr
+5);
3353 regs
.u
.r8
.al
= inb(addr
+6);
3354 ClearCF(iret_addr
.flags
);
3357 timer
= read_word(0x0040, 0x006C);
3358 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3359 val16
= read_word(0x0040, 0x006C);
3360 if (val16
!= timer
) {
3365 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3366 regs
.u
.r8
.ah
= inb(addr
+5);
3367 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3368 ClearCF(iret_addr
.flags
);
3371 timer
= read_word(0x0040, 0x006C);
3372 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3373 val16
= read_word(0x0040, 0x006C);
3374 if (val16
!= timer
) {
3381 regs
.u
.r8
.al
= inb(addr
);
3383 regs
.u
.r8
.ah
= inb(addr
+5);
3385 ClearCF(iret_addr
.flags
);
3388 regs
.u
.r8
.ah
= inb(addr
+5);
3389 regs
.u
.r8
.al
= inb(addr
+6);
3390 ClearCF(iret_addr
.flags
);
3393 SetCF(iret_addr
.flags
); // Unsupported
3396 SetCF(iret_addr
.flags
); // Unsupported
3401 int15_function(regs
, ES
, DS
, FLAGS
)
3402 pusha_regs_t regs
; // REGS pushed via pusha
3403 Bit16u ES
, DS
, FLAGS
;
3405 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3406 bx_bool prev_a20_enable
;
3415 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3417 switch (regs
.u
.r8
.ah
) {
3418 case 0x24: /* A20 Control */
3419 switch (regs
.u
.r8
.al
) {
3431 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3441 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3443 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3449 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3453 /* keyboard intercept */
3455 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3462 case 0x52: // removable media eject
3464 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3468 if( regs
.u
.r8
.al
== 0 ) {
3469 // Set Interval requested.
3470 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3471 // Interval not already set.
3472 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3473 write_word( 0x40, 0x98, ES
); // Byte location, segment
3474 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3475 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3476 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3478 irqDisable
= inb( 0xA1 );
3479 outb( 0xA1, irqDisable
& 0xFE );
3480 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3481 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3483 // Interval already set.
3484 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3486 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3488 } else if( regs
.u
.r8
.al
== 1 ) {
3489 // Clear Interval requested
3490 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3492 bRegister
= inb_cmos( 0xB );
3493 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3495 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3497 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3506 # error "Int15 function 87h not supported on < 80386"
3508 // +++ should probably have descriptor checks
3509 // +++ should have exception handlers
3511 // turn off interrupts
3516 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3518 // 128K max of transfer on 386+ ???
3519 // source == destination ???
3521 // ES:SI points to descriptor table
3522 // offset use initially comments
3523 // ==============================================
3524 // 00..07 Unused zeros Null descriptor
3525 // 08..0f GDT zeros filled in by BIOS
3526 // 10..17 source ssssssss source of data
3527 // 18..1f dest dddddddd destination of data
3528 // 20..27 CS zeros filled in by BIOS
3529 // 28..2f SS zeros filled in by BIOS
3536 // check for access rights of source & dest here
3538 // Initialize GDT descriptor
3539 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3540 base23_16
= ES
>> 12;
3541 if (base15_00
< (ES
<<4))
3543 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3544 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3545 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3546 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3547 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3549 // Initialize CS descriptor
3550 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3551 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3552 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3553 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3554 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3556 // Initialize SS descriptor
3558 base15_00
= ss
<< 4;
3559 base23_16
= ss
>> 12;
3560 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3561 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3562 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3563 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3564 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3568 // Compile generates locals offset info relative to SP.
3569 // Get CX (word count) from stack.
3572 mov cx
, _int15_function
.CX
[bx
]
3574 // since we need to set SS:SP, save them to the BDA
3575 // for future restore
3585 lidt
[pmode_IDT_info
]
3586 ;; perhaps
do something with IDT here
3588 ;; set PE bit in CR0
3592 ;; far jump to flush CPU queue after transition to
protected mode
3593 JMP_AP(0x0020, protected_mode
)
3596 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3597 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3599 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3601 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3607 movsw
;; move CX words from DS
:SI to ES
:DI
3609 ;; make sure DS
and ES limits are
64KB
3614 ;; reset PG bit in CR0
???
3619 ;; far jump to flush CPU queue after transition to real mode
3620 JMP_AP(0xf000, real_mode
)
3623 ;; restore IDT to normal real
-mode defaults
3625 lidt
[rmode_IDT_info
]
3627 // restore SS:SP from the BDA
3635 set_enable_a20(prev_a20_enable
);
3637 // turn back on interrupts
3648 // Get the amount of extended memory (above 1M)
3650 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3653 regs
.u
.r8
.al
= inb_cmos(0x30);
3654 regs
.u
.r8
.ah
= inb_cmos(0x31);
3657 if(regs
.u
.r16
.ax
> 0x3c00)
3658 regs
.u
.r16
.ax
= 0x3c00;
3665 /* Device busy interrupt. Called by Int 16h when no key available */
3669 /* Interrupt complete. Called by Int 16h when key becomes available */
3673 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3675 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3681 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3686 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3696 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3698 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3702 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3703 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3705 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3710 #if BX_USE_PS2_MOUSE
3712 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3713 pusha_regs_t regs
; // REGS pushed via pusha
3714 Bit16u ES
, DS
, FLAGS
;
3716 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3717 Bit8u mouse_flags_1
, mouse_flags_2
;
3718 Bit16u mouse_driver_seg
;
3719 Bit16u mouse_driver_offset
;
3720 Bit8u comm_byte
, prev_command_byte
;
3721 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3723 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3725 switch (regs
.u
.r8
.ah
) {
3727 // Return Codes status in AH
3728 // =========================
3730 // 01: invalid subfunction (AL > 7)
3731 // 02: invalid input value (out of allowable range)
3732 // 03: interface error
3733 // 04: resend command received from mouse controller,
3734 // device driver should attempt command again
3735 // 05: cannot enable mouse, since no far call has been installed
3736 // 80/86: mouse service not implemented
3738 switch (regs
.u
.r8
.al
) {
3739 case 0: // Disable/Enable Mouse
3740 BX_DEBUG_INT15("case 0:\n");
3741 switch (regs
.u
.r8
.bh
) {
3742 case 0: // Disable Mouse
3743 BX_DEBUG_INT15("case 0: disable mouse\n");
3744 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3745 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3747 ret
= get_mouse_data(&mouse_data1
);
3748 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3761 case 1: // Enable Mouse
3762 BX_DEBUG_INT15("case 1: enable mouse\n");
3763 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3764 if ( (mouse_flags_2
& 0x80) == 0 ) {
3765 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3767 regs
.u
.r8
.ah
= 5; // no far call installed
3770 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3771 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3773 ret
= get_mouse_data(&mouse_data1
);
3774 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3775 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3785 default: // invalid subfunction
3786 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3788 regs
.u
.r8
.ah
= 1; // invalid subfunction
3793 case 1: // Reset Mouse
3794 case 5: // Initialize Mouse
3795 BX_DEBUG_INT15("case 1 or 5:\n");
3796 if (regs
.u
.r8
.al
== 5) {
3797 if (regs
.u
.r8
.bh
!= 3) {
3799 regs
.u
.r8
.ah
= 0x02; // invalid input
3802 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3803 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3804 mouse_flags_1
= 0x00;
3805 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3806 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3809 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3810 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
3812 ret
= get_mouse_data(&mouse_data3
);
3813 // if no mouse attached, it will return RESEND
3814 if (mouse_data3
== 0xfe) {
3818 if (mouse_data3
!= 0xfa)
3819 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
3821 ret
= get_mouse_data(&mouse_data1
);
3823 ret
= get_mouse_data(&mouse_data2
);
3825 // turn IRQ12 and packet generation on
3826 enable_mouse_int_and_events();
3829 regs
.u
.r8
.bl
= mouse_data1
;
3830 regs
.u
.r8
.bh
= mouse_data2
;
3842 case 2: // Set Sample Rate
3843 BX_DEBUG_INT15("case 2:\n");
3844 switch (regs
.u
.r8
.bh
) {
3845 case 0: mouse_data1
= 10; break; // 10 reports/sec
3846 case 1: mouse_data1
= 20; break; // 20 reports/sec
3847 case 2: mouse_data1
= 40; break; // 40 reports/sec
3848 case 3: mouse_data1
= 60; break; // 60 reports/sec
3849 case 4: mouse_data1
= 80; break; // 80 reports/sec
3850 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
3851 case 6: mouse_data1
= 200; break; // 200 reports/sec
3852 default: mouse_data1
= 0;
3854 if (mouse_data1
> 0) {
3855 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
3857 ret
= get_mouse_data(&mouse_data2
);
3858 ret
= send_to_mouse_ctrl(mouse_data1
);
3859 ret
= get_mouse_data(&mouse_data2
);
3865 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3870 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3874 case 3: // Set Resolution
3875 BX_DEBUG_INT15("case 3:\n");
3877 // 0 = 25 dpi, 1 count per millimeter
3878 // 1 = 50 dpi, 2 counts per millimeter
3879 // 2 = 100 dpi, 4 counts per millimeter
3880 // 3 = 200 dpi, 8 counts per millimeter
3885 case 4: // Get Device ID
3886 BX_DEBUG_INT15("case 4:\n");
3887 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3888 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
3890 ret
= get_mouse_data(&mouse_data1
);
3891 ret
= get_mouse_data(&mouse_data2
);
3894 regs
.u
.r8
.bh
= mouse_data2
;
3898 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3902 case 6: // Return Status & Set Scaling Factor...
3903 BX_DEBUG_INT15("case 6:\n");
3904 switch (regs
.u
.r8
.bh
) {
3905 case 0: // Return Status
3906 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3907 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
3909 ret
= get_mouse_data(&mouse_data1
);
3910 if (mouse_data1
!= 0xfa)
3911 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3913 ret
= get_mouse_data(&mouse_data1
);
3915 ret
= get_mouse_data(&mouse_data2
);
3917 ret
= get_mouse_data(&mouse_data3
);
3921 regs
.u
.r8
.bl
= mouse_data1
;
3922 regs
.u
.r8
.cl
= mouse_data2
;
3923 regs
.u
.r8
.dl
= mouse_data3
;
3924 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3935 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3938 case 1: // Set Scaling Factor to 1:1
3939 case 2: // Set Scaling Factor to 2:1
3940 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3941 if (regs
.u
.r8
.bh
== 1) {
3942 ret
= send_to_mouse_ctrl(0xE6);
3944 ret
= send_to_mouse_ctrl(0xE7);
3947 get_mouse_data(&mouse_data1
);
3948 ret
= (mouse_data1
!= 0xFA);
3956 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3958 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3962 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3966 case 7: // Set Mouse Handler Address
3967 BX_DEBUG_INT15("case 7:\n");
3968 mouse_driver_seg
= ES
;
3969 mouse_driver_offset
= regs
.u
.r16
.bx
;
3970 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
3971 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
3972 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3973 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
3974 /* remove handler */
3975 if ( (mouse_flags_2
& 0x80) != 0 ) {
3976 mouse_flags_2
&= ~0x80;
3977 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3981 /* install handler */
3982 mouse_flags_2
|= 0x80;
3984 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3990 BX_DEBUG_INT15("case default:\n");
3991 regs
.u
.r8
.ah
= 1; // invalid function
3997 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3998 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4000 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4007 int15_function32(regs
, ES
, DS
, FLAGS
)
4008 pushad_regs_t regs
; // REGS pushed via pushad
4009 Bit16u ES
, DS
, FLAGS
;
4011 Bit32u extended_memory_size
=0; // 64bits long
4014 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4016 switch (regs
.u
.r8
.ah
) {
4018 // Wait for CX:DX microseconds. currently using the
4019 // refresh request port 0x61 bit4, toggling every 15usec
4027 ;; Get the count in eax
4030 mov ax
, _int15_function
.CX
[bx
]
4033 mov ax
, _int15_function
.DX
[bx
]
4035 ;; convert to numbers of
15usec ticks
4041 ;; wait
for ecx number of refresh requests
4062 switch(regs
.u
.r8
.al
)
4064 case 0x20: // coded by osmaker aka K.J.
4065 if(regs
.u
.r32
.edx
== 0x534D4150)
4067 switch(regs
.u
.r16
.bx
)
4070 write_word(ES
, regs
.u
.r16
.di
, 0x00);
4071 write_word(ES
, regs
.u
.r16
.di
+2, 0x00);
4072 write_word(ES
, regs
.u
.r16
.di
+4, 0x00);
4073 write_word(ES
, regs
.u
.r16
.di
+6, 0x00);
4075 write_word(ES
, regs
.u
.r16
.di
+8, 0xFC00);
4076 write_word(ES
, regs
.u
.r16
.di
+10, 0x0009);
4077 write_word(ES
, regs
.u
.r16
.di
+12, 0x0000);
4078 write_word(ES
, regs
.u
.r16
.di
+14, 0x0000);
4080 write_word(ES
, regs
.u
.r16
.di
+16, 0x1);
4081 write_word(ES
, regs
.u
.r16
.di
+18, 0x0);
4084 regs
.u
.r32
.eax
= 0x534D4150;
4085 regs
.u
.r32
.ecx
= 0x14;
4090 extended_memory_size
= inb_cmos(0x35);
4091 extended_memory_size
<<= 8;
4092 extended_memory_size
|= inb_cmos(0x34);
4093 extended_memory_size
*= 64;
4094 if(extended_memory_size
> 0x3bc000) // greater than EFF00000???
4096 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4098 extended_memory_size
*= 1024;
4099 extended_memory_size
+= 15728640; // make up for the 16mb of memory that is chopped off
4101 if(extended_memory_size
<= 15728640)
4103 extended_memory_size
= inb_cmos(0x31);
4104 extended_memory_size
<<= 8;
4105 extended_memory_size
|= inb_cmos(0x30);
4106 extended_memory_size
*= 1024;
4109 write_word(ES
, regs
.u
.r16
.di
, 0x0000);
4110 write_word(ES
, regs
.u
.r16
.di
+2, 0x0010);
4111 write_word(ES
, regs
.u
.r16
.di
+4, 0x0000);
4112 write_word(ES
, regs
.u
.r16
.di
+6, 0x0000);
4114 write_word(ES
, regs
.u
.r16
.di
+8, extended_memory_size
);
4115 extended_memory_size
>>= 16;
4116 write_word(ES
, regs
.u
.r16
.di
+10, extended_memory_size
);
4117 extended_memory_size
>>= 16;
4118 write_word(ES
, regs
.u
.r16
.di
+12, extended_memory_size
);
4119 extended_memory_size
>>= 16;
4120 write_word(ES
, regs
.u
.r16
.di
+14, extended_memory_size
);
4122 write_word(ES
, regs
.u
.r16
.di
+16, 0x1);
4123 write_word(ES
, regs
.u
.r16
.di
+18, 0x0);
4126 regs
.u
.r32
.eax
= 0x534D4150;
4127 regs
.u
.r32
.ecx
= 0x14;
4131 default: /* AX=E820, DX=534D4150, BX unrecognized */
4132 goto int15_unimplemented
;
4136 // if DX != 0x534D4150)
4137 goto int15_unimplemented
;
4142 // do we have any reason to fail here ?
4145 // my real system sets ax and bx to 0
4146 // this is confirmed by Ralph Brown list
4147 // but syslinux v1.48 is known to behave
4148 // strangely if ax is set to 0
4149 // regs.u.r16.ax = 0;
4150 // regs.u.r16.bx = 0;
4152 // Get the amount of extended memory (above 1M)
4153 regs
.u
.r8
.cl
= inb_cmos(0x30);
4154 regs
.u
.r8
.ch
= inb_cmos(0x31);
4157 if(regs
.u
.r16
.cx
> 0x3c00)
4159 regs
.u
.r16
.cx
= 0x3c00;
4162 // Get the amount of extended memory above 16M in 64k blocs
4163 regs
.u
.r8
.dl
= inb_cmos(0x34);
4164 regs
.u
.r8
.dh
= inb_cmos(0x35);
4166 // Set configured memory equal to extended memory
4167 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4168 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4170 default: /* AH=0xE8?? but not implemented */
4171 goto int15_unimplemented
;
4174 int15_unimplemented
:
4175 // fall into the default
4177 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4178 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4180 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4186 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4187 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4189 Bit8u scan_code
, ascii_code
, shift_flags
, count
;
4190 Bit16u kbd_code
, max
;
4192 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4195 case 0x00: /* read keyboard input */
4197 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4198 BX_PANIC("KBD: int16h: out of keyboard input\n");
4200 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4201 else if (ascii_code
== 0xE0) ascii_code
= 0;
4202 AX
= (scan_code
<< 8) | ascii_code
;
4205 case 0x01: /* check keyboard status */
4206 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4210 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4211 else if (ascii_code
== 0xE0) ascii_code
= 0;
4212 AX
= (scan_code
<< 8) | ascii_code
;
4216 case 0x02: /* get shift flag status */
4217 shift_flags
= read_byte(0x0040, 0x17);
4218 SET_AL(shift_flags
);
4221 case 0x05: /* store key-stroke into buffer */
4222 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4230 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4231 // bit Bochs Description
4233 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4234 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4235 // 4 1 INT 16/AH=0Ah supported
4236 // 3 0 INT 16/AX=0306h supported
4237 // 2 0 INT 16/AX=0305h supported
4238 // 1 0 INT 16/AX=0304h supported
4239 // 0 0 INT 16/AX=0300h supported
4244 case 0x0A: /* GET KEYBOARD ID */
4250 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4252 if ((inb(0x60) == 0xfa)) {
4255 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4258 kbd_code
|= (inb(0x60) << 8);
4260 } while (--count
>0);
4266 case 0x10: /* read MF-II keyboard input */
4268 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4269 BX_PANIC("KBD: int16h: out of keyboard input\n");
4271 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4272 AX
= (scan_code
<< 8) | ascii_code
;
4275 case 0x11: /* check MF-II keyboard status */
4276 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4280 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4281 AX
= (scan_code
<< 8) | ascii_code
;
4285 case 0x12: /* get extended keyboard status */
4286 shift_flags
= read_byte(0x0040, 0x17);
4287 SET_AL(shift_flags
);
4288 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4289 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4290 SET_AH(shift_flags
);
4291 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4294 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4295 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4298 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4299 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4303 if (GET_AL() == 0x08)
4304 SET_AH(0x02); // unsupported, aka normal keyboard
4307 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4312 dequeue_key(scan_code
, ascii_code
, incr
)
4317 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4322 buffer_start
= 0x001E;
4323 buffer_end
= 0x003E;
4325 buffer_start
= read_word(0x0040, 0x0080);
4326 buffer_end
= read_word(0x0040, 0x0082);
4329 buffer_head
= read_word(0x0040, 0x001a);
4330 buffer_tail
= read_word(0x0040, 0x001c);
4332 if (buffer_head
!= buffer_tail
) {
4334 acode
= read_byte(0x0040, buffer_head
);
4335 scode
= read_byte(0x0040, buffer_head
+1);
4336 write_byte(ss
, ascii_code
, acode
);
4337 write_byte(ss
, scan_code
, scode
);
4341 if (buffer_head
>= buffer_end
)
4342 buffer_head
= buffer_start
;
4343 write_word(0x0040, 0x001a, buffer_head
);
4352 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4355 inhibit_mouse_int_and_events()
4357 Bit8u command_byte
, prev_command_byte
;
4359 // Turn off IRQ generation and aux data line
4360 if ( inb(0x64) & 0x02 )
4361 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4362 outb(0x64, 0x20); // get command byte
4363 while ( (inb(0x64) & 0x01) != 0x01 );
4364 prev_command_byte
= inb(0x60);
4365 command_byte
= prev_command_byte
;
4366 //while ( (inb(0x64) & 0x02) );
4367 if ( inb(0x64) & 0x02 )
4368 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4369 command_byte
&= 0xfd; // turn off IRQ 12 generation
4370 command_byte
|= 0x20; // disable mouse serial clock line
4371 outb(0x64, 0x60); // write command byte
4372 outb(0x60, command_byte
);
4373 return(prev_command_byte
);
4377 enable_mouse_int_and_events()
4381 // Turn on IRQ generation and aux data line
4382 if ( inb(0x64) & 0x02 )
4383 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4384 outb(0x64, 0x20); // get command byte
4385 while ( (inb(0x64) & 0x01) != 0x01 );
4386 command_byte
= inb(0x60);
4387 //while ( (inb(0x64) & 0x02) );
4388 if ( inb(0x64) & 0x02 )
4389 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4390 command_byte
|= 0x02; // turn on IRQ 12 generation
4391 command_byte
&= 0xdf; // enable mouse serial clock line
4392 outb(0x64, 0x60); // write command byte
4393 outb(0x60, command_byte
);
4397 send_to_mouse_ctrl(sendbyte
)
4402 // wait for chance to write to ctrl
4403 if ( inb(0x64) & 0x02 )
4404 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4406 outb(0x60, sendbyte
);
4412 get_mouse_data(data
)
4418 while ( (inb(0x64) & 0x21) != 0x21 ) {
4421 response
= inb(0x60);
4424 write_byte(ss
, data
, response
);
4429 set_kbd_command_byte(command_byte
)
4432 if ( inb(0x64) & 0x02 )
4433 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4436 outb(0x64, 0x60); // write command byte
4437 outb(0x60, command_byte
);
4441 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4442 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4444 Bit8u scancode
, asciicode
, shift_flags
;
4445 Bit8u mf2_flags
, mf2_state
, led_flags
;
4448 // DS has been set to F000 before call
4452 scancode
= GET_AL();
4454 if (scancode
== 0) {
4455 BX_INFO("KBD: int09 handler: AL=0\n");
4460 shift_flags
= read_byte(0x0040, 0x17);
4461 mf2_flags
= read_byte(0x0040, 0x18);
4462 mf2_state
= read_byte(0x0040, 0x96);
4463 led_flags
= read_byte(0x0040, 0x97);
4467 case 0x3a: /* Caps Lock press */
4468 shift_flags
^= 0x40;
4469 write_byte(0x0040, 0x17, shift_flags
);
4472 write_byte(0x0040, 0x18, mf2_flags
);
4473 write_byte(0x0040, 0x97, led_flags
);
4475 case 0xba: /* Caps Lock release */
4477 write_byte(0x0040, 0x18, mf2_flags
);
4480 case 0x2a: /* L Shift press */
4481 shift_flags
|= 0x02;
4482 write_byte(0x0040, 0x17, shift_flags
);
4484 case 0xaa: /* L Shift release */
4485 shift_flags
&= ~0x02;
4486 write_byte(0x0040, 0x17, shift_flags
);
4489 case 0x36: /* R Shift press */
4490 shift_flags
|= 0x01;
4491 write_byte(0x0040, 0x17, shift_flags
);
4493 case 0xb6: /* R Shift release */
4494 shift_flags
&= ~0x01;
4495 write_byte(0x0040, 0x17, shift_flags
);
4498 case 0x1d: /* Ctrl press */
4499 shift_flags
|= 0x04;
4500 write_byte(0x0040, 0x17, shift_flags
);
4501 if (mf2_state
& 0x01) {
4503 write_byte(0x0040, 0x96, mf2_state
);
4506 write_byte(0x0040, 0x18, mf2_flags
);
4509 case 0x9d: /* Ctrl release */
4510 shift_flags
&= ~0x04;
4511 write_byte(0x0040, 0x17, shift_flags
);
4512 if (mf2_state
& 0x01) {
4514 write_byte(0x0040, 0x96, mf2_state
);
4517 write_byte(0x0040, 0x18, mf2_flags
);
4521 case 0x38: /* Alt press */
4522 shift_flags
|= 0x08;
4523 write_byte(0x0040, 0x17, shift_flags
);
4524 if (mf2_state
& 0x01) {
4526 write_byte(0x0040, 0x96, mf2_state
);
4529 write_byte(0x0040, 0x18, mf2_flags
);
4532 case 0xb8: /* Alt release */
4533 shift_flags
&= ~0x08;
4534 write_byte(0x0040, 0x17, shift_flags
);
4535 if (mf2_state
& 0x01) {
4537 write_byte(0x0040, 0x96, mf2_state
);
4540 write_byte(0x0040, 0x18, mf2_flags
);
4544 case 0x45: /* Num Lock press */
4545 if ((mf2_state
& 0x01) == 0) {
4547 write_byte(0x0040, 0x18, mf2_flags
);
4548 shift_flags
^= 0x20;
4550 write_byte(0x0040, 0x17, shift_flags
);
4551 write_byte(0x0040, 0x97, led_flags
);
4554 case 0xc5: /* Num Lock release */
4555 if ((mf2_state
& 0x01) == 0) {
4557 write_byte(0x0040, 0x18, mf2_flags
);
4561 case 0x46: /* Scroll Lock press */
4563 write_byte(0x0040, 0x18, mf2_flags
);
4564 shift_flags
^= 0x10;
4566 write_byte(0x0040, 0x17, shift_flags
);
4567 write_byte(0x0040, 0x97, led_flags
);
4570 case 0xc6: /* Scroll Lock release */
4572 write_byte(0x0040, 0x18, mf2_flags
);
4576 if (scancode
& 0x80) return; /* toss key releases ... */
4577 if (scancode
> MAX_SCAN_CODE
) {
4578 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4581 if (shift_flags
& 0x08) { /* ALT */
4582 asciicode
= scan_to_scanascii
[scancode
].alt
;
4583 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4585 else if (shift_flags
& 0x04) { /* CONTROL */
4586 asciicode
= scan_to_scanascii
[scancode
].control
;
4587 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4589 else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4590 /* check if lock state should be ignored
4591 * because a SHIFT key are pressed */
4593 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4594 asciicode
= scan_to_scanascii
[scancode
].normal
;
4595 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4598 asciicode
= scan_to_scanascii
[scancode
].shift
;
4599 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4603 /* check if lock is on */
4604 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4605 asciicode
= scan_to_scanascii
[scancode
].shift
;
4606 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4609 asciicode
= scan_to_scanascii
[scancode
].normal
;
4610 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4613 if (scancode
==0 && asciicode
==0) {
4614 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4616 enqueue_key(scancode
, asciicode
);
4620 write_byte(0x0040, 0x96, mf2_state
);
4624 enqueue_key(scan_code
, ascii_code
)
4625 Bit8u scan_code
, ascii_code
;
4627 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4629 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4630 // scan_code, ascii_code);
4633 buffer_start
= 0x001E;
4634 buffer_end
= 0x003E;
4636 buffer_start
= read_word(0x0040, 0x0080);
4637 buffer_end
= read_word(0x0040, 0x0082);
4640 buffer_head
= read_word(0x0040, 0x001A);
4641 buffer_tail
= read_word(0x0040, 0x001C);
4643 temp_tail
= buffer_tail
;
4645 if (buffer_tail
>= buffer_end
)
4646 buffer_tail
= buffer_start
;
4648 if (buffer_tail
== buffer_head
) {
4652 write_byte(0x0040, temp_tail
, ascii_code
);
4653 write_byte(0x0040, temp_tail
+1, scan_code
);
4654 write_word(0x0040, 0x001C, buffer_tail
);
4660 int74_function(make_farcall
, Z
, Y
, X
, status
)
4661 Bit16u make_farcall
, Z
, Y
, X
, status
;
4663 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4664 Bit8u in_byte
, index
, package_count
;
4665 Bit8u mouse_flags_1
, mouse_flags_2
;
4667 BX_DEBUG_INT74("entering int74_function\n");
4670 in_byte
= inb(0x64);
4671 if ( (in_byte
& 0x21) != 0x21 ) {
4674 in_byte
= inb(0x60);
4675 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4677 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4678 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4680 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4681 // BX_PANIC("int74_function:\n");
4685 package_count
= mouse_flags_2
& 0x07;
4686 index
= mouse_flags_1
& 0x07;
4687 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4689 if ( (index
+1) >= package_count
) {
4690 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4691 status
= read_byte(ebda_seg
, 0x0028 + 0);
4692 X
= read_byte(ebda_seg
, 0x0028 + 1);
4693 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4696 // check if far call handler installed
4697 if (mouse_flags_2
& 0x80)
4703 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4706 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4711 int13_harddisk(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4712 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4715 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4716 Bit16u cylinder
, head
, sector
;
4717 Bit16u segment
, offset
;
4718 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4720 Bit8u device
, status
;
4722 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4724 write_byte(0x0040, 0x008e, 0); // clear completion flag
4726 // basic check : device has to be defined
4727 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4728 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4732 // Get the ata channel
4733 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
4735 // basic check : device has to be valid
4736 if (device
>= BX_MAX_ATA_DEVICES
) {
4737 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4743 case 0x00: /* disk controller reset */
4748 case 0x01: /* read disk status */
4749 status
= read_byte(0x0040, 0x0074);
4751 SET_DISK_RET_STATUS(0);
4752 /* set CF if error status read */
4753 if (status
) goto int13_fail_nostatus
;
4754 else goto int13_success_noah
;
4757 case 0x02: // read disk sectors
4758 case 0x03: // write disk sectors
4759 case 0x04: // verify disk sectors
4762 cylinder
= GET_CH();
4763 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
4764 sector
= (GET_CL() & 0x3f);
4770 if ( (count
> 128) || (count
== 0) ) {
4771 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4775 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4776 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4777 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4779 // sanity check on cyl heads, sec
4780 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
4781 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
4786 if ( GET_AH() == 0x04 ) goto int13_success
;
4788 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4789 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4791 // if needed, translate lchs to lba, and execute command
4792 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
4793 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
4794 sector
= 0; // this forces the command to be lba
4797 if ( GET_AH() == 0x02 )
4798 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4800 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4802 // Set nb of sector transferred
4803 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
4806 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4808 goto int13_fail_noah
;
4814 case 0x05: /* format disk track */
4815 BX_INFO("format disk track called\n");
4820 case 0x08: /* read disk drive parameters */
4822 // Get logical geometry from table
4823 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4824 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4825 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4826 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
4828 nlc
= nlc
- 2; /* 0 based , last sector not used */
4831 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
4833 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
4835 // FIXME should set ES & DI
4840 case 0x10: /* check drive ready */
4841 // should look at 40:8E also???
4843 // Read the status from controller
4844 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
4845 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
4850 goto int13_fail_noah
;
4854 case 0x15: /* read disk drive size */
4856 // Get physical geometry from table
4857 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
4858 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4859 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4861 // Compute sector count seen by int13
4862 lba
= (Bit32u
)(npc
- 1) * (Bit32u
)nph
* (Bit32u
)npspt
;
4866 SET_AH(3); // hard disk accessible
4867 goto int13_success_noah
;
4870 case 0x41: // IBM/MS installation check
4871 BX
=0xaa55; // install check
4872 SET_AH(0x30); // EDD 3.0
4873 CX
=0x0007; // ext disk access and edd, removable supported
4874 goto int13_success_noah
;
4877 case 0x42: // IBM/MS extended read
4878 case 0x43: // IBM/MS extended write
4879 case 0x44: // IBM/MS verify
4880 case 0x47: // IBM/MS extended seek
4882 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
4883 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
4884 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
4886 // Can't use 64 bits lba
4887 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
4889 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4893 // Get 32 bits lba and check
4894 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
4895 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
4896 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4900 // If verify or seek
4901 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4904 // Execute the command
4905 if ( GET_AH() == 0x42 )
4906 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4908 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4910 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
4911 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
4914 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4916 goto int13_fail_noah
;
4922 case 0x45: // IBM/MS lock/unlock drive
4923 case 0x49: // IBM/MS extended media change
4924 goto int13_success
; // Always success for HD
4927 case 0x46: // IBM/MS eject media
4928 SET_AH(0xb2); // Volume Not Removable
4929 goto int13_fail_noah
; // Always fail for HD
4932 case 0x48: // IBM/MS get drive parameters
4933 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
4935 // Buffer is too small
4943 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
4944 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4945 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4946 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
4947 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
4949 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
4950 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
4951 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
4952 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
4953 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
4954 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
4955 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
4956 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
4961 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
4962 Bit16u iobase1
, iobase2
, options
;
4964 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
4966 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
4967 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
4970 channel
= device
/ 2;
4971 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
4972 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
4973 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
4974 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
4975 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
4977 options
= (translation
==ATA_TRANSLATION_NONE
?0:1<<3); // chs translation
4978 options
|= (1<<4); // lba translation
4979 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
4980 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0<<9);
4981 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0<<9);
4983 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
4984 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
4985 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
4986 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
4987 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
4988 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
4989 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
4990 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
4991 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
4992 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
4993 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
4996 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
4997 checksum
= ~checksum
;
4998 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5003 Bit8u channel
, iface
, checksum
, i
;
5006 channel
= device
/ 2;
5007 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5008 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5010 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5011 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5012 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5013 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5014 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5016 if (iface
==ATA_IFACE_ISA
) {
5017 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5018 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5019 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5020 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5025 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5026 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5027 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5028 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5030 if (iface
==ATA_IFACE_ISA
) {
5031 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5032 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5033 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5038 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5039 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5040 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5041 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5044 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5045 checksum
= ~checksum
;
5046 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5052 case 0x4e: // // IBM/MS set hardware configuration
5053 // DMA, prefetch, PIO maximum not supported
5066 case 0x09: /* initialize drive parameters */
5067 case 0x0c: /* seek to specified cylinder */
5068 case 0x0d: /* alternate disk reset */
5069 case 0x11: /* recalibrate */
5070 case 0x14: /* controller internal diagnostic */
5071 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5075 case 0x0a: /* read disk sectors with ECC */
5076 case 0x0b: /* write disk sectors with ECC */
5077 case 0x18: // set media type for format
5078 case 0x50: // IBM/MS send packet command
5080 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5086 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5088 SET_DISK_RET_STATUS(GET_AH());
5089 int13_fail_nostatus
:
5090 SET_CF(); // error occurred
5094 SET_AH(0x00); // no error
5096 SET_DISK_RET_STATUS(0x00);
5097 CLEAR_CF(); // no error
5101 // ---------------------------------------------------------------------------
5102 // Start of int13 for cdrom
5103 // ---------------------------------------------------------------------------
5106 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5107 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5109 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5110 Bit8u device
, status
, locks
;
5113 Bit16u count
, segment
, offset
, i
, size
;
5115 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5116 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5118 SET_DISK_RET_STATUS(0x00);
5120 /* basic check : device should be 0xE0+ */
5121 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5122 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5126 // Get the ata channel
5127 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5129 /* basic check : device has to be valid */
5130 if (device
>= BX_MAX_ATA_DEVICES
) {
5131 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5137 // all those functions return SUCCESS
5138 case 0x00: /* disk controller reset */
5139 case 0x09: /* initialize drive parameters */
5140 case 0x0c: /* seek to specified cylinder */
5141 case 0x0d: /* alternate disk reset */
5142 case 0x10: /* check drive ready */
5143 case 0x11: /* recalibrate */
5144 case 0x14: /* controller internal diagnostic */
5145 case 0x16: /* detect disk change */
5149 // all those functions return disk write-protected
5150 case 0x03: /* write disk sectors */
5151 case 0x05: /* format disk track */
5152 case 0x43: // IBM/MS extended write
5154 goto int13_fail_noah
;
5157 case 0x01: /* read disk status */
5158 status
= read_byte(0x0040, 0x0074);
5160 SET_DISK_RET_STATUS(0);
5162 /* set CF if error status read */
5163 if (status
) goto int13_fail_nostatus
;
5164 else goto int13_success_noah
;
5167 case 0x15: /* read disk drive size */
5169 goto int13_fail_noah
;
5172 case 0x41: // IBM/MS installation check
5173 BX
=0xaa55; // install check
5174 SET_AH(0x30); // EDD 2.1
5175 CX
=0x0007; // ext disk access, removable and edd
5176 goto int13_success_noah
;
5179 case 0x42: // IBM/MS extended read
5180 case 0x44: // IBM/MS verify sectors
5181 case 0x47: // IBM/MS extended seek
5183 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5184 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5185 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5187 // Can't use 64 bits lba
5188 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5190 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5195 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5197 // If verify or seek
5198 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5201 memsetb(get_SS(),atacmd
,0,12);
5202 atacmd
[0]=0x28; // READ command
5203 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5204 atacmd
[8]=(count
& 0x00ff); // Sectors
5205 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5206 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5207 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5208 atacmd
[5]=(lba
& 0x000000ff);
5209 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5211 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5212 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5215 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5217 goto int13_fail_noah
;
5223 case 0x45: // IBM/MS lock/unlock drive
5224 if (GET_AL() > 2) goto int13_fail
;
5226 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5230 if (locks
== 0xff) {
5233 goto int13_fail_noah
;
5235 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5239 if (locks
== 0x00) {
5242 goto int13_fail_noah
;
5244 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5245 SET_AL(locks
==0?0:1);
5248 SET_AL(locks
==0?0:1);
5254 case 0x46: // IBM/MS eject media
5255 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5258 SET_AH(0xb1); // media locked
5259 goto int13_fail_noah
;
5261 // FIXME should handle 0x31 no media in device
5262 // FIXME should handle 0xb5 valid request failed
5264 // Call removable media eject
5271 mov _int13_cdrom
.status
+ 2[bp
], ah
5272 jnc int13_cdrom_rme_end
5273 mov _int13_cdrom
.status
, #1
5274 int13_cdrom_rme_end
:
5279 SET_AH(0xb1); // media locked
5280 goto int13_fail_noah
;
5286 case 0x48: // IBM/MS get drive parameters
5287 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5289 // Buffer is too small
5295 Bit16u cylinders
, heads
, spt
, blksize
;
5297 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5299 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5300 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5301 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5302 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5303 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5304 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5305 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5306 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5311 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5312 Bit16u iobase1
, iobase2
, options
;
5314 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5316 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5317 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5320 channel
= device
/ 2;
5321 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5322 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5323 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5324 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5326 // FIXME atapi device
5327 options
= (1<<4); // lba translation
5328 options
|= (1<<5); // removable device
5329 options
|= (1<<6); // atapi device
5330 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5332 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5333 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5334 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5335 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5336 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5337 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5338 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5339 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5340 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5341 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5342 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5345 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5346 checksum
= ~checksum
;
5347 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5352 Bit8u channel
, iface
, checksum
, i
;
5355 channel
= device
/ 2;
5356 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5357 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5359 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5360 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5361 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5362 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5363 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5365 if (iface
==ATA_IFACE_ISA
) {
5366 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5367 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5368 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5369 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5374 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5375 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5376 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5377 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5379 if (iface
==ATA_IFACE_ISA
) {
5380 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5381 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5382 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5387 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5388 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5389 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5390 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5393 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5394 checksum
= ~checksum
;
5395 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5401 case 0x49: // IBM/MS extended media change
5402 // always send changed ??
5404 goto int13_fail_nostatus
;
5407 case 0x4e: // // IBM/MS set hardware configuration
5408 // DMA, prefetch, PIO maximum not supported
5421 // all those functions return unimplemented
5422 case 0x02: /* read sectors */
5423 case 0x04: /* verify sectors */
5424 case 0x08: /* read disk drive parameters */
5425 case 0x0a: /* read disk sectors with ECC */
5426 case 0x0b: /* write disk sectors with ECC */
5427 case 0x18: /* set media type for format */
5428 case 0x50: // ? - send packet command
5430 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5436 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5438 SET_DISK_RET_STATUS(GET_AH());
5439 int13_fail_nostatus
:
5440 SET_CF(); // error occurred
5444 SET_AH(0x00); // no error
5446 SET_DISK_RET_STATUS(0x00);
5447 CLEAR_CF(); // no error
5451 // ---------------------------------------------------------------------------
5452 // End of int13 for cdrom
5453 // ---------------------------------------------------------------------------
5455 #if BX_ELTORITO_BOOT
5456 // ---------------------------------------------------------------------------
5457 // Start of int13 for eltorito functions
5458 // ---------------------------------------------------------------------------
5461 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5462 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5464 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5466 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5467 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5471 // FIXME ElTorito Various. Should be implemented
5472 case 0x4a: // ElTorito - Initiate disk emu
5473 case 0x4c: // ElTorito - Initiate disk emu and boot
5474 case 0x4d: // ElTorito - Return Boot catalog
5475 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5479 case 0x4b: // ElTorito - Terminate disk emu
5480 // FIXME ElTorito Hardcoded
5481 write_byte(DS
,SI
+0x00,0x13);
5482 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5483 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5484 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5485 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5486 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5487 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5488 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5489 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5490 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5491 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5492 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5494 // If we have to terminate emulation
5495 if(GET_AL() == 0x00) {
5496 // FIXME ElTorito Various. Should be handled accordingly to spec
5497 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5504 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5510 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5511 SET_DISK_RET_STATUS(GET_AH());
5512 SET_CF(); // error occurred
5516 SET_AH(0x00); // no error
5517 SET_DISK_RET_STATUS(0x00);
5518 CLEAR_CF(); // no error
5522 // ---------------------------------------------------------------------------
5523 // End of int13 for eltorito functions
5524 // ---------------------------------------------------------------------------
5526 // ---------------------------------------------------------------------------
5527 // Start of int13 when emulating a device from the cd
5528 // ---------------------------------------------------------------------------
5531 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5532 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5534 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5535 Bit8u device
, status
;
5536 Bit16u vheads
, vspt
, vcylinders
;
5537 Bit16u head
, sector
, cylinder
, nbsectors
;
5538 Bit32u vlba
, ilba
, slba
, elba
;
5539 Bit16u before
, segment
, offset
;
5542 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5543 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5545 /* at this point, we are emulating a floppy/harddisk */
5547 // Recompute the device number
5548 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5549 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5551 SET_DISK_RET_STATUS(0x00);
5553 /* basic checks : emulation should be active, dl should equal the emulated drive */
5554 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5555 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5556 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5562 // all those functions return SUCCESS
5563 case 0x00: /* disk controller reset */
5564 case 0x09: /* initialize drive parameters */
5565 case 0x0c: /* seek to specified cylinder */
5566 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5567 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5568 case 0x11: /* recalibrate */
5569 case 0x14: /* controller internal diagnostic */
5570 case 0x16: /* detect disk change */
5574 // all those functions return disk write-protected
5575 case 0x03: /* write disk sectors */
5576 case 0x05: /* format disk track */
5578 goto int13_fail_noah
;
5581 case 0x01: /* read disk status */
5582 status
=read_byte(0x0040, 0x0074);
5584 SET_DISK_RET_STATUS(0);
5586 /* set CF if error status read */
5587 if (status
) goto int13_fail_nostatus
;
5588 else goto int13_success_noah
;
5591 case 0x02: // read disk sectors
5592 case 0x04: // verify disk sectors
5593 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5594 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5595 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5597 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5599 sector
= GET_CL() & 0x003f;
5600 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5602 nbsectors
= GET_AL();
5606 // no sector to read ?
5607 if(nbsectors
==0) goto int13_success
;
5609 // sanity checks sco openserver needs this!
5611 || (cylinder
>= vcylinders
)
5612 || (head
>= vheads
)) {
5616 // After controls, verify do nothing
5617 if (GET_AH() == 0x04) goto int13_success
;
5619 segment
= ES
+(BX
/ 16);
5622 // calculate the virtual lba inside the image
5623 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5625 // In advance so we don't loose the count
5629 slba
= (Bit32u
)vlba
/4;
5630 before
= (Bit16u
)vlba
%4;
5633 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5635 memsetb(get_SS(),atacmd
,0,12);
5636 atacmd
[0]=0x28; // READ command
5637 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5638 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5639 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5640 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5641 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5642 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5643 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5644 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5647 goto int13_fail_noah
;
5653 case 0x08: /* read disk drive parameters */
5654 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5655 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5656 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5660 SET_CH( vcylinders
& 0xff );
5661 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5663 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5664 // FIXME ElTorito Harddisk. should send the HD count
5666 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5667 case 0x01: SET_BL( 0x02 ); break;
5668 case 0x02: SET_BL( 0x04 ); break;
5669 case 0x03: SET_BL( 0x06 ); break;
5675 mov ax
, #diskette_param_table2
5676 mov _int13_cdemu
.DI
+2[bp
], ax
5677 mov _int13_cdemu
.ES
+2[bp
], cs
5683 case 0x15: /* read disk drive size */
5684 // FIXME ElTorito Harddisk. What geometry to send ?
5686 goto int13_success_noah
;
5689 // all those functions return unimplemented
5690 case 0x0a: /* read disk sectors with ECC */
5691 case 0x0b: /* write disk sectors with ECC */
5692 case 0x18: /* set media type for format */
5693 case 0x41: // IBM/MS installation check
5694 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5695 case 0x42: // IBM/MS extended read
5696 case 0x43: // IBM/MS extended write
5697 case 0x44: // IBM/MS verify sectors
5698 case 0x45: // IBM/MS lock/unlock drive
5699 case 0x46: // IBM/MS eject media
5700 case 0x47: // IBM/MS extended seek
5701 case 0x48: // IBM/MS get drive parameters
5702 case 0x49: // IBM/MS extended media change
5703 case 0x4e: // ? - set hardware configuration
5704 case 0x50: // ? - send packet command
5706 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5712 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5714 SET_DISK_RET_STATUS(GET_AH());
5715 int13_fail_nostatus
:
5716 SET_CF(); // error occurred
5720 SET_AH(0x00); // no error
5722 SET_DISK_RET_STATUS(0x00);
5723 CLEAR_CF(); // no error
5727 // ---------------------------------------------------------------------------
5728 // End of int13 when emulating a device from the cd
5729 // ---------------------------------------------------------------------------
5731 #endif // BX_ELTORITO_BOOT
5733 #else //BX_USE_ATADRV
5736 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
5751 mov ax
,4[bp
] // cylinder
5753 mov bl
,6[bp
] // hd_heads
5756 mov bl
,8[bp
] // head
5758 mov bl
,10[bp
] // hd_sectors
5760 mov bl
,12[bp
] // sector
5789 int13_harddisk(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5790 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5792 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
5796 Bit16u max_cylinder
, cylinder
, total_sectors
;
5797 Bit16u hd_cylinders
;
5798 Bit8u hd_heads
, hd_sectors
;
5805 Bit16u count
, segment
, offset
;
5809 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5811 write_byte(0x0040, 0x008e, 0); // clear completion flag
5813 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5815 /* check how many disks first (cmos reg 0x12), return an error if
5816 drive not present */
5817 drive_map
= inb_cmos(0x12);
5818 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
5819 (((drive_map
& 0x0f)==0) ? 0 : 2);
5820 n_drives
= (drive_map
==0) ? 0 :
5821 ((drive_map
==3) ? 2 : 1);
5823 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5825 SET_DISK_RET_STATUS(0x01);
5826 SET_CF(); /* error occurred */
5832 case 0x00: /* disk controller reset */
5833 BX_DEBUG_INT13_HD("int13_f00\n");
5836 SET_DISK_RET_STATUS(0);
5837 set_diskette_ret_status(0);
5838 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5839 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5840 CLEAR_CF(); /* successful */
5844 case 0x01: /* read disk status */
5845 BX_DEBUG_INT13_HD("int13_f01\n");
5846 status
= read_byte(0x0040, 0x0074);
5848 SET_DISK_RET_STATUS(0);
5849 /* set CF if error status read */
5850 if (status
) SET_CF();
5855 case 0x04: // verify disk sectors
5856 case 0x02: // read disk sectors
5858 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
5860 num_sectors
= GET_AL();
5861 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5862 sector
= (GET_CL() & 0x3f);
5866 if (hd_cylinders
> 1024) {
5867 if (hd_cylinders
<= 2048) {
5870 else if (hd_cylinders
<= 4096) {
5873 else if (hd_cylinders
<= 8192) {
5876 else { // hd_cylinders <= 16384
5880 ax
= head
/ hd_heads
;
5881 cyl_mod
= ax
& 0xff;
5883 cylinder
|= cyl_mod
;
5886 if ( (cylinder
>= hd_cylinders
) ||
5887 (sector
> hd_sectors
) ||
5888 (head
>= hd_heads
) ) {
5890 SET_DISK_RET_STATUS(1);
5891 SET_CF(); /* error occurred */
5895 if ( (num_sectors
> 128) || (num_sectors
== 0) )
5896 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5899 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5901 if ( GET_AH() == 0x04 ) {
5903 SET_DISK_RET_STATUS(0);
5908 status
= inb(0x1f7);
5909 if (status
& 0x80) {
5910 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5912 outb(0x01f2, num_sectors
);
5913 /* activate LBA? (tomv) */
5914 if (hd_heads
> 16) {
5915 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
5916 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
5919 outb(0x01f3, sector
);
5920 outb(0x01f4, cylinder
& 0x00ff);
5921 outb(0x01f5, cylinder
>> 8);
5922 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
5927 status
= inb(0x1f7);
5928 if ( !(status
& 0x80) ) break;
5931 if (status
& 0x01) {
5932 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
5933 } else if ( !(status
& 0x08) ) {
5934 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
5935 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
5942 sti
;; enable higher priority interrupts
5947 ;; store temp bx in real DI
register
5950 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
5953 ;; adjust
if there will be an overrun
5955 jbe i13_f02_no_adjust
5957 sub di
, #0x0200 ; sub 512 bytes from offset
5959 add ax
, #0x0020 ; add 512 to segment
5963 mov cx
, #0x0100 ;; counter (256 words = 512b)
5964 mov dx
, #0x01f0 ;; AT data read port
5967 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
5970 ;; store real DI
register back to temp bx
5973 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
5979 if (num_sectors
== 0) {
5980 status
= inb(0x1f7);
5981 if ( (status
& 0xc9) != 0x40 )
5982 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
5986 status
= inb(0x1f7);
5987 if ( (status
& 0xc9) != 0x48 )
5988 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
5994 SET_DISK_RET_STATUS(0);
5995 SET_AL(sector_count
);
5996 CLEAR_CF(); /* successful */
6001 case 0x03: /* write disk sectors */
6002 BX_DEBUG_INT13_HD("int13_f03\n");
6003 drive
= GET_ELDL ();
6004 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6006 num_sectors
= GET_AL();
6007 cylinder
= GET_CH();
6008 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6009 sector
= (GET_CL() & 0x3f);
6012 if (hd_cylinders
> 1024) {
6013 if (hd_cylinders
<= 2048) {
6016 else if (hd_cylinders
<= 4096) {
6019 else if (hd_cylinders
<= 8192) {
6022 else { // hd_cylinders <= 16384
6026 ax
= head
/ hd_heads
;
6027 cyl_mod
= ax
& 0xff;
6029 cylinder
|= cyl_mod
;
6032 if ( (cylinder
>= hd_cylinders
) ||
6033 (sector
> hd_sectors
) ||
6034 (head
>= hd_heads
) ) {
6036 SET_DISK_RET_STATUS(1);
6037 SET_CF(); /* error occurred */
6041 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6042 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6045 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6047 status
= inb(0x1f7);
6048 if (status
& 0x80) {
6049 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6051 // should check for Drive Ready Bit also in status reg
6052 outb(0x01f2, num_sectors
);
6054 /* activate LBA? (tomv) */
6055 if (hd_heads
> 16) {
6056 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6057 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6060 outb(0x01f3, sector
);
6061 outb(0x01f4, cylinder
& 0x00ff);
6062 outb(0x01f5, cylinder
>> 8);
6063 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6067 // wait for busy bit to turn off after seeking
6069 status
= inb(0x1f7);
6070 if ( !(status
& 0x80) ) break;
6073 if ( !(status
& 0x08) ) {
6074 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6075 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6082 sti
;; enable higher priority interrupts
6087 ;; store temp bx in real SI
register
6090 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6093 ;; adjust
if there will be an overrun
6095 jbe i13_f03_no_adjust
6097 sub si
, #0x0200 ; sub 512 bytes from offset
6099 add ax
, #0x0020 ; add 512 to segment
6103 mov cx
, #0x0100 ;; counter (256 words = 512b)
6104 mov dx
, #0x01f0 ;; AT data read port
6108 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6110 ;; store real SI
register back to temp bx
6113 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6119 if (num_sectors
== 0) {
6120 status
= inb(0x1f7);
6121 if ( (status
& 0xe9) != 0x40 )
6122 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6126 status
= inb(0x1f7);
6127 if ( (status
& 0xc9) != 0x48 )
6128 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6134 SET_DISK_RET_STATUS(0);
6135 SET_AL(sector_count
);
6136 CLEAR_CF(); /* successful */
6140 case 0x05: /* format disk track */
6141 BX_DEBUG_INT13_HD("int13_f05\n");
6142 BX_PANIC("format disk track called\n");
6145 SET_DISK_RET_STATUS(0);
6146 CLEAR_CF(); /* successful */
6150 case 0x08: /* read disk drive parameters */
6151 BX_DEBUG_INT13_HD("int13_f08\n");
6153 drive
= GET_ELDL ();
6154 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6158 if (hd_cylinders
<= 1024) {
6159 // hd_cylinders >>= 0;
6162 else if (hd_cylinders
<= 2048) {
6166 else if (hd_cylinders
<= 4096) {
6170 else if (hd_cylinders
<= 8192) {
6174 else { // hd_cylinders <= 16384
6179 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6181 SET_CH(max_cylinder
& 0xff);
6182 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6183 SET_DH(hd_heads
- 1);
6184 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6186 SET_DISK_RET_STATUS(0);
6187 CLEAR_CF(); /* successful */
6192 case 0x09: /* initialize drive parameters */
6193 BX_DEBUG_INT13_HD("int13_f09\n");
6195 SET_DISK_RET_STATUS(0);
6196 CLEAR_CF(); /* successful */
6200 case 0x0a: /* read disk sectors with ECC */
6201 BX_DEBUG_INT13_HD("int13_f0a\n");
6202 case 0x0b: /* write disk sectors with ECC */
6203 BX_DEBUG_INT13_HD("int13_f0b\n");
6204 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6208 case 0x0c: /* seek to specified cylinder */
6209 BX_DEBUG_INT13_HD("int13_f0c\n");
6210 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6212 SET_DISK_RET_STATUS(0);
6213 CLEAR_CF(); /* successful */
6217 case 0x0d: /* alternate disk reset */
6218 BX_DEBUG_INT13_HD("int13_f0d\n");
6220 SET_DISK_RET_STATUS(0);
6221 CLEAR_CF(); /* successful */
6225 case 0x10: /* check drive ready */
6226 BX_DEBUG_INT13_HD("int13_f10\n");
6228 //SET_DISK_RET_STATUS(0);
6229 //CLEAR_CF(); /* successful */
6233 // should look at 40:8E also???
6234 status
= inb(0x01f7);
6235 if ( (status
& 0xc0) == 0x40 ) {
6237 SET_DISK_RET_STATUS(0);
6238 CLEAR_CF(); // drive ready
6243 SET_DISK_RET_STATUS(0xAA);
6244 SET_CF(); // not ready
6249 case 0x11: /* recalibrate */
6250 BX_DEBUG_INT13_HD("int13_f11\n");
6252 SET_DISK_RET_STATUS(0);
6253 CLEAR_CF(); /* successful */
6257 case 0x14: /* controller internal diagnostic */
6258 BX_DEBUG_INT13_HD("int13_f14\n");
6260 SET_DISK_RET_STATUS(0);
6261 CLEAR_CF(); /* successful */
6266 case 0x15: /* read disk drive size */
6268 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6272 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6273 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6274 mul al
, ah
;; ax
= heads
* sectors
6275 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6276 dec bx
;; use (cylinders
- 1) ???
6277 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6278 ;; now we need to move the
32bit result dx
:ax to what the
6279 ;; BIOS wants which is cx
:dx
.
6280 ;; and then into CX
:DX on the stack
6281 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6282 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6285 SET_AH(3); // hard disk accessible
6286 SET_DISK_RET_STATUS(0); // ??? should this be 0
6287 CLEAR_CF(); // successful
6291 case 0x18: // set media type for format
6292 case 0x41: // IBM/MS
6293 case 0x42: // IBM/MS
6294 case 0x43: // IBM/MS
6295 case 0x44: // IBM/MS
6296 case 0x45: // IBM/MS lock/unlock drive
6297 case 0x46: // IBM/MS eject media
6298 case 0x47: // IBM/MS extended seek
6299 case 0x49: // IBM/MS extended media change
6300 case 0x50: // IBM/MS send packet command
6302 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6304 SET_AH(1); // code=invalid function in AH or invalid parameter
6305 SET_DISK_RET_STATUS(1);
6306 SET_CF(); /* unsuccessful */
6312 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6313 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6316 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6318 Bit16u
*hd_cylinders
;
6328 if (drive
== 0x80) {
6329 hd_type
= inb_cmos(0x12) & 0xf0;
6330 if (hd_type
!= 0xf0)
6331 BX_INFO(panic_msg_reg12h
,0);
6332 hd_type
= inb_cmos(0x19); // HD0: extended type
6334 BX_INFO(panic_msg_reg19h
,0,0x19);
6337 hd_type
= inb_cmos(0x12) & 0x0f;
6338 if (hd_type
!= 0x0f)
6339 BX_INFO(panic_msg_reg12h
,1);
6340 hd_type
= inb_cmos(0x1a); // HD0: extended type
6342 BX_INFO(panic_msg_reg19h
,0,0x1a);
6347 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6348 write_word(ss
, hd_cylinders
, cylinders
);
6351 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6353 // sectors per track
6354 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6357 #endif //else BX_USE_ATADRV
6360 //////////////////////
6361 // FLOPPY functions //
6362 //////////////////////
6365 floppy_reset_controller()
6371 outb(0x03f2, val8
& ~0x04);
6372 outb(0x03f2, val8
| 0x04);
6374 // Wait for controller to come out of reset
6376 while ( (val8
& 0xc0) != 0x80 ) {
6382 floppy_media_known(drive
)
6386 Bit16u media_state_offset
;
6388 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6395 media_state_offset
= 0x0090;
6397 media_state_offset
+= 1;
6399 val8
= read_byte(0x0040, media_state_offset
);
6400 val8
= (val8
>> 4) & 0x01;
6404 // check pass, return KNOWN
6409 floppy_media_sense(drive
)
6413 Bit16u media_state_offset
;
6414 Bit8u drive_type
, config_data
, media_state
;
6416 if (floppy_drive_recal(drive
) == 0) {
6420 // for now cheat and get drive type from CMOS,
6421 // assume media is same as drive type
6423 // ** config_data **
6424 // Bitfields for diskette media control:
6425 // Bit(s) Description (Table M0028)
6426 // 7-6 last data rate set by controller
6427 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6428 // 5-4 last diskette drive step rate selected
6429 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6430 // 3-2 {data rate at start of operation}
6433 // ** media_state **
6434 // Bitfields for diskette drive media state:
6435 // Bit(s) Description (Table M0030)
6437 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6438 // 5 double stepping required (e.g. 360kB in 1.2MB)
6439 // 4 media type established
6440 // 3 drive capable of supporting 4MB media
6441 // 2-0 on exit from BIOS, contains
6442 // 000 trying 360kB in 360kB
6443 // 001 trying 360kB in 1.2MB
6444 // 010 trying 1.2MB in 1.2MB
6445 // 011 360kB in 360kB established
6446 // 100 360kB in 1.2MB established
6447 // 101 1.2MB in 1.2MB established
6449 // 111 all other formats/drives
6451 drive_type
= inb_cmos(0x10);
6456 if ( drive_type
== 1 ) {
6458 config_data
= 0x00; // 0000 0000
6459 media_state
= 0x25; // 0010 0101
6462 else if ( drive_type
== 2 ) {
6463 // 1.2 MB 5.25" drive
6464 config_data
= 0x00; // 0000 0000
6465 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6468 else if ( drive_type
== 3 ) {
6470 config_data
= 0x00; // 0000 0000 ???
6471 media_state
= 0x17; // 0001 0111
6474 else if ( drive_type
== 4 ) {
6475 // 1.44 MB 3.5" drive
6476 config_data
= 0x00; // 0000 0000
6477 media_state
= 0x17; // 0001 0111
6480 else if ( drive_type
== 5 ) {
6481 // 2.88 MB 3.5" drive
6482 config_data
= 0xCC; // 1100 1100
6483 media_state
= 0xD7; // 1101 0111
6487 // Extended floppy size uses special cmos setting
6488 else if ( drive_type
== 6 ) {
6490 config_data
= 0x00; // 0000 0000
6491 media_state
= 0x27; // 0010 0111
6494 else if ( drive_type
== 7 ) {
6496 config_data
= 0x00; // 0000 0000
6497 media_state
= 0x27; // 0010 0111
6500 else if ( drive_type
== 8 ) {
6502 config_data
= 0x00; // 0000 0000
6503 media_state
= 0x27; // 0010 0111
6509 config_data
= 0x00; // 0000 0000
6510 media_state
= 0x00; // 0000 0000
6515 media_state_offset
= 0x90;
6517 media_state_offset
= 0x91;
6518 write_byte(0x0040, 0x008B, config_data
);
6519 write_byte(0x0040, media_state_offset
, media_state
);
6525 floppy_drive_recal(drive
)
6528 Bit8u val8
, dor
, prev_reset
;
6529 Bit16u curr_cyl_offset
;
6531 // set 40:3e bit 7 to 0
6532 val8
= read_byte(0x0040, 0x003e);
6534 write_byte(0x0040, 0x003e, val8
);
6536 // turn on motor of selected drive, DMA & int enabled, normal operation
6537 prev_reset
= inb(0x03f2) & 0x04;
6546 // reset the disk motor timeout value of INT 08
6547 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6549 // wait for drive readiness
6552 } while ( (val8
& 0xc0) != 0x80 );
6554 if (prev_reset
== 0) {
6555 // turn on interrupts
6559 // wait on 40:3e bit 7 to become 1
6561 val8
= read_byte(0x0040, 0x003e);
6562 } while ( (val8
& 0x80) == 0 );
6564 write_byte(0x0040, 0x003e, val8
);
6567 // send Recalibrate command (2 bytes) to controller
6568 outb(0x03f5, 0x07); // 07: Recalibrate
6569 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6571 // turn on interrupts
6576 // wait on 40:3e bit 7 to become 1
6578 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6579 } while ( val8
== 0 );
6581 val8
= 0; // separate asm from while() loop
6582 // turn off interrupts
6587 // set 40:3e bit 7 to 0, and calibrated bit
6588 val8
= read_byte(0x0040, 0x003e);
6591 val8
|= 0x02; // Drive 1 calibrated
6592 curr_cyl_offset
= 0x0095;
6595 val8
|= 0x01; // Drive 0 calibrated
6596 curr_cyl_offset
= 0x0094;
6598 write_byte(0x0040, 0x003e, val8
);
6599 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6607 floppy_drive_exists(drive
)
6612 // check CMOS to see if drive exists
6613 drive_type
= inb_cmos(0x10);
6618 if ( drive_type
== 0 )
6624 #if BX_SUPPORT_FLOPPY
6626 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6627 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6629 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6630 Bit16u base_address
, base_count
, base_es
;
6631 Bit8u page
, mode_register
, val8
, dor
;
6632 Bit8u return_status
[7];
6633 Bit8u drive_type
, num_floppies
, ah
;
6634 Bit16u es
, last_addr
;
6636 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6637 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6642 case 0x00: // diskette controller reset
6643 BX_DEBUG_INT13_FL("floppy f00\n");
6646 SET_AH(1); // invalid param
6647 set_diskette_ret_status(1);
6651 drive_type
= inb_cmos(0x10);
6657 if (drive_type
== 0) {
6658 SET_AH(0x80); // drive not responding
6659 set_diskette_ret_status(0x80);
6664 set_diskette_ret_status(0);
6665 CLEAR_CF(); // successful
6666 set_diskette_current_cyl(drive
, 0); // current cylinder
6669 case 0x01: // Read Diskette Status
6671 val8
= read_byte(0x0000, 0x0441);
6678 case 0x02: // Read Diskette Sectors
6679 case 0x03: // Write Diskette Sectors
6680 case 0x04: // Verify Diskette Sectors
6681 num_sectors
= GET_AL();
6687 if ( (drive
> 1) || (head
> 1) ||
6688 (num_sectors
== 0) || (num_sectors
> 72) ) {
6689 BX_INFO("floppy: drive>1 || head>1 ...\n");
6691 set_diskette_ret_status(1);
6692 SET_AL(0); // no sectors read
6693 SET_CF(); // error occurred
6697 // see if drive exists
6698 if (floppy_drive_exists(drive
) == 0) {
6699 SET_AH(0x80); // not responding
6700 set_diskette_ret_status(0x80);
6701 SET_AL(0); // no sectors read
6702 SET_CF(); // error occurred
6706 // see if media in drive, and type is known
6707 if (floppy_media_known(drive
) == 0) {
6708 if (floppy_media_sense(drive
) == 0) {
6709 SET_AH(0x0C); // Media type not found
6710 set_diskette_ret_status(0x0C);
6711 SET_AL(0); // no sectors read
6712 SET_CF(); // error occurred
6718 // Read Diskette Sectors
6720 //-----------------------------------
6721 // set up DMA controller for transfer
6722 //-----------------------------------
6724 // es:bx = pointer to where to place information from diskette
6725 // port 04: DMA-1 base and current address, channel 2
6726 // port 05: DMA-1 base and current count, channel 2
6727 page
= (ES
>> 12); // upper 4 bits
6728 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6729 base_address
= base_es
+ BX
; // lower 16 bits of address
6730 // contributed by ES:BX
6731 if ( base_address
< base_es
) {
6732 // in case of carry, adjust page by 1
6735 base_count
= (num_sectors
* 512) - 1;
6737 // check for 64K boundary overrun
6738 last_addr
= base_address
+ base_count
;
6739 if (last_addr
< base_address
) {
6741 set_diskette_ret_status(0x09);
6742 SET_AL(0); // no sectors read
6743 SET_CF(); // error occurred
6747 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6750 BX_DEBUG_INT13_FL("clear flip-flop\n");
6751 outb(0x000c, 0x00); // clear flip-flop
6752 outb(0x0004, base_address
);
6753 outb(0x0004, base_address
>>8);
6754 BX_DEBUG_INT13_FL("clear flip-flop\n");
6755 outb(0x000c, 0x00); // clear flip-flop
6756 outb(0x0005, base_count
);
6757 outb(0x0005, base_count
>>8);
6759 // port 0b: DMA-1 Mode Register
6760 mode_register
= 0x46; // single mode, increment, autoinit disable,
6761 // transfer type=write, channel 2
6762 BX_DEBUG_INT13_FL("setting mode register\n");
6763 outb(0x000b, mode_register
);
6765 BX_DEBUG_INT13_FL("setting page register\n");
6766 // port 81: DMA-1 Page Register, channel 2
6769 BX_DEBUG_INT13_FL("unmask chan 2\n");
6770 outb(0x000a, 0x02); // unmask channel 2
6772 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6775 //--------------------------------------
6776 // set up floppy controller for transfer
6777 //--------------------------------------
6779 // set 40:3e bit 7 to 0
6780 val8
= read_byte(0x0040, 0x003e);
6782 write_byte(0x0040, 0x003e, val8
);
6784 // turn on motor of selected drive, DMA & int enabled, normal operation
6793 // reset the disk motor timeout value of INT 08
6794 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6796 // check port 3f4 for drive readiness
6798 if ( (val8
& 0xf0) != 0x80 )
6799 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6801 // send read-normal-data command (9 bytes) to controller
6802 outb(0x03f5, 0xe6); // e6: read normal data
6803 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6804 outb(0x03f5, track
);
6806 outb(0x03f5, sector
);
6807 outb(0x03f5, 2); // 512 byte sector size
6808 outb(0x03f5, 0); // last sector number possible on track
6809 outb(0x03f5, 0); // Gap length
6810 outb(0x03f5, 0xff); // Gap length
6812 // turn on interrupts
6817 // wait on 40:3e bit 7 to become 1
6819 val8
= read_byte(0x0040, 0x0040);
6821 floppy_reset_controller();
6822 SET_AH(0x80); // drive not ready (timeout)
6823 set_diskette_ret_status(0x80);
6824 SET_AL(0); // no sectors read
6825 SET_CF(); // error occurred
6828 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6829 } while ( val8
== 0 );
6831 val8
= 0; // separate asm from while() loop
6832 // turn off interrupts
6837 // set 40:3e bit 7 to 0
6838 val8
= read_byte(0x0040, 0x003e);
6840 write_byte(0x0040, 0x003e, val8
);
6842 // check port 3f4 for accessibility to status bytes
6844 if ( (val8
& 0xc0) != 0xc0 )
6845 BX_PANIC("int13_diskette: ctrl not ready\n");
6847 // read 7 return status bytes from controller
6848 // using loop index broken, have to unroll...
6849 return_status
[0] = inb(0x3f5);
6850 return_status
[1] = inb(0x3f5);
6851 return_status
[2] = inb(0x3f5);
6852 return_status
[3] = inb(0x3f5);
6853 return_status
[4] = inb(0x3f5);
6854 return_status
[5] = inb(0x3f5);
6855 return_status
[6] = inb(0x3f5);
6856 // record in BIOS Data Area
6857 write_byte(0x0040, 0x0042, return_status
[0]);
6858 write_byte(0x0040, 0x0043, return_status
[1]);
6859 write_byte(0x0040, 0x0044, return_status
[2]);
6860 write_byte(0x0040, 0x0045, return_status
[3]);
6861 write_byte(0x0040, 0x0046, return_status
[4]);
6862 write_byte(0x0040, 0x0047, return_status
[5]);
6863 write_byte(0x0040, 0x0048, return_status
[6]);
6865 if ( (return_status
[0] & 0xc0) != 0 ) {
6867 set_diskette_ret_status(0x20);
6868 SET_AL(0); // no sectors read
6869 SET_CF(); // error occurred
6873 // ??? should track be new val from return_status[3] ?
6874 set_diskette_current_cyl(drive
, track
);
6875 // AL = number of sectors read (same value as passed)
6876 SET_AH(0x00); // success
6877 CLEAR_CF(); // success
6880 else if (ah
== 0x03) {
6881 // Write Diskette Sectors
6883 //-----------------------------------
6884 // set up DMA controller for transfer
6885 //-----------------------------------
6887 // es:bx = pointer to where to place information from diskette
6888 // port 04: DMA-1 base and current address, channel 2
6889 // port 05: DMA-1 base and current count, channel 2
6890 page
= (ES
>> 12); // upper 4 bits
6891 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6892 base_address
= base_es
+ BX
; // lower 16 bits of address
6893 // contributed by ES:BX
6894 if ( base_address
< base_es
) {
6895 // in case of carry, adjust page by 1
6898 base_count
= (num_sectors
* 512) - 1;
6900 // check for 64K boundary overrun
6901 last_addr
= base_address
+ base_count
;
6902 if (last_addr
< base_address
) {
6904 set_diskette_ret_status(0x09);
6905 SET_AL(0); // no sectors read
6906 SET_CF(); // error occurred
6910 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6913 outb(0x000c, 0x00); // clear flip-flop
6914 outb(0x0004, base_address
);
6915 outb(0x0004, base_address
>>8);
6916 outb(0x000c, 0x00); // clear flip-flop
6917 outb(0x0005, base_count
);
6918 outb(0x0005, base_count
>>8);
6920 // port 0b: DMA-1 Mode Register
6921 mode_register
= 0x4a; // single mode, increment, autoinit disable,
6922 // transfer type=read, channel 2
6923 outb(0x000b, mode_register
);
6925 // port 81: DMA-1 Page Register, channel 2
6928 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6931 //--------------------------------------
6932 // set up floppy controller for transfer
6933 //--------------------------------------
6935 // set 40:3e bit 7 to 0
6936 val8
= read_byte(0x0040, 0x003e);
6938 write_byte(0x0040, 0x003e, val8
);
6940 // turn on motor of selected drive, DMA & int enabled, normal operation
6949 // reset the disk motor timeout value of INT 08
6950 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6952 // check port 3f4 for drive readiness
6954 if ( (val8
& 0xf0) != 0x80 )
6955 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
6957 // send read-normal-data command (9 bytes) to controller
6958 outb(0x03f5, 0xc5); // c5: write normal data
6959 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6960 outb(0x03f5, track
);
6962 outb(0x03f5, sector
);
6963 outb(0x03f5, 2); // 512 byte sector size
6964 outb(0x03f5, 0); // last sector number possible on track
6965 outb(0x03f5, 0); // Gap length
6966 outb(0x03f5, 0xff); // Gap length
6968 // turn on interrupts
6973 // wait on 40:3e bit 7 to become 1
6975 val8
= read_byte(0x0040, 0x0040);
6977 floppy_reset_controller();
6978 SET_AH(0x80); // drive not ready (timeout)
6979 set_diskette_ret_status(0x80);
6980 SET_AL(0); // no sectors written
6981 SET_CF(); // error occurred
6984 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6985 } while ( val8
== 0 );
6987 val8
= 0; // separate asm from while() loop
6988 // turn off interrupts
6993 // set 40:3e bit 7 to 0
6994 val8
= read_byte(0x0040, 0x003e);
6996 write_byte(0x0040, 0x003e, val8
);
6998 // check port 3f4 for accessibility to status bytes
7000 if ( (val8
& 0xc0) != 0xc0 )
7001 BX_PANIC("int13_diskette: ctrl not ready\n");
7003 // read 7 return status bytes from controller
7004 // using loop index broken, have to unroll...
7005 return_status
[0] = inb(0x3f5);
7006 return_status
[1] = inb(0x3f5);
7007 return_status
[2] = inb(0x3f5);
7008 return_status
[3] = inb(0x3f5);
7009 return_status
[4] = inb(0x3f5);
7010 return_status
[5] = inb(0x3f5);
7011 return_status
[6] = inb(0x3f5);
7012 // record in BIOS Data Area
7013 write_byte(0x0040, 0x0042, return_status
[0]);
7014 write_byte(0x0040, 0x0043, return_status
[1]);
7015 write_byte(0x0040, 0x0044, return_status
[2]);
7016 write_byte(0x0040, 0x0045, return_status
[3]);
7017 write_byte(0x0040, 0x0046, return_status
[4]);
7018 write_byte(0x0040, 0x0047, return_status
[5]);
7019 write_byte(0x0040, 0x0048, return_status
[6]);
7021 if ( (return_status
[0] & 0xc0) != 0 ) {
7022 if ( (return_status
[1] & 0x02) != 0 ) {
7023 // diskette not writable.
7024 // AH=status code=0x03 (tried to write on write-protected disk)
7025 // AL=number of sectors written=0
7030 BX_PANIC("int13_diskette_function: read error\n");
7034 // ??? should track be new val from return_status[3] ?
7035 set_diskette_current_cyl(drive
, track
);
7036 // AL = number of sectors read (same value as passed)
7037 SET_AH(0x00); // success
7038 CLEAR_CF(); // success
7041 else { // if (ah == 0x04)
7042 // Verify Diskette Sectors
7044 // ??? should track be new val from return_status[3] ?
7045 set_diskette_current_cyl(drive
, track
);
7046 // AL = number of sectors verified (same value as passed)
7047 CLEAR_CF(); // success
7048 SET_AH(0x00); // success
7053 case 0x05: // format diskette track
7054 BX_DEBUG_INT13_FL("floppy f05\n");
7056 num_sectors
= GET_AL();
7061 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7062 (num_sectors
== 0) || (num_sectors
> 18)) {
7064 set_diskette_ret_status(1);
7065 SET_CF(); // error occurred
7068 // see if drive exists
7069 if (floppy_drive_exists(drive
) == 0) {
7070 SET_AH(0x80); // drive not responding
7071 set_diskette_ret_status(0x80);
7072 SET_CF(); // error occurred
7076 // see if media in drive, and type is known
7077 if (floppy_media_known(drive
) == 0) {
7078 if (floppy_media_sense(drive
) == 0) {
7079 SET_AH(0x0C); // Media type not found
7080 set_diskette_ret_status(0x0C);
7081 SET_AL(0); // no sectors read
7082 SET_CF(); // error occurred
7087 // set up DMA controller for transfer
7088 page
= (ES
>> 12); // upper 4 bits
7089 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7090 base_address
= base_es
+ BX
; // lower 16 bits of address
7091 // contributed by ES:BX
7092 if ( base_address
< base_es
) {
7093 // in case of carry, adjust page by 1
7096 base_count
= (num_sectors
* 4) - 1;
7098 // check for 64K boundary overrun
7099 last_addr
= base_address
+ base_count
;
7100 if (last_addr
< base_address
) {
7102 set_diskette_ret_status(0x09);
7103 SET_AL(0); // no sectors read
7104 SET_CF(); // error occurred
7109 outb(0x000c, 0x00); // clear flip-flop
7110 outb(0x0004, base_address
);
7111 outb(0x0004, base_address
>>8);
7112 outb(0x000c, 0x00); // clear flip-flop
7113 outb(0x0005, base_count
);
7114 outb(0x0005, base_count
>>8);
7115 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7116 // transfer type=read, channel 2
7117 outb(0x000b, mode_register
);
7118 // port 81: DMA-1 Page Register, channel 2
7122 // set up floppy controller for transfer
7123 val8
= read_byte(0x0040, 0x003e);
7125 write_byte(0x0040, 0x003e, val8
);
7126 // turn on motor of selected drive, DMA & int enabled, normal operation
7135 // reset the disk motor timeout value of INT 08
7136 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
7138 // check port 3f4 for drive readiness
7140 if ( (val8
& 0xf0) != 0x80 )
7141 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7143 // send read-normal-data command (6 bytes) to controller
7144 outb(0x03f5, 0x4d); // 4d: format track
7145 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7146 outb(0x03f5, 2); // 512 byte sector size
7147 outb(0x03f5, num_sectors
); // number of sectors per track
7148 outb(0x03f5, 0); // Gap length
7149 outb(0x03f5, 0xf6); // Fill byte
7150 // turn on interrupts
7155 // wait on 40:3e bit 7 to become 1
7157 val8
= read_byte(0x0040, 0x0040);
7159 floppy_reset_controller();
7160 SET_AH(0x80); // drive not ready (timeout)
7161 set_diskette_ret_status(0x80);
7162 SET_CF(); // error occurred
7165 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7166 } while ( val8
== 0 );
7168 val8
= 0; // separate asm from while() loop
7169 // turn off interrupts
7173 // set 40:3e bit 7 to 0
7174 val8
= read_byte(0x0040, 0x003e);
7176 write_byte(0x0040, 0x003e, val8
);
7177 // check port 3f4 for accessibility to status bytes
7179 if ( (val8
& 0xc0) != 0xc0 )
7180 BX_PANIC("int13_diskette: ctrl not ready\n");
7182 // read 7 return status bytes from controller
7183 // using loop index broken, have to unroll...
7184 return_status
[0] = inb(0x3f5);
7185 return_status
[1] = inb(0x3f5);
7186 return_status
[2] = inb(0x3f5);
7187 return_status
[3] = inb(0x3f5);
7188 return_status
[4] = inb(0x3f5);
7189 return_status
[5] = inb(0x3f5);
7190 return_status
[6] = inb(0x3f5);
7191 // record in BIOS Data Area
7192 write_byte(0x0040, 0x0042, return_status
[0]);
7193 write_byte(0x0040, 0x0043, return_status
[1]);
7194 write_byte(0x0040, 0x0044, return_status
[2]);
7195 write_byte(0x0040, 0x0045, return_status
[3]);
7196 write_byte(0x0040, 0x0046, return_status
[4]);
7197 write_byte(0x0040, 0x0047, return_status
[5]);
7198 write_byte(0x0040, 0x0048, return_status
[6]);
7200 if ( (return_status
[0] & 0xc0) != 0 ) {
7201 if ( (return_status
[1] & 0x02) != 0 ) {
7202 // diskette not writable.
7203 // AH=status code=0x03 (tried to write on write-protected disk)
7204 // AL=number of sectors written=0
7209 BX_PANIC("int13_diskette_function: write error\n");
7214 set_diskette_ret_status(0);
7215 set_diskette_current_cyl(drive
, 0);
7216 CLEAR_CF(); // successful
7220 case 0x08: // read diskette drive parameters
7221 BX_DEBUG_INT13_FL("floppy f08\n");
7231 SET_DL(num_floppies
);
7236 drive_type
= inb_cmos(0x10);
7238 if (drive_type
& 0xf0)
7240 if (drive_type
& 0x0f)
7252 SET_DL(num_floppies
);
7254 switch (drive_type
) {
7257 SET_DH(0); // max head #
7260 case 1: // 360KB, 5.25"
7261 CX
= 0x2709; // 40 tracks, 9 sectors
7262 SET_DH(1); // max head #
7265 case 2: // 1.2MB, 5.25"
7266 CX
= 0x4f0f; // 80 tracks, 15 sectors
7267 SET_DH(1); // max head #
7270 case 3: // 720KB, 3.5"
7271 CX
= 0x4f09; // 80 tracks, 9 sectors
7272 SET_DH(1); // max head #
7275 case 4: // 1.44MB, 3.5"
7276 CX
= 0x4f12; // 80 tracks, 18 sectors
7277 SET_DH(1); // max head #
7280 case 5: // 2.88MB, 3.5"
7281 CX
= 0x4f24; // 80 tracks, 36 sectors
7282 SET_DH(1); // max head #
7285 case 6: // 160k, 5.25"
7286 CX
= 0x2708; // 40 tracks, 8 sectors
7287 SET_DH(0); // max head #
7290 case 7: // 180k, 5.25"
7291 CX
= 0x2709; // 40 tracks, 9 sectors
7292 SET_DH(0); // max head #
7295 case 8: // 320k, 5.25"
7296 CX
= 0x2708; // 40 tracks, 8 sectors
7297 SET_DH(1); // max head #
7301 BX_PANIC("floppy: int13: bad floppy type\n");
7304 /* set es & di to point to 11 byte diskette param table in ROM */
7308 mov ax
, #diskette_param_table2
7309 mov _int13_diskette_function
.DI
+2[bp
], ax
7310 mov _int13_diskette_function
.ES
+2[bp
], cs
7313 CLEAR_CF(); // success
7314 /* disk status not changed upon success */
7318 case 0x15: // read diskette drive type
7319 BX_DEBUG_INT13_FL("floppy f15\n");
7322 SET_AH(0); // only 2 drives supported
7323 // set_diskette_ret_status here ???
7327 drive_type
= inb_cmos(0x10);
7333 CLEAR_CF(); // successful, not present
7334 if (drive_type
==0) {
7335 SET_AH(0); // drive not present
7338 SET_AH(1); // drive present, does not support change line
7343 case 0x16: // get diskette change line status
7344 BX_DEBUG_INT13_FL("floppy f16\n");
7347 SET_AH(0x01); // invalid drive
7348 set_diskette_ret_status(0x01);
7353 SET_AH(0x06); // change line not supported
7354 set_diskette_ret_status(0x06);
7358 case 0x17: // set diskette type for format(old)
7359 BX_DEBUG_INT13_FL("floppy f17\n");
7360 /* not used for 1.44M floppies */
7361 SET_AH(0x01); // not supported
7362 set_diskette_ret_status(1); /* not supported */
7366 case 0x18: // set diskette type for format(new)
7367 BX_DEBUG_INT13_FL("floppy f18\n");
7368 SET_AH(0x01); // do later
7369 set_diskette_ret_status(1);
7374 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7376 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7377 SET_AH(0x01); // ???
7378 set_diskette_ret_status(1);
7384 #else // #if BX_SUPPORT_FLOPPY
7386 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7387 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7391 switch ( GET_AH() ) {
7393 case 0x01: // Read Diskette Status
7395 val8
= read_byte(0x0000, 0x0441);
7404 write_byte(0x0000, 0x0441, 0x01);
7408 #endif // #if BX_SUPPORT_FLOPPY
7411 set_diskette_ret_status(value
)
7414 write_byte(0x0040, 0x0041, value
);
7418 set_diskette_current_cyl(drive
, cyl
)
7423 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7424 write_byte(0x0040, 0x0094+drive
, cyl
);
7428 determine_floppy_media(drive
)
7432 Bit8u val8
, DOR
, ctrl_info
;
7434 ctrl_info
= read_byte(0x0040, 0x008F);
7442 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7445 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7449 if ( (ctrl_info
& 0x04) != 0x04 ) {
7450 // Drive not determined means no drive exists, done.
7455 // check Main Status Register for readiness
7456 val8
= inb(0x03f4) & 0x80; // Main Status Register
7458 BX_PANIC("d_f_m: MRQ bit not set\n");
7462 // existing BDA values
7464 // turn on drive motor
7465 outb(0x03f2, DOR
); // Digital Output Register
7468 BX_PANIC("d_f_m: OK so far\n");
7473 int17_function(regs
, ds
, iret_addr
)
7474 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7475 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7476 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7478 Bit16u addr
,timeout
;
7485 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7486 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7487 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7488 if (regs
.u
.r8
.ah
== 0) {
7489 outb(addr
, regs
.u
.r8
.al
);
7491 outb(addr
+2, val8
| 0x01); // send strobe
7495 outb(addr
+2, val8
& ~0x01);
7496 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7500 if (regs
.u
.r8
.ah
== 1) {
7502 outb(addr
+2, val8
& ~0x04); // send init
7506 outb(addr
+2, val8
| 0x04);
7509 regs
.u
.r8
.ah
= (val8
^ 0x48);
7510 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7511 ClearCF(iret_addr
.flags
);
7513 SetCF(iret_addr
.flags
); // Unsupported
7517 // returns bootsegment in ax, drive in bl
7519 int19_function(bseqnr
)
7522 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7531 // if BX_ELTORITO_BOOT is not defined, old behavior
7532 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7533 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7534 // 0: system boot sequence, first drive C: then A:
7535 // 1: system boot sequence, first drive A: then C:
7536 // else BX_ELTORITO_BOOT is defined
7537 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7538 // CMOS reg 0x3D & 0x0f : 1st boot device
7539 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7540 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7541 // boot device codes:
7542 // 0x00 : not defined
7543 // 0x01 : first floppy
7544 // 0x02 : first harddrive
7545 // 0x03 : first cdrom
7546 // else : boot failure
7548 // Get the boot sequence
7549 #if BX_ELTORITO_BOOT
7550 bootseq
=inb_cmos(0x3d);
7551 bootseq
|=((inb_cmos(0x38) & 0xf0) << 4);
7553 if (bseqnr
==2) bootseq
>>= 4;
7554 if (bseqnr
==3) bootseq
>>= 8;
7555 if (bootseq
<0x10) lastdrive
= 1;
7556 bootdrv
=0x00; bootcd
=0;
7557 switch(bootseq
& 0x0f) {
7558 case 0x01: bootdrv
=0x00; bootcd
=0; break;
7559 case 0x02: bootdrv
=0x80; bootcd
=0; break;
7560 case 0x03: bootdrv
=0x00; bootcd
=1; break;
7561 default: return 0x00000000;
7564 bootseq
=inb_cmos(0x2d);
7570 bootdrv
=0x00; bootcd
=0;
7571 if((bootseq
&0x20)==0) bootdrv
=0x80;
7572 #endif // BX_ELTORITO_BOOT
7574 #if BX_ELTORITO_BOOT
7575 // We have to boot from cd
7577 status
= cdrom_boot();
7580 if ( (status
& 0x00ff) !=0 ) {
7581 print_cdromboot_failure(status
);
7582 print_boot_failure(bootcd
, bootdrv
, 1, lastdrive
);
7586 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7587 bootdrv
= (Bit8u
)(status
>>8);
7590 #endif // BX_ELTORITO_BOOT
7592 // We have to boot from harddisk or floppy
7601 mov _int19_function
.status
+ 2[bp
], ax
7602 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7603 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7604 mov es
, ax
;; segment
7605 mov bx
, #0x0000 ;; offset
7606 mov ah
, #0x02 ;; function 2, read diskette sector
7607 mov al
, #0x01 ;; read 1 sector
7608 mov ch
, #0x00 ;; track 0
7609 mov cl
, #0x01 ;; sector 1
7610 mov dh
, #0x00 ;; head 0
7611 int #0x13 ;; read sector
7614 mov _int19_function
.status
+ 2[bp
], ax
7621 print_boot_failure(bootcd
, bootdrv
, 1, lastdrive
);
7626 // check signature if instructed by cmos reg 0x38, only for floppy
7627 // bootchk = 1 : signature check disabled
7628 // bootchk = 0 : signature check enabled
7629 if (bootdrv
!= 0) bootchk
= 0;
7630 else bootchk
= inb_cmos(0x38) & 0x01;
7632 #if BX_ELTORITO_BOOT
7633 // if boot from cd, no signature check
7636 #endif // BX_ELTORITO_BOOT
7639 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7640 print_boot_failure(bootcd
, bootdrv
, 0, lastdrive
);
7645 #if BX_ELTORITO_BOOT
7646 // Print out the boot string
7647 print_boot_device(bootcd
, bootdrv
);
7648 #else // BX_ELTORITO_BOOT
7649 print_boot_device(0, bootdrv
);
7650 #endif // BX_ELTORITO_BOOT
7652 // return the boot segment
7653 return (((Bit32u
)bootdrv
) << 16) + bootseg
;
7657 int1a_function(regs
, ds
, iret_addr
)
7658 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7659 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7660 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7664 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
);
7670 switch (regs
.u
.r8
.ah
) {
7671 case 0: // get current clock count
7675 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7676 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7677 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7678 BiosData
->midnight_flag
= 0; // reset flag
7683 ClearCF(iret_addr
.flags
); // OK
7686 case 1: // Set Current Clock Count
7690 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7691 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7692 BiosData
->midnight_flag
= 0; // reset flag
7697 ClearCF(iret_addr
.flags
); // OK
7701 case 2: // Read CMOS Time
7702 if (rtc_updating()) {
7703 SetCF(iret_addr
.flags
);
7707 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7708 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7709 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7710 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7712 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7713 ClearCF(iret_addr
.flags
); // OK
7716 case 3: // Set CMOS Time
7717 // Using a debugger, I notice the following masking/setting
7718 // of bits in Status Register B, by setting Reg B to
7719 // a few values and getting its value after INT 1A was called.
7721 // try#1 try#2 try#3
7722 // before 1111 1101 0111 1101 0000 0000
7723 // after 0110 0010 0110 0010 0000 0010
7725 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7726 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7727 if (rtc_updating()) {
7729 // fall through as if an update were not in progress
7731 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7732 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7733 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7734 // Set Daylight Savings time enabled bit to requested value
7735 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7736 // (reg B already selected)
7737 outb_cmos(0x0b, val8
);
7739 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7740 ClearCF(iret_addr
.flags
); // OK
7743 case 4: // Read CMOS Date
7745 if (rtc_updating()) {
7746 SetCF(iret_addr
.flags
);
7749 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
7750 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
7751 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
7752 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
7753 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7754 ClearCF(iret_addr
.flags
); // OK
7757 case 5: // Set CMOS Date
7758 // Using a debugger, I notice the following masking/setting
7759 // of bits in Status Register B, by setting Reg B to
7760 // a few values and getting its value after INT 1A was called.
7762 // try#1 try#2 try#3 try#4
7763 // before 1111 1101 0111 1101 0000 0010 0000 0000
7764 // after 0110 1101 0111 1101 0000 0010 0000 0000
7766 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7767 // My assumption: RegB = (RegB & 01111111b)
7768 if (rtc_updating()) {
7770 SetCF(iret_addr
.flags
);
7773 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
7774 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
7775 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
7776 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
7777 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7778 outb_cmos(0x0b, val8
);
7780 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
7781 ClearCF(iret_addr
.flags
); // OK
7784 case 6: // Set Alarm Time in CMOS
7785 // Using a debugger, I notice the following masking/setting
7786 // of bits in Status Register B, by setting Reg B to
7787 // a few values and getting its value after INT 1A was called.
7789 // try#1 try#2 try#3
7790 // before 1101 1111 0101 1111 0000 0000
7791 // after 0110 1111 0111 1111 0010 0000
7793 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7794 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7795 val8
= inb_cmos(0x0b); // Get Status Reg B
7798 // Alarm interrupt enabled already
7799 SetCF(iret_addr
.flags
); // Error: alarm in use
7802 if (rtc_updating()) {
7804 // fall through as if an update were not in progress
7806 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
7807 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
7808 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
7809 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7810 // enable Status Reg B alarm bit, clear halt clock bit
7811 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
7812 ClearCF(iret_addr
.flags
); // OK
7815 case 7: // Turn off Alarm
7816 // Using a debugger, I notice the following masking/setting
7817 // of bits in Status Register B, by setting Reg B to
7818 // a few values and getting its value after INT 1A was called.
7820 // try#1 try#2 try#3 try#4
7821 // before 1111 1101 0111 1101 0010 0000 0010 0010
7822 // after 0100 0101 0101 0101 0000 0000 0000 0010
7824 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7825 // My assumption: RegB = (RegB & 01010111b)
7826 val8
= inb_cmos(0x0b); // Get Status Reg B
7827 // clear clock-halt bit, disable alarm bit
7828 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
7830 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7831 ClearCF(iret_addr
.flags
); // OK
7835 // real mode PCI BIOS functions now handled in assembler code
7836 // this C code handles the error code for information only
7837 if (regs
.u
.r8
.bl
== 0xff) {
7838 BX_INFO("PCI BIOS: PCI not present\n");
7839 } else if (regs
.u
.r8
.bl
== 0x81) {
7840 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
7841 } else if (regs
.u
.r8
.bl
== 0x83) {
7842 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
7843 } else if (regs
.u
.r8
.bl
== 0x86) {
7844 BX_INFO("PCI device %04x:%04x not found\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
);
7846 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
7847 SetCF(iret_addr
.flags
);
7852 SetCF(iret_addr
.flags
); // Unsupported
7857 int70_function(regs
, ds
, iret_addr
)
7858 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7859 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7860 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7862 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7863 Bit8u registerB
= 0, registerC
= 0;
7865 // Check which modes are enabled and have occurred.
7866 registerB
= inb_cmos( 0xB );
7867 registerC
= inb_cmos( 0xC );
7869 if( ( registerB
& 0x60 ) != 0 ) {
7870 if( ( registerC
& 0x20 ) != 0 ) {
7871 // Handle Alarm Interrupt.
7878 if( ( registerC
& 0x40 ) != 0 ) {
7879 // Handle Periodic Interrupt.
7881 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7882 // Wait Interval (Int 15, AH=83) active.
7883 Bit32u time
, toggle
;
7885 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
7886 if( time
< 0x3D1 ) {
7888 Bit16u segment
, offset
;
7890 segment
= read_word( 0x40, 0x98 );
7891 offset
= read_word( 0x40, 0x9A );
7892 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7893 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
7894 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
7896 // Continue waiting.
7898 write_dword( 0x40, 0x9C, time
);
7911 ;------------------------------------------
7912 ;- INT74h
: PS
/2 mouse hardware interrupt
-
7913 ;------------------------------------------
7918 push
#0x00 ;; placeholder for status
7919 push
#0x00 ;; placeholder for X
7920 push
#0x00 ;; placeholder for Y
7921 push
#0x00 ;; placeholder for Z
7922 push
#0x00 ;; placeholder for make_far_call boolean
7923 call _int74_function
7924 pop cx
;; remove make_far_call from stack
7927 ;; make far call to EBDA
:0022
7930 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
7932 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7937 add sp
, #8 ;; pop status, x, y, z
7939 pop ds
;; restore DS
7944 ;; This will perform an IRET
, but will retain value of current CF
7945 ;; by altering flags on stack
. Better than RETF
#02.
7950 and BYTE
[bp
+ 0x06], #0xfe
7956 or BYTE
[bp
+ 0x06], #0x01
7961 ;----------------------
7962 ;- INT13h (relocated
) -
7963 ;----------------------
7965 ; int13_relocated is a little bit messed up since I played with it
7966 ; I have to rewrite it
:
7967 ; - call a function that detect which function to call
7968 ; - make all called C function get the same parameters list
7972 #if BX_ELTORITO_BOOT
7973 ;; check
for an eltorito function
7975 jb int13_not_eltorito
7977 ja int13_not_eltorito
7986 jmp _int13_eltorito
;; ELDX
not used
7994 ;; check
if emulation active
7995 call _cdemu_isactive
7997 je int13_cdemu_inactive
7999 ;; check
if access to the emulated drive
8000 call _cdemu_emulated_drive
8003 cmp al
,dl
;; int13 on emulated drive
8018 jmp _int13_cdemu
;; ELDX
not used
8021 and dl
,#0xE0 ;; mask to get device class, including cdroms
8022 cmp al
,dl
;; al is
0x00 or 0x80
8023 jne int13_cdemu_inactive
;; inactive
for device
class
8035 dec dl
;; real drive is dl
- 1
8038 int13_cdemu_inactive
:
8044 #endif // BX_ELTORITO_BOOT
8055 push dx
;; push eltorito value of dx instead of sp
8066 ;; now the
16-bit registers can be restored with
:
8067 ;; pop ds
; pop es
; popa
; iret
8068 ;; arguments passed to functions should be
8069 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8075 jmp _int13_diskette_function
8084 // ebx is modified: BSD 5.2.1 boot loader problem
8085 // someone should figure out which 32 bit register that actually are used
8102 call _int13_harddisk
8114 int18_handler
: ;; Boot Failure routing
8115 call _int18_panic_msg
8122 int19_relocated
: ;; Boot function
, relocated
8124 ;; int19 was beginning to be really
complex, so now it
8125 ;; just calls an C function
, that does the work
8126 ;; it returns in BL the boot drive
, and in AX the boot segment
8127 ;; the boot segment will be
0x0000 if something has failed
8139 call _int19_function
8142 ;; bl contains the boot drive
8143 ;; ax contains the boot segment
or 0 if failure
8145 test ax
, ax
;; if ax is
0 try next boot device
8151 call _int19_function
8154 test ax
, ax
;; if ax is
0 try next boot device
8160 call _int19_function
8163 test ax
, ax
;; if ax is
0 call int18
8167 mov dl
, bl
;; set drive so guest os find it
8168 shl eax
, #0x04 ;; convert seg to ip
8169 mov
2[bp
], ax
;; set ip
8171 shr eax
, #0x04 ;; get cs back
8172 and ax
, #0xF000 ;; remove what went in ip
8173 mov
4[bp
], ax
;; set cs
8175 mov es
, ax
;; set es to zero fixes
[ 549815 ]
8176 mov
[bp
], ax
;; set bp to zero
8177 mov ax
, #0xaa55 ;; set ok flag
8180 iret
;; Beam me up Scotty
8185 int1c_handler
: ;; User Timer Tick
8189 ;----------------------
8190 ;- POST
: Floppy Drive
-
8191 ;----------------------
8197 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8199 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8201 mov
0x0440, al
;; diskette motor timeout counter
: not active
8202 mov
0x0441, al
;; diskette controller status
return code
8204 mov
0x0442, al
;; disk
& diskette controller status
register 0
8205 mov
0x0443, al
;; diskette controller status
register 1
8206 mov
0x0444, al
;; diskette controller status
register 2
8207 mov
0x0445, al
;; diskette controller cylinder number
8208 mov
0x0446, al
;; diskette controller head number
8209 mov
0x0447, al
;; diskette controller sector number
8210 mov
0x0448, al
;; diskette controller bytes written
8212 mov
0x048b, al
;; diskette configuration data
8214 ;; -----------------------------------------------------------------
8215 ;; (048F
) diskette controller information
8217 mov al
, #0x10 ;; get CMOS diskette drive type
8220 mov ah
, al
;; save byte to AH
8223 shr al
, #4 ;; look at top 4 bits for drive 0
8224 jz f0_missing
;; jump
if no drive0
8225 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8228 mov bl
, #0x00 ;; no drive0
8231 mov al
, ah
;; restore from AH
8232 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8233 jz f1_missing
;; jump
if no drive1
8234 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8236 ;; leave high bits in BL zerod
8237 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8238 ;; -----------------------------------------------------------------
8241 mov
0x0490, al
;; diskette
0 media state
8242 mov
0x0491, al
;; diskette
1 media state
8244 ;; diskette
0,1 operational starting state
8245 ;; drive type has
not been determined
,
8246 ;; has no changed detection line
8250 mov
0x0494, al
;; diskette
0 current cylinder
8251 mov
0x0495, al
;; diskette
1 current cylinder
8254 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8256 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8257 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8258 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8263 ;--------------------
8264 ;- POST
: HARD DRIVE
-
8265 ;--------------------
8266 ; relocated here because the primary POST area isnt big enough
.
8269 // INT 76h calls INT 15h function ax=9100
8271 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8277 mov
0x0474, al
/* hard disk status of last operation */
8278 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8279 mov
0x048c, al
/* hard disk status register */
8280 mov
0x048d, al
/* hard disk error register */
8281 mov
0x048e, al
/* hard disk task complete flag */
8283 mov
0x0475, al
/* hard disk number attached */
8285 mov
0x0476, al
/* hard disk control byte */
8286 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8287 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8288 ;; INT
41h
: hard disk
0 configuration pointer
8289 ;; INT
46h
: hard disk
1 configuration pointer
8290 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8291 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8293 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8305 cmp al
, #47 ;; decimal 47 - user definable
8309 ;; CMOS purpose param table offset
8310 ;; 1b cylinders low
0
8311 ;; 1c cylinders high
1
8313 ;; 1e write pre
-comp low
5
8314 ;; 1f write pre
-comp high
6
8315 ;; 20 retries
/bad map
/heads
>8 8
8316 ;; 21 landing zone low C
8317 ;; 22 landing zone high D
8318 ;; 23 sectors
/track E
8323 ;;; Filling EBDA table
for hard disk
0.
8331 mov (0x003d + 0x05), ax
;; write precomp word
8336 mov (0x003d + 0x08), al
;; drive control byte
8345 mov (0x003d + 0x0C), ax
;; landing zone word
8347 mov al
, #0x1c ;; get cylinders word in AX
8349 in al
, #0x71 ;; high byte
8353 in al
, #0x71 ;; low byte
8354 mov bx
, ax
;; BX
= cylinders
8359 mov cl
, al
;; CL
= heads
8364 mov dl
, al
;; DL
= sectors
8367 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8369 hd0_post_physical_chs
:
8370 ;; no logical CHS mapping used
, just physical CHS
8371 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8372 mov (0x003d + 0x00), bx
;; number of physical cylinders
8373 mov (0x003d + 0x02), cl
;; number of physical heads
8374 mov (0x003d + 0x0E), dl
;; number of physical sectors
8377 hd0_post_logical_chs
:
8378 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8379 mov (0x003d + 0x09), bx
;; number of physical cylinders
8380 mov (0x003d + 0x0b), cl
;; number of physical heads
8381 mov (0x003d + 0x04), dl
;; number of physical sectors
8382 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8384 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8387 jnbe hd0_post_above_2048
8388 ;; 1024 < c
<= 2048 cylinders
8391 jmp hd0_post_store_logical
8393 hd0_post_above_2048
:
8395 jnbe hd0_post_above_4096
8396 ;; 2048 < c
<= 4096 cylinders
8399 jmp hd0_post_store_logical
8401 hd0_post_above_4096
:
8403 jnbe hd0_post_above_8192
8404 ;; 4096 < c
<= 8192 cylinders
8407 jmp hd0_post_store_logical
8409 hd0_post_above_8192
:
8410 ;; 8192 < c
<= 16384 cylinders
8414 hd0_post_store_logical
:
8415 mov (0x003d + 0x00), bx
;; number of physical cylinders
8416 mov (0x003d + 0x02), cl
;; number of physical heads
8418 mov cl
, #0x0f ;; repeat count
8419 mov si
, #0x003d ;; offset to disk0 FDPT
8420 mov al
, #0x00 ;; sum
8421 hd0_post_checksum_loop
:
8425 jnz hd0_post_checksum_loop
8426 not al
;; now take
2s complement
8429 ;;; Done filling EBDA table
for hard disk
0.
8433 ;; is there really a second hard disk
? if not, return now
8441 ;; check that the hd type is really
0x0f.
8446 ;; check that the extended type is
47 - user definable
8450 cmp al
, #47 ;; decimal 47 - user definable
8455 ;; CMOS purpose param table offset
8456 ;; 0x24 cylinders low
0
8457 ;; 0x25 cylinders high
1
8459 ;; 0x27 write pre
-comp low
5
8460 ;; 0x28 write pre
-comp high
6
8462 ;; 0x2a landing zone low C
8463 ;; 0x2b landing zone high D
8464 ;; 0x2c sectors
/track E
8465 ;;; Fill EBDA table
for hard disk
1.
8475 mov (0x004d + 0x05), ax
;; write precomp word
8480 mov (0x004d + 0x08), al
;; drive control byte
8489 mov (0x004d + 0x0C), ax
;; landing zone word
8491 mov al
, #0x25 ;; get cylinders word in AX
8493 in al
, #0x71 ;; high byte
8497 in al
, #0x71 ;; low byte
8498 mov bx
, ax
;; BX
= cylinders
8503 mov cl
, al
;; CL
= heads
8508 mov dl
, al
;; DL
= sectors
8511 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8513 hd1_post_physical_chs
:
8514 ;; no logical CHS mapping used
, just physical CHS
8515 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8516 mov (0x004d + 0x00), bx
;; number of physical cylinders
8517 mov (0x004d + 0x02), cl
;; number of physical heads
8518 mov (0x004d + 0x0E), dl
;; number of physical sectors
8521 hd1_post_logical_chs
:
8522 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8523 mov (0x004d + 0x09), bx
;; number of physical cylinders
8524 mov (0x004d + 0x0b), cl
;; number of physical heads
8525 mov (0x004d + 0x04), dl
;; number of physical sectors
8526 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8528 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8531 jnbe hd1_post_above_2048
8532 ;; 1024 < c
<= 2048 cylinders
8535 jmp hd1_post_store_logical
8537 hd1_post_above_2048
:
8539 jnbe hd1_post_above_4096
8540 ;; 2048 < c
<= 4096 cylinders
8543 jmp hd1_post_store_logical
8545 hd1_post_above_4096
:
8547 jnbe hd1_post_above_8192
8548 ;; 4096 < c
<= 8192 cylinders
8551 jmp hd1_post_store_logical
8553 hd1_post_above_8192
:
8554 ;; 8192 < c
<= 16384 cylinders
8558 hd1_post_store_logical
:
8559 mov (0x004d + 0x00), bx
;; number of physical cylinders
8560 mov (0x004d + 0x02), cl
;; number of physical heads
8562 mov cl
, #0x0f ;; repeat count
8563 mov si
, #0x004d ;; offset to disk0 FDPT
8564 mov al
, #0x00 ;; sum
8565 hd1_post_checksum_loop
:
8569 jnz hd1_post_checksum_loop
8570 not al
;; now take
2s complement
8573 ;;; Done filling EBDA table
for hard disk
1.
8577 ;--------------------
8578 ;- POST
: EBDA segment
8579 ;--------------------
8580 ; relocated here because the primary POST area isnt big enough
.
8585 mov byte ptr
[0x0], #EBDA_SIZE
8587 xor ax
, ax
; mov EBDA seg into
40E
8589 mov word ptr
[0x40E], #EBDA_SEG
8592 ;--------------------
8593 ;- POST
: EOI
+ jmp via
[0x40:67)
8594 ;--------------------
8595 ; relocated here because the primary POST area isnt big enough
.
8605 ;--------------------
8608 out
#0xA0, al ;; slave PIC EOI
8611 out
#0x20, al ;; master PIC EOI
8614 ;--------------------
8616 ;; in
: AL in BCD format
8617 ;; out
: AL in binary format
, AH will always be
0
8620 and bl
, #0x0f ;; bl has low digit
8621 shr al
, #4 ;; al has high digit
8623 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8624 add al
, bl
;; then add low digit
8627 ;--------------------
8629 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8630 ;; Timer Ticks Roller
Flag (0x470:byte
)
8631 ;; The Timer Ticks Count needs to be set according to
8632 ;; the current CMOS time
, as
if ticks have been occurring
8633 ;; at
18.2hz since midnight up to
this point
. Calculating
8634 ;; this is a little complicated
. Here are the factors I gather
8635 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8636 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8637 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8638 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8639 ;; the timer
. With a maximum
16bit timer count
, this is again
8640 ;; divided down by
65536 to
18.2hz
.
8642 ;; 14,318,180 Hz clock
8643 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8644 ;; /4 = 1,193,181 Hz fed to timer
8645 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8646 ;; 1 second
= 18.20650736 ticks
8647 ;; 1 minute
= 1092.390442 ticks
8648 ;; 1 hour
= 65543.42651 ticks
8650 ;; Given the values in the CMOS clock
, one could calculate
8651 ;; the number of ticks by the following
:
8652 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8653 ;; (BcdToBin(minutes
) * 1092.3904)
8654 ;; (BcdToBin(hours
) * 65543.427)
8655 ;; To get a little more accuracy
, since Im
using integer
8656 ;; arithmatic
, I use
:
8657 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8658 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8659 ;; (BcdToBin(hours
) * 65543427) / 1000
8664 xor eax
, eax
;; clear EAX
8667 in al
, #0x71 ;; AL has CMOS seconds in BCD
8668 call BcdToBin
;; EAX now has seconds in binary
8674 mov ecx
, eax
;; ECX will accumulate total ticks
8677 xor eax
, eax
;; clear EAX
8680 in al
, #0x71 ;; AL has CMOS minutes in BCD
8681 call BcdToBin
;; EAX now has minutes in binary
8687 add ecx
, eax
;; add to total ticks
8690 xor eax
, eax
;; clear EAX
8693 in al
, #0x71 ;; AL has CMOS hours in BCD
8694 call BcdToBin
;; EAX now has hours in binary
8700 add ecx
, eax
;; add to total ticks
8702 mov
0x46C, ecx
;; Timer Ticks Count
8704 mov
0x470, al
;; Timer Ticks Rollover Flag
8707 ;--------------------
8709 ;; record completion in BIOS task complete flag
8721 ;--------------------
8726 #include "apmbios.S"
8730 #include "apmbios.S"
8733 #include "apmbios.S"
8737 ;--------------------
8742 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8743 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8744 db
0 ;; revision level
8745 ;; length in paragraphs
and checksum stored in a word to prevent errors
8746 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8747 & 0xff) << 8) + 0x01
8748 db
0,0,0,0,0 ;; reserved
8753 cmp eax
, #0x49435024 ;; "$PCI"
8755 mov eax
, #0x80000000
8760 #ifdef PCI_FIXED_HOST_BRIDGE
8761 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8764 ;; say ok
if a device is present
8765 cmp eax
, #0xffffffff
8768 mov ebx
, #0x000f0000
8770 mov edx
, #pcibios_protected
8785 cmp al
, #0x01 ;; installation check
8789 mov edx
, #0x20494350 ;; "PCI "
8792 pci_pro_f02
: ;; find pci device
8800 call pci_pro_select_reg
8814 pci_pro_f08
: ;; read configuration byte
8817 call pci_pro_select_reg
8826 pci_pro_f09
: ;; read configuration word
8829 call pci_pro_select_reg
8838 pci_pro_f0a
: ;; read configuration dword
8841 call pci_pro_select_reg
8848 pci_pro_f0b
: ;; write configuration byte
8851 call pci_pro_select_reg
8860 pci_pro_f0c
: ;; write configuration word
8863 call pci_pro_select_reg
8872 pci_pro_f0d
: ;; write configuration dword
8875 call pci_pro_select_reg
8918 mov eax
, #0x80000000
8923 #ifdef PCI_FIXED_HOST_BRIDGE
8924 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8927 ;; say ok
if a device is present
8928 cmp eax
, #0xffffffff
8939 cmp al
, #0x01 ;; installation check
8944 mov edx
, #0x20494350 ;; "PCI "
8946 mov di
, #pcibios_protected
8949 pci_real_f02
: ;; find pci device
8959 call pci_real_select_reg
8963 jne pci_real_nextdev
8970 jne pci_real_devloop
8975 pci_real_f08
: ;; read configuration byte
8978 call pci_real_select_reg
8987 pci_real_f09
: ;; read configuration word
8990 call pci_real_select_reg
8999 pci_real_f0a
: ;; read configuration dword
9002 call pci_real_select_reg
9009 pci_real_f0b
: ;; write configuration byte
9012 call pci_real_select_reg
9021 pci_real_f0c
: ;; write configuration word
9024 call pci_real_select_reg
9033 pci_real_f0d
: ;; write configuration dword
9035 jne pci_real_unknown
9036 call pci_real_select_reg
9057 pci_real_select_reg
:
9071 pci_routing_table_structure
:
9072 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9074 dw
32 + (6 * 16) ;; table size
9075 db
0 ;; PCI interrupt router bus
9076 db
0x08 ;; PCI interrupt router DevFunc
9077 dw
0x0000 ;; PCI exclusive IRQs
9078 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9079 dw
0x7000 ;; compatible PCI interrupt router device ID
9080 dw
0,0 ;; Miniport data
9081 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9083 ;; first slot entry PCI
-to
-ISA (embedded
)
9084 db
0 ;; pci bus number
9085 db
0x08 ;; pci device
number (bit
7-3)
9086 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9087 dw
0xdef8 ;; IRQ bitmap INTA
#
9088 db
0x61 ;; link value INTB
#
9089 dw
0xdef8 ;; IRQ bitmap INTB
#
9090 db
0x62 ;; link value INTC
#
9091 dw
0xdef8 ;; IRQ bitmap INTC
#
9092 db
0x63 ;; link value INTD
#
9093 dw
0xdef8 ;; IRQ bitmap INTD
#
9094 db
0 ;; physical
slot (0 = embedded
)
9096 ;; second slot entry
: 1st PCI slot
9097 db
0 ;; pci bus number
9098 db
0x10 ;; pci device
number (bit
7-3)
9099 db
0x61 ;; link value INTA
#
9100 dw
0xdef8 ;; IRQ bitmap INTA
#
9101 db
0x62 ;; link value INTB
#
9102 dw
0xdef8 ;; IRQ bitmap INTB
#
9103 db
0x63 ;; link value INTC
#
9104 dw
0xdef8 ;; IRQ bitmap INTC
#
9105 db
0x60 ;; link value INTD
#
9106 dw
0xdef8 ;; IRQ bitmap INTD
#
9107 db
1 ;; physical
slot (0 = embedded
)
9109 ;; third slot entry
: 2nd PCI slot
9110 db
0 ;; pci bus number
9111 db
0x18 ;; pci device
number (bit
7-3)
9112 db
0x62 ;; link value INTA
#
9113 dw
0xdef8 ;; IRQ bitmap INTA
#
9114 db
0x63 ;; link value INTB
#
9115 dw
0xdef8 ;; IRQ bitmap INTB
#
9116 db
0x60 ;; link value INTC
#
9117 dw
0xdef8 ;; IRQ bitmap INTC
#
9118 db
0x61 ;; link value INTD
#
9119 dw
0xdef8 ;; IRQ bitmap INTD
#
9120 db
2 ;; physical
slot (0 = embedded
)
9122 ;; 4th slot entry
: 3rd PCI slot
9123 db
0 ;; pci bus number
9124 db
0x20 ;; pci device
number (bit
7-3)
9125 db
0x63 ;; link value INTA
#
9126 dw
0xdef8 ;; IRQ bitmap INTA
#
9127 db
0x60 ;; link value INTB
#
9128 dw
0xdef8 ;; IRQ bitmap INTB
#
9129 db
0x61 ;; link value INTC
#
9130 dw
0xdef8 ;; IRQ bitmap INTC
#
9131 db
0x62 ;; link value INTD
#
9132 dw
0xdef8 ;; IRQ bitmap INTD
#
9133 db
3 ;; physical
slot (0 = embedded
)
9135 ;; 5th slot entry
: 4rd PCI slot
9136 db
0 ;; pci bus number
9137 db
0x28 ;; pci device
number (bit
7-3)
9138 db
0x60 ;; link value INTA
#
9139 dw
0xdef8 ;; IRQ bitmap INTA
#
9140 db
0x61 ;; link value INTB
#
9141 dw
0xdef8 ;; IRQ bitmap INTB
#
9142 db
0x62 ;; link value INTC
#
9143 dw
0xdef8 ;; IRQ bitmap INTC
#
9144 db
0x63 ;; link value INTD
#
9145 dw
0xdef8 ;; IRQ bitmap INTD
#
9146 db
4 ;; physical
slot (0 = embedded
)
9148 ;; 6th slot entry
: 5rd PCI slot
9149 db
0 ;; pci bus number
9150 db
0x30 ;; pci device
number (bit
7-3)
9151 db
0x61 ;; link value INTA
#
9152 dw
0xdef8 ;; IRQ bitmap INTA
#
9153 db
0x62 ;; link value INTB
#
9154 dw
0xdef8 ;; IRQ bitmap INTB
#
9155 db
0x63 ;; link value INTC
#
9156 dw
0xdef8 ;; IRQ bitmap INTC
#
9157 db
0x60 ;; link value INTD
#
9158 dw
0xdef8 ;; IRQ bitmap INTD
#
9159 db
5 ;; physical
slot (0 = embedded
)
9165 pcibios_init_sel_reg
:
9177 pcibios_init_set_elcr
:
9201 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9206 mov si
, #pci_routing_table_structure
9210 call pcibios_init_sel_reg
9213 cmp eax
, [si
+12] ;; check irq router
9216 call pcibios_init_sel_reg
9217 push bx
;; save irq router bus
+ devfunc
9220 out dx
, ax
;; reset PIRQ route control
9228 add si
, #0x20 ;; set pointer to 1st entry
9230 mov ax
, #pci_irq_list
9239 call pcibios_init_sel_reg
9243 jnz pci_test_int_pin
9249 call pcibios_init_sel_reg
9254 dec al
;; determine pirq reg
9263 call pcibios_init_sel_reg
9270 mov bx
, [bp
-2] ;; pci irq list pointer
9275 call pcibios_init_set_elcr
9279 add bl
, [bp
-3] ;; pci function number
9281 call pcibios_init_sel_reg
9291 mov byte ptr
[bp
-3], #0x00
9299 #endif // BX_PCIBIOS
9301 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9306 and al
, #0xdf ; clear input mode
9316 mov
[bx
+0x408], dx
; Parallel I
/O address
9318 mov
[bx
+0x478], cl
; Parallel printer timeout
9323 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9342 mov
[bx
+0x400], dx
; Serial I
/O address
9344 mov
[bx
+0x47c], cl
; Serial timeout
9371 ;; Scan
for existence of valid expansion ROMS
.
9372 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9373 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9374 ;; System ROM
: only
0xE0000
9380 ;; 2 ROM length in
512-byte blocks
9381 ;; 3 ROM initialization entry
point (FAR CALL
)
9386 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9387 cmp
[0], #0xAA55 ;; look for signature
9388 jne rom_scan_increment
9390 jnz rom_scan_increment
9391 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9393 ;; We want our increment in
512-byte quantities
, rounded to
9394 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9396 jz block_count_rounded
9397 and al
, #0xfc ;; needs rounding up
9399 block_count_rounded
:
9401 xor bx
, bx
;; Restore DS back to
0000:
9404 ;; Push addr of ROM entry point
9406 push
#0x0003 ;; Push offset
9407 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9408 db
0xff ;; call_far ss
:[bp
+0]
9411 cli
;; In
case expansion ROM BIOS turns IF on
9412 add sp
, #2 ;; Pop offset value
9413 pop cx
;; Pop seg
value (restore CX
)
9414 pop ax
;; Restore AX
9416 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
9417 ;; because the segment selector is shifted left
4 bits
.
9422 xor ax
, ax
;; Restore DS back to
0000:
9426 ;; for 'C' strings
and other data
, insert them here with
9427 ;; a the following hack
:
9428 ;; DATA_SEG_DEFS_HERE
9434 .org
0xe05b ; POST Entry Point
9439 ;; first reset the DMA controllers
9443 ;; then initialize the DMA controllers
9445 out
0xD6, al
; cascade mode of channel
4 enabled
9447 out
0xD4, al
; unmask channel
4
9449 ;; Examine CMOS shutdown status
.
9457 ;; Reset CMOS shutdown status
.
9459 out
0x70, AL
; select CMOS
register Fh
9461 out
0x71, AL
; set shutdown action to normal
9463 ;; Examine CMOS shutdown status
.
9466 ;; 0x00, 0x09, 0x0D+ = normal startup
9474 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
9478 ;; Examine CMOS shutdown status
.
9479 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
9481 call _shutdown_status_panic
9487 ; 0xb0, 0x20, /* mov al, #0x20 */
9488 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9498 ; case 0: normal startup
9507 ;; zero out BIOS data
area (40:00..40:ff
)
9509 mov cx
, #0x0080 ;; 128 words
9515 call _log_bios_start
9517 ;; set all interrupts to
default handler
9518 mov bx
, #0x0000 ;; offset index
9519 mov cx
, #0x0100 ;; counter (256 interrupts)
9520 mov ax
, #dummy_iret_handler
9530 loop post_default_ints
9532 ;; set vector
0x79 to zero
9533 ;; this is used by
'gardian angel' protection system
9534 SET_INT_VECTOR(0x79, #0, #0)
9536 ;; base memory in K
40:13 (word
)
9537 mov ax
, #BASE_MEM_IN_K
9541 ;; Manufacturing Test
40:12
9544 ;; Warm Boot Flag
0040:0072
9545 ;; value of
1234h
= skip memory checks
9549 ;; Printer Services vector
9550 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9552 ;; Bootstrap failure vector
9553 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9555 ;; Bootstrap Loader vector
9556 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9558 ;; User Timer Tick vector
9559 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9561 ;; Memory Size Check vector
9562 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9564 ;; Equipment Configuration Check vector
9565 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9568 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9574 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9575 ;; int 1C already points at
dummy_iret_handler (above
)
9576 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
9578 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
9583 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9584 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9588 mov
0x0417, al
/* keyboard shift flags, set 1 */
9589 mov
0x0418, al
/* keyboard shift flags, set 2 */
9590 mov
0x0419, al
/* keyboard alt-numpad work area */
9591 mov
0x0471, al
/* keyboard ctrl-break flag */
9592 mov
0x0497, al
/* keyboard status flags 4 */
9594 mov
0x0496, al
/* keyboard status flags 3 */
9597 /* keyboard head of buffer pointer */
9601 /* keyboard end of buffer pointer */
9604 /* keyboard pointer to start of buffer */
9608 /* keyboard pointer to end of buffer */
9612 /* init the keyboard */
9615 ;; mov CMOS Equipment Byte to BDA Equipment Word
9624 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9628 mov cl
, #0x14 ; timeout value
9629 mov dx
, #0x378 ; Parallel I/O address, port 1
9631 mov dx
, #0x278 ; Parallel I/O address, port 2
9634 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
9636 or ax
, bx
; set number of parallel ports
9640 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9641 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9643 mov cl
, #0x0a ; timeout value
9644 mov dx
, #0x03f8 ; Serial I/O address, port 1
9646 mov dx
, #0x02f8 ; Serial I/O address, port 2
9648 mov dx
, #0x03e8 ; Serial I/O address, port 3
9650 mov dx
, #0x02e8 ; Serial I/O address, port 4
9653 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
9655 or ax
, bx
; set number of serial port
9659 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9660 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9661 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9662 ;; BIOS DATA AREA
0x4CE ???
9663 call timer_tick_post
9666 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9668 ;; IRQ13 (FPU exception
) setup
9669 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9672 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9675 mov al
, #0x11 ; send initialisation commands
9690 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
9691 #if BX_USE_PS2_MOUSE
9696 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
9702 call _print_bios_banner
9707 call floppy_drive_post
9714 call hard_drive_post
9717 ;; ATA
/ATAPI driver setup
9722 #else // BX_USE_ATADRV
9727 call hard_drive_post
9729 #endif // BX_USE_ATADRV
9731 #if BX_ELTORITO_BOOT
9733 ;; eltorito floppy
/harddisk emulation from cd
9737 #endif // BX_ELTORITO_BOOT
9740 //JMP_EP(0x0064) ; INT 19h location
9743 .org
0xe2c3 ; NMI Handler Entry Point
9745 ;; FIXME the NMI handler should
not panic
9746 ;; but iret when called from
int75 (fpu exception
)
9747 call _nmi_handler_msg
9751 out
0xf0, al
// clear irq13
9752 call eoi_both_pics
// clear interrupt
9753 int 2 // legacy nmi call
9756 ;-------------------------------------------
9757 ;- INT
13h Fixed Disk Services Entry Point
-
9758 ;-------------------------------------------
9759 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
9761 //JMPL(int13_relocated)
9764 .org
0xe401 ; Fixed Disk Parameter Table
9769 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
9773 ;-------------------------------------------
9774 ;- System BIOS Configuration Data Table
9775 ;-------------------------------------------
9776 .org BIOS_CONFIG_TABLE
9777 db
0x08 ; Table
size (bytes
) -Lo
9778 db
0x00 ; Table
size (bytes
) -Hi
9783 ; b7
: 1=DMA channel
3 used by hard disk
9784 ; b6
: 1=2 interrupt controllers present
9786 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
9787 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
9788 ; b2
: 1=extended BIOS data area used
9789 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
9790 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
9794 (BX_CALL_INT15_4F
<< 4) | \
9796 (BX_USE_EBDA
<< 2) | \
9800 ; b7
: 1=32-bit DMA supported
9801 ; b6
: 1=int16h
, function
9 supported
9802 ; b5
: 1=int15h
/C6h (get POS data
) supported
9803 ; b4
: 1=int15h
/C7h (get mem map info
) supported
9804 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
9805 ; b2
: 1=non
-8042 kb controller
9806 ; b1
: 1=data streaming supported
9820 ; b4
: POST supports ROM
-to
-RAM enable
/disable
9821 ; b3
: SCSI on system board
9822 ; b2
: info panel installed
9823 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
9824 ; b0
: SCSI supported in IML
9828 ; b6
: EEPROM present
9829 ; b5
-3: ABIOS
presence (011 = not supported
)
9831 ; b1
: memory split above
16Mb supported
9832 ; b0
: POSTEXT directly supported by POST
9834 ; Feature byte
5 (IBM
)
9835 ; b1
: enhanced mouse
9841 .org
0xe729 ; Baud Rate Generator Table
9846 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
9852 call _int14_function
9858 ;----------------------------------------
9859 ;- INT
16h Keyboard Service Entry Point
-
9860 ;----------------------------------------
9876 call _int16_function
9886 and BYTE
[bp
+ 0x06], #0xbf
9894 or BYTE
[bp
+ 0x06], #0x40
9910 /* no key yet, call int 15h, function AX=9002 */
9912 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9913 0xcd, 0x15, /* int 15h */
9915 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
9917 jmp int16_wait_for_key
9922 call _int16_function
9927 /* notify int16 complete w/ int 15h, function AX=9102 */
9929 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
9930 0xcd, 0x15, /* int 15h */
9937 ;-------------------------------------------------
9938 ;- INT09h
: Keyboard Hardware Service Entry Point
-
9939 ;-------------------------------------------------
9945 mov al
, #0xAD ;;disable keyboard
9954 in al
, #0x60 ;;read key from keyboard controller
9955 //test al, #0x80 ;;look for key release
9956 //jnz int09_process_key ;; dont pass releases to intercept?
9958 ;; check
for extended key
9960 jne int09_call_int15_4f
9965 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
9967 mov BYTE
[0x496], al
9970 in al
, #0x60 ;;read another key from keyboard controller
9974 int09_call_int15_4f
:
9977 #ifdef BX_CALL_INT15_4F
9978 mov ah
, #0x4f ;; allow for keyboard intercept
9985 //int09_process_key:
9988 call _int09_function
9997 mov al
, #0xAE ;;enable keyboard
10005 ;----------------------------------------
10006 ;- INT
13h Diskette Service Entry Point
-
10007 ;----------------------------------------
10010 jmp int13_noeltorito
10012 ;---------------------------------------------
10013 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10014 ;---------------------------------------------
10015 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10025 mov al
, #0x08 ; sense interrupt status
10043 mov ax
, #0x0000 ;; segment 0000
10045 call eoi_master_pic
10047 or al
, #0x80 ;; diskette interrupt has occurred
10055 .org
0xefc7 ; Diskette Controller Parameter Table
10056 diskette_param_table
:
10057 ;; Since no provisions are made
for multiple drive types
, most
10058 ;; values in
this table are ignored
. I set parameters
for 1.44M
10061 db
0x02 ;; head load time
0000001, DMA used
10073 ;----------------------------------------
10074 ;- INT17h
: Printer Service Entry Point
-
10075 ;----------------------------------------
10082 call _int17_function
10087 diskette_param_table2
:
10088 ;; New diskette parameter table adding
3 parameters from IBM
10089 ;; Since no provisions are made
for multiple drive types
, most
10090 ;; values in
this table are ignored
. I set parameters
for 1.44M
10093 db
0x02 ;; head load time
0000001, DMA used
10103 db
79 ;; maximum track
10104 db
0 ;; data transfer rate
10105 db
4 ;; drive type in cmos
10107 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10114 .org
0xf065 ; INT
10h Video Support Service Entry Point
10116 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10119 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10124 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10125 ; ??? different
for Pentium (machine check
)?
10137 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10149 .org
0xf859 ; INT
15h System Services Entry Point
10163 #if BX_USE_PS2_MOUSE
10165 je int15_handler_mouse
10167 call _int15_function
10168 int15_handler_mouse_ret
:
10170 int15_handler32_ret
:
10180 #if BX_USE_PS2_MOUSE
10181 int15_handler_mouse
:
10182 call _int15_function_mouse
10183 jmp int15_handler_mouse_ret
10188 call _int15_function32
10190 jmp int15_handler32_ret
10192 ;; Protected mode IDT descriptor
10194 ;; I just make the limit
0, so the machine will shutdown
10195 ;; if an exception occurs during
protected mode memory
10198 ;; Set base to f0000 to correspond to beginning of BIOS
,
10199 ;; in
case I actually define an IDT later
10203 dw
0x0000 ;; limit
15:00
10204 dw
0x0000 ;; base
15:00
10205 db
0x0f ;; base
23:16
10207 ;; Real mode IDT descriptor
10209 ;; Set to typical real
-mode values
.
10214 dw
0x03ff ;; limit
15:00
10215 dw
0x0000 ;; base
15:00
10216 db
0x00 ;; base
23:16
10222 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10235 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10236 mov ds
, ax
; on
16bit
protected mode
.
10237 jmp int1a_callfunction
10244 int1a_callfunction
:
10245 call _int1a_function
10251 ;; int70h
: IRQ8
- CMOS RTC
10258 call _int70_function
10266 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10274 ;; time to turn off
drive(s
)?
10277 jz int08_floppy_off
10280 jnz int08_floppy_off
10281 ;; turn
motor(s
) off
10290 mov eax
, 0x046c ;; get ticks dword
10293 ;; compare eax to one days worth of timer ticks at
18.2 hz
10294 cmp eax
, #0x001800B0
10295 jb int08_store_ticks
10296 ;; there has been a midnight rollover at
this point
10297 xor eax
, eax
;; zero out counter
10298 inc BYTE
0x0470 ;; increment rollover flag
10301 mov
0x046c, eax
;; store
new ticks dword
10302 ;; chain to user timer tick INT
#0x1c
10304 //;; call_ep [ds:loc]
10305 //CALL_EP( 0x1c << 2 )
10308 call eoi_master_pic
10313 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10317 .ascii BIOS_COPYRIGHT_STRING
10319 ;------------------------------------------------
10320 ;- IRET Instruction
for Dummy Interrupt Handler
-
10321 ;------------------------------------------------
10322 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10323 dummy_iret_handler
:
10326 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10330 .org
0xfff0 ; Power
-up Entry Point
10333 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10334 .ascii BIOS_BUILD_DATE
10336 .org
0xfffe ; System Model ID
10340 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10343 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10344 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10345 * This font is public domain
10347 static Bit8u vgafont8
[128*8]=
10349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10350 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10351 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10352 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10353 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10354 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10355 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10356 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10357 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10358 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10359 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10360 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10361 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10362 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10363 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10364 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10365 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10366 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10367 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10368 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10369 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10370 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10371 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10372 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10373 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10374 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10375 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10376 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10377 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10378 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10379 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10380 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10382 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10383 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10384 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10385 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10386 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10387 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10388 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10389 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10390 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10391 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10392 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10393 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10394 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10395 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10396 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10397 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10398 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10399 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10400 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10401 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10402 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10403 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10404 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10405 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10406 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10407 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10408 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10409 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10410 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10411 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10412 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10413 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10414 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10415 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10416 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10417 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10418 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10419 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10420 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10421 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10422 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10423 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10424 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10425 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10426 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10427 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10428 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10429 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10430 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10431 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10432 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10433 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10434 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10435 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10436 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10437 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10438 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10439 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10440 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10441 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10442 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10443 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10444 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10445 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10446 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10447 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10448 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10449 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10450 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10451 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10452 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10453 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10454 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10455 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10456 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10457 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10458 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10459 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10460 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10461 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10462 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10463 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10464 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10465 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10466 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10467 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10468 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10469 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10470 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10471 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10472 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10473 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10474 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10475 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10476 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10481 // bcc-generated data will be placed here
10483 // For documentation of this config structure, look on developer.intel.com and
10484 // search for multiprocessor specification. Note that when you change anything
10485 // you must update the checksum (a pain!). It would be better to construct this
10486 // with C structures, or at least fill in the checksum automatically.
10488 // Maybe this structs could be moved elsewhere than d000
10490 #if (BX_SMP_PROCESSORS==1)
10491 // no structure necessary.
10492 #elif (BX_SMP_PROCESSORS==2)
10493 // define the Intel MP Configuration Structure for 2 processors at
10494 // APIC ID 0,1. I/O APIC at ID=2.
10497 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10498 dw (mp_config_end
-mp_config_table
) ;; table length
10500 db
0x65 ;; checksum
10501 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10502 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10503 db
0x20, 0x20, 0x20, 0x20
10504 db
0x20, 0x20, 0x20, 0x20
10505 dw
0,0 ;; oem table ptr
10506 dw
0 ;; oem table size
10507 dw
20 ;; entry count
10508 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10509 dw
0 ;; extended table length
10510 db
0 ;; extended table checksum
10513 db
0 ;; entry type
=processor
10514 db
0 ;; local APIC id
10515 db
0x11 ;; local APIC version number
10516 db
3 ;; cpu flags
: enabled
, bootstrap processor
10517 db
0,6,0,0 ;; cpu signature
10518 dw
0x201,0 ;; feature flags
10522 db
0 ;; entry type
=processor
10523 db
1 ;; local APIC id
10524 db
0x11 ;; local APIC version number
10525 db
1 ;; cpu flags
: enabled
10526 db
0,6,0,0 ;; cpu signature
10527 dw
0x201,0 ;; feature flags
10531 db
1 ;; entry type
=bus
10533 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10535 db
2 ;; entry type
=I
/O APIC
10536 db
2 ;; apic id
=2. linux will set
.
10537 db
0x11 ;; I
/O APIC version number
10538 db
1 ;; flags
=1=enabled
10539 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10541 db
3 ;; entry type
=I
/O interrupt
10542 db
0 ;; interrupt type
=vectored interrupt
10543 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10544 db
0 ;; source bus ID is ISA
10545 db
0 ;; source bus IRQ
10546 db
2 ;; destination I
/O APIC ID
10547 db
0 ;; destination I
/O APIC interrrupt in
10548 ;; repeat pattern
for interrupts
0-15
10558 db
3,0,0,0,0,10,2,10
10559 db
3,0,0,0,0,11,2,11
10560 db
3,0,0,0,0,12,2,12
10561 db
3,0,0,0,0,13,2,13
10562 db
3,0,0,0,0,14,2,14
10563 db
3,0,0,0,0,15,2,15
10564 #elif (BX_SMP_PROCESSORS==4)
10565 // define the Intel MP Configuration Structure for 4 processors at
10566 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10569 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10570 dw (mp_config_end
-mp_config_table
) ;; table length
10572 db
0xdd ;; checksum
10573 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10574 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10575 db
0x20, 0x20, 0x20, 0x20
10576 db
0x20, 0x20, 0x20, 0x20
10577 dw
0,0 ;; oem table ptr
10578 dw
0 ;; oem table size
10579 dw
22 ;; entry count
10580 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10581 dw
0 ;; extended table length
10582 db
0 ;; extended table checksum
10585 db
0 ;; entry type
=processor
10586 db
0 ;; local APIC id
10587 db
0x11 ;; local APIC version number
10588 db
3 ;; cpu flags
: enabled
, bootstrap processor
10589 db
0,6,0,0 ;; cpu signature
10590 dw
0x201,0 ;; feature flags
10594 db
0 ;; entry type
=processor
10595 db
1 ;; local APIC id
10596 db
0x11 ;; local APIC version number
10597 db
1 ;; cpu flags
: enabled
10598 db
0,6,0,0 ;; cpu signature
10599 dw
0x201,0 ;; feature flags
10603 db
0 ;; entry type
=processor
10604 db
2 ;; local APIC id
10605 db
0x11 ;; local APIC version number
10606 db
1 ;; cpu flags
: enabled
10607 db
0,6,0,0 ;; cpu signature
10608 dw
0x201,0 ;; feature flags
10612 db
0 ;; entry type
=processor
10613 db
3 ;; local APIC id
10614 db
0x11 ;; local APIC version number
10615 db
1 ;; cpu flags
: enabled
10616 db
0,6,0,0 ;; cpu signature
10617 dw
0x201,0 ;; feature flags
10621 db
1 ;; entry type
=bus
10623 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10625 db
2 ;; entry type
=I
/O APIC
10626 db
4 ;; apic id
=4. linux will set
.
10627 db
0x11 ;; I
/O APIC version number
10628 db
1 ;; flags
=1=enabled
10629 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10631 db
3 ;; entry type
=I
/O interrupt
10632 db
0 ;; interrupt type
=vectored interrupt
10633 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10634 db
0 ;; source bus ID is ISA
10635 db
0 ;; source bus IRQ
10636 db
4 ;; destination I
/O APIC ID
10637 db
0 ;; destination I
/O APIC interrrupt in
10638 ;; repeat pattern
for interrupts
0-15
10648 db
3,0,0,0,0,10,4,10
10649 db
3,0,0,0,0,11,4,11
10650 db
3,0,0,0,0,12,4,12
10651 db
3,0,0,0,0,13,4,13
10652 db
3,0,0,0,0,14,4,14
10653 db
3,0,0,0,0,15,4,15
10654 #elif (BX_SMP_PROCESSORS==8)
10655 // define the Intel MP Configuration Structure for 8 processors at
10656 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10659 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10660 dw (mp_config_end
-mp_config_table
) ;; table length
10662 db
0xc3 ;; checksum
10663 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10664 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10665 db
0x20, 0x20, 0x20, 0x20
10666 db
0x20, 0x20, 0x20, 0x20
10667 dw
0,0 ;; oem table ptr
10668 dw
0 ;; oem table size
10669 dw
26 ;; entry count
10670 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10671 dw
0 ;; extended table length
10672 db
0 ;; extended table checksum
10675 db
0 ;; entry type
=processor
10676 db
0 ;; local APIC id
10677 db
0x11 ;; local APIC version number
10678 db
3 ;; cpu flags
: enabled
, bootstrap processor
10679 db
0,6,0,0 ;; cpu signature
10680 dw
0x201,0 ;; feature flags
10684 db
0 ;; entry type
=processor
10685 db
1 ;; local APIC id
10686 db
0x11 ;; local APIC version number
10687 db
1 ;; cpu flags
: enabled
10688 db
0,6,0,0 ;; cpu signature
10689 dw
0x201,0 ;; feature flags
10693 db
0 ;; entry type
=processor
10694 db
2 ;; local APIC id
10695 db
0x11 ;; local APIC version number
10696 db
1 ;; cpu flags
: enabled
10697 db
0,6,0,0 ;; cpu signature
10698 dw
0x201,0 ;; feature flags
10702 db
0 ;; entry type
=processor
10703 db
3 ;; local APIC id
10704 db
0x11 ;; local APIC version number
10705 db
1 ;; cpu flags
: enabled
10706 db
0,6,0,0 ;; cpu signature
10707 dw
0x201,0 ;; feature flags
10711 db
0 ;; entry type
=processor
10712 db
4 ;; local APIC id
10713 db
0x11 ;; local APIC version number
10714 db
1 ;; cpu flags
: enabled
10715 db
0,6,0,0 ;; cpu signature
10716 dw
0x201,0 ;; feature flags
10720 db
0 ;; entry type
=processor
10721 db
5 ;; local APIC id
10722 db
0x11 ;; local APIC version number
10723 db
1 ;; cpu flags
: enabled
10724 db
0,6,0,0 ;; cpu signature
10725 dw
0x201,0 ;; feature flags
10729 db
0 ;; entry type
=processor
10730 db
6 ;; local APIC id
10731 db
0x11 ;; local APIC version number
10732 db
1 ;; cpu flags
: enabled
10733 db
0,6,0,0 ;; cpu signature
10734 dw
0x201,0 ;; feature flags
10738 db
0 ;; entry type
=processor
10739 db
7 ;; local APIC id
10740 db
0x11 ;; local APIC version number
10741 db
1 ;; cpu flags
: enabled
10742 db
0,6,0,0 ;; cpu signature
10743 dw
0x201,0 ;; feature flags
10747 db
1 ;; entry type
=bus
10749 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10751 db
2 ;; entry type
=I
/O APIC
10753 db
0x11 ;; I
/O APIC version number
10754 db
1 ;; flags
=1=enabled
10755 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10757 db
3 ;; entry type
=I
/O interrupt
10758 db
0 ;; interrupt type
=vectored interrupt
10759 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10760 db
0 ;; source bus ID is ISA
10761 db
0 ;; source bus IRQ
10762 db
8 ;; destination I
/O APIC ID
10763 db
0 ;; destination I
/O APIC interrrupt in
10764 ;; repeat pattern
for interrupts
0-15
10774 db
3,0,0,0,0,10,8,10
10775 db
3,0,0,0,0,11,8,11
10776 db
3,0,0,0,0,12,8,12
10777 db
3,0,0,0,0,13,8,13
10778 db
3,0,0,0,0,14,8,14
10779 db
3,0,0,0,0,15,8,15
10781 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
10782 #endif // if (BX_SMP_PROCESSORS==...)
10784 mp_config_end
: // this label used to find length of mp structure
10787 #if (BX_SMP_PROCESSORS>1)
10789 mp_floating_pointer_structure
:
10790 db
0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
10791 dw mp_config_table
, 0xf ;; pointer to MP configuration table
10792 db
1 ;; length of
this struct in
16-bit byte chunks
10793 db
4 ;; MP spec revision
10794 db
0xc1 ;; checksum
10795 db
0 ;; MP feature byte
1. value
0 means look at the config table
10796 db
0,0,0,0 ;; MP feature bytes
2-5.