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 ");
1832 printf("%s %s\n", bios_cvs_version_string
, bios_date_string
);
1833 printf("Options: ");
1834 #if BX_SMP_PROCESSORS > 1
1835 printf("smp (%d cpus) ", BX_SMP_PROCESSORS
);
1846 #ifdef BX_ELTORITO_BOOT
1852 //--------------------------------------------------------------------------
1853 // print_boot_device
1854 // displays the boot device
1855 //--------------------------------------------------------------------------
1857 static char drivetypes
[][10]={"Floppy","Hard Disk","CD-Rom"};
1860 print_boot_device(cdboot
, drive
)
1861 Bit8u cdboot
; Bit16u drive
;
1865 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1866 // drive contains real/emulated boot drive
1868 if(cdboot
)i
=2; // CD-Rom
1869 else if((drive
&0x0080)==0x00)i
=0; // Floppy
1870 else if((drive
&0x0080)==0x80)i
=1; // Hard drive
1873 printf("Booting from %s...\n",drivetypes
[i
]);
1876 //--------------------------------------------------------------------------
1877 // print_boot_failure
1878 // displays the reason why boot failed
1879 //--------------------------------------------------------------------------
1881 print_boot_failure(cdboot
, drive
, reason
, lastdrive
)
1882 Bit8u cdboot
; Bit8u drive
; Bit8u lastdrive
;
1884 Bit16u drivenum
= drive
&0x7f;
1886 // cdboot: 1 if boot from cd, 0 otherwise
1887 // drive : drive number
1888 // reason: 0 signature check failed, 1 read error
1889 // lastdrive: 1 boot drive is the last one in boot sequence
1892 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s failed\n",drivetypes
[2]);
1893 else if (drive
& 0x80)
1894 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[1],drivenum
);
1896 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[0],drivenum
);
1900 BX_PANIC("Not a bootable disk\n");
1902 BX_PANIC("Could not read the boot disk\n");
1906 //--------------------------------------------------------------------------
1907 // print_cdromboot_failure
1908 // displays the reason why boot failed
1909 //--------------------------------------------------------------------------
1911 print_cdromboot_failure( code
)
1914 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1922 BX_PANIC("NMI Handler called\n");
1928 BX_PANIC("INT18: BOOT FAILURE\n");
1935 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
1937 BX_INFO("%s\n", bios_version_string
);
1946 // Use PS2 System Control port A to set A20 enable
1948 // get current setting first
1951 // change A20 status
1953 outb(0x92, oldval
| 0x02);
1955 outb(0x92, oldval
& 0xfd);
1957 return((oldval
& 0x02) != 0);
1974 // ---------------------------------------------------------------------------
1975 // Start of ATA/ATAPI Driver
1976 // ---------------------------------------------------------------------------
1978 // Global defines -- ATA register and register bits.
1979 // command block & control block regs
1980 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1981 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1982 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1983 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1984 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1985 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1986 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1987 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1988 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1989 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1990 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1991 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1992 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1994 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1995 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1996 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1997 #define ATA_CB_ER_MC 0x20 // ATA media change
1998 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1999 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2000 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2001 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2002 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2004 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2005 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2006 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2007 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2008 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2010 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2011 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2012 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2013 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2014 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2016 // bits 7-4 of the device/head (CB_DH) reg
2017 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2018 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2020 // status reg (CB_STAT and CB_ASTAT) bits
2021 #define ATA_CB_STAT_BSY 0x80 // busy
2022 #define ATA_CB_STAT_RDY 0x40 // ready
2023 #define ATA_CB_STAT_DF 0x20 // device fault
2024 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2025 #define ATA_CB_STAT_SKC 0x10 // seek complete
2026 #define ATA_CB_STAT_SERV 0x10 // service
2027 #define ATA_CB_STAT_DRQ 0x08 // data request
2028 #define ATA_CB_STAT_CORR 0x04 // corrected
2029 #define ATA_CB_STAT_IDX 0x02 // index
2030 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2031 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2033 // device control reg (CB_DC) bits
2034 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2035 #define ATA_CB_DC_SRST 0x04 // soft reset
2036 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2038 // Most mandtory and optional ATA commands (from ATA-3),
2039 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2040 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2041 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2042 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2043 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2044 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2045 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2046 #define ATA_CMD_DEVICE_RESET 0x08
2047 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2048 #define ATA_CMD_FLUSH_CACHE 0xE7
2049 #define ATA_CMD_FORMAT_TRACK 0x50
2050 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2051 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2052 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2053 #define ATA_CMD_IDLE1 0xE3
2054 #define ATA_CMD_IDLE2 0x97
2055 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2056 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2057 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2058 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2059 #define ATA_CMD_NOP 0x00
2060 #define ATA_CMD_PACKET 0xA0
2061 #define ATA_CMD_READ_BUFFER 0xE4
2062 #define ATA_CMD_READ_DMA 0xC8
2063 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2064 #define ATA_CMD_READ_MULTIPLE 0xC4
2065 #define ATA_CMD_READ_SECTORS 0x20
2066 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2067 #define ATA_CMD_RECALIBRATE 0x10
2068 #define ATA_CMD_SEEK 0x70
2069 #define ATA_CMD_SET_FEATURES 0xEF
2070 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2071 #define ATA_CMD_SLEEP1 0xE6
2072 #define ATA_CMD_SLEEP2 0x99
2073 #define ATA_CMD_STANDBY1 0xE2
2074 #define ATA_CMD_STANDBY2 0x96
2075 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2076 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2077 #define ATA_CMD_WRITE_BUFFER 0xE8
2078 #define ATA_CMD_WRITE_DMA 0xCA
2079 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2080 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2081 #define ATA_CMD_WRITE_SECTORS 0x30
2082 #define ATA_CMD_WRITE_VERIFY 0x3C
2084 #define ATA_IFACE_NONE 0x00
2085 #define ATA_IFACE_ISA 0x00
2086 #define ATA_IFACE_PCI 0x01
2088 #define ATA_TYPE_NONE 0x00
2089 #define ATA_TYPE_UNKNOWN 0x01
2090 #define ATA_TYPE_ATA 0x02
2091 #define ATA_TYPE_ATAPI 0x03
2093 #define ATA_DEVICE_NONE 0x00
2094 #define ATA_DEVICE_HD 0xFF
2095 #define ATA_DEVICE_CDROM 0x05
2097 #define ATA_MODE_NONE 0x00
2098 #define ATA_MODE_PIO16 0x00
2099 #define ATA_MODE_PIO32 0x01
2100 #define ATA_MODE_ISADMA 0x02
2101 #define ATA_MODE_PCIDMA 0x03
2102 #define ATA_MODE_USEIRQ 0x10
2104 #define ATA_TRANSLATION_NONE 0
2105 #define ATA_TRANSLATION_LBA 1
2106 #define ATA_TRANSLATION_LARGE 2
2107 #define ATA_TRANSLATION_RECHS 3
2109 #define ATA_DATA_NO 0x00
2110 #define ATA_DATA_IN 0x01
2111 #define ATA_DATA_OUT 0x02
2113 // ---------------------------------------------------------------------------
2114 // ATA/ATAPI driver : initialization
2115 // ---------------------------------------------------------------------------
2118 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2119 Bit8u channel
, device
;
2121 // Channels info init.
2122 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2123 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2124 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2125 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2126 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2129 // Devices info init.
2130 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2131 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2132 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2133 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2134 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2135 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2136 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2137 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2138 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2139 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2140 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2141 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2142 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2143 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2145 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2148 // hdidmap and cdidmap init.
2149 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2150 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2151 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2154 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2155 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2158 // ---------------------------------------------------------------------------
2159 // ATA/ATAPI driver : device detection
2160 // ---------------------------------------------------------------------------
2164 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2165 Bit8u hdcount
, cdcount
, device
, type
;
2166 Bit8u buffer
[0x0200];
2168 #if BX_MAX_ATA_INTERFACES > 0
2169 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2170 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2171 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2172 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2174 #if BX_MAX_ATA_INTERFACES > 1
2175 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2176 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2177 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2178 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2180 #if BX_MAX_ATA_INTERFACES > 2
2181 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2182 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2183 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2184 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2186 #if BX_MAX_ATA_INTERFACES > 3
2187 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2188 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2189 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2190 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2192 #if BX_MAX_ATA_INTERFACES > 4
2193 #error Please fill the ATA interface informations
2199 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2200 Bit16u iobase1
, iobase2
;
2201 Bit8u channel
, slave
, shift
;
2202 Bit8u sc
, sn
, cl
, ch
, st
;
2204 channel
= device
/ 2;
2207 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2208 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2210 // Disable interrupts
2211 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2214 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2215 outb(iobase1
+ATA_CB_SC
, 0x55);
2216 outb(iobase1
+ATA_CB_SN
, 0xaa);
2217 outb(iobase1
+ATA_CB_SC
, 0xaa);
2218 outb(iobase1
+ATA_CB_SN
, 0x55);
2219 outb(iobase1
+ATA_CB_SC
, 0x55);
2220 outb(iobase1
+ATA_CB_SN
, 0xaa);
2222 // If we found something
2223 sc
= inb(iobase1
+ATA_CB_SC
);
2224 sn
= inb(iobase1
+ATA_CB_SN
);
2226 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2227 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2229 // reset the channel
2232 // check for ATA or ATAPI
2233 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2234 sc
= inb(iobase1
+ATA_CB_SC
);
2235 sn
= inb(iobase1
+ATA_CB_SN
);
2236 if ( (sc
==0x01) && (sn
==0x01) ) {
2237 cl
= inb(iobase1
+ATA_CB_CL
);
2238 ch
= inb(iobase1
+ATA_CB_CH
);
2239 st
= inb(iobase1
+ATA_CB_STAT
);
2241 if ( (cl
==0x14) && (ch
==0xeb) ) {
2242 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2244 else if ( (cl
==0x00) && (ch
==0x00) && (st
!=0x00) ) {
2245 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2250 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2252 // Now we send a IDENTIFY command to ATA device
2253 if(type
== ATA_TYPE_ATA
) {
2255 Bit16u cylinders
, heads
, spt
, blksize
;
2256 Bit8u translation
, removable
, mode
;
2258 //Temporary values to do the transfer
2259 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2260 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2262 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2263 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2265 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2266 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2267 blksize
= read_word(get_SS(),buffer
+10);
2269 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2270 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2271 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2273 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2275 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2276 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2277 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2278 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2279 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2280 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2281 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2282 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2283 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2285 translation
= inb_cmos(0x39 + channel
/2);
2286 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2287 translation
&= 0x03;
2289 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2291 switch (translation
) {
2292 case ATA_TRANSLATION_NONE
:
2295 case ATA_TRANSLATION_LBA
:
2298 case ATA_TRANSLATION_LARGE
:
2301 case ATA_TRANSLATION_RECHS
:
2305 switch (translation
) {
2306 case ATA_TRANSLATION_NONE
:
2308 case ATA_TRANSLATION_LBA
:
2311 heads
= sectors
/ 1024;
2312 if (heads
>128) heads
= 255;
2313 else if (heads
>64) heads
= 128;
2314 else if (heads
>32) heads
= 64;
2315 else if (heads
>16) heads
= 32;
2317 cylinders
= sectors
/ heads
;
2319 case ATA_TRANSLATION_RECHS
:
2320 // Take care not to overflow
2322 if(cylinders
>61439) cylinders
=61439;
2324 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2326 // then go through the large bitshift process
2327 case ATA_TRANSLATION_LARGE
:
2328 while(cylinders
> 1024) {
2332 // If we max out the head count
2333 if (heads
> 127) break;
2337 // clip to 1024 cylinders in lchs
2338 if (cylinders
> 1024) cylinders
=1024;
2339 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2341 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2342 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2343 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2346 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2350 // Now we send a IDENTIFY command to ATAPI device
2351 if(type
== ATA_TYPE_ATAPI
) {
2353 Bit8u type
, removable
, mode
;
2356 //Temporary values to do the transfer
2357 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2358 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2360 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2361 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2363 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2364 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2365 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2368 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2369 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2370 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2371 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2374 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2381 Bit8u c
, i
, version
, model
[41];
2385 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2387 case ATA_TYPE_ATAPI
:
2388 // Read ATA/ATAPI version
2389 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2390 for(version
=15;version
>0;version
--) {
2391 if((ataversion
&(1<<version
))!=0)
2397 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2398 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2402 write_byte(get_SS(),model
+40,0x00);
2404 if(read_byte(get_SS(),model
+i
)==0x20)
2405 write_byte(get_SS(),model
+i
,0x00);
2413 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2414 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2415 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version
,(Bit16u
)sizeinmb
);
2417 case ATA_TYPE_ATAPI
:
2418 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2419 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2420 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2421 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2423 printf(" ATAPI-%d Device\n",version
);
2425 case ATA_TYPE_UNKNOWN
:
2426 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2432 // Store the devices counts
2433 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2434 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2435 write_byte(0x40,0x75, hdcount
);
2439 // FIXME : should use bios=cmos|auto|disable bits
2440 // FIXME : should know about translation bits
2441 // FIXME : move hard_drive_post here
2445 // ---------------------------------------------------------------------------
2446 // ATA/ATAPI driver : software reset
2447 // ---------------------------------------------------------------------------
2449 // 8.2.1 Software reset - Device 0
2451 void ata_reset(device
)
2454 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2455 Bit16u iobase1
, iobase2
;
2456 Bit8u channel
, slave
, sn
, sc
;
2459 channel
= device
/ 2;
2462 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2463 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2467 // 8.2.1 (a) -- set SRST in DC
2468 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2470 // 8.2.1 (b) -- wait for BSY
2473 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2474 if ((status
& ATA_CB_STAT_BSY
) != 0) break;
2477 // 8.2.1 (f) -- clear SRST
2478 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2480 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_NONE
) {
2482 // 8.2.1 (g) -- check for sc==sn==0x01
2484 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2485 sc
= inb(iobase1
+ATA_CB_SC
);
2486 sn
= inb(iobase1
+ATA_CB_SN
);
2488 if ( (sc
==0x01) && (sn
==0x01) ) {
2490 // 8.2.1 (h) -- wait for not BSY
2493 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2494 if ((status
& ATA_CB_STAT_BSY
) == 0) break;
2499 // 8.2.1 (i) -- wait for DRDY
2502 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2503 if ((status
& ATA_CB_STAT_RDY
) != 0) break;
2506 // Enable interrupts
2507 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2510 // ---------------------------------------------------------------------------
2511 // ATA/ATAPI driver : execute a non data command
2512 // ---------------------------------------------------------------------------
2514 Bit16u
ata_cmd_non_data()
2517 // ---------------------------------------------------------------------------
2518 // ATA/ATAPI driver : execute a data-in command
2519 // ---------------------------------------------------------------------------
2524 // 3 : expected DRQ=1
2525 // 4 : no sectors left to read/verify
2526 // 5 : more sectors to read/verify
2527 // 6 : no sectors left to write
2528 // 7 : more sectors to write
2529 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2530 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2533 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2534 Bit16u iobase1
, iobase2
, blksize
;
2535 Bit8u channel
, slave
;
2536 Bit8u status
, current
, mode
;
2538 channel
= device
/ 2;
2541 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2542 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2543 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2544 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2545 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2548 // sector will be 0 only on lba access. Convert to lba-chs
2550 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2552 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2554 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2557 // Reset count of transferred data
2558 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2559 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2562 status
= inb(iobase1
+ ATA_CB_STAT
);
2563 if (status
& ATA_CB_STAT_BSY
) return 1;
2565 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2566 outb(iobase1
+ ATA_CB_FR
, 0x00);
2567 outb(iobase1
+ ATA_CB_SC
, count
);
2568 outb(iobase1
+ ATA_CB_SN
, sector
);
2569 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2570 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2571 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2572 outb(iobase1
+ ATA_CB_CMD
, command
);
2575 status
= inb(iobase1
+ ATA_CB_STAT
);
2576 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2579 if (status
& ATA_CB_STAT_ERR
) {
2580 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2582 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2583 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2587 // FIXME : move seg/off translation here
2590 sti
;; enable higher priority interrupts
2598 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2599 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2600 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2602 ;; adjust
if there will be an overrun
. 2K max sector size
2604 jbe ata_in_no_adjust
2607 sub di
, #0x0800 ;; sub 2 kbytes from offset
2608 add ax
, #0x0080 ;; add 2 Kbytes to segment
2611 mov es
, ax
;; segment in es
2613 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2615 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2616 cmp ah
, #ATA_MODE_PIO32
2621 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2626 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2629 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2630 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2635 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2637 status
= inb(iobase1
+ ATA_CB_STAT
);
2639 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2640 != ATA_CB_STAT_RDY
) {
2641 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2647 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2648 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2649 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2655 // Enable interrupts
2656 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2660 // ---------------------------------------------------------------------------
2661 // ATA/ATAPI driver : execute a data-out command
2662 // ---------------------------------------------------------------------------
2667 // 3 : expected DRQ=1
2668 // 4 : no sectors left to read/verify
2669 // 5 : more sectors to read/verify
2670 // 6 : no sectors left to write
2671 // 7 : more sectors to write
2672 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2673 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2676 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2677 Bit16u iobase1
, iobase2
, blksize
;
2678 Bit8u channel
, slave
;
2679 Bit8u status
, current
, mode
;
2681 channel
= device
/ 2;
2684 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2685 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2686 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2687 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2688 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2691 // sector will be 0 only on lba access. Convert to lba-chs
2693 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2695 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2697 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2700 // Reset count of transferred data
2701 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2702 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2705 status
= inb(iobase1
+ ATA_CB_STAT
);
2706 if (status
& ATA_CB_STAT_BSY
) return 1;
2708 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2709 outb(iobase1
+ ATA_CB_FR
, 0x00);
2710 outb(iobase1
+ ATA_CB_SC
, count
);
2711 outb(iobase1
+ ATA_CB_SN
, sector
);
2712 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2713 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2714 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2715 outb(iobase1
+ ATA_CB_CMD
, command
);
2718 status
= inb(iobase1
+ ATA_CB_STAT
);
2719 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2722 if (status
& ATA_CB_STAT_ERR
) {
2723 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2725 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2726 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2730 // FIXME : move seg/off translation here
2733 sti
;; enable higher priority interrupts
2741 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2742 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2743 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2745 ;; adjust
if there will be an overrun
. 2K max sector size
2747 jbe ata_out_no_adjust
2750 sub si
, #0x0800 ;; sub 2 kbytes from offset
2751 add ax
, #0x0080 ;; add 2 Kbytes to segment
2754 mov es
, ax
;; segment in es
2756 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2758 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2759 cmp ah
, #ATA_MODE_PIO32
2765 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2771 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2774 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2775 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2780 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2782 status
= inb(iobase1
+ ATA_CB_STAT
);
2784 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2785 != ATA_CB_STAT_RDY
) {
2786 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2792 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2793 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2794 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2800 // Enable interrupts
2801 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2805 // ---------------------------------------------------------------------------
2806 // ATA/ATAPI driver : execute a packet command
2807 // ---------------------------------------------------------------------------
2810 // 1 : error in parameters
2814 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2816 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2820 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2821 Bit16u iobase1
, iobase2
;
2822 Bit16u lcount
, lbefore
, lafter
, count
;
2823 Bit8u channel
, slave
;
2824 Bit8u status
, mode
, lmode
;
2825 Bit32u total
, transfer
;
2827 channel
= device
/ 2;
2830 // Data out is not supported yet
2831 if (inout
== ATA_DATA_OUT
) {
2832 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2836 // The header length must be even
2838 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2842 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2843 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2844 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2847 if (cmdlen
< 12) cmdlen
=12;
2848 if (cmdlen
> 12) cmdlen
=16;
2851 // Reset count of transferred data
2852 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2853 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2855 status
= inb(iobase1
+ ATA_CB_STAT
);
2856 if (status
& ATA_CB_STAT_BSY
) return 2;
2858 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2859 // outb(iobase1 + ATA_CB_FR, 0x00);
2860 // outb(iobase1 + ATA_CB_SC, 0x00);
2861 // outb(iobase1 + ATA_CB_SN, 0x00);
2862 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2863 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2864 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2865 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2867 // Device should ok to receive command
2869 status
= inb(iobase1
+ ATA_CB_STAT
);
2870 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2873 if (status
& ATA_CB_STAT_ERR
) {
2874 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2876 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2877 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2881 // Normalize address
2882 cmdseg
+= (cmdoff
/ 16);
2885 // Send command to device
2887 sti
;; enable higher priority interrupts
2892 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
2893 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
2894 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
2895 mov es
, ax
;; segment in es
2897 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
2901 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2906 if (inout
== ATA_DATA_NO
) {
2907 status
= inb(iobase1
+ ATA_CB_STAT
);
2912 status
= inb(iobase1
+ ATA_CB_STAT
);
2914 // Check if command completed
2915 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_DRQ
) ) ==0 ) break;
2917 if (status
& ATA_CB_STAT_ERR
) {
2918 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
2922 // Device must be ready to send data
2923 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2924 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2925 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status
);
2929 // Normalize address
2930 bufseg
+= (bufoff
/ 16);
2933 // Get the byte count
2934 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
2936 // adjust to read what we want
2949 lafter
=lcount
-length
;
2961 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
2962 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
2964 // If counts not dividable by 4, use 16bits mode
2966 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
2967 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
2968 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
2970 // adds an extra byte if count are odd. before is always even
2971 if (lcount
& 0x01) {
2973 if ((lafter
> 0) && (lafter
& 0x01)) {
2978 if (lmode
== ATA_MODE_PIO32
) {
2979 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
2982 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
2991 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
2993 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
2994 jcxz ata_packet_no_before
2996 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
2997 cmp ah
, #ATA_MODE_PIO32
2998 je ata_packet_in_before_32
3000 ata_packet_in_before_16
:
3002 loop ata_packet_in_before_16
3003 jmp ata_packet_no_before
3005 ata_packet_in_before_32
:
3007 ata_packet_in_before_32_loop
:
3009 loop ata_packet_in_before_32_loop
3012 ata_packet_no_before
:
3013 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3014 jcxz ata_packet_after
3016 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3017 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3020 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3021 cmp ah
, #ATA_MODE_PIO32
3026 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3027 jmp ata_packet_after
3031 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3034 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3035 jcxz ata_packet_done
3037 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3038 cmp ah
, #ATA_MODE_PIO32
3039 je ata_packet_in_after_32
3041 ata_packet_in_after_16
:
3043 loop ata_packet_in_after_16
3046 ata_packet_in_after_32
:
3048 ata_packet_in_after_32_loop
:
3050 loop ata_packet_in_after_32_loop
3057 // Compute new buffer address
3060 // Save transferred bytes count
3062 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3066 // Final check, device must be ready
3067 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3068 != ATA_CB_STAT_RDY
) {
3069 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3073 // Enable interrupts
3074 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3078 // ---------------------------------------------------------------------------
3079 // End of ATA/ATAPI Driver
3080 // ---------------------------------------------------------------------------
3082 // ---------------------------------------------------------------------------
3083 // Start of ATA/ATAPI generic functions
3084 // ---------------------------------------------------------------------------
3087 atapi_get_sense(device
)
3094 memsetb(get_SS(),atacmd
,0,12);
3099 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 16L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3102 if ((buffer
[0] & 0x7e) == 0x70) {
3103 return (((Bit16u
)buffer
[2]&0x0f)*0x100)+buffer
[12];
3110 atapi_is_ready(device
)
3116 memsetb(get_SS(),atacmd
,0,12);
3119 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3122 if (atapi_get_sense(device
) !=0 ) {
3123 memsetb(get_SS(),atacmd
,0,12);
3125 // try to send Test Unit Ready again
3126 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3129 return atapi_get_sense(device
);
3135 atapi_is_cdrom(device
)
3138 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3140 if (device
>= BX_MAX_ATA_DEVICES
)
3143 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3146 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3152 // ---------------------------------------------------------------------------
3153 // End of ATA/ATAPI generic functions
3154 // ---------------------------------------------------------------------------
3156 #endif // BX_USE_ATADRV
3158 #if BX_ELTORITO_BOOT
3160 // ---------------------------------------------------------------------------
3161 // Start of El-Torito boot functions
3162 // ---------------------------------------------------------------------------
3167 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3169 // the only important data is this one for now
3170 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3176 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3178 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3182 cdemu_emulated_drive()
3184 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3186 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3189 static char isotag
[6]="CD001";
3190 static char eltorito
[24]="EL TORITO SPECIFICATION";
3192 // Returns ah: emulated drive, al: error code
3197 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3198 Bit8u atacmd
[12], buffer
[2048];
3200 Bit16u boot_segment
, nbsectors
, i
, error
;
3203 // Find out the first cdrom
3204 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3205 if (atapi_is_cdrom(device
)) break;
3209 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3211 // Read the Boot Record Volume Descriptor
3212 memsetb(get_SS(),atacmd
,0,12);
3213 atacmd
[0]=0x28; // READ command
3214 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3215 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3216 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3217 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3218 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3219 atacmd
[5]=(0x11 & 0x000000ff);
3220 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3224 if(buffer
[0]!=0)return 4;
3226 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3229 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3231 // ok, now we calculate the Boot catalog address
3232 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3234 // And we read the Boot Catalog
3235 memsetb(get_SS(),atacmd
,0,12);
3236 atacmd
[0]=0x28; // READ command
3237 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3238 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3239 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3240 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3241 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3242 atacmd
[5]=(lba
& 0x000000ff);
3243 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3247 if(buffer
[0x00]!=0x01)return 8; // Header
3248 if(buffer
[0x01]!=0x00)return 9; // Platform
3249 if(buffer
[0x1E]!=0x55)return 10; // key 1
3250 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3252 // Initial/Default Entry
3253 if(buffer
[0x20]!=0x88)return 11; // Bootable
3255 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3256 if(buffer
[0x21]==0){
3257 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3258 // Win2000 cd boot needs to know it booted from cd
3259 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3261 else if(buffer
[0x21]<4)
3262 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3264 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3266 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3267 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3269 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3270 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3272 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3273 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3275 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3276 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3278 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3279 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3281 // And we read the image in memory
3282 memsetb(get_SS(),atacmd
,0,12);
3283 atacmd
[0]=0x28; // READ command
3284 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3285 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3286 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3287 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3288 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3289 atacmd
[5]=(lba
& 0x000000ff);
3290 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3293 // Remember the media type
3294 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3295 case 0x01: // 1.2M floppy
3296 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3297 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3298 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3300 case 0x02: // 1.44M floppy
3301 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3302 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3303 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3305 case 0x03: // 2.88M floppy
3306 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3307 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3308 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3310 case 0x04: // Harddrive
3311 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3312 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3313 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3314 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3318 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3319 // Increase bios installed hardware number of devices
3320 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3321 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3323 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3327 // everything is ok, so from now on, the emulation is active
3328 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3329 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3331 // return the boot drive + no error
3332 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3335 // ---------------------------------------------------------------------------
3336 // End of El-Torito boot functions
3337 // ---------------------------------------------------------------------------
3338 #endif // BX_ELTORITO_BOOT
3341 int14_function(regs
, ds
, iret_addr
)
3342 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3343 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3344 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3346 Bit16u addr
,timer
,val16
;
3353 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3354 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3355 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3356 switch (regs
.u
.r8
.ah
) {
3358 outb(addr
+3, inb(addr
+3) | 0x80);
3359 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3363 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3364 outb(addr
, val16
& 0xFF);
3365 outb(addr
+1, val16
>> 8);
3367 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3368 regs
.u
.r8
.ah
= inb(addr
+5);
3369 regs
.u
.r8
.al
= inb(addr
+6);
3370 ClearCF(iret_addr
.flags
);
3373 timer
= read_word(0x0040, 0x006C);
3374 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3375 val16
= read_word(0x0040, 0x006C);
3376 if (val16
!= timer
) {
3381 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3382 regs
.u
.r8
.ah
= inb(addr
+5);
3383 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3384 ClearCF(iret_addr
.flags
);
3387 timer
= read_word(0x0040, 0x006C);
3388 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3389 val16
= read_word(0x0040, 0x006C);
3390 if (val16
!= timer
) {
3397 regs
.u
.r8
.al
= inb(addr
);
3399 regs
.u
.r8
.ah
= inb(addr
+5);
3401 ClearCF(iret_addr
.flags
);
3404 regs
.u
.r8
.ah
= inb(addr
+5);
3405 regs
.u
.r8
.al
= inb(addr
+6);
3406 ClearCF(iret_addr
.flags
);
3409 SetCF(iret_addr
.flags
); // Unsupported
3412 SetCF(iret_addr
.flags
); // Unsupported
3417 int15_function(regs
, ES
, DS
, FLAGS
)
3418 pusha_regs_t regs
; // REGS pushed via pusha
3419 Bit16u ES
, DS
, FLAGS
;
3421 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3422 bx_bool prev_a20_enable
;
3431 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3433 switch (regs
.u
.r8
.ah
) {
3434 case 0x24: /* A20 Control */
3435 switch (regs
.u
.r8
.al
) {
3447 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3457 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3459 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3465 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3469 /* keyboard intercept */
3471 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3478 case 0x52: // removable media eject
3480 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3484 if( regs
.u
.r8
.al
== 0 ) {
3485 // Set Interval requested.
3486 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3487 // Interval not already set.
3488 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3489 write_word( 0x40, 0x98, ES
); // Byte location, segment
3490 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3491 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3492 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3494 irqDisable
= inb( 0xA1 );
3495 outb( 0xA1, irqDisable
& 0xFE );
3496 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3497 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3499 // Interval already set.
3500 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3502 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3504 } else if( regs
.u
.r8
.al
== 1 ) {
3505 // Clear Interval requested
3506 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3508 bRegister
= inb_cmos( 0xB );
3509 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3511 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3513 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3522 # error "Int15 function 87h not supported on < 80386"
3524 // +++ should probably have descriptor checks
3525 // +++ should have exception handlers
3527 // turn off interrupts
3532 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3534 // 128K max of transfer on 386+ ???
3535 // source == destination ???
3537 // ES:SI points to descriptor table
3538 // offset use initially comments
3539 // ==============================================
3540 // 00..07 Unused zeros Null descriptor
3541 // 08..0f GDT zeros filled in by BIOS
3542 // 10..17 source ssssssss source of data
3543 // 18..1f dest dddddddd destination of data
3544 // 20..27 CS zeros filled in by BIOS
3545 // 28..2f SS zeros filled in by BIOS
3552 // check for access rights of source & dest here
3554 // Initialize GDT descriptor
3555 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3556 base23_16
= ES
>> 12;
3557 if (base15_00
< (ES
<<4))
3559 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3560 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3561 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3562 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3563 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3565 // Initialize CS descriptor
3566 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3567 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3568 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3569 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3570 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3572 // Initialize SS descriptor
3574 base15_00
= ss
<< 4;
3575 base23_16
= ss
>> 12;
3576 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3577 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3578 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3579 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3580 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3584 // Compile generates locals offset info relative to SP.
3585 // Get CX (word count) from stack.
3588 mov cx
, _int15_function
.CX
[bx
]
3590 // since we need to set SS:SP, save them to the BDA
3591 // for future restore
3601 lidt
[pmode_IDT_info
]
3602 ;; perhaps
do something with IDT here
3604 ;; set PE bit in CR0
3608 ;; far jump to flush CPU queue after transition to
protected mode
3609 JMP_AP(0x0020, protected_mode
)
3612 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3613 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3615 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3617 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3623 movsw
;; move CX words from DS
:SI to ES
:DI
3625 ;; make sure DS
and ES limits are
64KB
3630 ;; reset PG bit in CR0
???
3635 ;; far jump to flush CPU queue after transition to real mode
3636 JMP_AP(0xf000, real_mode
)
3639 ;; restore IDT to normal real
-mode defaults
3641 lidt
[rmode_IDT_info
]
3643 // restore SS:SP from the BDA
3651 set_enable_a20(prev_a20_enable
);
3653 // turn back on interrupts
3664 // Get the amount of extended memory (above 1M)
3666 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3669 regs
.u
.r8
.al
= inb_cmos(0x30);
3670 regs
.u
.r8
.ah
= inb_cmos(0x31);
3673 if(regs
.u
.r16
.ax
> 0x3c00)
3674 regs
.u
.r16
.ax
= 0x3c00;
3681 /* Device busy interrupt. Called by Int 16h when no key available */
3685 /* Interrupt complete. Called by Int 16h when key becomes available */
3689 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3691 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3697 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3702 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3712 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3714 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3718 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3719 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3721 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3726 #if BX_USE_PS2_MOUSE
3728 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3729 pusha_regs_t regs
; // REGS pushed via pusha
3730 Bit16u ES
, DS
, FLAGS
;
3732 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3733 Bit8u mouse_flags_1
, mouse_flags_2
;
3734 Bit16u mouse_driver_seg
;
3735 Bit16u mouse_driver_offset
;
3736 Bit8u comm_byte
, prev_command_byte
;
3737 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3739 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3741 switch (regs
.u
.r8
.ah
) {
3743 // Return Codes status in AH
3744 // =========================
3746 // 01: invalid subfunction (AL > 7)
3747 // 02: invalid input value (out of allowable range)
3748 // 03: interface error
3749 // 04: resend command received from mouse controller,
3750 // device driver should attempt command again
3751 // 05: cannot enable mouse, since no far call has been installed
3752 // 80/86: mouse service not implemented
3754 switch (regs
.u
.r8
.al
) {
3755 case 0: // Disable/Enable Mouse
3756 BX_DEBUG_INT15("case 0:\n");
3757 switch (regs
.u
.r8
.bh
) {
3758 case 0: // Disable Mouse
3759 BX_DEBUG_INT15("case 0: disable mouse\n");
3760 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3761 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3763 ret
= get_mouse_data(&mouse_data1
);
3764 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3777 case 1: // Enable Mouse
3778 BX_DEBUG_INT15("case 1: enable mouse\n");
3779 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3780 if ( (mouse_flags_2
& 0x80) == 0 ) {
3781 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3783 regs
.u
.r8
.ah
= 5; // no far call installed
3786 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3787 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3789 ret
= get_mouse_data(&mouse_data1
);
3790 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3791 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3801 default: // invalid subfunction
3802 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3804 regs
.u
.r8
.ah
= 1; // invalid subfunction
3809 case 1: // Reset Mouse
3810 case 5: // Initialize Mouse
3811 BX_DEBUG_INT15("case 1 or 5:\n");
3812 if (regs
.u
.r8
.al
== 5) {
3813 if (regs
.u
.r8
.bh
!= 3) {
3815 regs
.u
.r8
.ah
= 0x02; // invalid input
3818 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3819 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3820 mouse_flags_1
= 0x00;
3821 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3822 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3825 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3826 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
3828 ret
= get_mouse_data(&mouse_data3
);
3829 // if no mouse attached, it will return RESEND
3830 if (mouse_data3
== 0xfe) {
3834 if (mouse_data3
!= 0xfa)
3835 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
3837 ret
= get_mouse_data(&mouse_data1
);
3839 ret
= get_mouse_data(&mouse_data2
);
3841 // turn IRQ12 and packet generation on
3842 enable_mouse_int_and_events();
3845 regs
.u
.r8
.bl
= mouse_data1
;
3846 regs
.u
.r8
.bh
= mouse_data2
;
3858 case 2: // Set Sample Rate
3859 BX_DEBUG_INT15("case 2:\n");
3860 switch (regs
.u
.r8
.bh
) {
3861 case 0: mouse_data1
= 10; break; // 10 reports/sec
3862 case 1: mouse_data1
= 20; break; // 20 reports/sec
3863 case 2: mouse_data1
= 40; break; // 40 reports/sec
3864 case 3: mouse_data1
= 60; break; // 60 reports/sec
3865 case 4: mouse_data1
= 80; break; // 80 reports/sec
3866 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
3867 case 6: mouse_data1
= 200; break; // 200 reports/sec
3868 default: mouse_data1
= 0;
3870 if (mouse_data1
> 0) {
3871 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
3873 ret
= get_mouse_data(&mouse_data2
);
3874 ret
= send_to_mouse_ctrl(mouse_data1
);
3875 ret
= get_mouse_data(&mouse_data2
);
3881 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3886 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3890 case 3: // Set Resolution
3891 BX_DEBUG_INT15("case 3:\n");
3893 // 0 = 25 dpi, 1 count per millimeter
3894 // 1 = 50 dpi, 2 counts per millimeter
3895 // 2 = 100 dpi, 4 counts per millimeter
3896 // 3 = 200 dpi, 8 counts per millimeter
3901 case 4: // Get Device ID
3902 BX_DEBUG_INT15("case 4:\n");
3903 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3904 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
3906 ret
= get_mouse_data(&mouse_data1
);
3907 ret
= get_mouse_data(&mouse_data2
);
3910 regs
.u
.r8
.bh
= mouse_data2
;
3914 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3918 case 6: // Return Status & Set Scaling Factor...
3919 BX_DEBUG_INT15("case 6:\n");
3920 switch (regs
.u
.r8
.bh
) {
3921 case 0: // Return Status
3922 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3923 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
3925 ret
= get_mouse_data(&mouse_data1
);
3926 if (mouse_data1
!= 0xfa)
3927 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3929 ret
= get_mouse_data(&mouse_data1
);
3931 ret
= get_mouse_data(&mouse_data2
);
3933 ret
= get_mouse_data(&mouse_data3
);
3937 regs
.u
.r8
.bl
= mouse_data1
;
3938 regs
.u
.r8
.cl
= mouse_data2
;
3939 regs
.u
.r8
.dl
= mouse_data3
;
3940 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3951 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3954 case 1: // Set Scaling Factor to 1:1
3955 case 2: // Set Scaling Factor to 2:1
3956 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3957 if (regs
.u
.r8
.bh
== 1) {
3958 ret
= send_to_mouse_ctrl(0xE6);
3960 ret
= send_to_mouse_ctrl(0xE7);
3963 get_mouse_data(&mouse_data1
);
3964 ret
= (mouse_data1
!= 0xFA);
3972 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3974 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3978 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3982 case 7: // Set Mouse Handler Address
3983 BX_DEBUG_INT15("case 7:\n");
3984 mouse_driver_seg
= ES
;
3985 mouse_driver_offset
= regs
.u
.r16
.bx
;
3986 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
3987 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
3988 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3989 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
3990 /* remove handler */
3991 if ( (mouse_flags_2
& 0x80) != 0 ) {
3992 mouse_flags_2
&= ~0x80;
3993 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3997 /* install handler */
3998 mouse_flags_2
|= 0x80;
4000 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
4006 BX_DEBUG_INT15("case default:\n");
4007 regs
.u
.r8
.ah
= 1; // invalid function
4013 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4014 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4016 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4023 int15_function32(regs
, ES
, DS
, FLAGS
)
4024 pushad_regs_t regs
; // REGS pushed via pushad
4025 Bit16u ES
, DS
, FLAGS
;
4027 Bit32u extended_memory_size
=0; // 64bits long
4030 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4032 switch (regs
.u
.r8
.ah
) {
4034 // Wait for CX:DX microseconds. currently using the
4035 // refresh request port 0x61 bit4, toggling every 15usec
4043 ;; Get the count in eax
4046 mov ax
, _int15_function
.CX
[bx
]
4049 mov ax
, _int15_function
.DX
[bx
]
4051 ;; convert to numbers of
15usec ticks
4057 ;; wait
for ecx number of refresh requests
4078 switch(regs
.u
.r8
.al
)
4080 case 0x20: // coded by osmaker aka K.J.
4081 if(regs
.u
.r32
.edx
== 0x534D4150)
4083 switch(regs
.u
.r16
.bx
)
4086 write_word(ES
, regs
.u
.r16
.di
, 0x00);
4087 write_word(ES
, regs
.u
.r16
.di
+2, 0x00);
4088 write_word(ES
, regs
.u
.r16
.di
+4, 0x00);
4089 write_word(ES
, regs
.u
.r16
.di
+6, 0x00);
4091 write_word(ES
, regs
.u
.r16
.di
+8, 0xFC00);
4092 write_word(ES
, regs
.u
.r16
.di
+10, 0x0009);
4093 write_word(ES
, regs
.u
.r16
.di
+12, 0x0000);
4094 write_word(ES
, regs
.u
.r16
.di
+14, 0x0000);
4096 write_word(ES
, regs
.u
.r16
.di
+16, 0x1);
4097 write_word(ES
, regs
.u
.r16
.di
+18, 0x0);
4100 regs
.u
.r32
.eax
= 0x534D4150;
4101 regs
.u
.r32
.ecx
= 0x14;
4106 extended_memory_size
= inb_cmos(0x35);
4107 extended_memory_size
<<= 8;
4108 extended_memory_size
|= inb_cmos(0x34);
4109 extended_memory_size
*= 64;
4110 if(extended_memory_size
> 0x3bc000) // greater than EFF00000???
4112 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4114 extended_memory_size
*= 1024;
4115 extended_memory_size
+= 15728640; // make up for the 16mb of memory that is chopped off
4117 if(extended_memory_size
<= 15728640)
4119 extended_memory_size
= inb_cmos(0x31);
4120 extended_memory_size
<<= 8;
4121 extended_memory_size
|= inb_cmos(0x30);
4122 extended_memory_size
*= 1024;
4125 write_word(ES
, regs
.u
.r16
.di
, 0x0000);
4126 write_word(ES
, regs
.u
.r16
.di
+2, 0x0010);
4127 write_word(ES
, regs
.u
.r16
.di
+4, 0x0000);
4128 write_word(ES
, regs
.u
.r16
.di
+6, 0x0000);
4130 write_word(ES
, regs
.u
.r16
.di
+8, extended_memory_size
);
4131 extended_memory_size
>>= 16;
4132 write_word(ES
, regs
.u
.r16
.di
+10, extended_memory_size
);
4133 extended_memory_size
>>= 16;
4134 write_word(ES
, regs
.u
.r16
.di
+12, extended_memory_size
);
4135 extended_memory_size
>>= 16;
4136 write_word(ES
, regs
.u
.r16
.di
+14, extended_memory_size
);
4138 write_word(ES
, regs
.u
.r16
.di
+16, 0x1);
4139 write_word(ES
, regs
.u
.r16
.di
+18, 0x0);
4142 regs
.u
.r32
.eax
= 0x534D4150;
4143 regs
.u
.r32
.ecx
= 0x14;
4147 default: /* AX=E820, DX=534D4150, BX unrecognized */
4148 goto int15_unimplemented
;
4152 // if DX != 0x534D4150)
4153 goto int15_unimplemented
;
4158 // do we have any reason to fail here ?
4161 // my real system sets ax and bx to 0
4162 // this is confirmed by Ralph Brown list
4163 // but syslinux v1.48 is known to behave
4164 // strangely if ax is set to 0
4165 // regs.u.r16.ax = 0;
4166 // regs.u.r16.bx = 0;
4168 // Get the amount of extended memory (above 1M)
4169 regs
.u
.r8
.cl
= inb_cmos(0x30);
4170 regs
.u
.r8
.ch
= inb_cmos(0x31);
4173 if(regs
.u
.r16
.cx
> 0x3c00)
4175 regs
.u
.r16
.cx
= 0x3c00;
4178 // Get the amount of extended memory above 16M in 64k blocs
4179 regs
.u
.r8
.dl
= inb_cmos(0x34);
4180 regs
.u
.r8
.dh
= inb_cmos(0x35);
4182 // Set configured memory equal to extended memory
4183 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4184 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4186 default: /* AH=0xE8?? but not implemented */
4187 goto int15_unimplemented
;
4190 int15_unimplemented
:
4191 // fall into the default
4193 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4194 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4196 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4202 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4203 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4205 Bit8u scan_code
, ascii_code
, shift_flags
, count
;
4206 Bit16u kbd_code
, max
;
4208 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4211 case 0x00: /* read keyboard input */
4213 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4214 BX_PANIC("KBD: int16h: out of keyboard input\n");
4216 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4217 else if (ascii_code
== 0xE0) ascii_code
= 0;
4218 AX
= (scan_code
<< 8) | ascii_code
;
4221 case 0x01: /* check keyboard status */
4222 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4226 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4227 else if (ascii_code
== 0xE0) ascii_code
= 0;
4228 AX
= (scan_code
<< 8) | ascii_code
;
4232 case 0x02: /* get shift flag status */
4233 shift_flags
= read_byte(0x0040, 0x17);
4234 SET_AL(shift_flags
);
4237 case 0x05: /* store key-stroke into buffer */
4238 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4246 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4247 // bit Bochs Description
4249 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4250 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4251 // 4 1 INT 16/AH=0Ah supported
4252 // 3 0 INT 16/AX=0306h supported
4253 // 2 0 INT 16/AX=0305h supported
4254 // 1 0 INT 16/AX=0304h supported
4255 // 0 0 INT 16/AX=0300h supported
4260 case 0x0A: /* GET KEYBOARD ID */
4266 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4268 if ((inb(0x60) == 0xfa)) {
4271 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4274 kbd_code
|= (inb(0x60) << 8);
4276 } while (--count
>0);
4282 case 0x10: /* read MF-II keyboard input */
4284 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4285 BX_PANIC("KBD: int16h: out of keyboard input\n");
4287 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4288 AX
= (scan_code
<< 8) | ascii_code
;
4291 case 0x11: /* check MF-II keyboard status */
4292 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4296 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4297 AX
= (scan_code
<< 8) | ascii_code
;
4301 case 0x12: /* get extended keyboard status */
4302 shift_flags
= read_byte(0x0040, 0x17);
4303 SET_AL(shift_flags
);
4304 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4305 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4306 SET_AH(shift_flags
);
4307 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4310 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4311 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4314 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4315 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4319 if (GET_AL() == 0x08)
4320 SET_AH(0x02); // unsupported, aka normal keyboard
4323 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4328 dequeue_key(scan_code
, ascii_code
, incr
)
4333 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4338 buffer_start
= 0x001E;
4339 buffer_end
= 0x003E;
4341 buffer_start
= read_word(0x0040, 0x0080);
4342 buffer_end
= read_word(0x0040, 0x0082);
4345 buffer_head
= read_word(0x0040, 0x001a);
4346 buffer_tail
= read_word(0x0040, 0x001c);
4348 if (buffer_head
!= buffer_tail
) {
4350 acode
= read_byte(0x0040, buffer_head
);
4351 scode
= read_byte(0x0040, buffer_head
+1);
4352 write_byte(ss
, ascii_code
, acode
);
4353 write_byte(ss
, scan_code
, scode
);
4357 if (buffer_head
>= buffer_end
)
4358 buffer_head
= buffer_start
;
4359 write_word(0x0040, 0x001a, buffer_head
);
4368 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4371 inhibit_mouse_int_and_events()
4373 Bit8u command_byte
, prev_command_byte
;
4375 // Turn off IRQ generation and aux data line
4376 if ( inb(0x64) & 0x02 )
4377 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4378 outb(0x64, 0x20); // get command byte
4379 while ( (inb(0x64) & 0x01) != 0x01 );
4380 prev_command_byte
= inb(0x60);
4381 command_byte
= prev_command_byte
;
4382 //while ( (inb(0x64) & 0x02) );
4383 if ( inb(0x64) & 0x02 )
4384 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4385 command_byte
&= 0xfd; // turn off IRQ 12 generation
4386 command_byte
|= 0x20; // disable mouse serial clock line
4387 outb(0x64, 0x60); // write command byte
4388 outb(0x60, command_byte
);
4389 return(prev_command_byte
);
4393 enable_mouse_int_and_events()
4397 // Turn on IRQ generation and aux data line
4398 if ( inb(0x64) & 0x02 )
4399 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4400 outb(0x64, 0x20); // get command byte
4401 while ( (inb(0x64) & 0x01) != 0x01 );
4402 command_byte
= inb(0x60);
4403 //while ( (inb(0x64) & 0x02) );
4404 if ( inb(0x64) & 0x02 )
4405 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4406 command_byte
|= 0x02; // turn on IRQ 12 generation
4407 command_byte
&= 0xdf; // enable mouse serial clock line
4408 outb(0x64, 0x60); // write command byte
4409 outb(0x60, command_byte
);
4413 send_to_mouse_ctrl(sendbyte
)
4418 // wait for chance to write to ctrl
4419 if ( inb(0x64) & 0x02 )
4420 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4422 outb(0x60, sendbyte
);
4428 get_mouse_data(data
)
4434 while ( (inb(0x64) & 0x21) != 0x21 ) {
4437 response
= inb(0x60);
4440 write_byte(ss
, data
, response
);
4445 set_kbd_command_byte(command_byte
)
4448 if ( inb(0x64) & 0x02 )
4449 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4452 outb(0x64, 0x60); // write command byte
4453 outb(0x60, command_byte
);
4457 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4458 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4460 Bit8u scancode
, asciicode
, shift_flags
;
4461 Bit8u mf2_flags
, mf2_state
, led_flags
;
4464 // DS has been set to F000 before call
4468 scancode
= GET_AL();
4470 if (scancode
== 0) {
4471 BX_INFO("KBD: int09 handler: AL=0\n");
4476 shift_flags
= read_byte(0x0040, 0x17);
4477 mf2_flags
= read_byte(0x0040, 0x18);
4478 mf2_state
= read_byte(0x0040, 0x96);
4479 led_flags
= read_byte(0x0040, 0x97);
4483 case 0x3a: /* Caps Lock press */
4484 shift_flags
^= 0x40;
4485 write_byte(0x0040, 0x17, shift_flags
);
4488 write_byte(0x0040, 0x18, mf2_flags
);
4489 write_byte(0x0040, 0x97, led_flags
);
4491 case 0xba: /* Caps Lock release */
4493 write_byte(0x0040, 0x18, mf2_flags
);
4496 case 0x2a: /* L Shift press */
4497 shift_flags
|= 0x02;
4498 write_byte(0x0040, 0x17, shift_flags
);
4500 case 0xaa: /* L Shift release */
4501 shift_flags
&= ~0x02;
4502 write_byte(0x0040, 0x17, shift_flags
);
4505 case 0x36: /* R Shift press */
4506 shift_flags
|= 0x01;
4507 write_byte(0x0040, 0x17, shift_flags
);
4509 case 0xb6: /* R Shift release */
4510 shift_flags
&= ~0x01;
4511 write_byte(0x0040, 0x17, shift_flags
);
4514 case 0x1d: /* Ctrl press */
4515 shift_flags
|= 0x04;
4516 write_byte(0x0040, 0x17, shift_flags
);
4517 if (mf2_state
& 0x02) {
4519 write_byte(0x0040, 0x96, mf2_state
);
4522 write_byte(0x0040, 0x18, mf2_flags
);
4525 case 0x9d: /* Ctrl release */
4526 shift_flags
&= ~0x04;
4527 write_byte(0x0040, 0x17, shift_flags
);
4528 if (mf2_state
& 0x02) {
4530 write_byte(0x0040, 0x96, mf2_state
);
4533 write_byte(0x0040, 0x18, mf2_flags
);
4537 case 0x38: /* Alt press */
4538 shift_flags
|= 0x08;
4539 write_byte(0x0040, 0x17, shift_flags
);
4540 if (mf2_state
& 0x02) {
4542 write_byte(0x0040, 0x96, mf2_state
);
4545 write_byte(0x0040, 0x18, mf2_flags
);
4548 case 0xb8: /* Alt release */
4549 shift_flags
&= ~0x08;
4550 write_byte(0x0040, 0x17, shift_flags
);
4551 if (mf2_state
& 0x02) {
4553 write_byte(0x0040, 0x96, mf2_state
);
4556 write_byte(0x0040, 0x18, mf2_flags
);
4560 case 0x45: /* Num Lock press */
4561 if ((mf2_state
& 0x02) == 0) {
4563 write_byte(0x0040, 0x18, mf2_flags
);
4564 shift_flags
^= 0x20;
4566 write_byte(0x0040, 0x17, shift_flags
);
4567 write_byte(0x0040, 0x97, led_flags
);
4570 case 0xc5: /* Num Lock release */
4571 if ((mf2_state
& 0x02) == 0) {
4573 write_byte(0x0040, 0x18, mf2_flags
);
4577 case 0x46: /* Scroll Lock press */
4579 write_byte(0x0040, 0x18, mf2_flags
);
4580 shift_flags
^= 0x10;
4582 write_byte(0x0040, 0x17, shift_flags
);
4583 write_byte(0x0040, 0x97, led_flags
);
4586 case 0xc6: /* Scroll Lock release */
4588 write_byte(0x0040, 0x18, mf2_flags
);
4592 if (scancode
& 0x80) return; /* toss key releases ... */
4593 if (scancode
> MAX_SCAN_CODE
) {
4594 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4597 if (shift_flags
& 0x08) { /* ALT */
4598 asciicode
= scan_to_scanascii
[scancode
].alt
;
4599 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4601 else if (shift_flags
& 0x04) { /* CONTROL */
4602 asciicode
= scan_to_scanascii
[scancode
].control
;
4603 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4605 else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4606 /* check if lock state should be ignored
4607 * because a SHIFT key are pressed */
4609 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4610 asciicode
= scan_to_scanascii
[scancode
].normal
;
4611 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4614 asciicode
= scan_to_scanascii
[scancode
].shift
;
4615 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4619 /* check if lock is on */
4620 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4621 asciicode
= scan_to_scanascii
[scancode
].shift
;
4622 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4625 asciicode
= scan_to_scanascii
[scancode
].normal
;
4626 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4629 if (scancode
==0 && asciicode
==0) {
4630 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4632 enqueue_key(scancode
, asciicode
);
4636 write_byte(0x0040, 0x96, mf2_state
);
4640 enqueue_key(scan_code
, ascii_code
)
4641 Bit8u scan_code
, ascii_code
;
4643 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4645 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4646 // scan_code, ascii_code);
4649 buffer_start
= 0x001E;
4650 buffer_end
= 0x003E;
4652 buffer_start
= read_word(0x0040, 0x0080);
4653 buffer_end
= read_word(0x0040, 0x0082);
4656 buffer_head
= read_word(0x0040, 0x001A);
4657 buffer_tail
= read_word(0x0040, 0x001C);
4659 temp_tail
= buffer_tail
;
4661 if (buffer_tail
>= buffer_end
)
4662 buffer_tail
= buffer_start
;
4664 if (buffer_tail
== buffer_head
) {
4668 write_byte(0x0040, temp_tail
, ascii_code
);
4669 write_byte(0x0040, temp_tail
+1, scan_code
);
4670 write_word(0x0040, 0x001C, buffer_tail
);
4676 int74_function(make_farcall
, Z
, Y
, X
, status
)
4677 Bit16u make_farcall
, Z
, Y
, X
, status
;
4679 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4680 Bit8u in_byte
, index
, package_count
;
4681 Bit8u mouse_flags_1
, mouse_flags_2
;
4683 BX_DEBUG_INT74("entering int74_function\n");
4686 in_byte
= inb(0x64);
4687 if ( (in_byte
& 0x21) != 0x21 ) {
4690 in_byte
= inb(0x60);
4691 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4693 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4694 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4696 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4697 // BX_PANIC("int74_function:\n");
4701 package_count
= mouse_flags_2
& 0x07;
4702 index
= mouse_flags_1
& 0x07;
4703 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4705 if ( (index
+1) >= package_count
) {
4706 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4707 status
= read_byte(ebda_seg
, 0x0028 + 0);
4708 X
= read_byte(ebda_seg
, 0x0028 + 1);
4709 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4712 // check if far call handler installed
4713 if (mouse_flags_2
& 0x80)
4719 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4722 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4727 int13_harddisk(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4728 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4731 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4732 Bit16u cylinder
, head
, sector
;
4733 Bit16u segment
, offset
;
4734 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4736 Bit8u device
, status
;
4738 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4740 write_byte(0x0040, 0x008e, 0); // clear completion flag
4742 // basic check : device has to be defined
4743 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4744 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4748 // Get the ata channel
4749 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
4751 // basic check : device has to be valid
4752 if (device
>= BX_MAX_ATA_DEVICES
) {
4753 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4759 case 0x00: /* disk controller reset */
4764 case 0x01: /* read disk status */
4765 status
= read_byte(0x0040, 0x0074);
4767 SET_DISK_RET_STATUS(0);
4768 /* set CF if error status read */
4769 if (status
) goto int13_fail_nostatus
;
4770 else goto int13_success_noah
;
4773 case 0x02: // read disk sectors
4774 case 0x03: // write disk sectors
4775 case 0x04: // verify disk sectors
4778 cylinder
= GET_CH();
4779 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
4780 sector
= (GET_CL() & 0x3f);
4786 if ( (count
> 128) || (count
== 0) ) {
4787 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4791 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4792 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4793 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4795 // sanity check on cyl heads, sec
4796 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
4797 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
4802 if ( GET_AH() == 0x04 ) goto int13_success
;
4804 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4805 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4807 // if needed, translate lchs to lba, and execute command
4808 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
4809 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
4810 sector
= 0; // this forces the command to be lba
4813 if ( GET_AH() == 0x02 )
4814 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4816 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4818 // Set nb of sector transferred
4819 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
4822 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4824 goto int13_fail_noah
;
4830 case 0x05: /* format disk track */
4831 BX_INFO("format disk track called\n");
4836 case 0x08: /* read disk drive parameters */
4838 // Get logical geometry from table
4839 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4840 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4841 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4842 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
4844 nlc
= nlc
- 2; /* 0 based , last sector not used */
4847 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
4849 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
4851 // FIXME should set ES & DI
4856 case 0x10: /* check drive ready */
4857 // should look at 40:8E also???
4859 // Read the status from controller
4860 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
4861 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
4866 goto int13_fail_noah
;
4870 case 0x15: /* read disk drive size */
4872 // Get physical geometry from table
4873 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
4874 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4875 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4877 // Compute sector count seen by int13
4878 lba
= (Bit32u
)(npc
- 1) * (Bit32u
)nph
* (Bit32u
)npspt
;
4882 SET_AH(3); // hard disk accessible
4883 goto int13_success_noah
;
4886 case 0x41: // IBM/MS installation check
4887 BX
=0xaa55; // install check
4888 SET_AH(0x30); // EDD 3.0
4889 CX
=0x0007; // ext disk access and edd, removable supported
4890 goto int13_success_noah
;
4893 case 0x42: // IBM/MS extended read
4894 case 0x43: // IBM/MS extended write
4895 case 0x44: // IBM/MS verify
4896 case 0x47: // IBM/MS extended seek
4898 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
4899 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
4900 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
4902 // Can't use 64 bits lba
4903 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
4905 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4909 // Get 32 bits lba and check
4910 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
4911 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
4912 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4916 // If verify or seek
4917 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4920 // Execute the command
4921 if ( GET_AH() == 0x42 )
4922 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4924 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4926 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
4927 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
4930 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4932 goto int13_fail_noah
;
4938 case 0x45: // IBM/MS lock/unlock drive
4939 case 0x49: // IBM/MS extended media change
4940 goto int13_success
; // Always success for HD
4943 case 0x46: // IBM/MS eject media
4944 SET_AH(0xb2); // Volume Not Removable
4945 goto int13_fail_noah
; // Always fail for HD
4948 case 0x48: // IBM/MS get drive parameters
4949 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
4951 // Buffer is too small
4959 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
4960 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4961 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4962 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
4963 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
4965 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
4966 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
4967 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
4968 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
4969 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
4970 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
4971 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
4972 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
4977 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
4978 Bit16u iobase1
, iobase2
, options
;
4980 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
4982 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
4983 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
4986 channel
= device
/ 2;
4987 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
4988 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
4989 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
4990 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
4991 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
4993 options
= (translation
==ATA_TRANSLATION_NONE
?0:1<<3); // chs translation
4994 options
|= (1<<4); // lba translation
4995 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
4996 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0<<9);
4997 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0<<9);
4999 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5000 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5001 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5002 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5003 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5004 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5005 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5006 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5007 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5008 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5009 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5012 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5013 checksum
= ~checksum
;
5014 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5019 Bit8u channel
, iface
, checksum
, i
;
5022 channel
= device
/ 2;
5023 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5024 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5026 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5027 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5028 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5029 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5030 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5032 if (iface
==ATA_IFACE_ISA
) {
5033 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5034 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5035 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5036 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5041 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5042 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5043 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5044 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5046 if (iface
==ATA_IFACE_ISA
) {
5047 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5048 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5049 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5054 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5055 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5056 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5057 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5060 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5061 checksum
= ~checksum
;
5062 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5068 case 0x4e: // // IBM/MS set hardware configuration
5069 // DMA, prefetch, PIO maximum not supported
5082 case 0x09: /* initialize drive parameters */
5083 case 0x0c: /* seek to specified cylinder */
5084 case 0x0d: /* alternate disk reset */
5085 case 0x11: /* recalibrate */
5086 case 0x14: /* controller internal diagnostic */
5087 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5091 case 0x0a: /* read disk sectors with ECC */
5092 case 0x0b: /* write disk sectors with ECC */
5093 case 0x18: // set media type for format
5094 case 0x50: // IBM/MS send packet command
5096 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5102 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5104 SET_DISK_RET_STATUS(GET_AH());
5105 int13_fail_nostatus
:
5106 SET_CF(); // error occurred
5110 SET_AH(0x00); // no error
5112 SET_DISK_RET_STATUS(0x00);
5113 CLEAR_CF(); // no error
5117 // ---------------------------------------------------------------------------
5118 // Start of int13 for cdrom
5119 // ---------------------------------------------------------------------------
5122 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5123 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5125 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5126 Bit8u device
, status
, locks
;
5129 Bit16u count
, segment
, offset
, i
, size
;
5131 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5132 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5134 SET_DISK_RET_STATUS(0x00);
5136 /* basic check : device should be 0xE0+ */
5137 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5138 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5142 // Get the ata channel
5143 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5145 /* basic check : device has to be valid */
5146 if (device
>= BX_MAX_ATA_DEVICES
) {
5147 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5153 // all those functions return SUCCESS
5154 case 0x00: /* disk controller reset */
5155 case 0x09: /* initialize drive parameters */
5156 case 0x0c: /* seek to specified cylinder */
5157 case 0x0d: /* alternate disk reset */
5158 case 0x10: /* check drive ready */
5159 case 0x11: /* recalibrate */
5160 case 0x14: /* controller internal diagnostic */
5161 case 0x16: /* detect disk change */
5165 // all those functions return disk write-protected
5166 case 0x03: /* write disk sectors */
5167 case 0x05: /* format disk track */
5168 case 0x43: // IBM/MS extended write
5170 goto int13_fail_noah
;
5173 case 0x01: /* read disk status */
5174 status
= read_byte(0x0040, 0x0074);
5176 SET_DISK_RET_STATUS(0);
5178 /* set CF if error status read */
5179 if (status
) goto int13_fail_nostatus
;
5180 else goto int13_success_noah
;
5183 case 0x15: /* read disk drive size */
5185 goto int13_fail_noah
;
5188 case 0x41: // IBM/MS installation check
5189 BX
=0xaa55; // install check
5190 SET_AH(0x30); // EDD 2.1
5191 CX
=0x0007; // ext disk access, removable and edd
5192 goto int13_success_noah
;
5195 case 0x42: // IBM/MS extended read
5196 case 0x44: // IBM/MS verify sectors
5197 case 0x47: // IBM/MS extended seek
5199 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5200 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5201 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5203 // Can't use 64 bits lba
5204 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5206 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5211 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5213 // If verify or seek
5214 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5217 memsetb(get_SS(),atacmd
,0,12);
5218 atacmd
[0]=0x28; // READ command
5219 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5220 atacmd
[8]=(count
& 0x00ff); // Sectors
5221 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5222 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5223 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5224 atacmd
[5]=(lba
& 0x000000ff);
5225 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5227 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5228 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5231 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5233 goto int13_fail_noah
;
5239 case 0x45: // IBM/MS lock/unlock drive
5240 if (GET_AL() > 2) goto int13_fail
;
5242 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5246 if (locks
== 0xff) {
5249 goto int13_fail_noah
;
5251 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5255 if (locks
== 0x00) {
5258 goto int13_fail_noah
;
5260 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5261 SET_AL(locks
==0?0:1);
5264 SET_AL(locks
==0?0:1);
5270 case 0x46: // IBM/MS eject media
5271 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5274 SET_AH(0xb1); // media locked
5275 goto int13_fail_noah
;
5277 // FIXME should handle 0x31 no media in device
5278 // FIXME should handle 0xb5 valid request failed
5280 // Call removable media eject
5287 mov _int13_cdrom
.status
+ 2[bp
], ah
5288 jnc int13_cdrom_rme_end
5289 mov _int13_cdrom
.status
, #1
5290 int13_cdrom_rme_end
:
5295 SET_AH(0xb1); // media locked
5296 goto int13_fail_noah
;
5302 case 0x48: // IBM/MS get drive parameters
5303 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5305 // Buffer is too small
5311 Bit16u cylinders
, heads
, spt
, blksize
;
5313 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5315 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5316 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5317 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5318 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5319 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5320 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5321 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5322 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5327 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5328 Bit16u iobase1
, iobase2
, options
;
5330 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5332 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5333 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5336 channel
= device
/ 2;
5337 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5338 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5339 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5340 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5342 // FIXME atapi device
5343 options
= (1<<4); // lba translation
5344 options
|= (1<<5); // removable device
5345 options
|= (1<<6); // atapi device
5346 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5348 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5349 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5350 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5351 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5352 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5353 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5354 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5355 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5356 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5357 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5358 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5361 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5362 checksum
= ~checksum
;
5363 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5368 Bit8u channel
, iface
, checksum
, i
;
5371 channel
= device
/ 2;
5372 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5373 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5375 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5376 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5377 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5378 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5379 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5381 if (iface
==ATA_IFACE_ISA
) {
5382 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5383 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5384 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5385 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5390 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5391 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5392 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5393 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5395 if (iface
==ATA_IFACE_ISA
) {
5396 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5397 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5398 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5403 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5404 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5405 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5406 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5409 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5410 checksum
= ~checksum
;
5411 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5417 case 0x49: // IBM/MS extended media change
5418 // always send changed ??
5420 goto int13_fail_nostatus
;
5423 case 0x4e: // // IBM/MS set hardware configuration
5424 // DMA, prefetch, PIO maximum not supported
5437 // all those functions return unimplemented
5438 case 0x02: /* read sectors */
5439 case 0x04: /* verify sectors */
5440 case 0x08: /* read disk drive parameters */
5441 case 0x0a: /* read disk sectors with ECC */
5442 case 0x0b: /* write disk sectors with ECC */
5443 case 0x18: /* set media type for format */
5444 case 0x50: // ? - send packet command
5446 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5452 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5454 SET_DISK_RET_STATUS(GET_AH());
5455 int13_fail_nostatus
:
5456 SET_CF(); // error occurred
5460 SET_AH(0x00); // no error
5462 SET_DISK_RET_STATUS(0x00);
5463 CLEAR_CF(); // no error
5467 // ---------------------------------------------------------------------------
5468 // End of int13 for cdrom
5469 // ---------------------------------------------------------------------------
5471 #if BX_ELTORITO_BOOT
5472 // ---------------------------------------------------------------------------
5473 // Start of int13 for eltorito functions
5474 // ---------------------------------------------------------------------------
5477 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5478 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5480 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5482 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5483 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5487 // FIXME ElTorito Various. Should be implemented
5488 case 0x4a: // ElTorito - Initiate disk emu
5489 case 0x4c: // ElTorito - Initiate disk emu and boot
5490 case 0x4d: // ElTorito - Return Boot catalog
5491 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5495 case 0x4b: // ElTorito - Terminate disk emu
5496 // FIXME ElTorito Hardcoded
5497 write_byte(DS
,SI
+0x00,0x13);
5498 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5499 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5500 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5501 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5502 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5503 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5504 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5505 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5506 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5507 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5508 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5510 // If we have to terminate emulation
5511 if(GET_AL() == 0x00) {
5512 // FIXME ElTorito Various. Should be handled accordingly to spec
5513 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5520 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5526 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5527 SET_DISK_RET_STATUS(GET_AH());
5528 SET_CF(); // error occurred
5532 SET_AH(0x00); // no error
5533 SET_DISK_RET_STATUS(0x00);
5534 CLEAR_CF(); // no error
5538 // ---------------------------------------------------------------------------
5539 // End of int13 for eltorito functions
5540 // ---------------------------------------------------------------------------
5542 // ---------------------------------------------------------------------------
5543 // Start of int13 when emulating a device from the cd
5544 // ---------------------------------------------------------------------------
5547 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5548 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5550 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5551 Bit8u device
, status
;
5552 Bit16u vheads
, vspt
, vcylinders
;
5553 Bit16u head
, sector
, cylinder
, nbsectors
;
5554 Bit32u vlba
, ilba
, slba
, elba
;
5555 Bit16u before
, segment
, offset
;
5558 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5559 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5561 /* at this point, we are emulating a floppy/harddisk */
5563 // Recompute the device number
5564 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5565 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5567 SET_DISK_RET_STATUS(0x00);
5569 /* basic checks : emulation should be active, dl should equal the emulated drive */
5570 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5571 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5572 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5578 // all those functions return SUCCESS
5579 case 0x00: /* disk controller reset */
5580 case 0x09: /* initialize drive parameters */
5581 case 0x0c: /* seek to specified cylinder */
5582 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5583 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5584 case 0x11: /* recalibrate */
5585 case 0x14: /* controller internal diagnostic */
5586 case 0x16: /* detect disk change */
5590 // all those functions return disk write-protected
5591 case 0x03: /* write disk sectors */
5592 case 0x05: /* format disk track */
5594 goto int13_fail_noah
;
5597 case 0x01: /* read disk status */
5598 status
=read_byte(0x0040, 0x0074);
5600 SET_DISK_RET_STATUS(0);
5602 /* set CF if error status read */
5603 if (status
) goto int13_fail_nostatus
;
5604 else goto int13_success_noah
;
5607 case 0x02: // read disk sectors
5608 case 0x04: // verify disk sectors
5609 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5610 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5611 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5613 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5615 sector
= GET_CL() & 0x003f;
5616 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5618 nbsectors
= GET_AL();
5622 // no sector to read ?
5623 if(nbsectors
==0) goto int13_success
;
5625 // sanity checks sco openserver needs this!
5627 || (cylinder
>= vcylinders
)
5628 || (head
>= vheads
)) {
5632 // After controls, verify do nothing
5633 if (GET_AH() == 0x04) goto int13_success
;
5635 segment
= ES
+(BX
/ 16);
5638 // calculate the virtual lba inside the image
5639 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5641 // In advance so we don't loose the count
5645 slba
= (Bit32u
)vlba
/4;
5646 before
= (Bit16u
)vlba
%4;
5649 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5651 memsetb(get_SS(),atacmd
,0,12);
5652 atacmd
[0]=0x28; // READ command
5653 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5654 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5655 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5656 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5657 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5658 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5659 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5660 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5663 goto int13_fail_noah
;
5669 case 0x08: /* read disk drive parameters */
5670 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5671 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5672 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5676 SET_CH( vcylinders
& 0xff );
5677 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5679 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5680 // FIXME ElTorito Harddisk. should send the HD count
5682 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5683 case 0x01: SET_BL( 0x02 ); break;
5684 case 0x02: SET_BL( 0x04 ); break;
5685 case 0x03: SET_BL( 0x06 ); break;
5691 mov ax
, #diskette_param_table2
5692 mov _int13_cdemu
.DI
+2[bp
], ax
5693 mov _int13_cdemu
.ES
+2[bp
], cs
5699 case 0x15: /* read disk drive size */
5700 // FIXME ElTorito Harddisk. What geometry to send ?
5702 goto int13_success_noah
;
5705 // all those functions return unimplemented
5706 case 0x0a: /* read disk sectors with ECC */
5707 case 0x0b: /* write disk sectors with ECC */
5708 case 0x18: /* set media type for format */
5709 case 0x41: // IBM/MS installation check
5710 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5711 case 0x42: // IBM/MS extended read
5712 case 0x43: // IBM/MS extended write
5713 case 0x44: // IBM/MS verify sectors
5714 case 0x45: // IBM/MS lock/unlock drive
5715 case 0x46: // IBM/MS eject media
5716 case 0x47: // IBM/MS extended seek
5717 case 0x48: // IBM/MS get drive parameters
5718 case 0x49: // IBM/MS extended media change
5719 case 0x4e: // ? - set hardware configuration
5720 case 0x50: // ? - send packet command
5722 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5728 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5730 SET_DISK_RET_STATUS(GET_AH());
5731 int13_fail_nostatus
:
5732 SET_CF(); // error occurred
5736 SET_AH(0x00); // no error
5738 SET_DISK_RET_STATUS(0x00);
5739 CLEAR_CF(); // no error
5743 // ---------------------------------------------------------------------------
5744 // End of int13 when emulating a device from the cd
5745 // ---------------------------------------------------------------------------
5747 #endif // BX_ELTORITO_BOOT
5749 #else //BX_USE_ATADRV
5752 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
5767 mov ax
,4[bp
] // cylinder
5769 mov bl
,6[bp
] // hd_heads
5772 mov bl
,8[bp
] // head
5774 mov bl
,10[bp
] // hd_sectors
5776 mov bl
,12[bp
] // sector
5805 int13_harddisk(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5806 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5808 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
5812 Bit16u max_cylinder
, cylinder
, total_sectors
;
5813 Bit16u hd_cylinders
;
5814 Bit8u hd_heads
, hd_sectors
;
5821 Bit16u count
, segment
, offset
;
5825 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5827 write_byte(0x0040, 0x008e, 0); // clear completion flag
5829 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5831 /* check how many disks first (cmos reg 0x12), return an error if
5832 drive not present */
5833 drive_map
= inb_cmos(0x12);
5834 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
5835 (((drive_map
& 0x0f)==0) ? 0 : 2);
5836 n_drives
= (drive_map
==0) ? 0 :
5837 ((drive_map
==3) ? 2 : 1);
5839 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5841 SET_DISK_RET_STATUS(0x01);
5842 SET_CF(); /* error occurred */
5848 case 0x00: /* disk controller reset */
5849 BX_DEBUG_INT13_HD("int13_f00\n");
5852 SET_DISK_RET_STATUS(0);
5853 set_diskette_ret_status(0);
5854 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5855 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5856 CLEAR_CF(); /* successful */
5860 case 0x01: /* read disk status */
5861 BX_DEBUG_INT13_HD("int13_f01\n");
5862 status
= read_byte(0x0040, 0x0074);
5864 SET_DISK_RET_STATUS(0);
5865 /* set CF if error status read */
5866 if (status
) SET_CF();
5871 case 0x04: // verify disk sectors
5872 case 0x02: // read disk sectors
5874 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
5876 num_sectors
= GET_AL();
5877 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5878 sector
= (GET_CL() & 0x3f);
5882 if (hd_cylinders
> 1024) {
5883 if (hd_cylinders
<= 2048) {
5886 else if (hd_cylinders
<= 4096) {
5889 else if (hd_cylinders
<= 8192) {
5892 else { // hd_cylinders <= 16384
5896 ax
= head
/ hd_heads
;
5897 cyl_mod
= ax
& 0xff;
5899 cylinder
|= cyl_mod
;
5902 if ( (cylinder
>= hd_cylinders
) ||
5903 (sector
> hd_sectors
) ||
5904 (head
>= hd_heads
) ) {
5906 SET_DISK_RET_STATUS(1);
5907 SET_CF(); /* error occurred */
5911 if ( (num_sectors
> 128) || (num_sectors
== 0) )
5912 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5915 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5917 if ( GET_AH() == 0x04 ) {
5919 SET_DISK_RET_STATUS(0);
5924 status
= inb(0x1f7);
5925 if (status
& 0x80) {
5926 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5928 outb(0x01f2, num_sectors
);
5929 /* activate LBA? (tomv) */
5930 if (hd_heads
> 16) {
5931 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
5932 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
5935 outb(0x01f3, sector
);
5936 outb(0x01f4, cylinder
& 0x00ff);
5937 outb(0x01f5, cylinder
>> 8);
5938 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
5943 status
= inb(0x1f7);
5944 if ( !(status
& 0x80) ) break;
5947 if (status
& 0x01) {
5948 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
5949 } else if ( !(status
& 0x08) ) {
5950 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
5951 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
5958 sti
;; enable higher priority interrupts
5963 ;; store temp bx in real DI
register
5966 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
5969 ;; adjust
if there will be an overrun
5971 jbe i13_f02_no_adjust
5973 sub di
, #0x0200 ; sub 512 bytes from offset
5975 add ax
, #0x0020 ; add 512 to segment
5979 mov cx
, #0x0100 ;; counter (256 words = 512b)
5980 mov dx
, #0x01f0 ;; AT data read port
5983 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
5986 ;; store real DI
register back to temp bx
5989 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
5995 if (num_sectors
== 0) {
5996 status
= inb(0x1f7);
5997 if ( (status
& 0xc9) != 0x40 )
5998 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6002 status
= inb(0x1f7);
6003 if ( (status
& 0xc9) != 0x48 )
6004 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6010 SET_DISK_RET_STATUS(0);
6011 SET_AL(sector_count
);
6012 CLEAR_CF(); /* successful */
6017 case 0x03: /* write disk sectors */
6018 BX_DEBUG_INT13_HD("int13_f03\n");
6019 drive
= GET_ELDL ();
6020 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6022 num_sectors
= GET_AL();
6023 cylinder
= GET_CH();
6024 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6025 sector
= (GET_CL() & 0x3f);
6028 if (hd_cylinders
> 1024) {
6029 if (hd_cylinders
<= 2048) {
6032 else if (hd_cylinders
<= 4096) {
6035 else if (hd_cylinders
<= 8192) {
6038 else { // hd_cylinders <= 16384
6042 ax
= head
/ hd_heads
;
6043 cyl_mod
= ax
& 0xff;
6045 cylinder
|= cyl_mod
;
6048 if ( (cylinder
>= hd_cylinders
) ||
6049 (sector
> hd_sectors
) ||
6050 (head
>= hd_heads
) ) {
6052 SET_DISK_RET_STATUS(1);
6053 SET_CF(); /* error occurred */
6057 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6058 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6061 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6063 status
= inb(0x1f7);
6064 if (status
& 0x80) {
6065 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6067 // should check for Drive Ready Bit also in status reg
6068 outb(0x01f2, num_sectors
);
6070 /* activate LBA? (tomv) */
6071 if (hd_heads
> 16) {
6072 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6073 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6076 outb(0x01f3, sector
);
6077 outb(0x01f4, cylinder
& 0x00ff);
6078 outb(0x01f5, cylinder
>> 8);
6079 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6083 // wait for busy bit to turn off after seeking
6085 status
= inb(0x1f7);
6086 if ( !(status
& 0x80) ) break;
6089 if ( !(status
& 0x08) ) {
6090 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6091 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6098 sti
;; enable higher priority interrupts
6103 ;; store temp bx in real SI
register
6106 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6109 ;; adjust
if there will be an overrun
6111 jbe i13_f03_no_adjust
6113 sub si
, #0x0200 ; sub 512 bytes from offset
6115 add ax
, #0x0020 ; add 512 to segment
6119 mov cx
, #0x0100 ;; counter (256 words = 512b)
6120 mov dx
, #0x01f0 ;; AT data read port
6124 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6126 ;; store real SI
register back to temp bx
6129 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6135 if (num_sectors
== 0) {
6136 status
= inb(0x1f7);
6137 if ( (status
& 0xe9) != 0x40 )
6138 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6142 status
= inb(0x1f7);
6143 if ( (status
& 0xc9) != 0x48 )
6144 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6150 SET_DISK_RET_STATUS(0);
6151 SET_AL(sector_count
);
6152 CLEAR_CF(); /* successful */
6156 case 0x05: /* format disk track */
6157 BX_DEBUG_INT13_HD("int13_f05\n");
6158 BX_PANIC("format disk track called\n");
6161 SET_DISK_RET_STATUS(0);
6162 CLEAR_CF(); /* successful */
6166 case 0x08: /* read disk drive parameters */
6167 BX_DEBUG_INT13_HD("int13_f08\n");
6169 drive
= GET_ELDL ();
6170 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6174 if (hd_cylinders
<= 1024) {
6175 // hd_cylinders >>= 0;
6178 else if (hd_cylinders
<= 2048) {
6182 else if (hd_cylinders
<= 4096) {
6186 else if (hd_cylinders
<= 8192) {
6190 else { // hd_cylinders <= 16384
6195 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6197 SET_CH(max_cylinder
& 0xff);
6198 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6199 SET_DH(hd_heads
- 1);
6200 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6202 SET_DISK_RET_STATUS(0);
6203 CLEAR_CF(); /* successful */
6208 case 0x09: /* initialize drive parameters */
6209 BX_DEBUG_INT13_HD("int13_f09\n");
6211 SET_DISK_RET_STATUS(0);
6212 CLEAR_CF(); /* successful */
6216 case 0x0a: /* read disk sectors with ECC */
6217 BX_DEBUG_INT13_HD("int13_f0a\n");
6218 case 0x0b: /* write disk sectors with ECC */
6219 BX_DEBUG_INT13_HD("int13_f0b\n");
6220 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6224 case 0x0c: /* seek to specified cylinder */
6225 BX_DEBUG_INT13_HD("int13_f0c\n");
6226 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6228 SET_DISK_RET_STATUS(0);
6229 CLEAR_CF(); /* successful */
6233 case 0x0d: /* alternate disk reset */
6234 BX_DEBUG_INT13_HD("int13_f0d\n");
6236 SET_DISK_RET_STATUS(0);
6237 CLEAR_CF(); /* successful */
6241 case 0x10: /* check drive ready */
6242 BX_DEBUG_INT13_HD("int13_f10\n");
6244 //SET_DISK_RET_STATUS(0);
6245 //CLEAR_CF(); /* successful */
6249 // should look at 40:8E also???
6250 status
= inb(0x01f7);
6251 if ( (status
& 0xc0) == 0x40 ) {
6253 SET_DISK_RET_STATUS(0);
6254 CLEAR_CF(); // drive ready
6259 SET_DISK_RET_STATUS(0xAA);
6260 SET_CF(); // not ready
6265 case 0x11: /* recalibrate */
6266 BX_DEBUG_INT13_HD("int13_f11\n");
6268 SET_DISK_RET_STATUS(0);
6269 CLEAR_CF(); /* successful */
6273 case 0x14: /* controller internal diagnostic */
6274 BX_DEBUG_INT13_HD("int13_f14\n");
6276 SET_DISK_RET_STATUS(0);
6277 CLEAR_CF(); /* successful */
6282 case 0x15: /* read disk drive size */
6284 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6288 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6289 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6290 mul al
, ah
;; ax
= heads
* sectors
6291 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6292 dec bx
;; use (cylinders
- 1) ???
6293 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6294 ;; now we need to move the
32bit result dx
:ax to what the
6295 ;; BIOS wants which is cx
:dx
.
6296 ;; and then into CX
:DX on the stack
6297 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6298 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6301 SET_AH(3); // hard disk accessible
6302 SET_DISK_RET_STATUS(0); // ??? should this be 0
6303 CLEAR_CF(); // successful
6307 case 0x18: // set media type for format
6308 case 0x41: // IBM/MS
6309 case 0x42: // IBM/MS
6310 case 0x43: // IBM/MS
6311 case 0x44: // IBM/MS
6312 case 0x45: // IBM/MS lock/unlock drive
6313 case 0x46: // IBM/MS eject media
6314 case 0x47: // IBM/MS extended seek
6315 case 0x49: // IBM/MS extended media change
6316 case 0x50: // IBM/MS send packet command
6318 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6320 SET_AH(1); // code=invalid function in AH or invalid parameter
6321 SET_DISK_RET_STATUS(1);
6322 SET_CF(); /* unsuccessful */
6328 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6329 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6332 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6334 Bit16u
*hd_cylinders
;
6344 if (drive
== 0x80) {
6345 hd_type
= inb_cmos(0x12) & 0xf0;
6346 if (hd_type
!= 0xf0)
6347 BX_INFO(panic_msg_reg12h
,0);
6348 hd_type
= inb_cmos(0x19); // HD0: extended type
6350 BX_INFO(panic_msg_reg19h
,0,0x19);
6353 hd_type
= inb_cmos(0x12) & 0x0f;
6354 if (hd_type
!= 0x0f)
6355 BX_INFO(panic_msg_reg12h
,1);
6356 hd_type
= inb_cmos(0x1a); // HD0: extended type
6358 BX_INFO(panic_msg_reg19h
,0,0x1a);
6363 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6364 write_word(ss
, hd_cylinders
, cylinders
);
6367 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6369 // sectors per track
6370 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6373 #endif //else BX_USE_ATADRV
6376 //////////////////////
6377 // FLOPPY functions //
6378 //////////////////////
6380 void floppy_reset_controller()
6386 outb(0x03f2, val8
& ~0x04);
6387 outb(0x03f2, val8
| 0x04);
6389 // Wait for controller to come out of reset
6392 } while ( (val8
& 0xc0) != 0x80 );
6395 void floppy_prepare_controller(drive
)
6398 Bit8u val8
, dor
, prev_reset
;
6400 // set 40:3e bit 7 to 0
6401 val8
= read_byte(0x0040, 0x003e);
6403 write_byte(0x0040, 0x003e, val8
);
6405 // turn on motor of selected drive, DMA & int enabled, normal operation
6406 prev_reset
= inb(0x03f2) & 0x04;
6415 // reset the disk motor timeout value of INT 08
6416 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6418 // wait for drive readiness
6421 } while ( (val8
& 0xc0) != 0x80 );
6423 if (prev_reset
== 0) {
6424 // turn on interrupts
6428 // wait on 40:3e bit 7 to become 1
6430 val8
= read_byte(0x0040, 0x003e);
6431 } while ( (val8
& 0x80) == 0 );
6436 write_byte(0x0040, 0x003e, val8
);
6441 floppy_media_known(drive
)
6445 Bit16u media_state_offset
;
6447 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6454 media_state_offset
= 0x0090;
6456 media_state_offset
+= 1;
6458 val8
= read_byte(0x0040, media_state_offset
);
6459 val8
= (val8
>> 4) & 0x01;
6463 // check pass, return KNOWN
6468 floppy_media_sense(drive
)
6472 Bit16u media_state_offset
;
6473 Bit8u drive_type
, config_data
, media_state
;
6475 if (floppy_drive_recal(drive
) == 0) {
6479 // for now cheat and get drive type from CMOS,
6480 // assume media is same as drive type
6482 // ** config_data **
6483 // Bitfields for diskette media control:
6484 // Bit(s) Description (Table M0028)
6485 // 7-6 last data rate set by controller
6486 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6487 // 5-4 last diskette drive step rate selected
6488 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6489 // 3-2 {data rate at start of operation}
6492 // ** media_state **
6493 // Bitfields for diskette drive media state:
6494 // Bit(s) Description (Table M0030)
6496 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6497 // 5 double stepping required (e.g. 360kB in 1.2MB)
6498 // 4 media type established
6499 // 3 drive capable of supporting 4MB media
6500 // 2-0 on exit from BIOS, contains
6501 // 000 trying 360kB in 360kB
6502 // 001 trying 360kB in 1.2MB
6503 // 010 trying 1.2MB in 1.2MB
6504 // 011 360kB in 360kB established
6505 // 100 360kB in 1.2MB established
6506 // 101 1.2MB in 1.2MB established
6508 // 111 all other formats/drives
6510 drive_type
= inb_cmos(0x10);
6515 if ( drive_type
== 1 ) {
6517 config_data
= 0x00; // 0000 0000
6518 media_state
= 0x25; // 0010 0101
6521 else if ( drive_type
== 2 ) {
6522 // 1.2 MB 5.25" drive
6523 config_data
= 0x00; // 0000 0000
6524 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6527 else if ( drive_type
== 3 ) {
6529 config_data
= 0x00; // 0000 0000 ???
6530 media_state
= 0x17; // 0001 0111
6533 else if ( drive_type
== 4 ) {
6534 // 1.44 MB 3.5" drive
6535 config_data
= 0x00; // 0000 0000
6536 media_state
= 0x17; // 0001 0111
6539 else if ( drive_type
== 5 ) {
6540 // 2.88 MB 3.5" drive
6541 config_data
= 0xCC; // 1100 1100
6542 media_state
= 0xD7; // 1101 0111
6546 // Extended floppy size uses special cmos setting
6547 else if ( drive_type
== 6 ) {
6549 config_data
= 0x00; // 0000 0000
6550 media_state
= 0x27; // 0010 0111
6553 else if ( drive_type
== 7 ) {
6555 config_data
= 0x00; // 0000 0000
6556 media_state
= 0x27; // 0010 0111
6559 else if ( drive_type
== 8 ) {
6561 config_data
= 0x00; // 0000 0000
6562 media_state
= 0x27; // 0010 0111
6568 config_data
= 0x00; // 0000 0000
6569 media_state
= 0x00; // 0000 0000
6574 media_state_offset
= 0x90;
6576 media_state_offset
= 0x91;
6577 write_byte(0x0040, 0x008B, config_data
);
6578 write_byte(0x0040, media_state_offset
, media_state
);
6584 floppy_drive_recal(drive
)
6588 Bit16u curr_cyl_offset
;
6590 floppy_prepare_controller(drive
);
6592 // send Recalibrate command (2 bytes) to controller
6593 outb(0x03f5, 0x07); // 07: Recalibrate
6594 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6596 // turn on interrupts
6601 // wait on 40:3e bit 7 to become 1
6603 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6604 } while ( val8
== 0 );
6606 val8
= 0; // separate asm from while() loop
6607 // turn off interrupts
6612 // set 40:3e bit 7 to 0, and calibrated bit
6613 val8
= read_byte(0x0040, 0x003e);
6616 val8
|= 0x02; // Drive 1 calibrated
6617 curr_cyl_offset
= 0x0095;
6619 val8
|= 0x01; // Drive 0 calibrated
6620 curr_cyl_offset
= 0x0094;
6622 write_byte(0x0040, 0x003e, val8
);
6623 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6631 floppy_drive_exists(drive
)
6636 // check CMOS to see if drive exists
6637 drive_type
= inb_cmos(0x10);
6642 if ( drive_type
== 0 )
6648 #if BX_SUPPORT_FLOPPY
6650 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6651 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6653 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6654 Bit16u base_address
, base_count
, base_es
;
6655 Bit8u page
, mode_register
, val8
, dor
;
6656 Bit8u return_status
[7];
6657 Bit8u drive_type
, num_floppies
, ah
;
6658 Bit16u es
, last_addr
;
6660 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6661 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6666 case 0x00: // diskette controller reset
6667 BX_DEBUG_INT13_FL("floppy f00\n");
6670 SET_AH(1); // invalid param
6671 set_diskette_ret_status(1);
6675 drive_type
= inb_cmos(0x10);
6681 if (drive_type
== 0) {
6682 SET_AH(0x80); // drive not responding
6683 set_diskette_ret_status(0x80);
6688 set_diskette_ret_status(0);
6689 CLEAR_CF(); // successful
6690 set_diskette_current_cyl(drive
, 0); // current cylinder
6693 case 0x01: // Read Diskette Status
6695 val8
= read_byte(0x0000, 0x0441);
6702 case 0x02: // Read Diskette Sectors
6703 case 0x03: // Write Diskette Sectors
6704 case 0x04: // Verify Diskette Sectors
6705 num_sectors
= GET_AL();
6711 if ( (drive
> 1) || (head
> 1) ||
6712 (num_sectors
== 0) || (num_sectors
> 72) ) {
6713 BX_INFO("floppy: drive>1 || head>1 ...\n");
6715 set_diskette_ret_status(1);
6716 SET_AL(0); // no sectors read
6717 SET_CF(); // error occurred
6721 // see if drive exists
6722 if (floppy_drive_exists(drive
) == 0) {
6723 SET_AH(0x80); // not responding
6724 set_diskette_ret_status(0x80);
6725 SET_AL(0); // no sectors read
6726 SET_CF(); // error occurred
6730 // see if media in drive, and type is known
6731 if (floppy_media_known(drive
) == 0) {
6732 if (floppy_media_sense(drive
) == 0) {
6733 SET_AH(0x0C); // Media type not found
6734 set_diskette_ret_status(0x0C);
6735 SET_AL(0); // no sectors read
6736 SET_CF(); // error occurred
6742 // Read Diskette Sectors
6744 //-----------------------------------
6745 // set up DMA controller for transfer
6746 //-----------------------------------
6748 // es:bx = pointer to where to place information from diskette
6749 // port 04: DMA-1 base and current address, channel 2
6750 // port 05: DMA-1 base and current count, channel 2
6751 page
= (ES
>> 12); // upper 4 bits
6752 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6753 base_address
= base_es
+ BX
; // lower 16 bits of address
6754 // contributed by ES:BX
6755 if ( base_address
< base_es
) {
6756 // in case of carry, adjust page by 1
6759 base_count
= (num_sectors
* 512) - 1;
6761 // check for 64K boundary overrun
6762 last_addr
= base_address
+ base_count
;
6763 if (last_addr
< base_address
) {
6765 set_diskette_ret_status(0x09);
6766 SET_AL(0); // no sectors read
6767 SET_CF(); // error occurred
6771 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6774 BX_DEBUG_INT13_FL("clear flip-flop\n");
6775 outb(0x000c, 0x00); // clear flip-flop
6776 outb(0x0004, base_address
);
6777 outb(0x0004, base_address
>>8);
6778 BX_DEBUG_INT13_FL("clear flip-flop\n");
6779 outb(0x000c, 0x00); // clear flip-flop
6780 outb(0x0005, base_count
);
6781 outb(0x0005, base_count
>>8);
6783 // port 0b: DMA-1 Mode Register
6784 mode_register
= 0x46; // single mode, increment, autoinit disable,
6785 // transfer type=write, channel 2
6786 BX_DEBUG_INT13_FL("setting mode register\n");
6787 outb(0x000b, mode_register
);
6789 BX_DEBUG_INT13_FL("setting page register\n");
6790 // port 81: DMA-1 Page Register, channel 2
6793 BX_DEBUG_INT13_FL("unmask chan 2\n");
6794 outb(0x000a, 0x02); // unmask channel 2
6796 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6799 //--------------------------------------
6800 // set up floppy controller for transfer
6801 //--------------------------------------
6802 floppy_prepare_controller(drive
);
6804 // send read-normal-data command (9 bytes) to controller
6805 outb(0x03f5, 0xe6); // e6: read normal data
6806 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6807 outb(0x03f5, track
);
6809 outb(0x03f5, sector
);
6810 outb(0x03f5, 2); // 512 byte sector size
6811 outb(0x03f5, 0); // last sector number possible on track
6812 outb(0x03f5, 0); // Gap length
6813 outb(0x03f5, 0xff); // Gap length
6815 // turn on interrupts
6820 // wait on 40:3e bit 7 to become 1
6822 val8
= read_byte(0x0040, 0x0040);
6824 floppy_reset_controller();
6825 SET_AH(0x80); // drive not ready (timeout)
6826 set_diskette_ret_status(0x80);
6827 SET_AL(0); // no sectors read
6828 SET_CF(); // error occurred
6831 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6832 } while ( val8
== 0 );
6834 val8
= 0; // separate asm from while() loop
6835 // turn off interrupts
6840 // set 40:3e bit 7 to 0
6841 val8
= read_byte(0x0040, 0x003e);
6843 write_byte(0x0040, 0x003e, val8
);
6845 // check port 3f4 for accessibility to status bytes
6847 if ( (val8
& 0xc0) != 0xc0 )
6848 BX_PANIC("int13_diskette: ctrl not ready\n");
6850 // read 7 return status bytes from controller
6851 // using loop index broken, have to unroll...
6852 return_status
[0] = inb(0x3f5);
6853 return_status
[1] = inb(0x3f5);
6854 return_status
[2] = inb(0x3f5);
6855 return_status
[3] = inb(0x3f5);
6856 return_status
[4] = inb(0x3f5);
6857 return_status
[5] = inb(0x3f5);
6858 return_status
[6] = inb(0x3f5);
6859 // record in BIOS Data Area
6860 write_byte(0x0040, 0x0042, return_status
[0]);
6861 write_byte(0x0040, 0x0043, return_status
[1]);
6862 write_byte(0x0040, 0x0044, return_status
[2]);
6863 write_byte(0x0040, 0x0045, return_status
[3]);
6864 write_byte(0x0040, 0x0046, return_status
[4]);
6865 write_byte(0x0040, 0x0047, return_status
[5]);
6866 write_byte(0x0040, 0x0048, return_status
[6]);
6868 if ( (return_status
[0] & 0xc0) != 0 ) {
6870 set_diskette_ret_status(0x20);
6871 SET_AL(0); // no sectors read
6872 SET_CF(); // error occurred
6876 // ??? should track be new val from return_status[3] ?
6877 set_diskette_current_cyl(drive
, track
);
6878 // AL = number of sectors read (same value as passed)
6879 SET_AH(0x00); // success
6880 CLEAR_CF(); // success
6882 } else if (ah
== 0x03) {
6883 // Write Diskette Sectors
6885 //-----------------------------------
6886 // set up DMA controller for transfer
6887 //-----------------------------------
6889 // es:bx = pointer to where to place information from diskette
6890 // port 04: DMA-1 base and current address, channel 2
6891 // port 05: DMA-1 base and current count, channel 2
6892 page
= (ES
>> 12); // upper 4 bits
6893 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6894 base_address
= base_es
+ BX
; // lower 16 bits of address
6895 // contributed by ES:BX
6896 if ( base_address
< base_es
) {
6897 // in case of carry, adjust page by 1
6900 base_count
= (num_sectors
* 512) - 1;
6902 // check for 64K boundary overrun
6903 last_addr
= base_address
+ base_count
;
6904 if (last_addr
< base_address
) {
6906 set_diskette_ret_status(0x09);
6907 SET_AL(0); // no sectors read
6908 SET_CF(); // error occurred
6912 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6915 outb(0x000c, 0x00); // clear flip-flop
6916 outb(0x0004, base_address
);
6917 outb(0x0004, base_address
>>8);
6918 outb(0x000c, 0x00); // clear flip-flop
6919 outb(0x0005, base_count
);
6920 outb(0x0005, base_count
>>8);
6922 // port 0b: DMA-1 Mode Register
6923 mode_register
= 0x4a; // single mode, increment, autoinit disable,
6924 // transfer type=read, channel 2
6925 outb(0x000b, mode_register
);
6927 // port 81: DMA-1 Page Register, channel 2
6930 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6933 //--------------------------------------
6934 // set up floppy controller for transfer
6935 //--------------------------------------
6936 floppy_prepare_controller(drive
);
6938 // send write-normal-data command (9 bytes) to controller
6939 outb(0x03f5, 0xc5); // c5: write normal data
6940 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6941 outb(0x03f5, track
);
6943 outb(0x03f5, sector
);
6944 outb(0x03f5, 2); // 512 byte sector size
6945 outb(0x03f5, 0); // last sector number possible on track
6946 outb(0x03f5, 0); // Gap length
6947 outb(0x03f5, 0xff); // Gap length
6949 // turn on interrupts
6954 // wait on 40:3e bit 7 to become 1
6956 val8
= read_byte(0x0040, 0x0040);
6958 floppy_reset_controller();
6959 SET_AH(0x80); // drive not ready (timeout)
6960 set_diskette_ret_status(0x80);
6961 SET_AL(0); // no sectors written
6962 SET_CF(); // error occurred
6965 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6966 } while ( val8
== 0 );
6968 val8
= 0; // separate asm from while() loop
6969 // turn off interrupts
6974 // set 40:3e bit 7 to 0
6975 val8
= read_byte(0x0040, 0x003e);
6977 write_byte(0x0040, 0x003e, val8
);
6979 // check port 3f4 for accessibility to status bytes
6981 if ( (val8
& 0xc0) != 0xc0 )
6982 BX_PANIC("int13_diskette: ctrl not ready\n");
6984 // read 7 return status bytes from controller
6985 // using loop index broken, have to unroll...
6986 return_status
[0] = inb(0x3f5);
6987 return_status
[1] = inb(0x3f5);
6988 return_status
[2] = inb(0x3f5);
6989 return_status
[3] = inb(0x3f5);
6990 return_status
[4] = inb(0x3f5);
6991 return_status
[5] = inb(0x3f5);
6992 return_status
[6] = inb(0x3f5);
6993 // record in BIOS Data Area
6994 write_byte(0x0040, 0x0042, return_status
[0]);
6995 write_byte(0x0040, 0x0043, return_status
[1]);
6996 write_byte(0x0040, 0x0044, return_status
[2]);
6997 write_byte(0x0040, 0x0045, return_status
[3]);
6998 write_byte(0x0040, 0x0046, return_status
[4]);
6999 write_byte(0x0040, 0x0047, return_status
[5]);
7000 write_byte(0x0040, 0x0048, return_status
[6]);
7002 if ( (return_status
[0] & 0xc0) != 0 ) {
7003 if ( (return_status
[1] & 0x02) != 0 ) {
7004 // diskette not writable.
7005 // AH=status code=0x03 (tried to write on write-protected disk)
7006 // AL=number of sectors written=0
7011 BX_PANIC("int13_diskette_function: read error\n");
7015 // ??? should track be new val from return_status[3] ?
7016 set_diskette_current_cyl(drive
, track
);
7017 // AL = number of sectors read (same value as passed)
7018 SET_AH(0x00); // success
7019 CLEAR_CF(); // success
7021 } else { // if (ah == 0x04)
7022 // Verify Diskette Sectors
7024 // ??? should track be new val from return_status[3] ?
7025 set_diskette_current_cyl(drive
, track
);
7026 // AL = number of sectors verified (same value as passed)
7027 CLEAR_CF(); // success
7028 SET_AH(0x00); // success
7033 case 0x05: // format diskette track
7034 BX_DEBUG_INT13_FL("floppy f05\n");
7036 num_sectors
= GET_AL();
7041 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7042 (num_sectors
== 0) || (num_sectors
> 18)) {
7044 set_diskette_ret_status(1);
7045 SET_CF(); // error occurred
7048 // see if drive exists
7049 if (floppy_drive_exists(drive
) == 0) {
7050 SET_AH(0x80); // drive not responding
7051 set_diskette_ret_status(0x80);
7052 SET_CF(); // error occurred
7056 // see if media in drive, and type is known
7057 if (floppy_media_known(drive
) == 0) {
7058 if (floppy_media_sense(drive
) == 0) {
7059 SET_AH(0x0C); // Media type not found
7060 set_diskette_ret_status(0x0C);
7061 SET_AL(0); // no sectors read
7062 SET_CF(); // error occurred
7067 // set up DMA controller for transfer
7068 page
= (ES
>> 12); // upper 4 bits
7069 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7070 base_address
= base_es
+ BX
; // lower 16 bits of address
7071 // contributed by ES:BX
7072 if ( base_address
< base_es
) {
7073 // in case of carry, adjust page by 1
7076 base_count
= (num_sectors
* 4) - 1;
7078 // check for 64K boundary overrun
7079 last_addr
= base_address
+ base_count
;
7080 if (last_addr
< base_address
) {
7082 set_diskette_ret_status(0x09);
7083 SET_AL(0); // no sectors read
7084 SET_CF(); // error occurred
7089 outb(0x000c, 0x00); // clear flip-flop
7090 outb(0x0004, base_address
);
7091 outb(0x0004, base_address
>>8);
7092 outb(0x000c, 0x00); // clear flip-flop
7093 outb(0x0005, base_count
);
7094 outb(0x0005, base_count
>>8);
7095 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7096 // transfer type=read, channel 2
7097 outb(0x000b, mode_register
);
7098 // port 81: DMA-1 Page Register, channel 2
7102 // set up floppy controller for transfer
7103 floppy_prepare_controller(drive
);
7105 // send format-track command (6 bytes) to controller
7106 outb(0x03f5, 0x4d); // 4d: format track
7107 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7108 outb(0x03f5, 2); // 512 byte sector size
7109 outb(0x03f5, num_sectors
); // number of sectors per track
7110 outb(0x03f5, 0); // Gap length
7111 outb(0x03f5, 0xf6); // Fill byte
7112 // turn on interrupts
7117 // wait on 40:3e bit 7 to become 1
7119 val8
= read_byte(0x0040, 0x0040);
7121 floppy_reset_controller();
7122 SET_AH(0x80); // drive not ready (timeout)
7123 set_diskette_ret_status(0x80);
7124 SET_CF(); // error occurred
7127 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7128 } while ( val8
== 0 );
7130 val8
= 0; // separate asm from while() loop
7131 // turn off interrupts
7135 // set 40:3e bit 7 to 0
7136 val8
= read_byte(0x0040, 0x003e);
7138 write_byte(0x0040, 0x003e, val8
);
7139 // check port 3f4 for accessibility to status bytes
7141 if ( (val8
& 0xc0) != 0xc0 )
7142 BX_PANIC("int13_diskette: ctrl not ready\n");
7144 // read 7 return status bytes from controller
7145 // using loop index broken, have to unroll...
7146 return_status
[0] = inb(0x3f5);
7147 return_status
[1] = inb(0x3f5);
7148 return_status
[2] = inb(0x3f5);
7149 return_status
[3] = inb(0x3f5);
7150 return_status
[4] = inb(0x3f5);
7151 return_status
[5] = inb(0x3f5);
7152 return_status
[6] = inb(0x3f5);
7153 // record in BIOS Data Area
7154 write_byte(0x0040, 0x0042, return_status
[0]);
7155 write_byte(0x0040, 0x0043, return_status
[1]);
7156 write_byte(0x0040, 0x0044, return_status
[2]);
7157 write_byte(0x0040, 0x0045, return_status
[3]);
7158 write_byte(0x0040, 0x0046, return_status
[4]);
7159 write_byte(0x0040, 0x0047, return_status
[5]);
7160 write_byte(0x0040, 0x0048, return_status
[6]);
7162 if ( (return_status
[0] & 0xc0) != 0 ) {
7163 if ( (return_status
[1] & 0x02) != 0 ) {
7164 // diskette not writable.
7165 // AH=status code=0x03 (tried to write on write-protected disk)
7166 // AL=number of sectors written=0
7171 BX_PANIC("int13_diskette_function: write error\n");
7176 set_diskette_ret_status(0);
7177 set_diskette_current_cyl(drive
, 0);
7178 CLEAR_CF(); // successful
7182 case 0x08: // read diskette drive parameters
7183 BX_DEBUG_INT13_FL("floppy f08\n");
7193 SET_DL(num_floppies
);
7198 drive_type
= inb_cmos(0x10);
7200 if (drive_type
& 0xf0)
7202 if (drive_type
& 0x0f)
7214 SET_DL(num_floppies
);
7216 switch (drive_type
) {
7219 SET_DH(0); // max head #
7222 case 1: // 360KB, 5.25"
7223 CX
= 0x2709; // 40 tracks, 9 sectors
7224 SET_DH(1); // max head #
7227 case 2: // 1.2MB, 5.25"
7228 CX
= 0x4f0f; // 80 tracks, 15 sectors
7229 SET_DH(1); // max head #
7232 case 3: // 720KB, 3.5"
7233 CX
= 0x4f09; // 80 tracks, 9 sectors
7234 SET_DH(1); // max head #
7237 case 4: // 1.44MB, 3.5"
7238 CX
= 0x4f12; // 80 tracks, 18 sectors
7239 SET_DH(1); // max head #
7242 case 5: // 2.88MB, 3.5"
7243 CX
= 0x4f24; // 80 tracks, 36 sectors
7244 SET_DH(1); // max head #
7247 case 6: // 160k, 5.25"
7248 CX
= 0x2708; // 40 tracks, 8 sectors
7249 SET_DH(0); // max head #
7252 case 7: // 180k, 5.25"
7253 CX
= 0x2709; // 40 tracks, 9 sectors
7254 SET_DH(0); // max head #
7257 case 8: // 320k, 5.25"
7258 CX
= 0x2708; // 40 tracks, 8 sectors
7259 SET_DH(1); // max head #
7263 BX_PANIC("floppy: int13: bad floppy type\n");
7266 /* set es & di to point to 11 byte diskette param table in ROM */
7270 mov ax
, #diskette_param_table2
7271 mov _int13_diskette_function
.DI
+2[bp
], ax
7272 mov _int13_diskette_function
.ES
+2[bp
], cs
7275 CLEAR_CF(); // success
7276 /* disk status not changed upon success */
7280 case 0x15: // read diskette drive type
7281 BX_DEBUG_INT13_FL("floppy f15\n");
7284 SET_AH(0); // only 2 drives supported
7285 // set_diskette_ret_status here ???
7289 drive_type
= inb_cmos(0x10);
7295 CLEAR_CF(); // successful, not present
7296 if (drive_type
==0) {
7297 SET_AH(0); // drive not present
7300 SET_AH(1); // drive present, does not support change line
7305 case 0x16: // get diskette change line status
7306 BX_DEBUG_INT13_FL("floppy f16\n");
7309 SET_AH(0x01); // invalid drive
7310 set_diskette_ret_status(0x01);
7315 SET_AH(0x06); // change line not supported
7316 set_diskette_ret_status(0x06);
7320 case 0x17: // set diskette type for format(old)
7321 BX_DEBUG_INT13_FL("floppy f17\n");
7322 /* not used for 1.44M floppies */
7323 SET_AH(0x01); // not supported
7324 set_diskette_ret_status(1); /* not supported */
7328 case 0x18: // set diskette type for format(new)
7329 BX_DEBUG_INT13_FL("floppy f18\n");
7330 SET_AH(0x01); // do later
7331 set_diskette_ret_status(1);
7336 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7338 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7339 SET_AH(0x01); // ???
7340 set_diskette_ret_status(1);
7346 #else // #if BX_SUPPORT_FLOPPY
7348 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7349 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7353 switch ( GET_AH() ) {
7355 case 0x01: // Read Diskette Status
7357 val8
= read_byte(0x0000, 0x0441);
7366 write_byte(0x0000, 0x0441, 0x01);
7370 #endif // #if BX_SUPPORT_FLOPPY
7373 set_diskette_ret_status(value
)
7376 write_byte(0x0040, 0x0041, value
);
7380 set_diskette_current_cyl(drive
, cyl
)
7385 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7386 write_byte(0x0040, 0x0094+drive
, cyl
);
7390 determine_floppy_media(drive
)
7394 Bit8u val8
, DOR
, ctrl_info
;
7396 ctrl_info
= read_byte(0x0040, 0x008F);
7404 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7407 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7411 if ( (ctrl_info
& 0x04) != 0x04 ) {
7412 // Drive not determined means no drive exists, done.
7417 // check Main Status Register for readiness
7418 val8
= inb(0x03f4) & 0x80; // Main Status Register
7420 BX_PANIC("d_f_m: MRQ bit not set\n");
7424 // existing BDA values
7426 // turn on drive motor
7427 outb(0x03f2, DOR
); // Digital Output Register
7430 BX_PANIC("d_f_m: OK so far\n");
7435 int17_function(regs
, ds
, iret_addr
)
7436 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7437 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7438 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7440 Bit16u addr
,timeout
;
7447 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7448 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7449 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7450 if (regs
.u
.r8
.ah
== 0) {
7451 outb(addr
, regs
.u
.r8
.al
);
7453 outb(addr
+2, val8
| 0x01); // send strobe
7457 outb(addr
+2, val8
& ~0x01);
7458 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7462 if (regs
.u
.r8
.ah
== 1) {
7464 outb(addr
+2, val8
& ~0x04); // send init
7468 outb(addr
+2, val8
| 0x04);
7471 regs
.u
.r8
.ah
= (val8
^ 0x48);
7472 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7473 ClearCF(iret_addr
.flags
);
7475 SetCF(iret_addr
.flags
); // Unsupported
7479 // returns bootsegment in ax, drive in bl
7481 int19_function(bseqnr
)
7484 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7493 // if BX_ELTORITO_BOOT is not defined, old behavior
7494 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7495 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7496 // 0: system boot sequence, first drive C: then A:
7497 // 1: system boot sequence, first drive A: then C:
7498 // else BX_ELTORITO_BOOT is defined
7499 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7500 // CMOS reg 0x3D & 0x0f : 1st boot device
7501 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7502 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7503 // boot device codes:
7504 // 0x00 : not defined
7505 // 0x01 : first floppy
7506 // 0x02 : first harddrive
7507 // 0x03 : first cdrom
7508 // else : boot failure
7510 // Get the boot sequence
7511 #if BX_ELTORITO_BOOT
7512 bootseq
=inb_cmos(0x3d);
7513 bootseq
|=((inb_cmos(0x38) & 0xf0) << 4);
7515 if (bseqnr
==2) bootseq
>>= 4;
7516 if (bseqnr
==3) bootseq
>>= 8;
7517 if (bootseq
<0x10) lastdrive
= 1;
7518 bootdrv
=0x00; bootcd
=0;
7519 switch(bootseq
& 0x0f) {
7520 case 0x01: bootdrv
=0x00; bootcd
=0; break;
7521 case 0x02: bootdrv
=0x80; bootcd
=0; break;
7522 case 0x03: bootdrv
=0x00; bootcd
=1; break;
7523 default: return 0x00000000;
7526 bootseq
=inb_cmos(0x2d);
7532 bootdrv
=0x00; bootcd
=0;
7533 if((bootseq
&0x20)==0) bootdrv
=0x80;
7534 #endif // BX_ELTORITO_BOOT
7536 #if BX_ELTORITO_BOOT
7537 // We have to boot from cd
7539 status
= cdrom_boot();
7542 if ( (status
& 0x00ff) !=0 ) {
7543 print_cdromboot_failure(status
);
7544 print_boot_failure(bootcd
, bootdrv
, 1, lastdrive
);
7548 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7549 bootdrv
= (Bit8u
)(status
>>8);
7552 #endif // BX_ELTORITO_BOOT
7554 // We have to boot from harddisk or floppy
7563 mov _int19_function
.status
+ 2[bp
], ax
7564 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7565 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7566 mov es
, ax
;; segment
7567 mov bx
, #0x0000 ;; offset
7568 mov ah
, #0x02 ;; function 2, read diskette sector
7569 mov al
, #0x01 ;; read 1 sector
7570 mov ch
, #0x00 ;; track 0
7571 mov cl
, #0x01 ;; sector 1
7572 mov dh
, #0x00 ;; head 0
7573 int #0x13 ;; read sector
7576 mov _int19_function
.status
+ 2[bp
], ax
7583 print_boot_failure(bootcd
, bootdrv
, 1, lastdrive
);
7588 // check signature if instructed by cmos reg 0x38, only for floppy
7589 // bootchk = 1 : signature check disabled
7590 // bootchk = 0 : signature check enabled
7591 if (bootdrv
!= 0) bootchk
= 0;
7592 else bootchk
= inb_cmos(0x38) & 0x01;
7594 #if BX_ELTORITO_BOOT
7595 // if boot from cd, no signature check
7598 #endif // BX_ELTORITO_BOOT
7601 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7602 print_boot_failure(bootcd
, bootdrv
, 0, lastdrive
);
7607 #if BX_ELTORITO_BOOT
7608 // Print out the boot string
7609 print_boot_device(bootcd
, bootdrv
);
7610 #else // BX_ELTORITO_BOOT
7611 print_boot_device(0, bootdrv
);
7612 #endif // BX_ELTORITO_BOOT
7614 // return the boot segment
7615 return (((Bit32u
)bootdrv
) << 16) + bootseg
;
7619 int1a_function(regs
, ds
, iret_addr
)
7620 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7621 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7622 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7626 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
);
7632 switch (regs
.u
.r8
.ah
) {
7633 case 0: // get current clock count
7637 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7638 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7639 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7640 BiosData
->midnight_flag
= 0; // reset flag
7645 ClearCF(iret_addr
.flags
); // OK
7648 case 1: // Set Current Clock Count
7652 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7653 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7654 BiosData
->midnight_flag
= 0; // reset flag
7659 ClearCF(iret_addr
.flags
); // OK
7663 case 2: // Read CMOS Time
7664 if (rtc_updating()) {
7665 SetCF(iret_addr
.flags
);
7669 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7670 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7671 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7672 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7674 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7675 ClearCF(iret_addr
.flags
); // OK
7678 case 3: // Set CMOS Time
7679 // Using a debugger, I notice the following masking/setting
7680 // of bits in Status Register B, by setting Reg B to
7681 // a few values and getting its value after INT 1A was called.
7683 // try#1 try#2 try#3
7684 // before 1111 1101 0111 1101 0000 0000
7685 // after 0110 0010 0110 0010 0000 0010
7687 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7688 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7689 if (rtc_updating()) {
7691 // fall through as if an update were not in progress
7693 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7694 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7695 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7696 // Set Daylight Savings time enabled bit to requested value
7697 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7698 // (reg B already selected)
7699 outb_cmos(0x0b, val8
);
7701 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7702 ClearCF(iret_addr
.flags
); // OK
7705 case 4: // Read CMOS Date
7707 if (rtc_updating()) {
7708 SetCF(iret_addr
.flags
);
7711 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
7712 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
7713 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
7714 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
7715 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7716 ClearCF(iret_addr
.flags
); // OK
7719 case 5: // Set CMOS Date
7720 // Using a debugger, I notice the following masking/setting
7721 // of bits in Status Register B, by setting Reg B to
7722 // a few values and getting its value after INT 1A was called.
7724 // try#1 try#2 try#3 try#4
7725 // before 1111 1101 0111 1101 0000 0010 0000 0000
7726 // after 0110 1101 0111 1101 0000 0010 0000 0000
7728 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7729 // My assumption: RegB = (RegB & 01111111b)
7730 if (rtc_updating()) {
7732 SetCF(iret_addr
.flags
);
7735 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
7736 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
7737 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
7738 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
7739 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7740 outb_cmos(0x0b, val8
);
7742 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
7743 ClearCF(iret_addr
.flags
); // OK
7746 case 6: // Set Alarm Time in CMOS
7747 // Using a debugger, I notice the following masking/setting
7748 // of bits in Status Register B, by setting Reg B to
7749 // a few values and getting its value after INT 1A was called.
7751 // try#1 try#2 try#3
7752 // before 1101 1111 0101 1111 0000 0000
7753 // after 0110 1111 0111 1111 0010 0000
7755 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7756 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7757 val8
= inb_cmos(0x0b); // Get Status Reg B
7760 // Alarm interrupt enabled already
7761 SetCF(iret_addr
.flags
); // Error: alarm in use
7764 if (rtc_updating()) {
7766 // fall through as if an update were not in progress
7768 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
7769 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
7770 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
7771 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7772 // enable Status Reg B alarm bit, clear halt clock bit
7773 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
7774 ClearCF(iret_addr
.flags
); // OK
7777 case 7: // Turn off Alarm
7778 // Using a debugger, I notice the following masking/setting
7779 // of bits in Status Register B, by setting Reg B to
7780 // a few values and getting its value after INT 1A was called.
7782 // try#1 try#2 try#3 try#4
7783 // before 1111 1101 0111 1101 0010 0000 0010 0010
7784 // after 0100 0101 0101 0101 0000 0000 0000 0010
7786 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7787 // My assumption: RegB = (RegB & 01010111b)
7788 val8
= inb_cmos(0x0b); // Get Status Reg B
7789 // clear clock-halt bit, disable alarm bit
7790 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
7792 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7793 ClearCF(iret_addr
.flags
); // OK
7797 // real mode PCI BIOS functions now handled in assembler code
7798 // this C code handles the error code for information only
7799 if (regs
.u
.r8
.bl
== 0xff) {
7800 BX_INFO("PCI BIOS: PCI not present\n");
7801 } else if (regs
.u
.r8
.bl
== 0x81) {
7802 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
7803 } else if (regs
.u
.r8
.bl
== 0x83) {
7804 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
7805 } else if (regs
.u
.r8
.bl
== 0x86) {
7806 BX_INFO("PCI device %04x:%04x not found\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
);
7808 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
7809 SetCF(iret_addr
.flags
);
7814 SetCF(iret_addr
.flags
); // Unsupported
7819 int70_function(regs
, ds
, iret_addr
)
7820 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7821 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7822 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7824 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7825 Bit8u registerB
= 0, registerC
= 0;
7827 // Check which modes are enabled and have occurred.
7828 registerB
= inb_cmos( 0xB );
7829 registerC
= inb_cmos( 0xC );
7831 if( ( registerB
& 0x60 ) != 0 ) {
7832 if( ( registerC
& 0x20 ) != 0 ) {
7833 // Handle Alarm Interrupt.
7840 if( ( registerC
& 0x40 ) != 0 ) {
7841 // Handle Periodic Interrupt.
7843 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7844 // Wait Interval (Int 15, AH=83) active.
7845 Bit32u time
, toggle
;
7847 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
7848 if( time
< 0x3D1 ) {
7850 Bit16u segment
, offset
;
7852 segment
= read_word( 0x40, 0x98 );
7853 offset
= read_word( 0x40, 0x9A );
7854 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7855 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
7856 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
7858 // Continue waiting.
7860 write_dword( 0x40, 0x9C, time
);
7873 ;------------------------------------------
7874 ;- INT74h
: PS
/2 mouse hardware interrupt
-
7875 ;------------------------------------------
7880 push
#0x00 ;; placeholder for status
7881 push
#0x00 ;; placeholder for X
7882 push
#0x00 ;; placeholder for Y
7883 push
#0x00 ;; placeholder for Z
7884 push
#0x00 ;; placeholder for make_far_call boolean
7885 call _int74_function
7886 pop cx
;; remove make_far_call from stack
7889 ;; make far call to EBDA
:0022
7892 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
7894 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7899 add sp
, #8 ;; pop status, x, y, z
7901 pop ds
;; restore DS
7906 ;; This will perform an IRET
, but will retain value of current CF
7907 ;; by altering flags on stack
. Better than RETF
#02.
7912 and BYTE
[bp
+ 0x06], #0xfe
7918 or BYTE
[bp
+ 0x06], #0x01
7923 ;----------------------
7924 ;- INT13h (relocated
) -
7925 ;----------------------
7927 ; int13_relocated is a little bit messed up since I played with it
7928 ; I have to rewrite it
:
7929 ; - call a function that detect which function to call
7930 ; - make all called C function get the same parameters list
7934 #if BX_ELTORITO_BOOT
7935 ;; check
for an eltorito function
7937 jb int13_not_eltorito
7939 ja int13_not_eltorito
7948 jmp _int13_eltorito
;; ELDX
not used
7956 ;; check
if emulation active
7957 call _cdemu_isactive
7959 je int13_cdemu_inactive
7961 ;; check
if access to the emulated drive
7962 call _cdemu_emulated_drive
7965 cmp al
,dl
;; int13 on emulated drive
7980 jmp _int13_cdemu
;; ELDX
not used
7983 and dl
,#0xE0 ;; mask to get device class, including cdroms
7984 cmp al
,dl
;; al is
0x00 or 0x80
7985 jne int13_cdemu_inactive
;; inactive
for device
class
7997 dec dl
;; real drive is dl
- 1
8000 int13_cdemu_inactive
:
8006 #endif // BX_ELTORITO_BOOT
8017 push dx
;; push eltorito value of dx instead of sp
8028 ;; now the
16-bit registers can be restored with
:
8029 ;; pop ds
; pop es
; popa
; iret
8030 ;; arguments passed to functions should be
8031 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8037 jmp _int13_diskette_function
8046 // ebx is modified: BSD 5.2.1 boot loader problem
8047 // someone should figure out which 32 bit register that actually are used
8064 call _int13_harddisk
8076 int18_handler
: ;; Boot Failure routing
8077 call _int18_panic_msg
8084 int19_relocated
: ;; Boot function
, relocated
8086 ;; int19 was beginning to be really
complex, so now it
8087 ;; just calls an C function
, that does the work
8088 ;; it returns in BL the boot drive
, and in AX the boot segment
8089 ;; the boot segment will be
0x0000 if something has failed
8101 call _int19_function
8104 ;; bl contains the boot drive
8105 ;; ax contains the boot segment
or 0 if failure
8107 test ax
, ax
;; if ax is
0 try next boot device
8113 call _int19_function
8116 test ax
, ax
;; if ax is
0 try next boot device
8122 call _int19_function
8125 test ax
, ax
;; if ax is
0 call int18
8129 mov dl
, bl
;; set drive so guest os find it
8130 shl eax
, #0x04 ;; convert seg to ip
8131 mov
2[bp
], ax
;; set ip
8133 shr eax
, #0x04 ;; get cs back
8134 and ax
, #0xF000 ;; remove what went in ip
8135 mov
4[bp
], ax
;; set cs
8137 mov es
, ax
;; set es to zero fixes
[ 549815 ]
8138 mov
[bp
], ax
;; set bp to zero
8139 mov ax
, #0xaa55 ;; set ok flag
8142 iret
;; Beam me up Scotty
8147 int1c_handler
: ;; User Timer Tick
8151 ;----------------------
8152 ;- POST
: Floppy Drive
-
8153 ;----------------------
8159 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8161 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8163 mov
0x0440, al
;; diskette motor timeout counter
: not active
8164 mov
0x0441, al
;; diskette controller status
return code
8166 mov
0x0442, al
;; disk
& diskette controller status
register 0
8167 mov
0x0443, al
;; diskette controller status
register 1
8168 mov
0x0444, al
;; diskette controller status
register 2
8169 mov
0x0445, al
;; diskette controller cylinder number
8170 mov
0x0446, al
;; diskette controller head number
8171 mov
0x0447, al
;; diskette controller sector number
8172 mov
0x0448, al
;; diskette controller bytes written
8174 mov
0x048b, al
;; diskette configuration data
8176 ;; -----------------------------------------------------------------
8177 ;; (048F
) diskette controller information
8179 mov al
, #0x10 ;; get CMOS diskette drive type
8182 mov ah
, al
;; save byte to AH
8185 shr al
, #4 ;; look at top 4 bits for drive 0
8186 jz f0_missing
;; jump
if no drive0
8187 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8190 mov bl
, #0x00 ;; no drive0
8193 mov al
, ah
;; restore from AH
8194 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8195 jz f1_missing
;; jump
if no drive1
8196 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8198 ;; leave high bits in BL zerod
8199 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8200 ;; -----------------------------------------------------------------
8203 mov
0x0490, al
;; diskette
0 media state
8204 mov
0x0491, al
;; diskette
1 media state
8206 ;; diskette
0,1 operational starting state
8207 ;; drive type has
not been determined
,
8208 ;; has no changed detection line
8212 mov
0x0494, al
;; diskette
0 current cylinder
8213 mov
0x0495, al
;; diskette
1 current cylinder
8216 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8218 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8219 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8220 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8225 ;--------------------
8226 ;- POST
: HARD DRIVE
-
8227 ;--------------------
8228 ; relocated here because the primary POST area isnt big enough
.
8231 // INT 76h calls INT 15h function ax=9100
8233 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8239 mov
0x0474, al
/* hard disk status of last operation */
8240 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8241 mov
0x048c, al
/* hard disk status register */
8242 mov
0x048d, al
/* hard disk error register */
8243 mov
0x048e, al
/* hard disk task complete flag */
8245 mov
0x0475, al
/* hard disk number attached */
8247 mov
0x0476, al
/* hard disk control byte */
8248 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8249 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8250 ;; INT
41h
: hard disk
0 configuration pointer
8251 ;; INT
46h
: hard disk
1 configuration pointer
8252 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8253 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8255 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8267 cmp al
, #47 ;; decimal 47 - user definable
8271 ;; CMOS purpose param table offset
8272 ;; 1b cylinders low
0
8273 ;; 1c cylinders high
1
8275 ;; 1e write pre
-comp low
5
8276 ;; 1f write pre
-comp high
6
8277 ;; 20 retries
/bad map
/heads
>8 8
8278 ;; 21 landing zone low C
8279 ;; 22 landing zone high D
8280 ;; 23 sectors
/track E
8285 ;;; Filling EBDA table
for hard disk
0.
8293 mov (0x003d + 0x05), ax
;; write precomp word
8298 mov (0x003d + 0x08), al
;; drive control byte
8307 mov (0x003d + 0x0C), ax
;; landing zone word
8309 mov al
, #0x1c ;; get cylinders word in AX
8311 in al
, #0x71 ;; high byte
8315 in al
, #0x71 ;; low byte
8316 mov bx
, ax
;; BX
= cylinders
8321 mov cl
, al
;; CL
= heads
8326 mov dl
, al
;; DL
= sectors
8329 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8331 hd0_post_physical_chs
:
8332 ;; no logical CHS mapping used
, just physical CHS
8333 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8334 mov (0x003d + 0x00), bx
;; number of physical cylinders
8335 mov (0x003d + 0x02), cl
;; number of physical heads
8336 mov (0x003d + 0x0E), dl
;; number of physical sectors
8339 hd0_post_logical_chs
:
8340 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8341 mov (0x003d + 0x09), bx
;; number of physical cylinders
8342 mov (0x003d + 0x0b), cl
;; number of physical heads
8343 mov (0x003d + 0x04), dl
;; number of physical sectors
8344 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8346 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8349 jnbe hd0_post_above_2048
8350 ;; 1024 < c
<= 2048 cylinders
8353 jmp hd0_post_store_logical
8355 hd0_post_above_2048
:
8357 jnbe hd0_post_above_4096
8358 ;; 2048 < c
<= 4096 cylinders
8361 jmp hd0_post_store_logical
8363 hd0_post_above_4096
:
8365 jnbe hd0_post_above_8192
8366 ;; 4096 < c
<= 8192 cylinders
8369 jmp hd0_post_store_logical
8371 hd0_post_above_8192
:
8372 ;; 8192 < c
<= 16384 cylinders
8376 hd0_post_store_logical
:
8377 mov (0x003d + 0x00), bx
;; number of physical cylinders
8378 mov (0x003d + 0x02), cl
;; number of physical heads
8380 mov cl
, #0x0f ;; repeat count
8381 mov si
, #0x003d ;; offset to disk0 FDPT
8382 mov al
, #0x00 ;; sum
8383 hd0_post_checksum_loop
:
8387 jnz hd0_post_checksum_loop
8388 not al
;; now take
2s complement
8391 ;;; Done filling EBDA table
for hard disk
0.
8395 ;; is there really a second hard disk
? if not, return now
8403 ;; check that the hd type is really
0x0f.
8408 ;; check that the extended type is
47 - user definable
8412 cmp al
, #47 ;; decimal 47 - user definable
8417 ;; CMOS purpose param table offset
8418 ;; 0x24 cylinders low
0
8419 ;; 0x25 cylinders high
1
8421 ;; 0x27 write pre
-comp low
5
8422 ;; 0x28 write pre
-comp high
6
8424 ;; 0x2a landing zone low C
8425 ;; 0x2b landing zone high D
8426 ;; 0x2c sectors
/track E
8427 ;;; Fill EBDA table
for hard disk
1.
8437 mov (0x004d + 0x05), ax
;; write precomp word
8442 mov (0x004d + 0x08), al
;; drive control byte
8451 mov (0x004d + 0x0C), ax
;; landing zone word
8453 mov al
, #0x25 ;; get cylinders word in AX
8455 in al
, #0x71 ;; high byte
8459 in al
, #0x71 ;; low byte
8460 mov bx
, ax
;; BX
= cylinders
8465 mov cl
, al
;; CL
= heads
8470 mov dl
, al
;; DL
= sectors
8473 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8475 hd1_post_physical_chs
:
8476 ;; no logical CHS mapping used
, just physical CHS
8477 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8478 mov (0x004d + 0x00), bx
;; number of physical cylinders
8479 mov (0x004d + 0x02), cl
;; number of physical heads
8480 mov (0x004d + 0x0E), dl
;; number of physical sectors
8483 hd1_post_logical_chs
:
8484 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8485 mov (0x004d + 0x09), bx
;; number of physical cylinders
8486 mov (0x004d + 0x0b), cl
;; number of physical heads
8487 mov (0x004d + 0x04), dl
;; number of physical sectors
8488 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8490 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8493 jnbe hd1_post_above_2048
8494 ;; 1024 < c
<= 2048 cylinders
8497 jmp hd1_post_store_logical
8499 hd1_post_above_2048
:
8501 jnbe hd1_post_above_4096
8502 ;; 2048 < c
<= 4096 cylinders
8505 jmp hd1_post_store_logical
8507 hd1_post_above_4096
:
8509 jnbe hd1_post_above_8192
8510 ;; 4096 < c
<= 8192 cylinders
8513 jmp hd1_post_store_logical
8515 hd1_post_above_8192
:
8516 ;; 8192 < c
<= 16384 cylinders
8520 hd1_post_store_logical
:
8521 mov (0x004d + 0x00), bx
;; number of physical cylinders
8522 mov (0x004d + 0x02), cl
;; number of physical heads
8524 mov cl
, #0x0f ;; repeat count
8525 mov si
, #0x004d ;; offset to disk0 FDPT
8526 mov al
, #0x00 ;; sum
8527 hd1_post_checksum_loop
:
8531 jnz hd1_post_checksum_loop
8532 not al
;; now take
2s complement
8535 ;;; Done filling EBDA table
for hard disk
1.
8539 ;--------------------
8540 ;- POST
: EBDA segment
8541 ;--------------------
8542 ; relocated here because the primary POST area isnt big enough
.
8547 mov byte ptr
[0x0], #EBDA_SIZE
8549 xor ax
, ax
; mov EBDA seg into
40E
8551 mov word ptr
[0x40E], #EBDA_SEG
8554 ;--------------------
8555 ;- POST
: EOI
+ jmp via
[0x40:67)
8556 ;--------------------
8557 ; relocated here because the primary POST area isnt big enough
.
8567 ;--------------------
8570 out
#0xA0, al ;; slave PIC EOI
8573 out
#0x20, al ;; master PIC EOI
8576 ;--------------------
8578 ;; in
: AL in BCD format
8579 ;; out
: AL in binary format
, AH will always be
0
8582 and bl
, #0x0f ;; bl has low digit
8583 shr al
, #4 ;; al has high digit
8585 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8586 add al
, bl
;; then add low digit
8589 ;--------------------
8591 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8592 ;; Timer Ticks Roller
Flag (0x470:byte
)
8593 ;; The Timer Ticks Count needs to be set according to
8594 ;; the current CMOS time
, as
if ticks have been occurring
8595 ;; at
18.2hz since midnight up to
this point
. Calculating
8596 ;; this is a little complicated
. Here are the factors I gather
8597 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8598 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8599 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8600 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8601 ;; the timer
. With a maximum
16bit timer count
, this is again
8602 ;; divided down by
65536 to
18.2hz
.
8604 ;; 14,318,180 Hz clock
8605 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8606 ;; /4 = 1,193,181 Hz fed to timer
8607 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8608 ;; 1 second
= 18.20650736 ticks
8609 ;; 1 minute
= 1092.390442 ticks
8610 ;; 1 hour
= 65543.42651 ticks
8612 ;; Given the values in the CMOS clock
, one could calculate
8613 ;; the number of ticks by the following
:
8614 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8615 ;; (BcdToBin(minutes
) * 1092.3904)
8616 ;; (BcdToBin(hours
) * 65543.427)
8617 ;; To get a little more accuracy
, since Im
using integer
8618 ;; arithmatic
, I use
:
8619 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8620 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8621 ;; (BcdToBin(hours
) * 65543427) / 1000
8626 xor eax
, eax
;; clear EAX
8629 in al
, #0x71 ;; AL has CMOS seconds in BCD
8630 call BcdToBin
;; EAX now has seconds in binary
8636 mov ecx
, eax
;; ECX will accumulate total ticks
8639 xor eax
, eax
;; clear EAX
8642 in al
, #0x71 ;; AL has CMOS minutes in BCD
8643 call BcdToBin
;; EAX now has minutes in binary
8649 add ecx
, eax
;; add to total ticks
8652 xor eax
, eax
;; clear EAX
8655 in al
, #0x71 ;; AL has CMOS hours in BCD
8656 call BcdToBin
;; EAX now has hours in binary
8662 add ecx
, eax
;; add to total ticks
8664 mov
0x46C, ecx
;; Timer Ticks Count
8666 mov
0x470, al
;; Timer Ticks Rollover Flag
8669 ;--------------------
8671 ;; record completion in BIOS task complete flag
8683 ;--------------------
8688 #include "apmbios.S"
8692 #include "apmbios.S"
8695 #include "apmbios.S"
8699 ;--------------------
8704 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8705 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8706 db
0 ;; revision level
8707 ;; length in paragraphs
and checksum stored in a word to prevent errors
8708 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8709 & 0xff) << 8) + 0x01
8710 db
0,0,0,0,0 ;; reserved
8715 cmp eax
, #0x49435024 ;; "$PCI"
8717 mov eax
, #0x80000000
8722 #ifdef PCI_FIXED_HOST_BRIDGE
8723 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8726 ;; say ok
if a device is present
8727 cmp eax
, #0xffffffff
8730 mov ebx
, #0x000f0000
8732 mov edx
, #pcibios_protected
8747 cmp al
, #0x01 ;; installation check
8751 mov edx
, #0x20494350 ;; "PCI "
8754 pci_pro_f02
: ;; find pci device
8762 call pci_pro_select_reg
8776 pci_pro_f08
: ;; read configuration byte
8779 call pci_pro_select_reg
8788 pci_pro_f09
: ;; read configuration word
8791 call pci_pro_select_reg
8800 pci_pro_f0a
: ;; read configuration dword
8803 call pci_pro_select_reg
8810 pci_pro_f0b
: ;; write configuration byte
8813 call pci_pro_select_reg
8822 pci_pro_f0c
: ;; write configuration word
8825 call pci_pro_select_reg
8834 pci_pro_f0d
: ;; write configuration dword
8837 call pci_pro_select_reg
8880 mov eax
, #0x80000000
8885 #ifdef PCI_FIXED_HOST_BRIDGE
8886 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8889 ;; say ok
if a device is present
8890 cmp eax
, #0xffffffff
8901 cmp al
, #0x01 ;; installation check
8906 mov edx
, #0x20494350 ;; "PCI "
8908 mov di
, #pcibios_protected
8911 pci_real_f02
: ;; find pci device
8921 call pci_real_select_reg
8925 jne pci_real_nextdev
8932 jne pci_real_devloop
8937 pci_real_f08
: ;; read configuration byte
8940 call pci_real_select_reg
8949 pci_real_f09
: ;; read configuration word
8952 call pci_real_select_reg
8961 pci_real_f0a
: ;; read configuration dword
8964 call pci_real_select_reg
8971 pci_real_f0b
: ;; write configuration byte
8974 call pci_real_select_reg
8983 pci_real_f0c
: ;; write configuration word
8986 call pci_real_select_reg
8995 pci_real_f0d
: ;; write configuration dword
8997 jne pci_real_unknown
8998 call pci_real_select_reg
9019 pci_real_select_reg
:
9033 pci_routing_table_structure
:
9034 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9036 dw
32 + (6 * 16) ;; table size
9037 db
0 ;; PCI interrupt router bus
9038 db
0x08 ;; PCI interrupt router DevFunc
9039 dw
0x0000 ;; PCI exclusive IRQs
9040 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9041 dw
0x7000 ;; compatible PCI interrupt router device ID
9042 dw
0,0 ;; Miniport data
9043 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9045 ;; first slot entry PCI
-to
-ISA (embedded
)
9046 db
0 ;; pci bus number
9047 db
0x08 ;; pci device
number (bit
7-3)
9048 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9049 dw
0xdef8 ;; IRQ bitmap INTA
#
9050 db
0x61 ;; link value INTB
#
9051 dw
0xdef8 ;; IRQ bitmap INTB
#
9052 db
0x62 ;; link value INTC
#
9053 dw
0xdef8 ;; IRQ bitmap INTC
#
9054 db
0x63 ;; link value INTD
#
9055 dw
0xdef8 ;; IRQ bitmap INTD
#
9056 db
0 ;; physical
slot (0 = embedded
)
9058 ;; second slot entry
: 1st PCI slot
9059 db
0 ;; pci bus number
9060 db
0x10 ;; pci device
number (bit
7-3)
9061 db
0x61 ;; link value INTA
#
9062 dw
0xdef8 ;; IRQ bitmap INTA
#
9063 db
0x62 ;; link value INTB
#
9064 dw
0xdef8 ;; IRQ bitmap INTB
#
9065 db
0x63 ;; link value INTC
#
9066 dw
0xdef8 ;; IRQ bitmap INTC
#
9067 db
0x60 ;; link value INTD
#
9068 dw
0xdef8 ;; IRQ bitmap INTD
#
9069 db
1 ;; physical
slot (0 = embedded
)
9071 ;; third slot entry
: 2nd PCI slot
9072 db
0 ;; pci bus number
9073 db
0x18 ;; pci device
number (bit
7-3)
9074 db
0x62 ;; link value INTA
#
9075 dw
0xdef8 ;; IRQ bitmap INTA
#
9076 db
0x63 ;; link value INTB
#
9077 dw
0xdef8 ;; IRQ bitmap INTB
#
9078 db
0x60 ;; link value INTC
#
9079 dw
0xdef8 ;; IRQ bitmap INTC
#
9080 db
0x61 ;; link value INTD
#
9081 dw
0xdef8 ;; IRQ bitmap INTD
#
9082 db
2 ;; physical
slot (0 = embedded
)
9084 ;; 4th slot entry
: 3rd PCI slot
9085 db
0 ;; pci bus number
9086 db
0x20 ;; pci device
number (bit
7-3)
9087 db
0x63 ;; link value INTA
#
9088 dw
0xdef8 ;; IRQ bitmap INTA
#
9089 db
0x60 ;; link value INTB
#
9090 dw
0xdef8 ;; IRQ bitmap INTB
#
9091 db
0x61 ;; link value INTC
#
9092 dw
0xdef8 ;; IRQ bitmap INTC
#
9093 db
0x62 ;; link value INTD
#
9094 dw
0xdef8 ;; IRQ bitmap INTD
#
9095 db
3 ;; physical
slot (0 = embedded
)
9097 ;; 5th slot entry
: 4rd PCI slot
9098 db
0 ;; pci bus number
9099 db
0x28 ;; pci device
number (bit
7-3)
9100 db
0x60 ;; link value INTA
#
9101 dw
0xdef8 ;; IRQ bitmap INTA
#
9102 db
0x61 ;; link value INTB
#
9103 dw
0xdef8 ;; IRQ bitmap INTB
#
9104 db
0x62 ;; link value INTC
#
9105 dw
0xdef8 ;; IRQ bitmap INTC
#
9106 db
0x63 ;; link value INTD
#
9107 dw
0xdef8 ;; IRQ bitmap INTD
#
9108 db
4 ;; physical
slot (0 = embedded
)
9110 ;; 6th slot entry
: 5rd PCI slot
9111 db
0 ;; pci bus number
9112 db
0x30 ;; pci device
number (bit
7-3)
9113 db
0x61 ;; link value INTA
#
9114 dw
0xdef8 ;; IRQ bitmap INTA
#
9115 db
0x62 ;; link value INTB
#
9116 dw
0xdef8 ;; IRQ bitmap INTB
#
9117 db
0x63 ;; link value INTC
#
9118 dw
0xdef8 ;; IRQ bitmap INTC
#
9119 db
0x60 ;; link value INTD
#
9120 dw
0xdef8 ;; IRQ bitmap INTD
#
9121 db
5 ;; physical
slot (0 = embedded
)
9127 pcibios_init_sel_reg
:
9139 pcibios_init_set_elcr
:
9163 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9168 mov si
, #pci_routing_table_structure
9172 call pcibios_init_sel_reg
9175 cmp eax
, [si
+12] ;; check irq router
9178 call pcibios_init_sel_reg
9179 push bx
;; save irq router bus
+ devfunc
9182 out dx
, ax
;; reset PIRQ route control
9190 add si
, #0x20 ;; set pointer to 1st entry
9192 mov ax
, #pci_irq_list
9201 call pcibios_init_sel_reg
9205 jnz pci_test_int_pin
9211 call pcibios_init_sel_reg
9216 dec al
;; determine pirq reg
9225 call pcibios_init_sel_reg
9232 mov bx
, [bp
-2] ;; pci irq list pointer
9237 call pcibios_init_set_elcr
9241 add bl
, [bp
-3] ;; pci function number
9243 call pcibios_init_sel_reg
9253 mov byte ptr
[bp
-3], #0x00
9261 #endif // BX_PCIBIOS
9263 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9268 and al
, #0xdf ; clear input mode
9278 mov
[bx
+0x408], dx
; Parallel I
/O address
9280 mov
[bx
+0x478], cl
; Parallel printer timeout
9285 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9304 mov
[bx
+0x400], dx
; Serial I
/O address
9306 mov
[bx
+0x47c], cl
; Serial timeout
9333 ;; Scan
for existence of valid expansion ROMS
.
9334 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9335 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9336 ;; System ROM
: only
0xE0000
9342 ;; 2 ROM length in
512-byte blocks
9343 ;; 3 ROM initialization entry
point (FAR CALL
)
9348 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9349 cmp
[0], #0xAA55 ;; look for signature
9350 jne rom_scan_increment
9352 jnz rom_scan_increment
9353 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9355 ;; We want our increment in
512-byte quantities
, rounded to
9356 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9358 jz block_count_rounded
9359 and al
, #0xfc ;; needs rounding up
9361 block_count_rounded
:
9363 xor bx
, bx
;; Restore DS back to
0000:
9366 ;; Push addr of ROM entry point
9368 push
#0x0003 ;; Push offset
9369 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9370 db
0xff ;; call_far ss
:[bp
+0]
9373 cli
;; In
case expansion ROM BIOS turns IF on
9374 add sp
, #2 ;; Pop offset value
9375 pop cx
;; Pop seg
value (restore CX
)
9376 pop ax
;; Restore AX
9378 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
9379 ;; because the segment selector is shifted left
4 bits
.
9384 xor ax
, ax
;; Restore DS back to
0000:
9388 ;; for 'C' strings
and other data
, insert them here with
9389 ;; a the following hack
:
9390 ;; DATA_SEG_DEFS_HERE
9396 .org
0xe05b ; POST Entry Point
9401 ;; first reset the DMA controllers
9405 ;; then initialize the DMA controllers
9407 out
0xD6, al
; cascade mode of channel
4 enabled
9409 out
0xD4, al
; unmask channel
4
9411 ;; Examine CMOS shutdown status
.
9419 ;; Reset CMOS shutdown status
.
9421 out
0x70, AL
; select CMOS
register Fh
9423 out
0x71, AL
; set shutdown action to normal
9425 ;; Examine CMOS shutdown status
.
9428 ;; 0x00, 0x09, 0x0D+ = normal startup
9436 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
9440 ;; Examine CMOS shutdown status
.
9441 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
9443 call _shutdown_status_panic
9449 ; 0xb0, 0x20, /* mov al, #0x20 */
9450 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9460 ; case 0: normal startup
9469 ;; zero out BIOS data
area (40:00..40:ff
)
9471 mov cx
, #0x0080 ;; 128 words
9477 call _log_bios_start
9479 ;; set all interrupts to
default handler
9480 mov bx
, #0x0000 ;; offset index
9481 mov cx
, #0x0100 ;; counter (256 interrupts)
9482 mov ax
, #dummy_iret_handler
9492 loop post_default_ints
9494 ;; set vector
0x79 to zero
9495 ;; this is used by
'gardian angel' protection system
9496 SET_INT_VECTOR(0x79, #0, #0)
9498 ;; base memory in K
40:13 (word
)
9499 mov ax
, #BASE_MEM_IN_K
9503 ;; Manufacturing Test
40:12
9506 ;; Warm Boot Flag
0040:0072
9507 ;; value of
1234h
= skip memory checks
9511 ;; Printer Services vector
9512 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9514 ;; Bootstrap failure vector
9515 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9517 ;; Bootstrap Loader vector
9518 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9520 ;; User Timer Tick vector
9521 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9523 ;; Memory Size Check vector
9524 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9526 ;; Equipment Configuration Check vector
9527 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9530 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9536 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9537 ;; int 1C already points at
dummy_iret_handler (above
)
9538 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
9540 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
9545 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9546 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9550 mov
0x0417, al
/* keyboard shift flags, set 1 */
9551 mov
0x0418, al
/* keyboard shift flags, set 2 */
9552 mov
0x0419, al
/* keyboard alt-numpad work area */
9553 mov
0x0471, al
/* keyboard ctrl-break flag */
9554 mov
0x0497, al
/* keyboard status flags 4 */
9556 mov
0x0496, al
/* keyboard status flags 3 */
9559 /* keyboard head of buffer pointer */
9563 /* keyboard end of buffer pointer */
9566 /* keyboard pointer to start of buffer */
9570 /* keyboard pointer to end of buffer */
9574 /* init the keyboard */
9577 ;; mov CMOS Equipment Byte to BDA Equipment Word
9586 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9590 mov cl
, #0x14 ; timeout value
9591 mov dx
, #0x378 ; Parallel I/O address, port 1
9593 mov dx
, #0x278 ; Parallel I/O address, port 2
9596 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
9598 or ax
, bx
; set number of parallel ports
9602 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9603 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9605 mov cl
, #0x0a ; timeout value
9606 mov dx
, #0x03f8 ; Serial I/O address, port 1
9608 mov dx
, #0x02f8 ; Serial I/O address, port 2
9610 mov dx
, #0x03e8 ; Serial I/O address, port 3
9612 mov dx
, #0x02e8 ; Serial I/O address, port 4
9615 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
9617 or ax
, bx
; set number of serial port
9621 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9622 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9623 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9624 ;; BIOS DATA AREA
0x4CE ???
9625 call timer_tick_post
9628 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9630 ;; IRQ13 (FPU exception
) setup
9631 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9634 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9637 mov al
, #0x11 ; send initialisation commands
9652 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
9653 #if BX_USE_PS2_MOUSE
9658 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
9664 call _print_bios_banner
9669 call floppy_drive_post
9676 call hard_drive_post
9679 ;; ATA
/ATAPI driver setup
9684 #else // BX_USE_ATADRV
9689 call hard_drive_post
9691 #endif // BX_USE_ATADRV
9693 #if BX_ELTORITO_BOOT
9695 ;; eltorito floppy
/harddisk emulation from cd
9699 #endif // BX_ELTORITO_BOOT
9702 //JMP_EP(0x0064) ; INT 19h location
9705 .org
0xe2c3 ; NMI Handler Entry Point
9707 ;; FIXME the NMI handler should
not panic
9708 ;; but iret when called from
int75 (fpu exception
)
9709 call _nmi_handler_msg
9713 out
0xf0, al
// clear irq13
9714 call eoi_both_pics
// clear interrupt
9715 int 2 // legacy nmi call
9718 ;-------------------------------------------
9719 ;- INT
13h Fixed Disk Services Entry Point
-
9720 ;-------------------------------------------
9721 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
9723 //JMPL(int13_relocated)
9726 .org
0xe401 ; Fixed Disk Parameter Table
9731 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
9735 ;-------------------------------------------
9736 ;- System BIOS Configuration Data Table
9737 ;-------------------------------------------
9738 .org BIOS_CONFIG_TABLE
9739 db
0x08 ; Table
size (bytes
) -Lo
9740 db
0x00 ; Table
size (bytes
) -Hi
9745 ; b7
: 1=DMA channel
3 used by hard disk
9746 ; b6
: 1=2 interrupt controllers present
9748 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
9749 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
9750 ; b2
: 1=extended BIOS data area used
9751 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
9752 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
9756 (BX_CALL_INT15_4F
<< 4) | \
9758 (BX_USE_EBDA
<< 2) | \
9762 ; b7
: 1=32-bit DMA supported
9763 ; b6
: 1=int16h
, function
9 supported
9764 ; b5
: 1=int15h
/C6h (get POS data
) supported
9765 ; b4
: 1=int15h
/C7h (get mem map info
) supported
9766 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
9767 ; b2
: 1=non
-8042 kb controller
9768 ; b1
: 1=data streaming supported
9782 ; b4
: POST supports ROM
-to
-RAM enable
/disable
9783 ; b3
: SCSI on system board
9784 ; b2
: info panel installed
9785 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
9786 ; b0
: SCSI supported in IML
9790 ; b6
: EEPROM present
9791 ; b5
-3: ABIOS
presence (011 = not supported
)
9793 ; b1
: memory split above
16Mb supported
9794 ; b0
: POSTEXT directly supported by POST
9796 ; Feature byte
5 (IBM
)
9797 ; b1
: enhanced mouse
9803 .org
0xe729 ; Baud Rate Generator Table
9808 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
9814 call _int14_function
9820 ;----------------------------------------
9821 ;- INT
16h Keyboard Service Entry Point
-
9822 ;----------------------------------------
9838 call _int16_function
9848 and BYTE
[bp
+ 0x06], #0xbf
9856 or BYTE
[bp
+ 0x06], #0x40
9872 /* no key yet, call int 15h, function AX=9002 */
9874 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9875 0xcd, 0x15, /* int 15h */
9877 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
9879 jmp int16_wait_for_key
9884 call _int16_function
9889 /* notify int16 complete w/ int 15h, function AX=9102 */
9891 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
9892 0xcd, 0x15, /* int 15h */
9899 ;-------------------------------------------------
9900 ;- INT09h
: Keyboard Hardware Service Entry Point
-
9901 ;-------------------------------------------------
9907 mov al
, #0xAD ;;disable keyboard
9916 in al
, #0x60 ;;read key from keyboard controller
9917 //test al, #0x80 ;;look for key release
9918 //jnz int09_process_key ;; dont pass releases to intercept?
9920 ;; check
for extended key
9922 jne int09_call_int15_4f
9927 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
9929 mov BYTE
[0x496], al
9932 in al
, #0x60 ;;read another key from keyboard controller
9936 int09_call_int15_4f
:
9939 #ifdef BX_CALL_INT15_4F
9940 mov ah
, #0x4f ;; allow for keyboard intercept
9947 //int09_process_key:
9950 call _int09_function
9959 mov al
, #0xAE ;;enable keyboard
9967 ;----------------------------------------
9968 ;- INT
13h Diskette Service Entry Point
-
9969 ;----------------------------------------
9972 jmp int13_noeltorito
9974 ;---------------------------------------------
9975 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
9976 ;---------------------------------------------
9977 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
9987 mov al
, #0x08 ; sense interrupt status
10005 mov ax
, #0x0000 ;; segment 0000
10007 call eoi_master_pic
10009 or al
, #0x80 ;; diskette interrupt has occurred
10017 .org
0xefc7 ; Diskette Controller Parameter Table
10018 diskette_param_table
:
10019 ;; Since no provisions are made
for multiple drive types
, most
10020 ;; values in
this table are ignored
. I set parameters
for 1.44M
10023 db
0x02 ;; head load time
0000001, DMA used
10035 ;----------------------------------------
10036 ;- INT17h
: Printer Service Entry Point
-
10037 ;----------------------------------------
10044 call _int17_function
10049 diskette_param_table2
:
10050 ;; New diskette parameter table adding
3 parameters from IBM
10051 ;; Since no provisions are made
for multiple drive types
, most
10052 ;; values in
this table are ignored
. I set parameters
for 1.44M
10055 db
0x02 ;; head load time
0000001, DMA used
10065 db
79 ;; maximum track
10066 db
0 ;; data transfer rate
10067 db
4 ;; drive type in cmos
10069 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10076 .org
0xf065 ; INT
10h Video Support Service Entry Point
10078 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10081 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10086 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10087 ; ??? different
for Pentium (machine check
)?
10099 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10111 .org
0xf859 ; INT
15h System Services Entry Point
10125 #if BX_USE_PS2_MOUSE
10127 je int15_handler_mouse
10129 call _int15_function
10130 int15_handler_mouse_ret
:
10132 int15_handler32_ret
:
10142 #if BX_USE_PS2_MOUSE
10143 int15_handler_mouse
:
10144 call _int15_function_mouse
10145 jmp int15_handler_mouse_ret
10150 call _int15_function32
10152 jmp int15_handler32_ret
10154 ;; Protected mode IDT descriptor
10156 ;; I just make the limit
0, so the machine will shutdown
10157 ;; if an exception occurs during
protected mode memory
10160 ;; Set base to f0000 to correspond to beginning of BIOS
,
10161 ;; in
case I actually define an IDT later
10165 dw
0x0000 ;; limit
15:00
10166 dw
0x0000 ;; base
15:00
10167 db
0x0f ;; base
23:16
10169 ;; Real mode IDT descriptor
10171 ;; Set to typical real
-mode values
.
10176 dw
0x03ff ;; limit
15:00
10177 dw
0x0000 ;; base
15:00
10178 db
0x00 ;; base
23:16
10184 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10197 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10198 mov ds
, ax
; on
16bit
protected mode
.
10199 jmp int1a_callfunction
10206 int1a_callfunction
:
10207 call _int1a_function
10213 ;; int70h
: IRQ8
- CMOS RTC
10220 call _int70_function
10228 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10236 ;; time to turn off
drive(s
)?
10239 jz int08_floppy_off
10242 jnz int08_floppy_off
10243 ;; turn
motor(s
) off
10252 mov eax
, 0x046c ;; get ticks dword
10255 ;; compare eax to one days worth of timer ticks at
18.2 hz
10256 cmp eax
, #0x001800B0
10257 jb int08_store_ticks
10258 ;; there has been a midnight rollover at
this point
10259 xor eax
, eax
;; zero out counter
10260 inc BYTE
0x0470 ;; increment rollover flag
10263 mov
0x046c, eax
;; store
new ticks dword
10264 ;; chain to user timer tick INT
#0x1c
10266 //;; call_ep [ds:loc]
10267 //CALL_EP( 0x1c << 2 )
10270 call eoi_master_pic
10275 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10279 .ascii BIOS_COPYRIGHT_STRING
10281 ;------------------------------------------------
10282 ;- IRET Instruction
for Dummy Interrupt Handler
-
10283 ;------------------------------------------------
10284 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10285 dummy_iret_handler
:
10288 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10292 .org
0xfff0 ; Power
-up Entry Point
10295 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10296 .ascii BIOS_BUILD_DATE
10298 .org
0xfffe ; System Model ID
10302 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10305 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10306 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10307 * This font is public domain
10309 static Bit8u vgafont8
[128*8]=
10311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10312 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10313 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10314 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10315 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10316 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10317 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10318 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10319 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10320 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10321 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10322 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10323 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10324 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10325 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10326 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10327 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10328 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10329 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10330 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10331 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10332 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10333 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10334 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10335 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10336 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10337 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10338 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10339 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10340 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10341 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10342 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10344 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10345 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10346 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10347 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10348 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10349 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10350 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10351 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10352 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10353 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10354 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10355 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10356 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10357 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10358 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10359 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10360 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10361 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10362 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10363 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10364 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10365 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10366 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10367 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10368 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10369 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10370 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10371 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10372 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10373 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10374 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10375 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10376 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10377 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10378 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10379 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10380 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10381 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10382 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10383 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10384 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10385 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10386 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10387 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10388 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10389 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10390 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10391 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10392 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10393 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10394 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10395 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10396 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10397 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10398 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10399 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10400 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10401 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10402 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10403 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10404 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10405 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10406 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10407 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10408 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10409 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10410 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10411 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10412 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10413 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10414 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10415 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10416 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10417 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10418 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10419 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10420 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10421 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10422 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10423 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10424 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10425 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10426 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10427 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10428 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10429 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10430 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10431 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10432 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10433 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10434 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10435 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10436 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10437 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10438 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10443 // bcc-generated data will be placed here
10445 // For documentation of this config structure, look on developer.intel.com and
10446 // search for multiprocessor specification. Note that when you change anything
10447 // you must update the checksum (a pain!). It would be better to construct this
10448 // with C structures, or at least fill in the checksum automatically.
10450 // Maybe this structs could be moved elsewhere than d000
10452 #if (BX_SMP_PROCESSORS==1)
10453 // no structure necessary.
10454 #elif (BX_SMP_PROCESSORS==2)
10455 // define the Intel MP Configuration Structure for 2 processors at
10456 // APIC ID 0,1. I/O APIC at ID=2.
10459 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10460 dw (mp_config_end
-mp_config_table
) ;; table length
10462 db
0x65 ;; checksum
10463 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10464 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10465 db
0x20, 0x20, 0x20, 0x20
10466 db
0x20, 0x20, 0x20, 0x20
10467 dw
0,0 ;; oem table ptr
10468 dw
0 ;; oem table size
10469 dw
20 ;; entry count
10470 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10471 dw
0 ;; extended table length
10472 db
0 ;; extended table checksum
10475 db
0 ;; entry type
=processor
10476 db
0 ;; local APIC id
10477 db
0x11 ;; local APIC version number
10478 db
3 ;; cpu flags
: enabled
, bootstrap processor
10479 db
0,6,0,0 ;; cpu signature
10480 dw
0x201,0 ;; feature flags
10484 db
0 ;; entry type
=processor
10485 db
1 ;; local APIC id
10486 db
0x11 ;; local APIC version number
10487 db
1 ;; cpu flags
: enabled
10488 db
0,6,0,0 ;; cpu signature
10489 dw
0x201,0 ;; feature flags
10493 db
1 ;; entry type
=bus
10495 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10497 db
2 ;; entry type
=I
/O APIC
10498 db
2 ;; apic id
=2. linux will set
.
10499 db
0x11 ;; I
/O APIC version number
10500 db
1 ;; flags
=1=enabled
10501 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10503 db
3 ;; entry type
=I
/O interrupt
10504 db
0 ;; interrupt type
=vectored interrupt
10505 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10506 db
0 ;; source bus ID is ISA
10507 db
0 ;; source bus IRQ
10508 db
2 ;; destination I
/O APIC ID
10509 db
0 ;; destination I
/O APIC interrrupt in
10510 ;; repeat pattern
for interrupts
0-15
10520 db
3,0,0,0,0,10,2,10
10521 db
3,0,0,0,0,11,2,11
10522 db
3,0,0,0,0,12,2,12
10523 db
3,0,0,0,0,13,2,13
10524 db
3,0,0,0,0,14,2,14
10525 db
3,0,0,0,0,15,2,15
10526 #elif (BX_SMP_PROCESSORS==4)
10527 // define the Intel MP Configuration Structure for 4 processors at
10528 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10531 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10532 dw (mp_config_end
-mp_config_table
) ;; table length
10534 db
0xdd ;; checksum
10535 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10536 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10537 db
0x20, 0x20, 0x20, 0x20
10538 db
0x20, 0x20, 0x20, 0x20
10539 dw
0,0 ;; oem table ptr
10540 dw
0 ;; oem table size
10541 dw
22 ;; entry count
10542 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10543 dw
0 ;; extended table length
10544 db
0 ;; extended table checksum
10547 db
0 ;; entry type
=processor
10548 db
0 ;; local APIC id
10549 db
0x11 ;; local APIC version number
10550 db
3 ;; cpu flags
: enabled
, bootstrap processor
10551 db
0,6,0,0 ;; cpu signature
10552 dw
0x201,0 ;; feature flags
10556 db
0 ;; entry type
=processor
10557 db
1 ;; local APIC id
10558 db
0x11 ;; local APIC version number
10559 db
1 ;; cpu flags
: enabled
10560 db
0,6,0,0 ;; cpu signature
10561 dw
0x201,0 ;; feature flags
10565 db
0 ;; entry type
=processor
10566 db
2 ;; local APIC id
10567 db
0x11 ;; local APIC version number
10568 db
1 ;; cpu flags
: enabled
10569 db
0,6,0,0 ;; cpu signature
10570 dw
0x201,0 ;; feature flags
10574 db
0 ;; entry type
=processor
10575 db
3 ;; local APIC id
10576 db
0x11 ;; local APIC version number
10577 db
1 ;; cpu flags
: enabled
10578 db
0,6,0,0 ;; cpu signature
10579 dw
0x201,0 ;; feature flags
10583 db
1 ;; entry type
=bus
10585 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10587 db
2 ;; entry type
=I
/O APIC
10588 db
4 ;; apic id
=4. linux will set
.
10589 db
0x11 ;; I
/O APIC version number
10590 db
1 ;; flags
=1=enabled
10591 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10593 db
3 ;; entry type
=I
/O interrupt
10594 db
0 ;; interrupt type
=vectored interrupt
10595 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10596 db
0 ;; source bus ID is ISA
10597 db
0 ;; source bus IRQ
10598 db
4 ;; destination I
/O APIC ID
10599 db
0 ;; destination I
/O APIC interrrupt in
10600 ;; repeat pattern
for interrupts
0-15
10610 db
3,0,0,0,0,10,4,10
10611 db
3,0,0,0,0,11,4,11
10612 db
3,0,0,0,0,12,4,12
10613 db
3,0,0,0,0,13,4,13
10614 db
3,0,0,0,0,14,4,14
10615 db
3,0,0,0,0,15,4,15
10616 #elif (BX_SMP_PROCESSORS==8)
10617 // define the Intel MP Configuration Structure for 8 processors at
10618 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10621 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10622 dw (mp_config_end
-mp_config_table
) ;; table length
10624 db
0xc3 ;; checksum
10625 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10626 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10627 db
0x20, 0x20, 0x20, 0x20
10628 db
0x20, 0x20, 0x20, 0x20
10629 dw
0,0 ;; oem table ptr
10630 dw
0 ;; oem table size
10631 dw
26 ;; entry count
10632 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10633 dw
0 ;; extended table length
10634 db
0 ;; extended table checksum
10637 db
0 ;; entry type
=processor
10638 db
0 ;; local APIC id
10639 db
0x11 ;; local APIC version number
10640 db
3 ;; cpu flags
: enabled
, bootstrap processor
10641 db
0,6,0,0 ;; cpu signature
10642 dw
0x201,0 ;; feature flags
10646 db
0 ;; entry type
=processor
10647 db
1 ;; local APIC id
10648 db
0x11 ;; local APIC version number
10649 db
1 ;; cpu flags
: enabled
10650 db
0,6,0,0 ;; cpu signature
10651 dw
0x201,0 ;; feature flags
10655 db
0 ;; entry type
=processor
10656 db
2 ;; local APIC id
10657 db
0x11 ;; local APIC version number
10658 db
1 ;; cpu flags
: enabled
10659 db
0,6,0,0 ;; cpu signature
10660 dw
0x201,0 ;; feature flags
10664 db
0 ;; entry type
=processor
10665 db
3 ;; local APIC id
10666 db
0x11 ;; local APIC version number
10667 db
1 ;; cpu flags
: enabled
10668 db
0,6,0,0 ;; cpu signature
10669 dw
0x201,0 ;; feature flags
10673 db
0 ;; entry type
=processor
10674 db
4 ;; local APIC id
10675 db
0x11 ;; local APIC version number
10676 db
1 ;; cpu flags
: enabled
10677 db
0,6,0,0 ;; cpu signature
10678 dw
0x201,0 ;; feature flags
10682 db
0 ;; entry type
=processor
10683 db
5 ;; local APIC id
10684 db
0x11 ;; local APIC version number
10685 db
1 ;; cpu flags
: enabled
10686 db
0,6,0,0 ;; cpu signature
10687 dw
0x201,0 ;; feature flags
10691 db
0 ;; entry type
=processor
10692 db
6 ;; local APIC id
10693 db
0x11 ;; local APIC version number
10694 db
1 ;; cpu flags
: enabled
10695 db
0,6,0,0 ;; cpu signature
10696 dw
0x201,0 ;; feature flags
10700 db
0 ;; entry type
=processor
10701 db
7 ;; local APIC id
10702 db
0x11 ;; local APIC version number
10703 db
1 ;; cpu flags
: enabled
10704 db
0,6,0,0 ;; cpu signature
10705 dw
0x201,0 ;; feature flags
10709 db
1 ;; entry type
=bus
10711 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10713 db
2 ;; entry type
=I
/O APIC
10715 db
0x11 ;; I
/O APIC version number
10716 db
1 ;; flags
=1=enabled
10717 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10719 db
3 ;; entry type
=I
/O interrupt
10720 db
0 ;; interrupt type
=vectored interrupt
10721 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10722 db
0 ;; source bus ID is ISA
10723 db
0 ;; source bus IRQ
10724 db
8 ;; destination I
/O APIC ID
10725 db
0 ;; destination I
/O APIC interrrupt in
10726 ;; repeat pattern
for interrupts
0-15
10736 db
3,0,0,0,0,10,8,10
10737 db
3,0,0,0,0,11,8,11
10738 db
3,0,0,0,0,12,8,12
10739 db
3,0,0,0,0,13,8,13
10740 db
3,0,0,0,0,14,8,14
10741 db
3,0,0,0,0,15,8,15
10743 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
10744 #endif // if (BX_SMP_PROCESSORS==...)
10746 mp_config_end
: // this label used to find length of mp structure
10749 #if (BX_SMP_PROCESSORS>1)
10751 mp_floating_pointer_structure
:
10752 db
0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
10753 dw mp_config_table
, 0xf ;; pointer to MP configuration table
10754 db
1 ;; length of
this struct in
16-bit byte chunks
10755 db
4 ;; MP spec revision
10756 db
0xc1 ;; checksum
10757 db
0 ;; MP feature byte
1. value
0 means look at the config table
10758 db
0,0,0,0 ;; MP feature bytes
2-5.