1 /////////////////////////////////////////////////////////////////////////
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
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 */
146 #define BX_ROMBIOS32 0
148 #define BX_USE_ATADRV 1
149 #define BX_ELTORITO_BOOT 1
151 #define BX_MAX_ATA_INTERFACES 4
152 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
154 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
155 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
157 /* model byte 0xFC = AT */
158 #define SYS_MODEL_ID 0xFC
159 #define SYS_SUBMODEL_ID 0x00
160 #define BIOS_REVISION 1
161 #define BIOS_CONFIG_TABLE 0xe6f5
163 /* define it to include QEMU specific code */
166 #ifndef BIOS_BUILD_DATE
167 # define BIOS_BUILD_DATE "06/23/99"
170 // 1K of base memory used for Extended Bios Data Area (EBDA)
171 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
172 #define EBDA_SEG 0x9FC0
173 #define EBDA_SIZE 1 // In KiB
174 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
176 // Define the application NAME
178 # define BX_APPNAME "QEMU"
179 #elif defined(PLEX86)
180 # define BX_APPNAME "Plex86"
182 # define BX_APPNAME "Bochs"
186 #if BX_USE_ATADRV && BX_CPU<3
187 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
189 #if BX_USE_ATADRV && !BX_USE_EBDA
190 # error ATA/ATAPI Driver can only be used if EBDA is available
192 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
193 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
195 #if BX_PCIBIOS && BX_CPU<3
196 # error PCI BIOS can only be used with 386+ cpu
198 #if BX_APM && BX_CPU<3
199 # error APM BIOS can only be used with 386+ cpu
202 #define PANIC_PORT 0x400
203 #define PANIC_PORT2 0x401
204 #define INFO_PORT 0x402
205 #define DEBUG_PORT 0x403
207 // define this if you want to make PCIBIOS working on a specific bridge only
208 // undef enables PCIBIOS when at least one PCI device is found
209 // i440FX is emulated by Bochs and QEMU
210 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
213 // #$20 is hex 20 = 32
214 // #0x20 is hex 20 = 32
221 // all hex literals should be prefixed with '0x'
222 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
223 // no mov SEG-REG, #value, must mov register into seg-reg
224 // grep -i "mov[ ]*.s" rombios.c
226 // This is for compiling with gcc2 and gcc3
227 #define ASM_START #asm
228 #define ASM_END #endasm
242 ;; the HALT macro is called with the line number of the HALT call
.
243 ;; The line number is then sent to the PANIC_PORT
, causing Bochs
/Plex
244 ;; to print a BX_PANIC message
. This will normally halt the simulation
245 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
246 ;; However
, users can choose to make panics non
-fatal
and continue.
273 typedef unsigned char Bit8u
;
274 typedef unsigned short Bit16u
;
275 typedef unsigned short bx_bool
;
276 typedef unsigned long Bit32u
;
280 void memsetb(seg
,offset
,value
,count
);
281 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
282 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
284 // memset of count bytes
286 memsetb(seg
,offset
,value
,count
)
301 mov cx
, 10[bp
] ; count
304 mov ax
, 4[bp
] ; segment
306 mov ax
, 6[bp
] ; offset
308 mov al
, 8[bp
] ; value
324 // memcpy of count bytes
326 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
344 mov cx
, 12[bp
] ; count
347 mov ax
, 4[bp
] ; dsegment
349 mov ax
, 6[bp
] ; doffset
351 mov ax
, 8[bp
] ; ssegment
353 mov ax
, 10[bp
] ; soffset
371 // memcpy of count dword
373 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
391 mov cx
, 12[bp
] ; count
394 mov ax
, 4[bp
] ; dsegment
396 mov ax
, 6[bp
] ; doffset
398 mov ax
, 8[bp
] ; ssegment
400 mov ax
, 10[bp
] ; soffset
418 #endif //BX_USE_ATADRV
420 // read_dword and write_dword functions
421 static Bit32u
read_dword();
422 static void write_dword();
425 read_dword(seg
, offset
)
435 mov ax
, 4[bp
] ; segment
437 mov bx
, 6[bp
] ; offset
442 ;; ax
= return value (word
)
443 ;; dx
= return value (word
)
452 write_dword(seg
, offset
, data
)
464 mov ax
, 4[bp
] ; segment
466 mov bx
, 6[bp
] ; offset
467 mov ax
, 8[bp
] ; data word
468 mov
[bx
], ax
; write data word
471 mov ax
, 10[bp
] ; data word
472 mov
[bx
], ax
; write data word
481 // Bit32u (unsigned long) and long helper functions
510 cmp eax
, dword ptr
[di
]
529 mul eax
, dword ptr
[di
]
625 // for access to RAM area which is used by interrupt vectors
626 // and BIOS Data Area
629 unsigned char filler1
[0x400];
630 unsigned char filler2
[0x6c];
636 #define BiosData ((bios_data_t *) 0)
640 Bit16u heads
; // # heads
641 Bit16u cylinders
; // # cylinders
642 Bit16u spt
; // # sectors / track
662 Bit8u iface
; // ISA or PCI
663 Bit16u iobase1
; // IO Base 1
664 Bit16u iobase2
; // IO Base 2
669 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
670 Bit8u device
; // Detected type of attached devices (hd/cd/none)
671 Bit8u removable
; // Removable device flag
672 Bit8u lock
; // Locks for removable devices
673 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
674 Bit8u mode
; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
675 Bit16u blksize
; // block size
677 Bit8u translation
; // type of translation
678 chs_t lchs
; // Logical CHS
679 chs_t pchs
; // Physical CHS
681 Bit32u sectors
; // Total sectors count
686 ata_channel_t channels
[BX_MAX_ATA_INTERFACES
];
689 ata_device_t devices
[BX_MAX_ATA_DEVICES
];
691 // map between (bios hd id - 0x80) and ata channels
692 Bit8u hdcount
, hdidmap
[BX_MAX_ATA_DEVICES
];
694 // map between (bios cd id - 0xE0) and ata channels
695 Bit8u cdcount
, cdidmap
[BX_MAX_ATA_DEVICES
];
697 // Buffer for DPTE table
700 // Count of transferred sectors and bytes
707 // ElTorito Device Emulation data
711 Bit8u emulated_drive
;
712 Bit8u controller_index
;
715 Bit16u buffer_segment
;
722 #endif // BX_ELTORITO_BOOT
724 // for access to EBDA area
725 // The EBDA structure should conform to
726 // http://www.frontiernet.net/~fys/rombios.htm document
727 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
729 unsigned char filler1
[0x3D];
731 // FDPT - Can be splitted in data members if needed
732 unsigned char fdpt0
[0x10];
733 unsigned char fdpt1
[0x10];
735 unsigned char filler2
[0xC4];
741 // El Torito Emulation data
743 #endif // BX_ELTORITO_BOOT
747 #define EbdaData ((ebda_data_t *) 0)
749 // for access to the int13ext structure
760 #define Int13Ext ((int13ext_t *) 0)
762 // Disk Physical Table definition
769 Bit32u sector_count1
;
770 Bit32u sector_count2
;
781 Bit8u device_path
[8];
786 #define Int13DPT ((dpt_t *) 0)
788 #endif // BX_USE_ATADRV
793 Bit16u di
, si
, bp
, sp
;
794 Bit16u bx
, dx
, cx
, ax
;
798 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
806 Bit32u edi
, esi
, ebp
, esp
;
807 Bit32u ebx
, edx
, ecx
, eax
;
810 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
811 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
839 #define SetCF(x) x.u.r8.flagsl |= 0x01
840 #define SetZF(x) x.u.r8.flagsl |= 0x40
841 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
842 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
843 #define GetCF(x) (x.u.r8.flagsl & 0x01)
854 static Bit8u
inb_cmos();
856 static void outb_cmos();
859 static void init_rtc();
860 static bx_bool
rtc_updating();
862 static Bit8u
read_byte();
863 static Bit16u
read_word();
864 static void write_byte();
865 static void write_word();
866 static void bios_printf();
868 static Bit8u
inhibit_mouse_int_and_events();
869 static void enable_mouse_int_and_events();
870 static Bit8u
send_to_mouse_ctrl();
871 static Bit8u
get_mouse_data();
872 static void set_kbd_command_byte();
874 static void int09_function();
875 static void int13_harddisk();
876 static void int13_cdrom();
877 static void int13_cdemu();
878 static void int13_eltorito();
879 static void int13_diskette_function();
880 static void int14_function();
881 static void int15_function();
882 static void int16_function();
883 static void int17_function();
884 static Bit32u
int19_function();
885 static void int1a_function();
886 static void int70_function();
887 static void int74_function();
888 static Bit16u
get_CS();
889 static Bit16u
get_SS();
890 static unsigned int enqueue_key();
891 static unsigned int dequeue_key();
892 static void get_hd_geometry();
893 static void set_diskette_ret_status();
894 static void set_diskette_current_cyl();
895 static void determine_floppy_media();
896 static bx_bool
floppy_drive_exists();
897 static bx_bool
floppy_drive_recal();
898 static bx_bool
floppy_media_known();
899 static bx_bool
floppy_media_sense();
900 static bx_bool
set_enable_a20();
901 static void debugger_on();
902 static void debugger_off();
903 static void keyboard_init();
904 static void keyboard_panic();
905 static void shutdown_status_panic();
906 static void nmi_handler_msg();
908 static void print_bios_banner();
909 static void print_boot_device();
910 static void print_boot_failure();
911 static void print_cdromboot_failure();
915 // ATA / ATAPI driver
920 Bit16u
ata_cmd_non_data();
921 Bit16u
ata_cmd_data_in();
922 Bit16u
ata_cmd_data_out();
923 Bit16u
ata_cmd_packet();
925 Bit16u
atapi_get_sense();
926 Bit16u
atapi_is_ready();
927 Bit16u
atapi_is_cdrom();
929 #endif // BX_USE_ATADRV
934 Bit8u
cdemu_isactive();
935 Bit8u
cdemu_emulated_drive();
939 #endif // BX_ELTORITO_BOOT
941 static char bios_cvs_version_string
[] = "$Revision$ $Date$";
943 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
945 #define BIOS_PRINTF_HALT 1
946 #define BIOS_PRINTF_SCREEN 2
947 #define BIOS_PRINTF_INFO 4
948 #define BIOS_PRINTF_DEBUG 8
949 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
950 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
952 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
954 // Defines the output macros.
955 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
956 // per-device basis. Debug info are sent only in debug mode
958 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
960 # define BX_DEBUG(format, p...)
962 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
963 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
966 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
968 # define BX_DEBUG_ATA(a...)
971 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
973 # define BX_DEBUG_INT13_HD(a...)
976 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
978 # define BX_DEBUG_INT13_CD(a...)
981 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
983 # define BX_DEBUG_INT13_ET(a...)
986 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
988 # define BX_DEBUG_INT13_FL(a...)
991 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
993 # define BX_DEBUG_INT15(a...)
996 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
998 # define BX_DEBUG_INT16(a...)
1001 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1003 # define BX_DEBUG_INT1A(a...)
1006 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1008 # define BX_DEBUG_INT74(a...)
1011 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1012 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1013 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1014 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1015 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1016 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1017 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1018 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1020 #define GET_AL() ( AX & 0x00ff )
1021 #define GET_BL() ( BX & 0x00ff )
1022 #define GET_CL() ( CX & 0x00ff )
1023 #define GET_DL() ( DX & 0x00ff )
1024 #define GET_AH() ( AX >> 8 )
1025 #define GET_BH() ( BX >> 8 )
1026 #define GET_CH() ( CX >> 8 )
1027 #define GET_DH() ( DX >> 8 )
1029 #define GET_ELDL() ( ELDX & 0x00ff )
1030 #define GET_ELDH() ( ELDX >> 8 )
1032 #define SET_CF() FLAGS |= 0x0001
1033 #define CLEAR_CF() FLAGS &= 0xfffe
1034 #define GET_CF() (FLAGS & 0x0001)
1036 #define SET_ZF() FLAGS |= 0x0040
1037 #define CLEAR_ZF() FLAGS &= 0xffbf
1038 #define GET_ZF() (FLAGS & 0x0040)
1040 #define UNSUPPORTED_FUNCTION 0x86
1043 #define MAX_SCAN_CODE 0x58
1051 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1052 { none
, none
, none
, none
, none
},
1053 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1054 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1055 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1056 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1057 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1058 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1059 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1060 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1061 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1062 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1063 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1064 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1065 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1066 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1067 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1068 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1069 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1070 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1071 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1072 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1073 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1074 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1075 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1076 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1077 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1078 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1079 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1080 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1081 { none
, none
, none
, none
, none
}, /* L Ctrl */
1082 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1083 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1084 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1085 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1086 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1087 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1088 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1089 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1090 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1091 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1092 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1093 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1094 { none
, none
, none
, none
, none
}, /* L shift */
1095 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1096 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1097 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1098 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1099 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1100 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1101 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1102 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1103 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1104 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1105 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1106 { none
, none
, none
, none
, none
}, /* R Shift */
1107 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1108 { none
, none
, none
, none
, none
}, /* L Alt */
1109 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1110 { none
, none
, none
, none
, none
}, /* caps lock */
1111 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1112 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1113 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1114 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1115 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1116 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1117 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1118 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1119 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1120 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1121 { none
, none
, none
, none
, none
}, /* Num Lock */
1122 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1123 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1124 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1125 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1126 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1127 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1128 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1129 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1130 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1131 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1132 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1133 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1134 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1135 { 0x5300, 0x532e, none
, none
, 0x20 }, /* Del */
1136 { none
, none
, none
, none
, none
},
1137 { none
, none
, none
, none
, none
},
1138 { 0x565c, 0x567c, none
, none
, none
}, /* \| */
1139 { 0x5700, 0x5700, none
, none
, none
}, /* F11 */
1140 { 0x5800, 0x5800, none
, none
, none
} /* F12 */
1224 outb_cmos(cmos_reg
, val
)
1232 mov al
, 4[bp
] ;; cmos_reg
1234 mov al
, 6[bp
] ;; val
1249 mov al
, 4[bp
] ;; cmos_reg
1260 outb_cmos(0x0a, 0x26);
1261 outb_cmos(0x0b, 0x02);
1269 // This function checks to see if the update-in-progress bit
1270 // is set in CMOS Status Register A. If not, it returns 0.
1271 // If it is set, it tries to wait until there is a transition
1272 // to 0, and will return 0 if such a transition occurs. A 1
1273 // is returned only after timing out. The maximum period
1274 // that this bit should be set is constrained to 244useconds.
1275 // The count I use below guarantees coverage or more than
1276 // this time, with any reasonable IPS setting.
1281 while (--count
!= 0) {
1282 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1285 return(1); // update-in-progress never transitioned to 0
1290 read_byte(seg
, offset
)
1300 mov ax
, 4[bp
] ; segment
1302 mov bx
, 6[bp
] ; offset
1304 ;; al
= return value (byte
)
1313 read_word(seg
, offset
)
1323 mov ax
, 4[bp
] ; segment
1325 mov bx
, 6[bp
] ; offset
1327 ;; ax
= return value (word
)
1336 write_byte(seg
, offset
, data
)
1348 mov ax
, 4[bp
] ; segment
1350 mov bx
, 6[bp
] ; offset
1351 mov al
, 8[bp
] ; data byte
1352 mov
[bx
], al
; write data byte
1362 write_word(seg
, offset
, data
)
1374 mov ax
, 4[bp
] ; segment
1376 mov bx
, 6[bp
] ; offset
1377 mov ax
, 8[bp
] ; data word
1378 mov
[bx
], ax
; write data word
1404 /* serial debug port*/
1405 #define BX_DEBUG_PORT 0x03f8
1408 #define UART_RBR 0x00
1409 #define UART_THR 0x00
1412 #define UART_IER 0x01
1413 #define UART_IIR 0x02
1414 #define UART_FCR 0x02
1415 #define UART_LCR 0x03
1416 #define UART_MCR 0x04
1417 #define UART_DLL 0x00
1418 #define UART_DLM 0x01
1421 #define UART_LSR 0x05
1422 #define UART_MSR 0x06
1423 #define UART_SCR 0x07
1425 int uart_can_tx_byte(base_port
)
1428 return inb(base_port
+ UART_LSR
) & 0x20;
1431 void uart_wait_to_tx_byte(base_port
)
1434 while (!uart_can_tx_byte(base_port
));
1437 void uart_wait_until_sent(base_port
)
1440 while (!(inb(base_port
+ UART_LSR
) & 0x40));
1443 void uart_tx_byte(base_port
, data
)
1447 uart_wait_to_tx_byte(base_port
);
1448 outb(base_port
+ UART_THR
, data
);
1449 uart_wait_until_sent(base_port
);
1478 if (c
== '\n') uart_tx_byte(BX_DEBUG_PORT
, '\r');
1479 uart_tx_byte(BX_DEBUG_PORT
, c
);
1481 #if BX_VIRTUAL_PORTS
1482 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1483 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1485 if (action
& BIOS_PRINTF_SCREEN
) {
1486 if (c
== '\n') wrch('\r');
1492 put_int(action
, val
, width
, neg
)
1497 short nval
= val
/ 10;
1499 put_int(action
, nval
, width
- 1, neg
);
1501 while (--width
> 0) send(action
, ' ');
1502 if (neg
) send(action
, '-');
1504 send(action
, val
- (nval
* 10) + '0');
1508 put_uint(action
, val
, width
, neg
)
1514 unsigned short nval
= val
/ 10;
1516 put_uint(action
, nval
, width
- 1, neg
);
1518 while (--width
> 0) send(action
, ' ');
1519 if (neg
) send(action
, '-');
1521 send(action
, val
- (nval
* 10) + '0');
1525 put_luint(action
, val
, width
, neg
)
1531 unsigned long nval
= val
/ 10;
1533 put_luint(action
, nval
, width
- 1, neg
);
1535 while (--width
> 0) send(action
, ' ');
1536 if (neg
) send(action
, '-');
1538 send(action
, val
- (nval
* 10) + '0');
1541 //--------------------------------------------------------------------------
1543 // A compact variable argument printf function which prints its output via
1544 // an I/O port so that it can be logged by Bochs/Plex.
1545 // Currently, only %x is supported (or %02x, %04x, etc).
1547 // Supports %[format_width][format]
1548 // where format can be d,x,c,s
1549 //--------------------------------------------------------------------------
1551 bios_printf(action
, s
)
1555 Bit8u c
, format_char
;
1559 Bit16u arg_seg
, arg
, nibble
, hibyte
, shift_count
, format_width
;
1567 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1568 #if BX_VIRTUAL_PORTS
1569 outb(PANIC_PORT2
, 0x00);
1571 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1574 while (c
= read_byte(get_CS(), s
)) {
1579 else if (in_format
) {
1580 if ( (c
>='0') && (c
<='9') ) {
1581 format_width
= (format_width
* 10) + (c
- '0');
1584 arg_ptr
++; // increment to next arg
1585 arg
= read_word(arg_seg
, arg_ptr
);
1587 if (format_width
== 0)
1589 for (i
=format_width
-1; i
>=0; i
--) {
1590 nibble
= (arg
>> (4 * i
)) & 0x000f;
1591 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+'A'));
1594 else if (c
== 'u') {
1595 put_uint(action
, arg
, format_width
, 0);
1597 else if (c
== 'l') {
1599 arg_ptr
++; /* increment to next arg */
1600 hibyte
= read_word(arg_seg
, arg_ptr
);
1601 put_luint(action
, ((Bit32u
) hibyte
<< 16) | arg
, format_width
, 0);
1603 else if (c
== 'd') {
1605 put_int(action
, -arg
, format_width
- 1, 1);
1607 put_int(action
, arg
, format_width
, 0);
1609 else if (c
== 's') {
1610 bios_printf(action
& (~BIOS_PRINTF_HALT
), arg
);
1612 else if (c
== 'c') {
1616 BX_PANIC("bios_printf: unknown format\n");
1626 if (action
& BIOS_PRINTF_HALT
) {
1627 // freeze in a busy loop.
1637 //--------------------------------------------------------------------------
1639 //--------------------------------------------------------------------------
1640 // this file is based on LinuxBIOS implementation of keyboard.c
1641 // could convert to #asm to gain space
1647 /* ------------------- Flush buffers ------------------------*/
1648 /* Wait until buffer is empty */
1650 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1652 /* flush incoming keys */
1656 if (inb(0x64) & 0x01) {
1662 // Due to timer issues, and if the IPS setting is > 15000000,
1663 // the incoming keys might not be flushed here. That will
1664 // cause a panic a few lines below. See sourceforge bug report :
1665 // [ 642031 ] FATAL: Keyboard RESET error:993
1667 /* ------------------- controller side ----------------------*/
1668 /* send cmd = 0xAA, self test 8042 */
1671 /* Wait until buffer is empty */
1673 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1674 if (max
==0x0) keyboard_panic(00);
1678 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1679 if (max
==0x0) keyboard_panic(01);
1681 /* read self-test result, 0x55 should be returned from 0x60 */
1682 if ((inb(0x60) != 0x55)){
1683 keyboard_panic(991);
1686 /* send cmd = 0xAB, keyboard interface test */
1689 /* Wait until buffer is empty */
1691 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1692 if (max
==0x0) keyboard_panic(10);
1696 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1697 if (max
==0x0) keyboard_panic(11);
1699 /* read keyboard interface test result, */
1700 /* 0x00 should be returned form 0x60 */
1701 if ((inb(0x60) != 0x00)) {
1702 keyboard_panic(992);
1705 /* Enable Keyboard clock */
1709 /* ------------------- keyboard side ------------------------*/
1710 /* reset kerboard and self test (keyboard side) */
1713 /* Wait until buffer is empty */
1715 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1716 if (max
==0x0) keyboard_panic(20);
1720 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1721 if (max
==0x0) keyboard_panic(21);
1723 /* keyboard should return ACK */
1724 if ((inb(0x60) != 0xfa)) {
1725 keyboard_panic(993);
1730 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1731 if (max
==0x0) keyboard_panic(31);
1733 if ((inb(0x60) != 0xaa)) {
1734 keyboard_panic(994);
1737 /* Disable keyboard */
1740 /* Wait until buffer is empty */
1742 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1743 if (max
==0x0) keyboard_panic(40);
1747 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1748 if (max
==0x0) keyboard_panic(41);
1750 /* keyboard should return ACK */
1751 if ((inb(0x60) != 0xfa)) {
1752 keyboard_panic(995);
1755 /* Write Keyboard Mode */
1758 /* Wait until buffer is empty */
1760 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1761 if (max
==0x0) keyboard_panic(50);
1763 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1766 /* Wait until buffer is empty */
1768 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1769 if (max
==0x0) keyboard_panic(60);
1771 /* Enable keyboard */
1774 /* Wait until buffer is empty */
1776 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1777 if (max
==0x0) keyboard_panic(70);
1781 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1782 if (max
==0x0) keyboard_panic(70);
1784 /* keyboard should return ACK */
1785 if ((inb(0x60) != 0xfa)) {
1786 keyboard_panic(996);
1792 //--------------------------------------------------------------------------
1794 //--------------------------------------------------------------------------
1796 keyboard_panic(status
)
1799 // If you're getting a 993 keyboard panic here,
1800 // please see the comment in keyboard_init
1802 BX_PANIC("Keyboard error:%u\n",status
);
1805 //--------------------------------------------------------------------------
1806 // shutdown_status_panic
1807 // called when the shutdown statsu is not implemented, displays the status
1808 //--------------------------------------------------------------------------
1810 shutdown_status_panic(status
)
1813 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1816 //--------------------------------------------------------------------------
1817 // print_bios_banner
1818 // displays a the bios version
1819 //--------------------------------------------------------------------------
1823 printf(BX_APPNAME
" BIOS - build: %s\n%s\nOptions: ",
1824 BIOS_BUILD_DATE
, bios_cvs_version_string
);
1832 #if BX_ELTORITO_BOOT
1841 //--------------------------------------------------------------------------
1842 // print_boot_device
1843 // displays the boot device
1844 //--------------------------------------------------------------------------
1846 static char drivetypes
[][10]={"Floppy","Hard Disk","CD-Rom"};
1849 print_boot_device(cdboot
, drive
)
1850 Bit8u cdboot
; Bit16u drive
;
1854 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1855 // drive contains real/emulated boot drive
1857 if(cdboot
)i
=2; // CD-Rom
1858 else if((drive
&0x0080)==0x00)i
=0; // Floppy
1859 else if((drive
&0x0080)==0x80)i
=1; // Hard drive
1862 printf("Booting from %s...\n",drivetypes
[i
]);
1865 //--------------------------------------------------------------------------
1866 // print_boot_failure
1867 // displays the reason why boot failed
1868 //--------------------------------------------------------------------------
1870 print_boot_failure(cdboot
, drive
, reason
, lastdrive
)
1871 Bit8u cdboot
; Bit8u drive
; Bit8u lastdrive
;
1873 Bit16u drivenum
= drive
&0x7f;
1875 // cdboot: 1 if boot from cd, 0 otherwise
1876 // drive : drive number
1877 // reason: 0 signature check failed, 1 read error
1878 // lastdrive: 1 boot drive is the last one in boot sequence
1881 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s failed\n",drivetypes
[2]);
1882 else if (drive
& 0x80)
1883 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[1],drivenum
);
1885 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[0],drivenum
);
1889 BX_PANIC("Not a bootable disk\n");
1891 BX_PANIC("Could not read the boot disk\n");
1895 //--------------------------------------------------------------------------
1896 // print_cdromboot_failure
1897 // displays the reason why boot failed
1898 //--------------------------------------------------------------------------
1900 print_cdromboot_failure( code
)
1903 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1911 BX_PANIC("NMI Handler called\n");
1917 BX_PANIC("INT18: BOOT FAILURE\n");
1924 outb(BX_DEBUG_PORT
+UART_LCR
, 0x03); /* setup for serial logging: 8N1 */
1926 BX_INFO("%s\n", bios_cvs_version_string
);
1935 // Use PS2 System Control port A to set A20 enable
1937 // get current setting first
1940 // change A20 status
1942 outb(0x92, oldval
| 0x02);
1944 outb(0x92, oldval
& 0xfd);
1946 return((oldval
& 0x02) != 0);
1963 // ---------------------------------------------------------------------------
1964 // Start of ATA/ATAPI Driver
1965 // ---------------------------------------------------------------------------
1967 // Global defines -- ATA register and register bits.
1968 // command block & control block regs
1969 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1970 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1971 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1972 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1973 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1974 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1975 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1976 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1977 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1978 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1979 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1980 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1981 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1983 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1984 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1985 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1986 #define ATA_CB_ER_MC 0x20 // ATA media change
1987 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1988 #define ATA_CB_ER_MCR 0x08 // ATA media change request
1989 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
1990 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
1991 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
1993 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
1994 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
1995 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
1996 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
1997 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
1999 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2000 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2001 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2002 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2003 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2005 // bits 7-4 of the device/head (CB_DH) reg
2006 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2007 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2009 // status reg (CB_STAT and CB_ASTAT) bits
2010 #define ATA_CB_STAT_BSY 0x80 // busy
2011 #define ATA_CB_STAT_RDY 0x40 // ready
2012 #define ATA_CB_STAT_DF 0x20 // device fault
2013 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2014 #define ATA_CB_STAT_SKC 0x10 // seek complete
2015 #define ATA_CB_STAT_SERV 0x10 // service
2016 #define ATA_CB_STAT_DRQ 0x08 // data request
2017 #define ATA_CB_STAT_CORR 0x04 // corrected
2018 #define ATA_CB_STAT_IDX 0x02 // index
2019 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2020 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2022 // device control reg (CB_DC) bits
2023 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2024 #define ATA_CB_DC_SRST 0x04 // soft reset
2025 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2027 // Most mandtory and optional ATA commands (from ATA-3),
2028 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2029 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2030 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2031 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2032 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2033 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2034 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2035 #define ATA_CMD_DEVICE_RESET 0x08
2036 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2037 #define ATA_CMD_FLUSH_CACHE 0xE7
2038 #define ATA_CMD_FORMAT_TRACK 0x50
2039 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2040 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2041 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2042 #define ATA_CMD_IDLE1 0xE3
2043 #define ATA_CMD_IDLE2 0x97
2044 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2045 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2046 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2047 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2048 #define ATA_CMD_NOP 0x00
2049 #define ATA_CMD_PACKET 0xA0
2050 #define ATA_CMD_READ_BUFFER 0xE4
2051 #define ATA_CMD_READ_DMA 0xC8
2052 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2053 #define ATA_CMD_READ_MULTIPLE 0xC4
2054 #define ATA_CMD_READ_SECTORS 0x20
2055 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2056 #define ATA_CMD_RECALIBRATE 0x10
2057 #define ATA_CMD_SEEK 0x70
2058 #define ATA_CMD_SET_FEATURES 0xEF
2059 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2060 #define ATA_CMD_SLEEP1 0xE6
2061 #define ATA_CMD_SLEEP2 0x99
2062 #define ATA_CMD_STANDBY1 0xE2
2063 #define ATA_CMD_STANDBY2 0x96
2064 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2065 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2066 #define ATA_CMD_WRITE_BUFFER 0xE8
2067 #define ATA_CMD_WRITE_DMA 0xCA
2068 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2069 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2070 #define ATA_CMD_WRITE_SECTORS 0x30
2071 #define ATA_CMD_WRITE_VERIFY 0x3C
2073 #define ATA_IFACE_NONE 0x00
2074 #define ATA_IFACE_ISA 0x00
2075 #define ATA_IFACE_PCI 0x01
2077 #define ATA_TYPE_NONE 0x00
2078 #define ATA_TYPE_UNKNOWN 0x01
2079 #define ATA_TYPE_ATA 0x02
2080 #define ATA_TYPE_ATAPI 0x03
2082 #define ATA_DEVICE_NONE 0x00
2083 #define ATA_DEVICE_HD 0xFF
2084 #define ATA_DEVICE_CDROM 0x05
2086 #define ATA_MODE_NONE 0x00
2087 #define ATA_MODE_PIO16 0x00
2088 #define ATA_MODE_PIO32 0x01
2089 #define ATA_MODE_ISADMA 0x02
2090 #define ATA_MODE_PCIDMA 0x03
2091 #define ATA_MODE_USEIRQ 0x10
2093 #define ATA_TRANSLATION_NONE 0
2094 #define ATA_TRANSLATION_LBA 1
2095 #define ATA_TRANSLATION_LARGE 2
2096 #define ATA_TRANSLATION_RECHS 3
2098 #define ATA_DATA_NO 0x00
2099 #define ATA_DATA_IN 0x01
2100 #define ATA_DATA_OUT 0x02
2102 // ---------------------------------------------------------------------------
2103 // ATA/ATAPI driver : initialization
2104 // ---------------------------------------------------------------------------
2107 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2108 Bit8u channel
, device
;
2110 // Channels info init.
2111 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2112 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2113 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2114 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2115 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2118 // Devices info init.
2119 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2120 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2121 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2122 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2123 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2124 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2125 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2126 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2127 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2128 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2129 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2130 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2131 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2132 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2134 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2137 // hdidmap and cdidmap init.
2138 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2139 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2140 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2143 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2144 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2147 // ---------------------------------------------------------------------------
2148 // ATA/ATAPI driver : device detection
2149 // ---------------------------------------------------------------------------
2153 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2154 Bit8u hdcount
, cdcount
, device
, type
;
2155 Bit8u buffer
[0x0200];
2157 #if BX_MAX_ATA_INTERFACES > 0
2158 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2159 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2160 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2161 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2163 #if BX_MAX_ATA_INTERFACES > 1
2164 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2165 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2166 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2167 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2169 #if BX_MAX_ATA_INTERFACES > 2
2170 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2171 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2172 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2173 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2175 #if BX_MAX_ATA_INTERFACES > 3
2176 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2177 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2178 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2179 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2181 #if BX_MAX_ATA_INTERFACES > 4
2182 #error Please fill the ATA interface informations
2188 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2189 Bit16u iobase1
, iobase2
;
2190 Bit8u channel
, slave
, shift
;
2191 Bit8u sc
, sn
, cl
, ch
, st
;
2193 channel
= device
/ 2;
2196 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2197 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2199 // Disable interrupts
2200 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2203 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2204 outb(iobase1
+ATA_CB_SC
, 0x55);
2205 outb(iobase1
+ATA_CB_SN
, 0xaa);
2206 outb(iobase1
+ATA_CB_SC
, 0xaa);
2207 outb(iobase1
+ATA_CB_SN
, 0x55);
2208 outb(iobase1
+ATA_CB_SC
, 0x55);
2209 outb(iobase1
+ATA_CB_SN
, 0xaa);
2211 // If we found something
2212 sc
= inb(iobase1
+ATA_CB_SC
);
2213 sn
= inb(iobase1
+ATA_CB_SN
);
2215 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2216 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2218 // reset the channel
2221 // check for ATA or ATAPI
2222 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2223 sc
= inb(iobase1
+ATA_CB_SC
);
2224 sn
= inb(iobase1
+ATA_CB_SN
);
2225 if ((sc
==0x01) && (sn
==0x01)) {
2226 cl
= inb(iobase1
+ATA_CB_CL
);
2227 ch
= inb(iobase1
+ATA_CB_CH
);
2228 st
= inb(iobase1
+ATA_CB_STAT
);
2230 if ((cl
==0x14) && (ch
==0xeb)) {
2231 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2232 } else if ((cl
==0x00) && (ch
==0x00) && (st
!=0x00)) {
2233 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2234 } else if ((cl
==0xff) && (ch
==0xff)) {
2235 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2240 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2242 // Now we send a IDENTIFY command to ATA device
2243 if(type
== ATA_TYPE_ATA
) {
2245 Bit16u cylinders
, heads
, spt
, blksize
;
2246 Bit8u translation
, removable
, mode
;
2248 //Temporary values to do the transfer
2249 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2250 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2252 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2253 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2255 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2256 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2257 blksize
= read_word(get_SS(),buffer
+10);
2259 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2260 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2261 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2263 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2265 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2266 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2267 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2268 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2269 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2270 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2271 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2272 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2273 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2275 translation
= inb_cmos(0x39 + channel
/2);
2276 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2277 translation
&= 0x03;
2279 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2281 switch (translation
) {
2282 case ATA_TRANSLATION_NONE
:
2285 case ATA_TRANSLATION_LBA
:
2288 case ATA_TRANSLATION_LARGE
:
2291 case ATA_TRANSLATION_RECHS
:
2295 switch (translation
) {
2296 case ATA_TRANSLATION_NONE
:
2298 case ATA_TRANSLATION_LBA
:
2301 heads
= sectors
/ 1024;
2302 if (heads
>128) heads
= 255;
2303 else if (heads
>64) heads
= 128;
2304 else if (heads
>32) heads
= 64;
2305 else if (heads
>16) heads
= 32;
2307 cylinders
= sectors
/ heads
;
2309 case ATA_TRANSLATION_RECHS
:
2310 // Take care not to overflow
2312 if(cylinders
>61439) cylinders
=61439;
2314 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2316 // then go through the large bitshift process
2317 case ATA_TRANSLATION_LARGE
:
2318 while(cylinders
> 1024) {
2322 // If we max out the head count
2323 if (heads
> 127) break;
2327 // clip to 1024 cylinders in lchs
2328 if (cylinders
> 1024) cylinders
=1024;
2329 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2331 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2332 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2333 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2336 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2340 // Now we send a IDENTIFY command to ATAPI device
2341 if(type
== ATA_TYPE_ATAPI
) {
2343 Bit8u type
, removable
, mode
;
2346 //Temporary values to do the transfer
2347 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2348 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2350 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2351 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2353 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2354 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2355 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2358 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2359 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2360 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2361 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2364 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2371 Bit8u c
, i
, version
, model
[41];
2375 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2377 case ATA_TYPE_ATAPI
:
2378 // Read ATA/ATAPI version
2379 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2380 for(version
=15;version
>0;version
--) {
2381 if((ataversion
&(1<<version
))!=0)
2387 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2388 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2392 write_byte(get_SS(),model
+40,0x00);
2394 if(read_byte(get_SS(),model
+i
)==0x20)
2395 write_byte(get_SS(),model
+i
,0x00);
2403 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2404 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2405 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version
, sizeinmb
);
2407 case ATA_TYPE_ATAPI
:
2408 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2409 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2410 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2411 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2413 printf(" ATAPI-%d Device\n",version
);
2415 case ATA_TYPE_UNKNOWN
:
2416 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2422 // Store the devices counts
2423 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2424 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2425 write_byte(0x40,0x75, hdcount
);
2429 // FIXME : should use bios=cmos|auto|disable bits
2430 // FIXME : should know about translation bits
2431 // FIXME : move hard_drive_post here
2435 // ---------------------------------------------------------------------------
2436 // ATA/ATAPI driver : software reset
2437 // ---------------------------------------------------------------------------
2439 // 8.2.1 Software reset - Device 0
2441 void ata_reset(device
)
2444 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2445 Bit16u iobase1
, iobase2
;
2446 Bit8u channel
, slave
, sn
, sc
;
2449 channel
= device
/ 2;
2452 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2453 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2457 // 8.2.1 (a) -- set SRST in DC
2458 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2460 // 8.2.1 (b) -- wait for BSY
2463 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2464 if ((status
& ATA_CB_STAT_BSY
) != 0) break;
2467 // 8.2.1 (f) -- clear SRST
2468 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2470 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_NONE
) {
2472 // 8.2.1 (g) -- check for sc==sn==0x01
2474 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2475 sc
= inb(iobase1
+ATA_CB_SC
);
2476 sn
= inb(iobase1
+ATA_CB_SN
);
2478 if ( (sc
==0x01) && (sn
==0x01) ) {
2480 // 8.2.1 (h) -- wait for not BSY
2483 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2484 if ((status
& ATA_CB_STAT_BSY
) == 0) break;
2489 // 8.2.1 (i) -- wait for DRDY
2492 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2493 if ((status
& ATA_CB_STAT_RDY
) != 0) break;
2496 // Enable interrupts
2497 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2500 // ---------------------------------------------------------------------------
2501 // ATA/ATAPI driver : execute a non data command
2502 // ---------------------------------------------------------------------------
2504 Bit16u
ata_cmd_non_data()
2507 // ---------------------------------------------------------------------------
2508 // ATA/ATAPI driver : execute a data-in command
2509 // ---------------------------------------------------------------------------
2514 // 3 : expected DRQ=1
2515 // 4 : no sectors left to read/verify
2516 // 5 : more sectors to read/verify
2517 // 6 : no sectors left to write
2518 // 7 : more sectors to write
2519 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2520 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2523 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2524 Bit16u iobase1
, iobase2
, blksize
;
2525 Bit8u channel
, slave
;
2526 Bit8u status
, current
, mode
;
2528 channel
= device
/ 2;
2531 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2532 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2533 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2534 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2535 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2538 // sector will be 0 only on lba access. Convert to lba-chs
2540 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2542 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2544 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2547 // Reset count of transferred data
2548 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2549 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2552 status
= inb(iobase1
+ ATA_CB_STAT
);
2553 if (status
& ATA_CB_STAT_BSY
) return 1;
2555 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2556 outb(iobase1
+ ATA_CB_FR
, 0x00);
2557 outb(iobase1
+ ATA_CB_SC
, count
);
2558 outb(iobase1
+ ATA_CB_SN
, sector
);
2559 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2560 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2561 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2562 outb(iobase1
+ ATA_CB_CMD
, command
);
2565 status
= inb(iobase1
+ ATA_CB_STAT
);
2566 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2569 if (status
& ATA_CB_STAT_ERR
) {
2570 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2572 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2573 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2577 // FIXME : move seg/off translation here
2580 sti
;; enable higher priority interrupts
2588 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2589 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2590 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2592 ;; adjust
if there will be an overrun
. 2K max sector size
2594 jbe ata_in_no_adjust
2597 sub di
, #0x0800 ;; sub 2 kbytes from offset
2598 add ax
, #0x0080 ;; add 2 Kbytes to segment
2601 mov es
, ax
;; segment in es
2603 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2605 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2606 cmp ah
, #ATA_MODE_PIO32
2611 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2616 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2619 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2620 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2625 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2627 status
= inb(iobase1
+ ATA_CB_STAT
);
2629 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2630 != ATA_CB_STAT_RDY
) {
2631 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2637 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2638 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2639 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2645 // Enable interrupts
2646 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2650 // ---------------------------------------------------------------------------
2651 // ATA/ATAPI driver : execute a data-out command
2652 // ---------------------------------------------------------------------------
2657 // 3 : expected DRQ=1
2658 // 4 : no sectors left to read/verify
2659 // 5 : more sectors to read/verify
2660 // 6 : no sectors left to write
2661 // 7 : more sectors to write
2662 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2663 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2666 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2667 Bit16u iobase1
, iobase2
, blksize
;
2668 Bit8u channel
, slave
;
2669 Bit8u status
, current
, mode
;
2671 channel
= device
/ 2;
2674 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2675 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2676 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2677 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2678 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2681 // sector will be 0 only on lba access. Convert to lba-chs
2683 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2685 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2687 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2690 // Reset count of transferred data
2691 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2692 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2695 status
= inb(iobase1
+ ATA_CB_STAT
);
2696 if (status
& ATA_CB_STAT_BSY
) return 1;
2698 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2699 outb(iobase1
+ ATA_CB_FR
, 0x00);
2700 outb(iobase1
+ ATA_CB_SC
, count
);
2701 outb(iobase1
+ ATA_CB_SN
, sector
);
2702 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2703 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2704 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2705 outb(iobase1
+ ATA_CB_CMD
, command
);
2708 status
= inb(iobase1
+ ATA_CB_STAT
);
2709 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2712 if (status
& ATA_CB_STAT_ERR
) {
2713 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2715 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2716 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2720 // FIXME : move seg/off translation here
2723 sti
;; enable higher priority interrupts
2731 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2732 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2733 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2735 ;; adjust
if there will be an overrun
. 2K max sector size
2737 jbe ata_out_no_adjust
2740 sub si
, #0x0800 ;; sub 2 kbytes from offset
2741 add ax
, #0x0080 ;; add 2 Kbytes to segment
2744 mov es
, ax
;; segment in es
2746 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2748 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2749 cmp ah
, #ATA_MODE_PIO32
2755 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2761 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2764 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2765 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2770 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2772 status
= inb(iobase1
+ ATA_CB_STAT
);
2774 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2775 != ATA_CB_STAT_RDY
) {
2776 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2782 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2783 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2784 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2790 // Enable interrupts
2791 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2795 // ---------------------------------------------------------------------------
2796 // ATA/ATAPI driver : execute a packet command
2797 // ---------------------------------------------------------------------------
2800 // 1 : error in parameters
2804 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2806 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2810 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2811 Bit16u iobase1
, iobase2
;
2812 Bit16u lcount
, lbefore
, lafter
, count
;
2813 Bit8u channel
, slave
;
2814 Bit8u status
, mode
, lmode
;
2815 Bit32u total
, transfer
;
2817 channel
= device
/ 2;
2820 // Data out is not supported yet
2821 if (inout
== ATA_DATA_OUT
) {
2822 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2826 // The header length must be even
2828 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2832 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2833 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2834 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2837 if (cmdlen
< 12) cmdlen
=12;
2838 if (cmdlen
> 12) cmdlen
=16;
2841 // Reset count of transferred data
2842 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2843 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2845 status
= inb(iobase1
+ ATA_CB_STAT
);
2846 if (status
& ATA_CB_STAT_BSY
) return 2;
2848 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2849 // outb(iobase1 + ATA_CB_FR, 0x00);
2850 // outb(iobase1 + ATA_CB_SC, 0x00);
2851 // outb(iobase1 + ATA_CB_SN, 0x00);
2852 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2853 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2854 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2855 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2857 // Device should ok to receive command
2859 status
= inb(iobase1
+ ATA_CB_STAT
);
2860 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2863 if (status
& ATA_CB_STAT_ERR
) {
2864 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2866 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2867 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2871 // Normalize address
2872 cmdseg
+= (cmdoff
/ 16);
2875 // Send command to device
2877 sti
;; enable higher priority interrupts
2882 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
2883 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
2884 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
2885 mov es
, ax
;; segment in es
2887 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
2891 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2896 if (inout
== ATA_DATA_NO
) {
2897 status
= inb(iobase1
+ ATA_CB_STAT
);
2902 status
= inb(iobase1
+ ATA_CB_STAT
);
2904 // Check if command completed
2905 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_DRQ
) ) ==0 ) break;
2907 if (status
& ATA_CB_STAT_ERR
) {
2908 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
2912 // Device must be ready to send data
2913 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2914 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2915 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status
);
2919 // Normalize address
2920 bufseg
+= (bufoff
/ 16);
2923 // Get the byte count
2924 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
2926 // adjust to read what we want
2939 lafter
=lcount
-length
;
2951 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
2952 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
2954 // If counts not dividable by 4, use 16bits mode
2956 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
2957 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
2958 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
2960 // adds an extra byte if count are odd. before is always even
2961 if (lcount
& 0x01) {
2963 if ((lafter
> 0) && (lafter
& 0x01)) {
2968 if (lmode
== ATA_MODE_PIO32
) {
2969 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
2972 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
2981 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
2983 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
2984 jcxz ata_packet_no_before
2986 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
2987 cmp ah
, #ATA_MODE_PIO32
2988 je ata_packet_in_before_32
2990 ata_packet_in_before_16
:
2992 loop ata_packet_in_before_16
2993 jmp ata_packet_no_before
2995 ata_packet_in_before_32
:
2997 ata_packet_in_before_32_loop
:
2999 loop ata_packet_in_before_32_loop
3002 ata_packet_no_before
:
3003 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
3004 jcxz ata_packet_after
3006 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
3007 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
3010 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3011 cmp ah
, #ATA_MODE_PIO32
3016 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
3017 jmp ata_packet_after
3021 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
3024 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
3025 jcxz ata_packet_done
3027 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
3028 cmp ah
, #ATA_MODE_PIO32
3029 je ata_packet_in_after_32
3031 ata_packet_in_after_16
:
3033 loop ata_packet_in_after_16
3036 ata_packet_in_after_32
:
3038 ata_packet_in_after_32_loop
:
3040 loop ata_packet_in_after_32_loop
3047 // Compute new buffer address
3050 // Save transferred bytes count
3052 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
3056 // Final check, device must be ready
3057 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
3058 != ATA_CB_STAT_RDY
) {
3059 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
3063 // Enable interrupts
3064 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
3068 // ---------------------------------------------------------------------------
3069 // End of ATA/ATAPI Driver
3070 // ---------------------------------------------------------------------------
3072 // ---------------------------------------------------------------------------
3073 // Start of ATA/ATAPI generic functions
3074 // ---------------------------------------------------------------------------
3077 atapi_get_sense(device
)
3084 memsetb(get_SS(),atacmd
,0,12);
3089 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 16L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
3092 if ((buffer
[0] & 0x7e) == 0x70) {
3093 return (((Bit16u
)buffer
[2]&0x0f)*0x100)+buffer
[12];
3100 atapi_is_ready(device
)
3106 memsetb(get_SS(),atacmd
,0,12);
3109 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3112 if (atapi_get_sense(device
) !=0 ) {
3113 memsetb(get_SS(),atacmd
,0,12);
3115 // try to send Test Unit Ready again
3116 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3119 return atapi_get_sense(device
);
3125 atapi_is_cdrom(device
)
3128 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3130 if (device
>= BX_MAX_ATA_DEVICES
)
3133 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3136 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3142 // ---------------------------------------------------------------------------
3143 // End of ATA/ATAPI generic functions
3144 // ---------------------------------------------------------------------------
3146 #endif // BX_USE_ATADRV
3148 #if BX_ELTORITO_BOOT
3150 // ---------------------------------------------------------------------------
3151 // Start of El-Torito boot functions
3152 // ---------------------------------------------------------------------------
3157 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3159 // the only important data is this one for now
3160 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3166 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3168 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3172 cdemu_emulated_drive()
3174 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3176 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3179 static char isotag
[6]="CD001";
3180 static char eltorito
[24]="EL TORITO SPECIFICATION";
3182 // Returns ah: emulated drive, al: error code
3187 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3188 Bit8u atacmd
[12], buffer
[2048];
3190 Bit16u boot_segment
, nbsectors
, i
, error
;
3193 // Find out the first cdrom
3194 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3195 if (atapi_is_cdrom(device
)) break;
3199 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3201 // Read the Boot Record Volume Descriptor
3202 memsetb(get_SS(),atacmd
,0,12);
3203 atacmd
[0]=0x28; // READ command
3204 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3205 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3206 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3207 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3208 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3209 atacmd
[5]=(0x11 & 0x000000ff);
3210 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3214 if(buffer
[0]!=0)return 4;
3216 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3219 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3221 // ok, now we calculate the Boot catalog address
3222 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3224 // And we read the Boot Catalog
3225 memsetb(get_SS(),atacmd
,0,12);
3226 atacmd
[0]=0x28; // READ command
3227 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3228 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3229 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3230 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3231 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3232 atacmd
[5]=(lba
& 0x000000ff);
3233 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3237 if(buffer
[0x00]!=0x01)return 8; // Header
3238 if(buffer
[0x01]!=0x00)return 9; // Platform
3239 if(buffer
[0x1E]!=0x55)return 10; // key 1
3240 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3242 // Initial/Default Entry
3243 if(buffer
[0x20]!=0x88)return 11; // Bootable
3245 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3246 if(buffer
[0x21]==0){
3247 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3248 // Win2000 cd boot needs to know it booted from cd
3249 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3251 else if(buffer
[0x21]<4)
3252 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3254 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3256 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3257 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3259 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3260 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3262 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3263 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3265 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3266 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3268 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3269 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3271 // And we read the image in memory
3272 memsetb(get_SS(),atacmd
,0,12);
3273 atacmd
[0]=0x28; // READ command
3274 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3275 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3276 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3277 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3278 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3279 atacmd
[5]=(lba
& 0x000000ff);
3280 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3283 // Remember the media type
3284 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3285 case 0x01: // 1.2M floppy
3286 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3287 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3288 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3290 case 0x02: // 1.44M floppy
3291 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3292 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3293 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3295 case 0x03: // 2.88M floppy
3296 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3297 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3298 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3300 case 0x04: // Harddrive
3301 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3302 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3303 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3304 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3308 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3309 // Increase bios installed hardware number of devices
3310 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3311 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3313 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3317 // everything is ok, so from now on, the emulation is active
3318 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3319 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3321 // return the boot drive + no error
3322 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3325 // ---------------------------------------------------------------------------
3326 // End of El-Torito boot functions
3327 // ---------------------------------------------------------------------------
3328 #endif // BX_ELTORITO_BOOT
3331 int14_function(regs
, ds
, iret_addr
)
3332 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3333 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3334 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3336 Bit16u addr
,timer
,val16
;
3343 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3344 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3345 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3346 switch (regs
.u
.r8
.ah
) {
3348 outb(addr
+3, inb(addr
+3) | 0x80);
3349 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3353 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3354 outb(addr
, val16
& 0xFF);
3355 outb(addr
+1, val16
>> 8);
3357 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3358 regs
.u
.r8
.ah
= inb(addr
+5);
3359 regs
.u
.r8
.al
= inb(addr
+6);
3360 ClearCF(iret_addr
.flags
);
3363 timer
= read_word(0x0040, 0x006C);
3364 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3365 val16
= read_word(0x0040, 0x006C);
3366 if (val16
!= timer
) {
3371 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3372 regs
.u
.r8
.ah
= inb(addr
+5);
3373 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3374 ClearCF(iret_addr
.flags
);
3377 timer
= read_word(0x0040, 0x006C);
3378 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3379 val16
= read_word(0x0040, 0x006C);
3380 if (val16
!= timer
) {
3387 regs
.u
.r8
.al
= inb(addr
);
3389 regs
.u
.r8
.ah
= inb(addr
+5);
3391 ClearCF(iret_addr
.flags
);
3394 regs
.u
.r8
.ah
= inb(addr
+5);
3395 regs
.u
.r8
.al
= inb(addr
+6);
3396 ClearCF(iret_addr
.flags
);
3399 SetCF(iret_addr
.flags
); // Unsupported
3402 SetCF(iret_addr
.flags
); // Unsupported
3407 int15_function(regs
, ES
, DS
, FLAGS
)
3408 pusha_regs_t regs
; // REGS pushed via pusha
3409 Bit16u ES
, DS
, FLAGS
;
3411 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3412 bx_bool prev_a20_enable
;
3421 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3423 switch (regs
.u
.r8
.ah
) {
3424 case 0x24: /* A20 Control */
3425 switch (regs
.u
.r8
.al
) {
3437 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3447 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3449 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3455 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3459 /* keyboard intercept */
3461 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3468 case 0x52: // removable media eject
3470 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3474 if( regs
.u
.r8
.al
== 0 ) {
3475 // Set Interval requested.
3476 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3477 // Interval not already set.
3478 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3479 write_word( 0x40, 0x98, ES
); // Byte location, segment
3480 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3481 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3482 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3484 irqDisable
= inb( 0xA1 );
3485 outb( 0xA1, irqDisable
& 0xFE );
3486 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3487 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3489 // Interval already set.
3490 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3492 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3494 } else if( regs
.u
.r8
.al
== 1 ) {
3495 // Clear Interval requested
3496 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3498 bRegister
= inb_cmos( 0xB );
3499 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3501 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3503 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3512 # error "Int15 function 87h not supported on < 80386"
3514 // +++ should probably have descriptor checks
3515 // +++ should have exception handlers
3517 // turn off interrupts
3522 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3524 // 128K max of transfer on 386+ ???
3525 // source == destination ???
3527 // ES:SI points to descriptor table
3528 // offset use initially comments
3529 // ==============================================
3530 // 00..07 Unused zeros Null descriptor
3531 // 08..0f GDT zeros filled in by BIOS
3532 // 10..17 source ssssssss source of data
3533 // 18..1f dest dddddddd destination of data
3534 // 20..27 CS zeros filled in by BIOS
3535 // 28..2f SS zeros filled in by BIOS
3542 // check for access rights of source & dest here
3544 // Initialize GDT descriptor
3545 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3546 base23_16
= ES
>> 12;
3547 if (base15_00
< (ES
<<4))
3549 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3550 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3551 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3552 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3553 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3555 // Initialize CS descriptor
3556 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3557 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3558 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3559 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3560 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3562 // Initialize SS descriptor
3564 base15_00
= ss
<< 4;
3565 base23_16
= ss
>> 12;
3566 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3567 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3568 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3569 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3570 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3574 // Compile generates locals offset info relative to SP.
3575 // Get CX (word count) from stack.
3578 mov cx
, _int15_function
.CX
[bx
]
3580 // since we need to set SS:SP, save them to the BDA
3581 // for future restore
3591 lidt
[pmode_IDT_info
]
3592 ;; perhaps
do something with IDT here
3594 ;; set PE bit in CR0
3598 ;; far jump to flush CPU queue after transition to
protected mode
3599 JMP_AP(0x0020, protected_mode
)
3602 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3603 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3605 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3607 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3613 movsw
;; move CX words from DS
:SI to ES
:DI
3615 ;; make sure DS
and ES limits are
64KB
3620 ;; reset PG bit in CR0
???
3625 ;; far jump to flush CPU queue after transition to real mode
3626 JMP_AP(0xf000, real_mode
)
3629 ;; restore IDT to normal real
-mode defaults
3631 lidt
[rmode_IDT_info
]
3633 // restore SS:SP from the BDA
3641 set_enable_a20(prev_a20_enable
);
3643 // turn back on interrupts
3654 // Get the amount of extended memory (above 1M)
3656 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3659 regs
.u
.r8
.al
= inb_cmos(0x30);
3660 regs
.u
.r8
.ah
= inb_cmos(0x31);
3662 // According to Ralf Brown's interrupt the limit should be 15M,
3663 // but real machines mostly return max. 63M.
3664 if(regs
.u
.r16
.ax
> 0xffc0)
3665 regs
.u
.r16
.ax
= 0xffc0;
3672 /* Device busy interrupt. Called by Int 16h when no key available */
3676 /* Interrupt complete. Called by Int 16h when key becomes available */
3680 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3682 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3688 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3693 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3703 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3705 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3709 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3710 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3712 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3717 #if BX_USE_PS2_MOUSE
3719 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3720 pusha_regs_t regs
; // REGS pushed via pusha
3721 Bit16u ES
, DS
, FLAGS
;
3723 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3724 Bit8u mouse_flags_1
, mouse_flags_2
;
3725 Bit16u mouse_driver_seg
;
3726 Bit16u mouse_driver_offset
;
3727 Bit8u comm_byte
, prev_command_byte
;
3728 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3730 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3732 switch (regs
.u
.r8
.ah
) {
3734 // Return Codes status in AH
3735 // =========================
3737 // 01: invalid subfunction (AL > 7)
3738 // 02: invalid input value (out of allowable range)
3739 // 03: interface error
3740 // 04: resend command received from mouse controller,
3741 // device driver should attempt command again
3742 // 05: cannot enable mouse, since no far call has been installed
3743 // 80/86: mouse service not implemented
3745 switch (regs
.u
.r8
.al
) {
3746 case 0: // Disable/Enable Mouse
3747 BX_DEBUG_INT15("case 0:\n");
3748 switch (regs
.u
.r8
.bh
) {
3749 case 0: // Disable Mouse
3750 BX_DEBUG_INT15("case 0: disable mouse\n");
3751 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3752 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3754 ret
= get_mouse_data(&mouse_data1
);
3755 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3768 case 1: // Enable Mouse
3769 BX_DEBUG_INT15("case 1: enable mouse\n");
3770 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3771 if ( (mouse_flags_2
& 0x80) == 0 ) {
3772 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3774 regs
.u
.r8
.ah
= 5; // no far call installed
3777 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3778 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3780 ret
= get_mouse_data(&mouse_data1
);
3781 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3782 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3792 default: // invalid subfunction
3793 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3795 regs
.u
.r8
.ah
= 1; // invalid subfunction
3800 case 1: // Reset Mouse
3801 case 5: // Initialize Mouse
3802 BX_DEBUG_INT15("case 1 or 5:\n");
3803 if (regs
.u
.r8
.al
== 5) {
3804 if (regs
.u
.r8
.bh
!= 3) {
3806 regs
.u
.r8
.ah
= 0x02; // invalid input
3809 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3810 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3811 mouse_flags_1
= 0x00;
3812 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3813 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3816 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3817 ret
= send_to_mouse_ctrl(0xFF); // reset mouse command
3819 ret
= get_mouse_data(&mouse_data3
);
3820 // if no mouse attached, it will return RESEND
3821 if (mouse_data3
== 0xfe) {
3825 if (mouse_data3
!= 0xfa)
3826 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
3828 ret
= get_mouse_data(&mouse_data1
);
3830 ret
= get_mouse_data(&mouse_data2
);
3832 // turn IRQ12 and packet generation on
3833 enable_mouse_int_and_events();
3836 regs
.u
.r8
.bl
= mouse_data1
;
3837 regs
.u
.r8
.bh
= mouse_data2
;
3849 case 2: // Set Sample Rate
3850 BX_DEBUG_INT15("case 2:\n");
3851 switch (regs
.u
.r8
.bh
) {
3852 case 0: mouse_data1
= 10; break; // 10 reports/sec
3853 case 1: mouse_data1
= 20; break; // 20 reports/sec
3854 case 2: mouse_data1
= 40; break; // 40 reports/sec
3855 case 3: mouse_data1
= 60; break; // 60 reports/sec
3856 case 4: mouse_data1
= 80; break; // 80 reports/sec
3857 case 5: mouse_data1
= 100; break; // 100 reports/sec (default)
3858 case 6: mouse_data1
= 200; break; // 200 reports/sec
3859 default: mouse_data1
= 0;
3861 if (mouse_data1
> 0) {
3862 ret
= send_to_mouse_ctrl(0xF3); // set sample rate command
3864 ret
= get_mouse_data(&mouse_data2
);
3865 ret
= send_to_mouse_ctrl(mouse_data1
);
3866 ret
= get_mouse_data(&mouse_data2
);
3872 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3877 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3881 case 3: // Set Resolution
3882 BX_DEBUG_INT15("case 3:\n");
3884 // 0 = 25 dpi, 1 count per millimeter
3885 // 1 = 50 dpi, 2 counts per millimeter
3886 // 2 = 100 dpi, 4 counts per millimeter
3887 // 3 = 200 dpi, 8 counts per millimeter
3892 case 4: // Get Device ID
3893 BX_DEBUG_INT15("case 4:\n");
3894 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3895 ret
= send_to_mouse_ctrl(0xF2); // get mouse ID command
3897 ret
= get_mouse_data(&mouse_data1
);
3898 ret
= get_mouse_data(&mouse_data2
);
3901 regs
.u
.r8
.bh
= mouse_data2
;
3905 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3909 case 6: // Return Status & Set Scaling Factor...
3910 BX_DEBUG_INT15("case 6:\n");
3911 switch (regs
.u
.r8
.bh
) {
3912 case 0: // Return Status
3913 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3914 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
3916 ret
= get_mouse_data(&mouse_data1
);
3917 if (mouse_data1
!= 0xfa)
3918 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3920 ret
= get_mouse_data(&mouse_data1
);
3922 ret
= get_mouse_data(&mouse_data2
);
3924 ret
= get_mouse_data(&mouse_data3
);
3928 regs
.u
.r8
.bl
= mouse_data1
;
3929 regs
.u
.r8
.cl
= mouse_data2
;
3930 regs
.u
.r8
.dl
= mouse_data3
;
3931 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3942 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3945 case 1: // Set Scaling Factor to 1:1
3946 case 2: // Set Scaling Factor to 2:1
3947 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3948 if (regs
.u
.r8
.bh
== 1) {
3949 ret
= send_to_mouse_ctrl(0xE6);
3951 ret
= send_to_mouse_ctrl(0xE7);
3954 get_mouse_data(&mouse_data1
);
3955 ret
= (mouse_data1
!= 0xFA);
3963 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3965 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3969 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3973 case 7: // Set Mouse Handler Address
3974 BX_DEBUG_INT15("case 7:\n");
3975 mouse_driver_seg
= ES
;
3976 mouse_driver_offset
= regs
.u
.r16
.bx
;
3977 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
3978 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
3979 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3980 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
3981 /* remove handler */
3982 if ( (mouse_flags_2
& 0x80) != 0 ) {
3983 mouse_flags_2
&= ~0x80;
3984 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3988 /* install handler */
3989 mouse_flags_2
|= 0x80;
3991 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3997 BX_DEBUG_INT15("case default:\n");
3998 regs
.u
.r8
.ah
= 1; // invalid function
4004 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4005 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4007 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4014 void set_e820_range(ES
, DI
, start
, end
, type
)
4021 write_word(ES
, DI
, start
);
4022 write_word(ES
, DI
+2, start
>> 16);
4023 write_word(ES
, DI
+4, 0x00);
4024 write_word(ES
, DI
+6, 0x00);
4027 write_word(ES
, DI
+8, end
);
4028 write_word(ES
, DI
+10, end
>> 16);
4029 write_word(ES
, DI
+12, 0x0000);
4030 write_word(ES
, DI
+14, 0x0000);
4032 write_word(ES
, DI
+16, type
);
4033 write_word(ES
, DI
+18, 0x0);
4037 int15_function32(regs
, ES
, DS
, FLAGS
)
4038 pushad_regs_t regs
; // REGS pushed via pushad
4039 Bit16u ES
, DS
, FLAGS
;
4041 Bit32u extended_memory_size
=0; // 64bits long
4044 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
4046 switch (regs
.u
.r8
.ah
) {
4048 // Wait for CX:DX microseconds. currently using the
4049 // refresh request port 0x61 bit4, toggling every 15usec
4057 ;; Get the count in eax
4060 mov ax
, _int15_function
.CX
[bx
]
4063 mov ax
, _int15_function
.DX
[bx
]
4065 ;; convert to numbers of
15usec ticks
4071 ;; wait
for ecx number of refresh requests
4092 switch(regs
.u
.r8
.al
)
4094 case 0x20: // coded by osmaker aka K.J.
4095 if(regs
.u
.r32
.edx
== 0x534D4150)
4097 extended_memory_size
= inb_cmos(0x35);
4098 extended_memory_size
<<= 8;
4099 extended_memory_size
|= inb_cmos(0x34);
4100 extended_memory_size
*= 64;
4101 // greater than EFF00000???
4102 if(extended_memory_size
> 0x3bc000) {
4103 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4105 extended_memory_size
*= 1024;
4106 extended_memory_size
+= (16L * 1024 * 1024);
4108 if(extended_memory_size
<= (16L * 1024 * 1024)) {
4109 extended_memory_size
= inb_cmos(0x31);
4110 extended_memory_size
<<= 8;
4111 extended_memory_size
|= inb_cmos(0x30);
4112 extended_memory_size
*= 1024;
4115 switch(regs
.u
.r16
.bx
)
4118 set_e820_range(ES
, regs
.u
.r16
.di
,
4119 0x0000000L
, 0x0009fc00L
, 1);
4121 regs
.u
.r32
.eax
= 0x534D4150;
4122 regs
.u
.r32
.ecx
= 0x14;
4127 set_e820_range(ES
, regs
.u
.r16
.di
,
4128 0x0009fc00L
, 0x000a0000L
, 2);
4130 regs
.u
.r32
.eax
= 0x534D4150;
4131 regs
.u
.r32
.ecx
= 0x14;
4136 set_e820_range(ES
, regs
.u
.r16
.di
,
4137 0x000e8000L
, 0x00100000L
, 2);
4139 regs
.u
.r32
.eax
= 0x534D4150;
4140 regs
.u
.r32
.ecx
= 0x14;
4145 set_e820_range(ES
, regs
.u
.r16
.di
,
4147 extended_memory_size
- 0x10000L
, 1);
4149 regs
.u
.r32
.eax
= 0x534D4150;
4150 regs
.u
.r32
.ecx
= 0x14;
4155 set_e820_range(ES
, regs
.u
.r16
.di
,
4156 extended_memory_size
- 0x10000L
,
4157 extended_memory_size
, 3); // ACPI RAM
4159 regs
.u
.r32
.eax
= 0x534D4150;
4160 regs
.u
.r32
.ecx
= 0x14;
4165 /* 256KB BIOS area at the end of 4 GB */
4166 set_e820_range(ES
, regs
.u
.r16
.di
,
4167 0xfffc0000L
, 0x00000000L
, 2);
4169 regs
.u
.r32
.eax
= 0x534D4150;
4170 regs
.u
.r32
.ecx
= 0x14;
4173 default: /* AX=E820, DX=534D4150, BX unrecognized */
4174 goto int15_unimplemented
;
4178 // if DX != 0x534D4150)
4179 goto int15_unimplemented
;
4184 // do we have any reason to fail here ?
4187 // my real system sets ax and bx to 0
4188 // this is confirmed by Ralph Brown list
4189 // but syslinux v1.48 is known to behave
4190 // strangely if ax is set to 0
4191 // regs.u.r16.ax = 0;
4192 // regs.u.r16.bx = 0;
4194 // Get the amount of extended memory (above 1M)
4195 regs
.u
.r8
.cl
= inb_cmos(0x30);
4196 regs
.u
.r8
.ch
= inb_cmos(0x31);
4199 if(regs
.u
.r16
.cx
> 0x3c00)
4201 regs
.u
.r16
.cx
= 0x3c00;
4204 // Get the amount of extended memory above 16M in 64k blocs
4205 regs
.u
.r8
.dl
= inb_cmos(0x34);
4206 regs
.u
.r8
.dh
= inb_cmos(0x35);
4208 // Set configured memory equal to extended memory
4209 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4210 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4212 default: /* AH=0xE8?? but not implemented */
4213 goto int15_unimplemented
;
4216 int15_unimplemented
:
4217 // fall into the default
4219 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4220 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4222 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4228 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4229 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4231 Bit8u scan_code
, ascii_code
, shift_flags
, led_flags
, count
;
4232 Bit16u kbd_code
, max
;
4234 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4236 shift_flags
= read_byte(0x0040, 0x17);
4237 led_flags
= read_byte(0x0040, 0x97);
4238 if ((((shift_flags
>> 4) & 0x07) ^ (led_flags
& 0x07)) != 0) {
4243 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4244 if ((inb(0x60) == 0xfa)) {
4246 led_flags
|= ((shift_flags
>> 4) & 0x07);
4247 outb(0x60, led_flags
& 0x07);
4248 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4250 write_byte(0x0040, 0x97, led_flags
);
4258 case 0x00: /* read keyboard input */
4260 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4261 BX_PANIC("KBD: int16h: out of keyboard input\n");
4263 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4264 else if (ascii_code
== 0xE0) ascii_code
= 0;
4265 AX
= (scan_code
<< 8) | ascii_code
;
4268 case 0x01: /* check keyboard status */
4269 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4273 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4274 else if (ascii_code
== 0xE0) ascii_code
= 0;
4275 AX
= (scan_code
<< 8) | ascii_code
;
4279 case 0x02: /* get shift flag status */
4280 shift_flags
= read_byte(0x0040, 0x17);
4281 SET_AL(shift_flags
);
4284 case 0x05: /* store key-stroke into buffer */
4285 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4293 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4294 // bit Bochs Description
4296 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4297 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4298 // 4 1 INT 16/AH=0Ah supported
4299 // 3 0 INT 16/AX=0306h supported
4300 // 2 0 INT 16/AX=0305h supported
4301 // 1 0 INT 16/AX=0304h supported
4302 // 0 0 INT 16/AX=0300h supported
4307 case 0x0A: /* GET KEYBOARD ID */
4313 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4315 if ((inb(0x60) == 0xfa)) {
4318 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4321 kbd_code
|= (inb(0x60) << 8);
4323 } while (--count
>0);
4329 case 0x10: /* read MF-II keyboard input */
4331 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4332 BX_PANIC("KBD: int16h: out of keyboard input\n");
4334 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4335 AX
= (scan_code
<< 8) | ascii_code
;
4338 case 0x11: /* check MF-II keyboard status */
4339 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4343 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4344 AX
= (scan_code
<< 8) | ascii_code
;
4348 case 0x12: /* get extended keyboard status */
4349 shift_flags
= read_byte(0x0040, 0x17);
4350 SET_AL(shift_flags
);
4351 shift_flags
= read_byte(0x0040, 0x18) & 0x73;
4352 shift_flags
|= read_byte(0x0040, 0x96) & 0x0c;
4353 SET_AH(shift_flags
);
4354 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4357 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4358 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4361 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4362 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4366 if (GET_AL() == 0x08)
4367 SET_AH(0x02); // unsupported, aka normal keyboard
4370 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4375 dequeue_key(scan_code
, ascii_code
, incr
)
4380 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4385 buffer_start
= 0x001E;
4386 buffer_end
= 0x003E;
4388 buffer_start
= read_word(0x0040, 0x0080);
4389 buffer_end
= read_word(0x0040, 0x0082);
4392 buffer_head
= read_word(0x0040, 0x001a);
4393 buffer_tail
= read_word(0x0040, 0x001c);
4395 if (buffer_head
!= buffer_tail
) {
4397 acode
= read_byte(0x0040, buffer_head
);
4398 scode
= read_byte(0x0040, buffer_head
+1);
4399 write_byte(ss
, ascii_code
, acode
);
4400 write_byte(ss
, scan_code
, scode
);
4404 if (buffer_head
>= buffer_end
)
4405 buffer_head
= buffer_start
;
4406 write_word(0x0040, 0x001a, buffer_head
);
4415 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4418 inhibit_mouse_int_and_events()
4420 Bit8u command_byte
, prev_command_byte
;
4422 // Turn off IRQ generation and aux data line
4423 if ( inb(0x64) & 0x02 )
4424 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4425 outb(0x64, 0x20); // get command byte
4426 while ( (inb(0x64) & 0x01) != 0x01 );
4427 prev_command_byte
= inb(0x60);
4428 command_byte
= prev_command_byte
;
4429 //while ( (inb(0x64) & 0x02) );
4430 if ( inb(0x64) & 0x02 )
4431 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4432 command_byte
&= 0xfd; // turn off IRQ 12 generation
4433 command_byte
|= 0x20; // disable mouse serial clock line
4434 outb(0x64, 0x60); // write command byte
4435 outb(0x60, command_byte
);
4436 return(prev_command_byte
);
4440 enable_mouse_int_and_events()
4444 // Turn on IRQ generation and aux data line
4445 if ( inb(0x64) & 0x02 )
4446 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4447 outb(0x64, 0x20); // get command byte
4448 while ( (inb(0x64) & 0x01) != 0x01 );
4449 command_byte
= inb(0x60);
4450 //while ( (inb(0x64) & 0x02) );
4451 if ( inb(0x64) & 0x02 )
4452 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4453 command_byte
|= 0x02; // turn on IRQ 12 generation
4454 command_byte
&= 0xdf; // enable mouse serial clock line
4455 outb(0x64, 0x60); // write command byte
4456 outb(0x60, command_byte
);
4460 send_to_mouse_ctrl(sendbyte
)
4465 // wait for chance to write to ctrl
4466 if ( inb(0x64) & 0x02 )
4467 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4469 outb(0x60, sendbyte
);
4475 get_mouse_data(data
)
4481 while ( (inb(0x64) & 0x21) != 0x21 ) {
4484 response
= inb(0x60);
4487 write_byte(ss
, data
, response
);
4492 set_kbd_command_byte(command_byte
)
4495 if ( inb(0x64) & 0x02 )
4496 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4499 outb(0x64, 0x60); // write command byte
4500 outb(0x60, command_byte
);
4504 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4505 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4507 Bit8u scancode
, asciicode
, shift_flags
;
4508 Bit8u mf2_flags
, mf2_state
;
4511 // DS has been set to F000 before call
4515 scancode
= GET_AL();
4517 if (scancode
== 0) {
4518 BX_INFO("KBD: int09 handler: AL=0\n");
4523 shift_flags
= read_byte(0x0040, 0x17);
4524 mf2_flags
= read_byte(0x0040, 0x18);
4525 mf2_state
= read_byte(0x0040, 0x96);
4529 case 0x3a: /* Caps Lock press */
4530 shift_flags
^= 0x40;
4531 write_byte(0x0040, 0x17, shift_flags
);
4533 write_byte(0x0040, 0x18, mf2_flags
);
4535 case 0xba: /* Caps Lock release */
4537 write_byte(0x0040, 0x18, mf2_flags
);
4540 case 0x2a: /* L Shift press */
4541 shift_flags
|= 0x02;
4542 write_byte(0x0040, 0x17, shift_flags
);
4544 case 0xaa: /* L Shift release */
4545 shift_flags
&= ~0x02;
4546 write_byte(0x0040, 0x17, shift_flags
);
4549 case 0x36: /* R Shift press */
4550 shift_flags
|= 0x01;
4551 write_byte(0x0040, 0x17, shift_flags
);
4553 case 0xb6: /* R Shift release */
4554 shift_flags
&= ~0x01;
4555 write_byte(0x0040, 0x17, shift_flags
);
4558 case 0x1d: /* Ctrl press */
4559 if ((mf2_state
& 0x01) == 0) {
4560 shift_flags
|= 0x04;
4561 write_byte(0x0040, 0x17, shift_flags
);
4562 if (mf2_state
& 0x02) {
4564 write_byte(0x0040, 0x96, mf2_state
);
4567 write_byte(0x0040, 0x18, mf2_flags
);
4571 case 0x9d: /* Ctrl release */
4572 if ((mf2_state
& 0x01) == 0) {
4573 shift_flags
&= ~0x04;
4574 write_byte(0x0040, 0x17, shift_flags
);
4575 if (mf2_state
& 0x02) {
4577 write_byte(0x0040, 0x96, mf2_state
);
4580 write_byte(0x0040, 0x18, mf2_flags
);
4585 case 0x38: /* Alt press */
4586 shift_flags
|= 0x08;
4587 write_byte(0x0040, 0x17, shift_flags
);
4588 if (mf2_state
& 0x02) {
4590 write_byte(0x0040, 0x96, mf2_state
);
4593 write_byte(0x0040, 0x18, mf2_flags
);
4596 case 0xb8: /* Alt release */
4597 shift_flags
&= ~0x08;
4598 write_byte(0x0040, 0x17, shift_flags
);
4599 if (mf2_state
& 0x02) {
4601 write_byte(0x0040, 0x96, mf2_state
);
4604 write_byte(0x0040, 0x18, mf2_flags
);
4608 case 0x45: /* Num Lock press */
4609 if ((mf2_state
& 0x03) == 0) {
4611 write_byte(0x0040, 0x18, mf2_flags
);
4612 shift_flags
^= 0x20;
4613 write_byte(0x0040, 0x17, shift_flags
);
4616 case 0xc5: /* Num Lock release */
4617 if ((mf2_state
& 0x03) == 0) {
4619 write_byte(0x0040, 0x18, mf2_flags
);
4623 case 0x46: /* Scroll Lock press */
4625 write_byte(0x0040, 0x18, mf2_flags
);
4626 shift_flags
^= 0x10;
4627 write_byte(0x0040, 0x17, shift_flags
);
4630 case 0xc6: /* Scroll Lock release */
4632 write_byte(0x0040, 0x18, mf2_flags
);
4636 if (scancode
& 0x80) {
4637 break; /* toss key releases ... */
4639 if (scancode
> MAX_SCAN_CODE
) {
4640 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode
);
4643 if (shift_flags
& 0x08) { /* ALT */
4644 asciicode
= scan_to_scanascii
[scancode
].alt
;
4645 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4646 } else if (shift_flags
& 0x04) { /* CONTROL */
4647 asciicode
= scan_to_scanascii
[scancode
].control
;
4648 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4649 } else if (((mf2_state
& 0x02) > 0) && ((scancode
>= 0x47) && (scancode
<= 0x53))) {
4650 /* extended keys handling */
4652 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4653 } else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4654 /* check if lock state should be ignored
4655 * because a SHIFT key are pressed */
4657 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4658 asciicode
= scan_to_scanascii
[scancode
].normal
;
4659 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4661 asciicode
= scan_to_scanascii
[scancode
].shift
;
4662 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4665 /* check if lock is on */
4666 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4667 asciicode
= scan_to_scanascii
[scancode
].shift
;
4668 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4670 asciicode
= scan_to_scanascii
[scancode
].normal
;
4671 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4674 if (scancode
==0 && asciicode
==0) {
4675 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4677 enqueue_key(scancode
, asciicode
);
4680 if ((scancode
& 0x7f) != 0x1d) {
4684 write_byte(0x0040, 0x96, mf2_state
);
4688 enqueue_key(scan_code
, ascii_code
)
4689 Bit8u scan_code
, ascii_code
;
4691 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4694 buffer_start
= 0x001E;
4695 buffer_end
= 0x003E;
4697 buffer_start
= read_word(0x0040, 0x0080);
4698 buffer_end
= read_word(0x0040, 0x0082);
4701 buffer_head
= read_word(0x0040, 0x001A);
4702 buffer_tail
= read_word(0x0040, 0x001C);
4704 temp_tail
= buffer_tail
;
4706 if (buffer_tail
>= buffer_end
)
4707 buffer_tail
= buffer_start
;
4709 if (buffer_tail
== buffer_head
) {
4713 write_byte(0x0040, temp_tail
, ascii_code
);
4714 write_byte(0x0040, temp_tail
+1, scan_code
);
4715 write_word(0x0040, 0x001C, buffer_tail
);
4721 int74_function(make_farcall
, Z
, Y
, X
, status
)
4722 Bit16u make_farcall
, Z
, Y
, X
, status
;
4724 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4725 Bit8u in_byte
, index
, package_count
;
4726 Bit8u mouse_flags_1
, mouse_flags_2
;
4728 BX_DEBUG_INT74("entering int74_function\n");
4731 in_byte
= inb(0x64);
4732 if ( (in_byte
& 0x21) != 0x21 ) {
4735 in_byte
= inb(0x60);
4736 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4738 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4739 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4741 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4745 package_count
= mouse_flags_2
& 0x07;
4746 index
= mouse_flags_1
& 0x07;
4747 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4749 if ( (index
+1) >= package_count
) {
4750 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4751 status
= read_byte(ebda_seg
, 0x0028 + 0);
4752 X
= read_byte(ebda_seg
, 0x0028 + 1);
4753 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4756 // check if far call handler installed
4757 if (mouse_flags_2
& 0x80)
4763 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4766 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4771 int13_harddisk(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
4772 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
4775 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4776 Bit16u cylinder
, head
, sector
;
4777 Bit16u segment
, offset
;
4778 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4780 Bit8u device
, status
;
4782 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4784 write_byte(0x0040, 0x008e, 0); // clear completion flag
4786 // basic check : device has to be defined
4787 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4788 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4792 // Get the ata channel
4793 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_ELDL()-0x80]);
4795 // basic check : device has to be valid
4796 if (device
>= BX_MAX_ATA_DEVICES
) {
4797 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4803 case 0x00: /* disk controller reset */
4808 case 0x01: /* read disk status */
4809 status
= read_byte(0x0040, 0x0074);
4811 SET_DISK_RET_STATUS(0);
4812 /* set CF if error status read */
4813 if (status
) goto int13_fail_nostatus
;
4814 else goto int13_success_noah
;
4817 case 0x02: // read disk sectors
4818 case 0x03: // write disk sectors
4819 case 0x04: // verify disk sectors
4822 cylinder
= GET_CH();
4823 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
4824 sector
= (GET_CL() & 0x3f);
4830 if ( (count
> 128) || (count
== 0) ) {
4831 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4835 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4836 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4837 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4839 // sanity check on cyl heads, sec
4840 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
4841 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
4846 if ( GET_AH() == 0x04 ) goto int13_success
;
4848 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4849 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4851 // if needed, translate lchs to lba, and execute command
4852 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
4853 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
4854 sector
= 0; // this forces the command to be lba
4857 if ( GET_AH() == 0x02 )
4858 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4860 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4862 // Set nb of sector transferred
4863 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
4866 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4868 goto int13_fail_noah
;
4874 case 0x05: /* format disk track */
4875 BX_INFO("format disk track called\n");
4880 case 0x08: /* read disk drive parameters */
4882 // Get logical geometry from table
4883 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4884 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4885 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4886 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
4888 nlc
= nlc
- 2; /* 0 based , last sector not used */
4891 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
4893 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
4895 // FIXME should set ES & DI
4900 case 0x10: /* check drive ready */
4901 // should look at 40:8E also???
4903 // Read the status from controller
4904 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
4905 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
4910 goto int13_fail_noah
;
4914 case 0x15: /* read disk drive size */
4916 // Get physical geometry from table
4917 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
4918 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4919 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4921 // Compute sector count seen by int13
4922 lba
= (Bit32u
)(npc
- 1) * (Bit32u
)nph
* (Bit32u
)npspt
;
4926 SET_AH(3); // hard disk accessible
4927 goto int13_success_noah
;
4930 case 0x41: // IBM/MS installation check
4931 BX
=0xaa55; // install check
4932 SET_AH(0x30); // EDD 3.0
4933 CX
=0x0007; // ext disk access and edd, removable supported
4934 goto int13_success_noah
;
4937 case 0x42: // IBM/MS extended read
4938 case 0x43: // IBM/MS extended write
4939 case 0x44: // IBM/MS verify
4940 case 0x47: // IBM/MS extended seek
4942 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
4943 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
4944 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
4946 // Can't use 64 bits lba
4947 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
4949 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4953 // Get 32 bits lba and check
4954 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
4955 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
4956 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4960 // If verify or seek
4961 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4964 // Execute the command
4965 if ( GET_AH() == 0x42 )
4966 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4968 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4970 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
4971 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
4974 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4976 goto int13_fail_noah
;
4982 case 0x45: // IBM/MS lock/unlock drive
4983 case 0x49: // IBM/MS extended media change
4984 goto int13_success
; // Always success for HD
4987 case 0x46: // IBM/MS eject media
4988 SET_AH(0xb2); // Volume Not Removable
4989 goto int13_fail_noah
; // Always fail for HD
4992 case 0x48: // IBM/MS get drive parameters
4993 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
4995 // Buffer is too small
5003 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
5004 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
5005 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
5006 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
5007 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5009 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5010 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
5011 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
5012 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
5013 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
5014 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
5015 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
5016 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5021 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
5022 Bit16u iobase1
, iobase2
, options
;
5024 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5026 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5027 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5030 channel
= device
/ 2;
5031 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5032 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5033 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5034 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5035 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
5037 options
= (translation
==ATA_TRANSLATION_NONE
?0:1<<3); // chs translation
5038 options
|= (1<<4); // lba translation
5039 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5040 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0<<9);
5041 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0<<9);
5043 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5044 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5045 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5046 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5047 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5048 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5049 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5050 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5051 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5052 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5053 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5056 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5057 checksum
= ~checksum
;
5058 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5063 Bit8u channel
, iface
, checksum
, i
;
5066 channel
= device
/ 2;
5067 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5068 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5070 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5071 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5072 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5073 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5074 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5076 if (iface
==ATA_IFACE_ISA
) {
5077 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5078 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5079 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5080 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5085 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5086 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5087 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5088 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5090 if (iface
==ATA_IFACE_ISA
) {
5091 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5092 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5093 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5098 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5099 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5100 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5101 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5104 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5105 checksum
= ~checksum
;
5106 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5112 case 0x4e: // // IBM/MS set hardware configuration
5113 // DMA, prefetch, PIO maximum not supported
5126 case 0x09: /* initialize drive parameters */
5127 case 0x0c: /* seek to specified cylinder */
5128 case 0x0d: /* alternate disk reset */
5129 case 0x11: /* recalibrate */
5130 case 0x14: /* controller internal diagnostic */
5131 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5135 case 0x0a: /* read disk sectors with ECC */
5136 case 0x0b: /* write disk sectors with ECC */
5137 case 0x18: // set media type for format
5138 case 0x50: // IBM/MS send packet command
5140 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5146 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5148 SET_DISK_RET_STATUS(GET_AH());
5149 int13_fail_nostatus
:
5150 SET_CF(); // error occurred
5154 SET_AH(0x00); // no error
5156 SET_DISK_RET_STATUS(0x00);
5157 CLEAR_CF(); // no error
5161 // ---------------------------------------------------------------------------
5162 // Start of int13 for cdrom
5163 // ---------------------------------------------------------------------------
5166 int13_cdrom(EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5167 Bit16u EHBX
, DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5169 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5170 Bit8u device
, status
, locks
;
5173 Bit16u count
, segment
, offset
, i
, size
;
5175 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5177 SET_DISK_RET_STATUS(0x00);
5179 /* basic check : device should be 0xE0+ */
5180 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
5181 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5185 // Get the ata channel
5186 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_ELDL()-0xE0]);
5188 /* basic check : device has to be valid */
5189 if (device
>= BX_MAX_ATA_DEVICES
) {
5190 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5196 // all those functions return SUCCESS
5197 case 0x00: /* disk controller reset */
5198 case 0x09: /* initialize drive parameters */
5199 case 0x0c: /* seek to specified cylinder */
5200 case 0x0d: /* alternate disk reset */
5201 case 0x10: /* check drive ready */
5202 case 0x11: /* recalibrate */
5203 case 0x14: /* controller internal diagnostic */
5204 case 0x16: /* detect disk change */
5208 // all those functions return disk write-protected
5209 case 0x03: /* write disk sectors */
5210 case 0x05: /* format disk track */
5211 case 0x43: // IBM/MS extended write
5213 goto int13_fail_noah
;
5216 case 0x01: /* read disk status */
5217 status
= read_byte(0x0040, 0x0074);
5219 SET_DISK_RET_STATUS(0);
5221 /* set CF if error status read */
5222 if (status
) goto int13_fail_nostatus
;
5223 else goto int13_success_noah
;
5226 case 0x15: /* read disk drive size */
5228 goto int13_fail_noah
;
5231 case 0x41: // IBM/MS installation check
5232 BX
=0xaa55; // install check
5233 SET_AH(0x30); // EDD 2.1
5234 CX
=0x0007; // ext disk access, removable and edd
5235 goto int13_success_noah
;
5238 case 0x42: // IBM/MS extended read
5239 case 0x44: // IBM/MS verify sectors
5240 case 0x47: // IBM/MS extended seek
5242 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5243 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5244 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5246 // Can't use 64 bits lba
5247 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5249 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5254 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5256 // If verify or seek
5257 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5260 memsetb(get_SS(),atacmd
,0,12);
5261 atacmd
[0]=0x28; // READ command
5262 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5263 atacmd
[8]=(count
& 0x00ff); // Sectors
5264 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5265 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5266 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5267 atacmd
[5]=(lba
& 0x000000ff);
5268 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5270 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5271 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5274 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5276 goto int13_fail_noah
;
5282 case 0x45: // IBM/MS lock/unlock drive
5283 if (GET_AL() > 2) goto int13_fail
;
5285 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5289 if (locks
== 0xff) {
5292 goto int13_fail_noah
;
5294 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5298 if (locks
== 0x00) {
5301 goto int13_fail_noah
;
5303 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5304 SET_AL(locks
==0?0:1);
5307 SET_AL(locks
==0?0:1);
5313 case 0x46: // IBM/MS eject media
5314 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5317 SET_AH(0xb1); // media locked
5318 goto int13_fail_noah
;
5320 // FIXME should handle 0x31 no media in device
5321 // FIXME should handle 0xb5 valid request failed
5323 // Call removable media eject
5330 mov _int13_cdrom
.status
+ 2[bp
], ah
5331 jnc int13_cdrom_rme_end
5332 mov _int13_cdrom
.status
, #1
5333 int13_cdrom_rme_end
:
5338 SET_AH(0xb1); // media locked
5339 goto int13_fail_noah
;
5345 case 0x48: // IBM/MS get drive parameters
5346 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5348 // Buffer is too small
5354 Bit16u cylinders
, heads
, spt
, blksize
;
5356 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5358 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5359 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5360 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5361 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5362 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5363 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5364 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5365 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5370 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5371 Bit16u iobase1
, iobase2
, options
;
5373 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5375 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5376 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5379 channel
= device
/ 2;
5380 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5381 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5382 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5383 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5385 // FIXME atapi device
5386 options
= (1<<4); // lba translation
5387 options
|= (1<<5); // removable device
5388 options
|= (1<<6); // atapi device
5389 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5391 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5392 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5393 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5394 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5395 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5396 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5397 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5398 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5399 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5400 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5401 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5404 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5405 checksum
= ~checksum
;
5406 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5411 Bit8u channel
, iface
, checksum
, i
;
5414 channel
= device
/ 2;
5415 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5416 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5418 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5419 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5420 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5421 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5422 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5424 if (iface
==ATA_IFACE_ISA
) {
5425 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5426 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5427 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5428 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5433 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5434 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5435 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5436 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5438 if (iface
==ATA_IFACE_ISA
) {
5439 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5440 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5441 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5446 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5447 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5448 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5449 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5452 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5453 checksum
= ~checksum
;
5454 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5460 case 0x49: // IBM/MS extended media change
5461 // always send changed ??
5463 goto int13_fail_nostatus
;
5466 case 0x4e: // // IBM/MS set hardware configuration
5467 // DMA, prefetch, PIO maximum not supported
5480 // all those functions return unimplemented
5481 case 0x02: /* read sectors */
5482 case 0x04: /* verify sectors */
5483 case 0x08: /* read disk drive parameters */
5484 case 0x0a: /* read disk sectors with ECC */
5485 case 0x0b: /* write disk sectors with ECC */
5486 case 0x18: /* set media type for format */
5487 case 0x50: // ? - send packet command
5489 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5495 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5497 SET_DISK_RET_STATUS(GET_AH());
5498 int13_fail_nostatus
:
5499 SET_CF(); // error occurred
5503 SET_AH(0x00); // no error
5505 SET_DISK_RET_STATUS(0x00);
5506 CLEAR_CF(); // no error
5510 // ---------------------------------------------------------------------------
5511 // End of int13 for cdrom
5512 // ---------------------------------------------------------------------------
5514 #if BX_ELTORITO_BOOT
5515 // ---------------------------------------------------------------------------
5516 // Start of int13 for eltorito functions
5517 // ---------------------------------------------------------------------------
5520 int13_eltorito(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5521 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5523 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5525 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5526 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5530 // FIXME ElTorito Various. Should be implemented
5531 case 0x4a: // ElTorito - Initiate disk emu
5532 case 0x4c: // ElTorito - Initiate disk emu and boot
5533 case 0x4d: // ElTorito - Return Boot catalog
5534 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5538 case 0x4b: // ElTorito - Terminate disk emu
5539 // FIXME ElTorito Hardcoded
5540 write_byte(DS
,SI
+0x00,0x13);
5541 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5542 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5543 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5544 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5545 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5546 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5547 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5548 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5549 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5550 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5551 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5553 // If we have to terminate emulation
5554 if(GET_AL() == 0x00) {
5555 // FIXME ElTorito Various. Should be handled accordingly to spec
5556 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5563 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5569 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5570 SET_DISK_RET_STATUS(GET_AH());
5571 SET_CF(); // error occurred
5575 SET_AH(0x00); // no error
5576 SET_DISK_RET_STATUS(0x00);
5577 CLEAR_CF(); // no error
5581 // ---------------------------------------------------------------------------
5582 // End of int13 for eltorito functions
5583 // ---------------------------------------------------------------------------
5585 // ---------------------------------------------------------------------------
5586 // Start of int13 when emulating a device from the cd
5587 // ---------------------------------------------------------------------------
5590 int13_cdemu(DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5591 Bit16u DS
, ES
, DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5593 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5594 Bit8u device
, status
;
5595 Bit16u vheads
, vspt
, vcylinders
;
5596 Bit16u head
, sector
, cylinder
, nbsectors
;
5597 Bit32u vlba
, ilba
, slba
, elba
;
5598 Bit16u before
, segment
, offset
;
5601 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5603 /* at this point, we are emulating a floppy/harddisk */
5605 // Recompute the device number
5606 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5607 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5609 SET_DISK_RET_STATUS(0x00);
5611 /* basic checks : emulation should be active, dl should equal the emulated drive */
5612 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5613 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5614 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5620 // all those functions return SUCCESS
5621 case 0x00: /* disk controller reset */
5622 case 0x09: /* initialize drive parameters */
5623 case 0x0c: /* seek to specified cylinder */
5624 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5625 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5626 case 0x11: /* recalibrate */
5627 case 0x14: /* controller internal diagnostic */
5628 case 0x16: /* detect disk change */
5632 // all those functions return disk write-protected
5633 case 0x03: /* write disk sectors */
5634 case 0x05: /* format disk track */
5636 goto int13_fail_noah
;
5639 case 0x01: /* read disk status */
5640 status
=read_byte(0x0040, 0x0074);
5642 SET_DISK_RET_STATUS(0);
5644 /* set CF if error status read */
5645 if (status
) goto int13_fail_nostatus
;
5646 else goto int13_success_noah
;
5649 case 0x02: // read disk sectors
5650 case 0x04: // verify disk sectors
5651 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5652 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5653 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5655 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5657 sector
= GET_CL() & 0x003f;
5658 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5660 nbsectors
= GET_AL();
5664 // no sector to read ?
5665 if(nbsectors
==0) goto int13_success
;
5667 // sanity checks sco openserver needs this!
5669 || (cylinder
>= vcylinders
)
5670 || (head
>= vheads
)) {
5674 // After controls, verify do nothing
5675 if (GET_AH() == 0x04) goto int13_success
;
5677 segment
= ES
+(BX
/ 16);
5680 // calculate the virtual lba inside the image
5681 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5683 // In advance so we don't loose the count
5687 slba
= (Bit32u
)vlba
/4;
5688 before
= (Bit16u
)vlba
%4;
5691 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5693 memsetb(get_SS(),atacmd
,0,12);
5694 atacmd
[0]=0x28; // READ command
5695 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5696 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5697 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5698 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5699 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5700 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5701 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5702 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5705 goto int13_fail_noah
;
5711 case 0x08: /* read disk drive parameters */
5712 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5713 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5714 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5718 SET_CH( vcylinders
& 0xff );
5719 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5721 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5722 // FIXME ElTorito Harddisk. should send the HD count
5724 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5725 case 0x01: SET_BL( 0x02 ); break;
5726 case 0x02: SET_BL( 0x04 ); break;
5727 case 0x03: SET_BL( 0x06 ); break;
5733 mov ax
, #diskette_param_table2
5734 mov _int13_cdemu
.DI
+2[bp
], ax
5735 mov _int13_cdemu
.ES
+2[bp
], cs
5741 case 0x15: /* read disk drive size */
5742 // FIXME ElTorito Harddisk. What geometry to send ?
5744 goto int13_success_noah
;
5747 // all those functions return unimplemented
5748 case 0x0a: /* read disk sectors with ECC */
5749 case 0x0b: /* write disk sectors with ECC */
5750 case 0x18: /* set media type for format */
5751 case 0x41: // IBM/MS installation check
5752 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5753 case 0x42: // IBM/MS extended read
5754 case 0x43: // IBM/MS extended write
5755 case 0x44: // IBM/MS verify sectors
5756 case 0x45: // IBM/MS lock/unlock drive
5757 case 0x46: // IBM/MS eject media
5758 case 0x47: // IBM/MS extended seek
5759 case 0x48: // IBM/MS get drive parameters
5760 case 0x49: // IBM/MS extended media change
5761 case 0x4e: // ? - set hardware configuration
5762 case 0x50: // ? - send packet command
5764 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5770 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5772 SET_DISK_RET_STATUS(GET_AH());
5773 int13_fail_nostatus
:
5774 SET_CF(); // error occurred
5778 SET_AH(0x00); // no error
5780 SET_DISK_RET_STATUS(0x00);
5781 CLEAR_CF(); // no error
5785 // ---------------------------------------------------------------------------
5786 // End of int13 when emulating a device from the cd
5787 // ---------------------------------------------------------------------------
5789 #endif // BX_ELTORITO_BOOT
5791 #else //BX_USE_ATADRV
5794 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
5809 mov ax
,4[bp
] // cylinder
5811 mov bl
,6[bp
] // hd_heads
5814 mov bl
,8[bp
] // head
5816 mov bl
,10[bp
] // hd_sectors
5818 mov bl
,12[bp
] // sector
5847 int13_harddisk(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
5848 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
5850 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
5854 Bit16u max_cylinder
, cylinder
, total_sectors
;
5855 Bit16u hd_cylinders
;
5856 Bit8u hd_heads
, hd_sectors
;
5863 Bit16u count
, segment
, offset
;
5867 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5869 write_byte(0x0040, 0x008e, 0); // clear completion flag
5871 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5873 /* check how many disks first (cmos reg 0x12), return an error if
5874 drive not present */
5875 drive_map
= inb_cmos(0x12);
5876 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
5877 (((drive_map
& 0x0f)==0) ? 0 : 2);
5878 n_drives
= (drive_map
==0) ? 0 :
5879 ((drive_map
==3) ? 2 : 1);
5881 if (!(drive_map
& (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5883 SET_DISK_RET_STATUS(0x01);
5884 SET_CF(); /* error occurred */
5890 case 0x00: /* disk controller reset */
5891 BX_DEBUG_INT13_HD("int13_f00\n");
5894 SET_DISK_RET_STATUS(0);
5895 set_diskette_ret_status(0);
5896 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5897 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5898 CLEAR_CF(); /* successful */
5902 case 0x01: /* read disk status */
5903 BX_DEBUG_INT13_HD("int13_f01\n");
5904 status
= read_byte(0x0040, 0x0074);
5906 SET_DISK_RET_STATUS(0);
5907 /* set CF if error status read */
5908 if (status
) SET_CF();
5913 case 0x04: // verify disk sectors
5914 case 0x02: // read disk sectors
5916 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
5918 num_sectors
= GET_AL();
5919 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5920 sector
= (GET_CL() & 0x3f);
5924 if (hd_cylinders
> 1024) {
5925 if (hd_cylinders
<= 2048) {
5928 else if (hd_cylinders
<= 4096) {
5931 else if (hd_cylinders
<= 8192) {
5934 else { // hd_cylinders <= 16384
5938 ax
= head
/ hd_heads
;
5939 cyl_mod
= ax
& 0xff;
5941 cylinder
|= cyl_mod
;
5944 if ( (cylinder
>= hd_cylinders
) ||
5945 (sector
> hd_sectors
) ||
5946 (head
>= hd_heads
) ) {
5948 SET_DISK_RET_STATUS(1);
5949 SET_CF(); /* error occurred */
5953 if ( (num_sectors
> 128) || (num_sectors
== 0) )
5954 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5957 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5959 if ( GET_AH() == 0x04 ) {
5961 SET_DISK_RET_STATUS(0);
5966 status
= inb(0x1f7);
5967 if (status
& 0x80) {
5968 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5970 outb(0x01f2, num_sectors
);
5971 /* activate LBA? (tomv) */
5972 if (hd_heads
> 16) {
5973 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
5974 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
5977 outb(0x01f3, sector
);
5978 outb(0x01f4, cylinder
& 0x00ff);
5979 outb(0x01f5, cylinder
>> 8);
5980 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
5985 status
= inb(0x1f7);
5986 if ( !(status
& 0x80) ) break;
5989 if (status
& 0x01) {
5990 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
5991 } else if ( !(status
& 0x08) ) {
5992 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
5993 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6000 sti
;; enable higher priority interrupts
6005 ;; store temp bx in real DI
register
6008 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
6011 ;; adjust
if there will be an overrun
6013 jbe i13_f02_no_adjust
6015 sub di
, #0x0200 ; sub 512 bytes from offset
6017 add ax
, #0x0020 ; add 512 to segment
6021 mov cx
, #0x0100 ;; counter (256 words = 512b)
6022 mov dx
, #0x01f0 ;; AT data read port
6025 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
6028 ;; store real DI
register back to temp bx
6031 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
6037 if (num_sectors
== 0) {
6038 status
= inb(0x1f7);
6039 if ( (status
& 0xc9) != 0x40 )
6040 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
6044 status
= inb(0x1f7);
6045 if ( (status
& 0xc9) != 0x48 )
6046 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
6052 SET_DISK_RET_STATUS(0);
6053 SET_AL(sector_count
);
6054 CLEAR_CF(); /* successful */
6059 case 0x03: /* write disk sectors */
6060 BX_DEBUG_INT13_HD("int13_f03\n");
6061 drive
= GET_ELDL ();
6062 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6064 num_sectors
= GET_AL();
6065 cylinder
= GET_CH();
6066 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
6067 sector
= (GET_CL() & 0x3f);
6070 if (hd_cylinders
> 1024) {
6071 if (hd_cylinders
<= 2048) {
6074 else if (hd_cylinders
<= 4096) {
6077 else if (hd_cylinders
<= 8192) {
6080 else { // hd_cylinders <= 16384
6084 ax
= head
/ hd_heads
;
6085 cyl_mod
= ax
& 0xff;
6087 cylinder
|= cyl_mod
;
6090 if ( (cylinder
>= hd_cylinders
) ||
6091 (sector
> hd_sectors
) ||
6092 (head
>= hd_heads
) ) {
6094 SET_DISK_RET_STATUS(1);
6095 SET_CF(); /* error occurred */
6099 if ( (num_sectors
> 128) || (num_sectors
== 0) )
6100 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6103 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6105 status
= inb(0x1f7);
6106 if (status
& 0x80) {
6107 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6109 // should check for Drive Ready Bit also in status reg
6110 outb(0x01f2, num_sectors
);
6112 /* activate LBA? (tomv) */
6113 if (hd_heads
> 16) {
6114 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
6115 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_ELDL());
6118 outb(0x01f3, sector
);
6119 outb(0x01f4, cylinder
& 0x00ff);
6120 outb(0x01f5, cylinder
>> 8);
6121 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head
& 0x0f));
6125 // wait for busy bit to turn off after seeking
6127 status
= inb(0x1f7);
6128 if ( !(status
& 0x80) ) break;
6131 if ( !(status
& 0x08) ) {
6132 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
6133 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6140 sti
;; enable higher priority interrupts
6145 ;; store temp bx in real SI
register
6148 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
6151 ;; adjust
if there will be an overrun
6153 jbe i13_f03_no_adjust
6155 sub si
, #0x0200 ; sub 512 bytes from offset
6157 add ax
, #0x0020 ; add 512 to segment
6161 mov cx
, #0x0100 ;; counter (256 words = 512b)
6162 mov dx
, #0x01f0 ;; AT data read port
6166 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
6168 ;; store real SI
register back to temp bx
6171 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
6177 if (num_sectors
== 0) {
6178 status
= inb(0x1f7);
6179 if ( (status
& 0xe9) != 0x40 )
6180 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
6184 status
= inb(0x1f7);
6185 if ( (status
& 0xc9) != 0x48 )
6186 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
6192 SET_DISK_RET_STATUS(0);
6193 SET_AL(sector_count
);
6194 CLEAR_CF(); /* successful */
6198 case 0x05: /* format disk track */
6199 BX_DEBUG_INT13_HD("int13_f05\n");
6200 BX_PANIC("format disk track called\n");
6203 SET_DISK_RET_STATUS(0);
6204 CLEAR_CF(); /* successful */
6208 case 0x08: /* read disk drive parameters */
6209 BX_DEBUG_INT13_HD("int13_f08\n");
6211 drive
= GET_ELDL ();
6212 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6216 if (hd_cylinders
<= 1024) {
6217 // hd_cylinders >>= 0;
6220 else if (hd_cylinders
<= 2048) {
6224 else if (hd_cylinders
<= 4096) {
6228 else if (hd_cylinders
<= 8192) {
6232 else { // hd_cylinders <= 16384
6237 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6239 SET_CH(max_cylinder
& 0xff);
6240 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6241 SET_DH(hd_heads
- 1);
6242 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6244 SET_DISK_RET_STATUS(0);
6245 CLEAR_CF(); /* successful */
6250 case 0x09: /* initialize drive parameters */
6251 BX_DEBUG_INT13_HD("int13_f09\n");
6253 SET_DISK_RET_STATUS(0);
6254 CLEAR_CF(); /* successful */
6258 case 0x0a: /* read disk sectors with ECC */
6259 BX_DEBUG_INT13_HD("int13_f0a\n");
6260 case 0x0b: /* write disk sectors with ECC */
6261 BX_DEBUG_INT13_HD("int13_f0b\n");
6262 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6266 case 0x0c: /* seek to specified cylinder */
6267 BX_DEBUG_INT13_HD("int13_f0c\n");
6268 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6270 SET_DISK_RET_STATUS(0);
6271 CLEAR_CF(); /* successful */
6275 case 0x0d: /* alternate disk reset */
6276 BX_DEBUG_INT13_HD("int13_f0d\n");
6278 SET_DISK_RET_STATUS(0);
6279 CLEAR_CF(); /* successful */
6283 case 0x10: /* check drive ready */
6284 BX_DEBUG_INT13_HD("int13_f10\n");
6286 //SET_DISK_RET_STATUS(0);
6287 //CLEAR_CF(); /* successful */
6291 // should look at 40:8E also???
6292 status
= inb(0x01f7);
6293 if ( (status
& 0xc0) == 0x40 ) {
6295 SET_DISK_RET_STATUS(0);
6296 CLEAR_CF(); // drive ready
6301 SET_DISK_RET_STATUS(0xAA);
6302 SET_CF(); // not ready
6307 case 0x11: /* recalibrate */
6308 BX_DEBUG_INT13_HD("int13_f11\n");
6310 SET_DISK_RET_STATUS(0);
6311 CLEAR_CF(); /* successful */
6315 case 0x14: /* controller internal diagnostic */
6316 BX_DEBUG_INT13_HD("int13_f14\n");
6318 SET_DISK_RET_STATUS(0);
6319 CLEAR_CF(); /* successful */
6324 case 0x15: /* read disk drive size */
6326 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6330 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6331 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6332 mul al
, ah
;; ax
= heads
* sectors
6333 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6334 dec bx
;; use (cylinders
- 1) ???
6335 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6336 ;; now we need to move the
32bit result dx
:ax to what the
6337 ;; BIOS wants which is cx
:dx
.
6338 ;; and then into CX
:DX on the stack
6339 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6340 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6343 SET_AH(3); // hard disk accessible
6344 SET_DISK_RET_STATUS(0); // ??? should this be 0
6345 CLEAR_CF(); // successful
6349 case 0x18: // set media type for format
6350 case 0x41: // IBM/MS
6351 case 0x42: // IBM/MS
6352 case 0x43: // IBM/MS
6353 case 0x44: // IBM/MS
6354 case 0x45: // IBM/MS lock/unlock drive
6355 case 0x46: // IBM/MS eject media
6356 case 0x47: // IBM/MS extended seek
6357 case 0x49: // IBM/MS extended media change
6358 case 0x50: // IBM/MS send packet command
6360 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6362 SET_AH(1); // code=invalid function in AH or invalid parameter
6363 SET_DISK_RET_STATUS(1);
6364 SET_CF(); /* unsuccessful */
6370 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F\n";
6371 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47\n";
6374 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6376 Bit16u
*hd_cylinders
;
6386 if (drive
== 0x80) {
6387 hd_type
= inb_cmos(0x12) & 0xf0;
6388 if (hd_type
!= 0xf0)
6389 BX_INFO(panic_msg_reg12h
,0);
6390 hd_type
= inb_cmos(0x19); // HD0: extended type
6392 BX_INFO(panic_msg_reg19h
,0,0x19);
6395 hd_type
= inb_cmos(0x12) & 0x0f;
6396 if (hd_type
!= 0x0f)
6397 BX_INFO(panic_msg_reg12h
,1);
6398 hd_type
= inb_cmos(0x1a); // HD0: extended type
6400 BX_INFO(panic_msg_reg19h
,0,0x1a);
6405 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6406 write_word(ss
, hd_cylinders
, cylinders
);
6409 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6411 // sectors per track
6412 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6415 #endif //else BX_USE_ATADRV
6418 //////////////////////
6419 // FLOPPY functions //
6420 //////////////////////
6422 void floppy_reset_controller()
6428 outb(0x03f2, val8
& ~0x04);
6429 outb(0x03f2, val8
| 0x04);
6431 // Wait for controller to come out of reset
6434 } while ( (val8
& 0xc0) != 0x80 );
6437 void floppy_prepare_controller(drive
)
6440 Bit8u val8
, dor
, prev_reset
;
6442 // set 40:3e bit 7 to 0
6443 val8
= read_byte(0x0040, 0x003e);
6445 write_byte(0x0040, 0x003e, val8
);
6447 // turn on motor of selected drive, DMA & int enabled, normal operation
6448 prev_reset
= inb(0x03f2) & 0x04;
6457 // reset the disk motor timeout value of INT 08
6458 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6460 // wait for drive readiness
6463 } while ( (val8
& 0xc0) != 0x80 );
6465 if (prev_reset
== 0) {
6466 // turn on interrupts
6470 // wait on 40:3e bit 7 to become 1
6472 val8
= read_byte(0x0040, 0x003e);
6473 } while ( (val8
& 0x80) == 0 );
6478 write_byte(0x0040, 0x003e, val8
);
6483 floppy_media_known(drive
)
6487 Bit16u media_state_offset
;
6489 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6496 media_state_offset
= 0x0090;
6498 media_state_offset
+= 1;
6500 val8
= read_byte(0x0040, media_state_offset
);
6501 val8
= (val8
>> 4) & 0x01;
6505 // check pass, return KNOWN
6510 floppy_media_sense(drive
)
6514 Bit16u media_state_offset
;
6515 Bit8u drive_type
, config_data
, media_state
;
6517 if (floppy_drive_recal(drive
) == 0) {
6521 // for now cheat and get drive type from CMOS,
6522 // assume media is same as drive type
6524 // ** config_data **
6525 // Bitfields for diskette media control:
6526 // Bit(s) Description (Table M0028)
6527 // 7-6 last data rate set by controller
6528 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6529 // 5-4 last diskette drive step rate selected
6530 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6531 // 3-2 {data rate at start of operation}
6534 // ** media_state **
6535 // Bitfields for diskette drive media state:
6536 // Bit(s) Description (Table M0030)
6538 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6539 // 5 double stepping required (e.g. 360kB in 1.2MB)
6540 // 4 media type established
6541 // 3 drive capable of supporting 4MB media
6542 // 2-0 on exit from BIOS, contains
6543 // 000 trying 360kB in 360kB
6544 // 001 trying 360kB in 1.2MB
6545 // 010 trying 1.2MB in 1.2MB
6546 // 011 360kB in 360kB established
6547 // 100 360kB in 1.2MB established
6548 // 101 1.2MB in 1.2MB established
6550 // 111 all other formats/drives
6552 drive_type
= inb_cmos(0x10);
6557 if ( drive_type
== 1 ) {
6559 config_data
= 0x00; // 0000 0000
6560 media_state
= 0x25; // 0010 0101
6563 else if ( drive_type
== 2 ) {
6564 // 1.2 MB 5.25" drive
6565 config_data
= 0x00; // 0000 0000
6566 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6569 else if ( drive_type
== 3 ) {
6571 config_data
= 0x00; // 0000 0000 ???
6572 media_state
= 0x17; // 0001 0111
6575 else if ( drive_type
== 4 ) {
6576 // 1.44 MB 3.5" drive
6577 config_data
= 0x00; // 0000 0000
6578 media_state
= 0x17; // 0001 0111
6581 else if ( drive_type
== 5 ) {
6582 // 2.88 MB 3.5" drive
6583 config_data
= 0xCC; // 1100 1100
6584 media_state
= 0xD7; // 1101 0111
6588 // Extended floppy size uses special cmos setting
6589 else if ( drive_type
== 6 ) {
6591 config_data
= 0x00; // 0000 0000
6592 media_state
= 0x27; // 0010 0111
6595 else if ( drive_type
== 7 ) {
6597 config_data
= 0x00; // 0000 0000
6598 media_state
= 0x27; // 0010 0111
6601 else if ( drive_type
== 8 ) {
6603 config_data
= 0x00; // 0000 0000
6604 media_state
= 0x27; // 0010 0111
6610 config_data
= 0x00; // 0000 0000
6611 media_state
= 0x00; // 0000 0000
6616 media_state_offset
= 0x90;
6618 media_state_offset
= 0x91;
6619 write_byte(0x0040, 0x008B, config_data
);
6620 write_byte(0x0040, media_state_offset
, media_state
);
6626 floppy_drive_recal(drive
)
6630 Bit16u curr_cyl_offset
;
6632 floppy_prepare_controller(drive
);
6634 // send Recalibrate command (2 bytes) to controller
6635 outb(0x03f5, 0x07); // 07: Recalibrate
6636 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6638 // turn on interrupts
6643 // wait on 40:3e bit 7 to become 1
6645 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6646 } while ( val8
== 0 );
6648 val8
= 0; // separate asm from while() loop
6649 // turn off interrupts
6654 // set 40:3e bit 7 to 0, and calibrated bit
6655 val8
= read_byte(0x0040, 0x003e);
6658 val8
|= 0x02; // Drive 1 calibrated
6659 curr_cyl_offset
= 0x0095;
6661 val8
|= 0x01; // Drive 0 calibrated
6662 curr_cyl_offset
= 0x0094;
6664 write_byte(0x0040, 0x003e, val8
);
6665 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6673 floppy_drive_exists(drive
)
6678 // check CMOS to see if drive exists
6679 drive_type
= inb_cmos(0x10);
6684 if ( drive_type
== 0 )
6690 #if BX_SUPPORT_FLOPPY
6692 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
6693 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
6695 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6696 Bit16u base_address
, base_count
, base_es
;
6697 Bit8u page
, mode_register
, val8
, dor
;
6698 Bit8u return_status
[7];
6699 Bit8u drive_type
, num_floppies
, ah
;
6700 Bit16u es
, last_addr
;
6702 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6707 case 0x00: // diskette controller reset
6708 BX_DEBUG_INT13_FL("floppy f00\n");
6711 SET_AH(1); // invalid param
6712 set_diskette_ret_status(1);
6716 drive_type
= inb_cmos(0x10);
6722 if (drive_type
== 0) {
6723 SET_AH(0x80); // drive not responding
6724 set_diskette_ret_status(0x80);
6729 set_diskette_ret_status(0);
6730 CLEAR_CF(); // successful
6731 set_diskette_current_cyl(drive
, 0); // current cylinder
6734 case 0x01: // Read Diskette Status
6736 val8
= read_byte(0x0000, 0x0441);
6743 case 0x02: // Read Diskette Sectors
6744 case 0x03: // Write Diskette Sectors
6745 case 0x04: // Verify Diskette Sectors
6746 num_sectors
= GET_AL();
6752 if ( (drive
> 1) || (head
> 1) ||
6753 (num_sectors
== 0) || (num_sectors
> 72) ) {
6754 BX_INFO("floppy: drive>1 || head>1 ...\n");
6756 set_diskette_ret_status(1);
6757 SET_AL(0); // no sectors read
6758 SET_CF(); // error occurred
6762 // see if drive exists
6763 if (floppy_drive_exists(drive
) == 0) {
6764 SET_AH(0x80); // not responding
6765 set_diskette_ret_status(0x80);
6766 SET_AL(0); // no sectors read
6767 SET_CF(); // error occurred
6771 // see if media in drive, and type is known
6772 if (floppy_media_known(drive
) == 0) {
6773 if (floppy_media_sense(drive
) == 0) {
6774 SET_AH(0x0C); // Media type not found
6775 set_diskette_ret_status(0x0C);
6776 SET_AL(0); // no sectors read
6777 SET_CF(); // error occurred
6783 // Read Diskette Sectors
6785 //-----------------------------------
6786 // set up DMA controller for transfer
6787 //-----------------------------------
6789 // es:bx = pointer to where to place information from diskette
6790 // port 04: DMA-1 base and current address, channel 2
6791 // port 05: DMA-1 base and current count, channel 2
6792 page
= (ES
>> 12); // upper 4 bits
6793 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6794 base_address
= base_es
+ BX
; // lower 16 bits of address
6795 // contributed by ES:BX
6796 if ( base_address
< base_es
) {
6797 // in case of carry, adjust page by 1
6800 base_count
= (num_sectors
* 512) - 1;
6802 // check for 64K boundary overrun
6803 last_addr
= base_address
+ base_count
;
6804 if (last_addr
< base_address
) {
6806 set_diskette_ret_status(0x09);
6807 SET_AL(0); // no sectors read
6808 SET_CF(); // error occurred
6812 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6815 BX_DEBUG_INT13_FL("clear flip-flop\n");
6816 outb(0x000c, 0x00); // clear flip-flop
6817 outb(0x0004, base_address
);
6818 outb(0x0004, base_address
>>8);
6819 BX_DEBUG_INT13_FL("clear flip-flop\n");
6820 outb(0x000c, 0x00); // clear flip-flop
6821 outb(0x0005, base_count
);
6822 outb(0x0005, base_count
>>8);
6824 // port 0b: DMA-1 Mode Register
6825 mode_register
= 0x46; // single mode, increment, autoinit disable,
6826 // transfer type=write, channel 2
6827 BX_DEBUG_INT13_FL("setting mode register\n");
6828 outb(0x000b, mode_register
);
6830 BX_DEBUG_INT13_FL("setting page register\n");
6831 // port 81: DMA-1 Page Register, channel 2
6834 BX_DEBUG_INT13_FL("unmask chan 2\n");
6835 outb(0x000a, 0x02); // unmask channel 2
6837 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6840 //--------------------------------------
6841 // set up floppy controller for transfer
6842 //--------------------------------------
6843 floppy_prepare_controller(drive
);
6845 // send read-normal-data command (9 bytes) to controller
6846 outb(0x03f5, 0xe6); // e6: read normal data
6847 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6848 outb(0x03f5, track
);
6850 outb(0x03f5, sector
);
6851 outb(0x03f5, 2); // 512 byte sector size
6852 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to read on track
6853 outb(0x03f5, 0); // Gap length
6854 outb(0x03f5, 0xff); // Gap length
6856 // turn on interrupts
6861 // wait on 40:3e bit 7 to become 1
6863 val8
= read_byte(0x0040, 0x0040);
6865 floppy_reset_controller();
6866 SET_AH(0x80); // drive not ready (timeout)
6867 set_diskette_ret_status(0x80);
6868 SET_AL(0); // no sectors read
6869 SET_CF(); // error occurred
6872 val8
= (read_byte(0x0040, 0x003e) & 0x80);
6873 } while ( val8
== 0 );
6875 val8
= 0; // separate asm from while() loop
6876 // turn off interrupts
6881 // set 40:3e bit 7 to 0
6882 val8
= read_byte(0x0040, 0x003e);
6884 write_byte(0x0040, 0x003e, val8
);
6886 // check port 3f4 for accessibility to status bytes
6888 if ( (val8
& 0xc0) != 0xc0 )
6889 BX_PANIC("int13_diskette: ctrl not ready\n");
6891 // read 7 return status bytes from controller
6892 // using loop index broken, have to unroll...
6893 return_status
[0] = inb(0x3f5);
6894 return_status
[1] = inb(0x3f5);
6895 return_status
[2] = inb(0x3f5);
6896 return_status
[3] = inb(0x3f5);
6897 return_status
[4] = inb(0x3f5);
6898 return_status
[5] = inb(0x3f5);
6899 return_status
[6] = inb(0x3f5);
6900 // record in BIOS Data Area
6901 write_byte(0x0040, 0x0042, return_status
[0]);
6902 write_byte(0x0040, 0x0043, return_status
[1]);
6903 write_byte(0x0040, 0x0044, return_status
[2]);
6904 write_byte(0x0040, 0x0045, return_status
[3]);
6905 write_byte(0x0040, 0x0046, return_status
[4]);
6906 write_byte(0x0040, 0x0047, return_status
[5]);
6907 write_byte(0x0040, 0x0048, return_status
[6]);
6909 if ( (return_status
[0] & 0xc0) != 0 ) {
6911 set_diskette_ret_status(0x20);
6912 SET_AL(0); // no sectors read
6913 SET_CF(); // error occurred
6917 // ??? should track be new val from return_status[3] ?
6918 set_diskette_current_cyl(drive
, track
);
6919 // AL = number of sectors read (same value as passed)
6920 SET_AH(0x00); // success
6921 CLEAR_CF(); // success
6923 } else if (ah
== 0x03) {
6924 // Write Diskette Sectors
6926 //-----------------------------------
6927 // set up DMA controller for transfer
6928 //-----------------------------------
6930 // es:bx = pointer to where to place information from diskette
6931 // port 04: DMA-1 base and current address, channel 2
6932 // port 05: DMA-1 base and current count, channel 2
6933 page
= (ES
>> 12); // upper 4 bits
6934 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6935 base_address
= base_es
+ BX
; // lower 16 bits of address
6936 // contributed by ES:BX
6937 if ( base_address
< base_es
) {
6938 // in case of carry, adjust page by 1
6941 base_count
= (num_sectors
* 512) - 1;
6943 // check for 64K boundary overrun
6944 last_addr
= base_address
+ base_count
;
6945 if (last_addr
< base_address
) {
6947 set_diskette_ret_status(0x09);
6948 SET_AL(0); // no sectors read
6949 SET_CF(); // error occurred
6953 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6956 outb(0x000c, 0x00); // clear flip-flop
6957 outb(0x0004, base_address
);
6958 outb(0x0004, base_address
>>8);
6959 outb(0x000c, 0x00); // clear flip-flop
6960 outb(0x0005, base_count
);
6961 outb(0x0005, base_count
>>8);
6963 // port 0b: DMA-1 Mode Register
6964 mode_register
= 0x4a; // single mode, increment, autoinit disable,
6965 // transfer type=read, channel 2
6966 outb(0x000b, mode_register
);
6968 // port 81: DMA-1 Page Register, channel 2
6971 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6974 //--------------------------------------
6975 // set up floppy controller for transfer
6976 //--------------------------------------
6977 floppy_prepare_controller(drive
);
6979 // send write-normal-data command (9 bytes) to controller
6980 outb(0x03f5, 0xc5); // c5: write normal data
6981 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6982 outb(0x03f5, track
);
6984 outb(0x03f5, sector
);
6985 outb(0x03f5, 2); // 512 byte sector size
6986 outb(0x03f5, sector
+ num_sectors
- 1); // last sector to write on track
6987 outb(0x03f5, 0); // Gap length
6988 outb(0x03f5, 0xff); // Gap length
6990 // turn on interrupts
6995 // wait on 40:3e bit 7 to become 1
6997 val8
= read_byte(0x0040, 0x0040);
6999 floppy_reset_controller();
7000 SET_AH(0x80); // drive not ready (timeout)
7001 set_diskette_ret_status(0x80);
7002 SET_AL(0); // no sectors written
7003 SET_CF(); // error occurred
7006 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7007 } while ( val8
== 0 );
7009 val8
= 0; // separate asm from while() loop
7010 // turn off interrupts
7015 // set 40:3e bit 7 to 0
7016 val8
= read_byte(0x0040, 0x003e);
7018 write_byte(0x0040, 0x003e, val8
);
7020 // check port 3f4 for accessibility to status bytes
7022 if ( (val8
& 0xc0) != 0xc0 )
7023 BX_PANIC("int13_diskette: ctrl not ready\n");
7025 // read 7 return status bytes from controller
7026 // using loop index broken, have to unroll...
7027 return_status
[0] = inb(0x3f5);
7028 return_status
[1] = inb(0x3f5);
7029 return_status
[2] = inb(0x3f5);
7030 return_status
[3] = inb(0x3f5);
7031 return_status
[4] = inb(0x3f5);
7032 return_status
[5] = inb(0x3f5);
7033 return_status
[6] = inb(0x3f5);
7034 // record in BIOS Data Area
7035 write_byte(0x0040, 0x0042, return_status
[0]);
7036 write_byte(0x0040, 0x0043, return_status
[1]);
7037 write_byte(0x0040, 0x0044, return_status
[2]);
7038 write_byte(0x0040, 0x0045, return_status
[3]);
7039 write_byte(0x0040, 0x0046, return_status
[4]);
7040 write_byte(0x0040, 0x0047, return_status
[5]);
7041 write_byte(0x0040, 0x0048, return_status
[6]);
7043 if ( (return_status
[0] & 0xc0) != 0 ) {
7044 if ( (return_status
[1] & 0x02) != 0 ) {
7045 // diskette not writable.
7046 // AH=status code=0x03 (tried to write on write-protected disk)
7047 // AL=number of sectors written=0
7052 BX_PANIC("int13_diskette_function: read error\n");
7056 // ??? should track be new val from return_status[3] ?
7057 set_diskette_current_cyl(drive
, track
);
7058 // AL = number of sectors read (same value as passed)
7059 SET_AH(0x00); // success
7060 CLEAR_CF(); // success
7062 } else { // if (ah == 0x04)
7063 // Verify Diskette Sectors
7065 // ??? should track be new val from return_status[3] ?
7066 set_diskette_current_cyl(drive
, track
);
7067 // AL = number of sectors verified (same value as passed)
7068 CLEAR_CF(); // success
7069 SET_AH(0x00); // success
7074 case 0x05: // format diskette track
7075 BX_DEBUG_INT13_FL("floppy f05\n");
7077 num_sectors
= GET_AL();
7082 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
7083 (num_sectors
== 0) || (num_sectors
> 18)) {
7085 set_diskette_ret_status(1);
7086 SET_CF(); // error occurred
7089 // see if drive exists
7090 if (floppy_drive_exists(drive
) == 0) {
7091 SET_AH(0x80); // drive not responding
7092 set_diskette_ret_status(0x80);
7093 SET_CF(); // error occurred
7097 // see if media in drive, and type is known
7098 if (floppy_media_known(drive
) == 0) {
7099 if (floppy_media_sense(drive
) == 0) {
7100 SET_AH(0x0C); // Media type not found
7101 set_diskette_ret_status(0x0C);
7102 SET_AL(0); // no sectors read
7103 SET_CF(); // error occurred
7108 // set up DMA controller for transfer
7109 page
= (ES
>> 12); // upper 4 bits
7110 base_es
= (ES
<< 4); // lower 16bits contributed by ES
7111 base_address
= base_es
+ BX
; // lower 16 bits of address
7112 // contributed by ES:BX
7113 if ( base_address
< base_es
) {
7114 // in case of carry, adjust page by 1
7117 base_count
= (num_sectors
* 4) - 1;
7119 // check for 64K boundary overrun
7120 last_addr
= base_address
+ base_count
;
7121 if (last_addr
< base_address
) {
7123 set_diskette_ret_status(0x09);
7124 SET_AL(0); // no sectors read
7125 SET_CF(); // error occurred
7130 outb(0x000c, 0x00); // clear flip-flop
7131 outb(0x0004, base_address
);
7132 outb(0x0004, base_address
>>8);
7133 outb(0x000c, 0x00); // clear flip-flop
7134 outb(0x0005, base_count
);
7135 outb(0x0005, base_count
>>8);
7136 mode_register
= 0x4a; // single mode, increment, autoinit disable,
7137 // transfer type=read, channel 2
7138 outb(0x000b, mode_register
);
7139 // port 81: DMA-1 Page Register, channel 2
7143 // set up floppy controller for transfer
7144 floppy_prepare_controller(drive
);
7146 // send format-track command (6 bytes) to controller
7147 outb(0x03f5, 0x4d); // 4d: format track
7148 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
7149 outb(0x03f5, 2); // 512 byte sector size
7150 outb(0x03f5, num_sectors
); // number of sectors per track
7151 outb(0x03f5, 0); // Gap length
7152 outb(0x03f5, 0xf6); // Fill byte
7153 // turn on interrupts
7158 // wait on 40:3e bit 7 to become 1
7160 val8
= read_byte(0x0040, 0x0040);
7162 floppy_reset_controller();
7163 SET_AH(0x80); // drive not ready (timeout)
7164 set_diskette_ret_status(0x80);
7165 SET_CF(); // error occurred
7168 val8
= (read_byte(0x0040, 0x003e) & 0x80);
7169 } while ( val8
== 0 );
7171 val8
= 0; // separate asm from while() loop
7172 // turn off interrupts
7176 // set 40:3e bit 7 to 0
7177 val8
= read_byte(0x0040, 0x003e);
7179 write_byte(0x0040, 0x003e, val8
);
7180 // check port 3f4 for accessibility to status bytes
7182 if ( (val8
& 0xc0) != 0xc0 )
7183 BX_PANIC("int13_diskette: ctrl not ready\n");
7185 // read 7 return status bytes from controller
7186 // using loop index broken, have to unroll...
7187 return_status
[0] = inb(0x3f5);
7188 return_status
[1] = inb(0x3f5);
7189 return_status
[2] = inb(0x3f5);
7190 return_status
[3] = inb(0x3f5);
7191 return_status
[4] = inb(0x3f5);
7192 return_status
[5] = inb(0x3f5);
7193 return_status
[6] = inb(0x3f5);
7194 // record in BIOS Data Area
7195 write_byte(0x0040, 0x0042, return_status
[0]);
7196 write_byte(0x0040, 0x0043, return_status
[1]);
7197 write_byte(0x0040, 0x0044, return_status
[2]);
7198 write_byte(0x0040, 0x0045, return_status
[3]);
7199 write_byte(0x0040, 0x0046, return_status
[4]);
7200 write_byte(0x0040, 0x0047, return_status
[5]);
7201 write_byte(0x0040, 0x0048, return_status
[6]);
7203 if ( (return_status
[0] & 0xc0) != 0 ) {
7204 if ( (return_status
[1] & 0x02) != 0 ) {
7205 // diskette not writable.
7206 // AH=status code=0x03 (tried to write on write-protected disk)
7207 // AL=number of sectors written=0
7212 BX_PANIC("int13_diskette_function: write error\n");
7217 set_diskette_ret_status(0);
7218 set_diskette_current_cyl(drive
, 0);
7219 CLEAR_CF(); // successful
7223 case 0x08: // read diskette drive parameters
7224 BX_DEBUG_INT13_FL("floppy f08\n");
7234 SET_DL(num_floppies
);
7239 drive_type
= inb_cmos(0x10);
7241 if (drive_type
& 0xf0)
7243 if (drive_type
& 0x0f)
7255 SET_DL(num_floppies
);
7257 switch (drive_type
) {
7260 SET_DH(0); // max head #
7263 case 1: // 360KB, 5.25"
7264 CX
= 0x2709; // 40 tracks, 9 sectors
7265 SET_DH(1); // max head #
7268 case 2: // 1.2MB, 5.25"
7269 CX
= 0x4f0f; // 80 tracks, 15 sectors
7270 SET_DH(1); // max head #
7273 case 3: // 720KB, 3.5"
7274 CX
= 0x4f09; // 80 tracks, 9 sectors
7275 SET_DH(1); // max head #
7278 case 4: // 1.44MB, 3.5"
7279 CX
= 0x4f12; // 80 tracks, 18 sectors
7280 SET_DH(1); // max head #
7283 case 5: // 2.88MB, 3.5"
7284 CX
= 0x4f24; // 80 tracks, 36 sectors
7285 SET_DH(1); // max head #
7288 case 6: // 160k, 5.25"
7289 CX
= 0x2708; // 40 tracks, 8 sectors
7290 SET_DH(0); // max head #
7293 case 7: // 180k, 5.25"
7294 CX
= 0x2709; // 40 tracks, 9 sectors
7295 SET_DH(0); // max head #
7298 case 8: // 320k, 5.25"
7299 CX
= 0x2708; // 40 tracks, 8 sectors
7300 SET_DH(1); // max head #
7304 BX_PANIC("floppy: int13: bad floppy type\n");
7307 /* set es & di to point to 11 byte diskette param table in ROM */
7311 mov ax
, #diskette_param_table2
7312 mov _int13_diskette_function
.DI
+2[bp
], ax
7313 mov _int13_diskette_function
.ES
+2[bp
], cs
7316 CLEAR_CF(); // success
7317 /* disk status not changed upon success */
7321 case 0x15: // read diskette drive type
7322 BX_DEBUG_INT13_FL("floppy f15\n");
7325 SET_AH(0); // only 2 drives supported
7326 // set_diskette_ret_status here ???
7330 drive_type
= inb_cmos(0x10);
7336 CLEAR_CF(); // successful, not present
7337 if (drive_type
==0) {
7338 SET_AH(0); // drive not present
7341 SET_AH(1); // drive present, does not support change line
7346 case 0x16: // get diskette change line status
7347 BX_DEBUG_INT13_FL("floppy f16\n");
7350 SET_AH(0x01); // invalid drive
7351 set_diskette_ret_status(0x01);
7356 SET_AH(0x06); // change line not supported
7357 set_diskette_ret_status(0x06);
7361 case 0x17: // set diskette type for format(old)
7362 BX_DEBUG_INT13_FL("floppy f17\n");
7363 /* not used for 1.44M floppies */
7364 SET_AH(0x01); // not supported
7365 set_diskette_ret_status(1); /* not supported */
7369 case 0x18: // set diskette type for format(new)
7370 BX_DEBUG_INT13_FL("floppy f18\n");
7371 SET_AH(0x01); // do later
7372 set_diskette_ret_status(1);
7377 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7379 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7380 SET_AH(0x01); // ???
7381 set_diskette_ret_status(1);
7387 #else // #if BX_SUPPORT_FLOPPY
7389 int13_diskette_function(DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
)
7390 Bit16u DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
;
7394 switch ( GET_AH() ) {
7396 case 0x01: // Read Diskette Status
7398 val8
= read_byte(0x0000, 0x0441);
7407 write_byte(0x0000, 0x0441, 0x01);
7411 #endif // #if BX_SUPPORT_FLOPPY
7414 set_diskette_ret_status(value
)
7417 write_byte(0x0040, 0x0041, value
);
7421 set_diskette_current_cyl(drive
, cyl
)
7426 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7427 write_byte(0x0040, 0x0094+drive
, cyl
);
7431 determine_floppy_media(drive
)
7435 Bit8u val8
, DOR
, ctrl_info
;
7437 ctrl_info
= read_byte(0x0040, 0x008F);
7445 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7448 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7452 if ( (ctrl_info
& 0x04) != 0x04 ) {
7453 // Drive not determined means no drive exists, done.
7458 // check Main Status Register for readiness
7459 val8
= inb(0x03f4) & 0x80; // Main Status Register
7461 BX_PANIC("d_f_m: MRQ bit not set\n");
7465 // existing BDA values
7467 // turn on drive motor
7468 outb(0x03f2, DOR
); // Digital Output Register
7471 BX_PANIC("d_f_m: OK so far\n");
7476 int17_function(regs
, ds
, iret_addr
)
7477 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7478 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7479 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7481 Bit16u addr
,timeout
;
7488 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7489 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7490 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7491 if (regs
.u
.r8
.ah
== 0) {
7492 outb(addr
, regs
.u
.r8
.al
);
7494 outb(addr
+2, val8
| 0x01); // send strobe
7498 outb(addr
+2, val8
& ~0x01);
7499 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7503 if (regs
.u
.r8
.ah
== 1) {
7505 outb(addr
+2, val8
& ~0x04); // send init
7509 outb(addr
+2, val8
| 0x04);
7512 regs
.u
.r8
.ah
= (val8
^ 0x48);
7513 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7514 ClearCF(iret_addr
.flags
);
7516 SetCF(iret_addr
.flags
); // Unsupported
7520 // returns bootsegment in ax, drive in bl
7522 int19_function(bseqnr
)
7525 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7534 // if BX_ELTORITO_BOOT is not defined, old behavior
7535 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7536 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7537 // 0: system boot sequence, first drive C: then A:
7538 // 1: system boot sequence, first drive A: then C:
7539 // else BX_ELTORITO_BOOT is defined
7540 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7541 // CMOS reg 0x3D & 0x0f : 1st boot device
7542 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7543 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7544 // boot device codes:
7545 // 0x00 : not defined
7546 // 0x01 : first floppy
7547 // 0x02 : first harddrive
7548 // 0x03 : first cdrom
7549 // else : boot failure
7551 // Get the boot sequence
7552 #if BX_ELTORITO_BOOT
7553 bootseq
=inb_cmos(0x3d);
7554 bootseq
|=((inb_cmos(0x38) & 0xf0) << 4);
7556 if (bseqnr
==2) bootseq
>>= 4;
7557 if (bseqnr
==3) bootseq
>>= 8;
7558 if (bootseq
<0x10) lastdrive
= 1;
7559 bootdrv
=0x00; bootcd
=0;
7560 switch(bootseq
& 0x0f) {
7561 case 0x01: bootdrv
=0x00; bootcd
=0; break;
7562 case 0x02: bootdrv
=0x80; bootcd
=0; break;
7563 case 0x03: bootdrv
=0x00; bootcd
=1; break;
7564 default: return 0x00000000;
7567 bootseq
=inb_cmos(0x2d);
7573 bootdrv
=0x00; bootcd
=0;
7574 if((bootseq
&0x20)==0) bootdrv
=0x80;
7575 #endif // BX_ELTORITO_BOOT
7577 #if BX_ELTORITO_BOOT
7578 // We have to boot from cd
7580 status
= cdrom_boot();
7583 if ( (status
& 0x00ff) !=0 ) {
7584 print_cdromboot_failure(status
);
7585 print_boot_failure(bootcd
, bootdrv
, 1, lastdrive
);
7589 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7590 bootdrv
= (Bit8u
)(status
>>8);
7593 #endif // BX_ELTORITO_BOOT
7595 // We have to boot from harddisk or floppy
7604 mov _int19_function
.status
+ 2[bp
], ax
7605 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7606 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7607 mov es
, ax
;; segment
7608 mov bx
, #0x0000 ;; offset
7609 mov ah
, #0x02 ;; function 2, read diskette sector
7610 mov al
, #0x01 ;; read 1 sector
7611 mov ch
, #0x00 ;; track 0
7612 mov cl
, #0x01 ;; sector 1
7613 mov dh
, #0x00 ;; head 0
7614 int #0x13 ;; read sector
7617 mov _int19_function
.status
+ 2[bp
], ax
7624 print_boot_failure(bootcd
, bootdrv
, 1, lastdrive
);
7629 // check signature if instructed by cmos reg 0x38, only for floppy
7630 // bootchk = 1 : signature check disabled
7631 // bootchk = 0 : signature check enabled
7632 if (bootdrv
!= 0) bootchk
= 0;
7633 else bootchk
= inb_cmos(0x38) & 0x01;
7635 #if BX_ELTORITO_BOOT
7636 // if boot from cd, no signature check
7639 #endif // BX_ELTORITO_BOOT
7642 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7643 print_boot_failure(bootcd
, bootdrv
, 0, lastdrive
);
7648 #if BX_ELTORITO_BOOT
7649 // Print out the boot string
7650 print_boot_device(bootcd
, bootdrv
);
7651 #else // BX_ELTORITO_BOOT
7652 print_boot_device(0, bootdrv
);
7653 #endif // BX_ELTORITO_BOOT
7655 // return the boot segment
7656 return (((Bit32u
)bootdrv
) << 16) + bootseg
;
7660 int1a_function(regs
, ds
, iret_addr
)
7661 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7662 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7663 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7667 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
);
7673 switch (regs
.u
.r8
.ah
) {
7674 case 0: // get current clock count
7678 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7679 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7680 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7681 BiosData
->midnight_flag
= 0; // reset flag
7686 ClearCF(iret_addr
.flags
); // OK
7689 case 1: // Set Current Clock Count
7693 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7694 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7695 BiosData
->midnight_flag
= 0; // reset flag
7700 ClearCF(iret_addr
.flags
); // OK
7704 case 2: // Read CMOS Time
7705 if (rtc_updating()) {
7706 SetCF(iret_addr
.flags
);
7710 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7711 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7712 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7713 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7715 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7716 ClearCF(iret_addr
.flags
); // OK
7719 case 3: // Set CMOS Time
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
7725 // before 1111 1101 0111 1101 0000 0000
7726 // after 0110 0010 0110 0010 0000 0010
7728 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7729 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7730 if (rtc_updating()) {
7732 // fall through as if an update were not in progress
7734 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7735 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7736 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7737 // Set Daylight Savings time enabled bit to requested value
7738 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7739 // (reg B already selected)
7740 outb_cmos(0x0b, val8
);
7742 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7743 ClearCF(iret_addr
.flags
); // OK
7746 case 4: // Read CMOS Date
7748 if (rtc_updating()) {
7749 SetCF(iret_addr
.flags
);
7752 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
7753 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
7754 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
7755 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
7756 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7757 ClearCF(iret_addr
.flags
); // OK
7760 case 5: // Set CMOS Date
7761 // Using a debugger, I notice the following masking/setting
7762 // of bits in Status Register B, by setting Reg B to
7763 // a few values and getting its value after INT 1A was called.
7765 // try#1 try#2 try#3 try#4
7766 // before 1111 1101 0111 1101 0000 0010 0000 0000
7767 // after 0110 1101 0111 1101 0000 0010 0000 0000
7769 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7770 // My assumption: RegB = (RegB & 01111111b)
7771 if (rtc_updating()) {
7773 SetCF(iret_addr
.flags
);
7776 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
7777 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
7778 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
7779 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
7780 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7781 outb_cmos(0x0b, val8
);
7783 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
7784 ClearCF(iret_addr
.flags
); // OK
7787 case 6: // Set Alarm Time in CMOS
7788 // Using a debugger, I notice the following masking/setting
7789 // of bits in Status Register B, by setting Reg B to
7790 // a few values and getting its value after INT 1A was called.
7792 // try#1 try#2 try#3
7793 // before 1101 1111 0101 1111 0000 0000
7794 // after 0110 1111 0111 1111 0010 0000
7796 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7797 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7798 val8
= inb_cmos(0x0b); // Get Status Reg B
7801 // Alarm interrupt enabled already
7802 SetCF(iret_addr
.flags
); // Error: alarm in use
7805 if (rtc_updating()) {
7807 // fall through as if an update were not in progress
7809 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
7810 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
7811 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
7812 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7813 // enable Status Reg B alarm bit, clear halt clock bit
7814 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
7815 ClearCF(iret_addr
.flags
); // OK
7818 case 7: // Turn off Alarm
7819 // Using a debugger, I notice the following masking/setting
7820 // of bits in Status Register B, by setting Reg B to
7821 // a few values and getting its value after INT 1A was called.
7823 // try#1 try#2 try#3 try#4
7824 // before 1111 1101 0111 1101 0010 0000 0010 0010
7825 // after 0100 0101 0101 0101 0000 0000 0000 0010
7827 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7828 // My assumption: RegB = (RegB & 01010111b)
7829 val8
= inb_cmos(0x0b); // Get Status Reg B
7830 // clear clock-halt bit, disable alarm bit
7831 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
7833 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7834 ClearCF(iret_addr
.flags
); // OK
7838 // real mode PCI BIOS functions now handled in assembler code
7839 // this C code handles the error code for information only
7840 if (regs
.u
.r8
.bl
== 0xff) {
7841 BX_INFO("PCI BIOS: PCI not present\n");
7842 } else if (regs
.u
.r8
.bl
== 0x81) {
7843 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
7844 } else if (regs
.u
.r8
.bl
== 0x83) {
7845 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
7846 } else if (regs
.u
.r8
.bl
== 0x86) {
7847 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
, regs
.u
.r16
.si
);
7849 regs
.u
.r8
.ah
= regs
.u
.r8
.bl
;
7850 SetCF(iret_addr
.flags
);
7855 SetCF(iret_addr
.flags
); // Unsupported
7860 int70_function(regs
, ds
, iret_addr
)
7861 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7862 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7863 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7865 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7866 Bit8u registerB
= 0, registerC
= 0;
7868 // Check which modes are enabled and have occurred.
7869 registerB
= inb_cmos( 0xB );
7870 registerC
= inb_cmos( 0xC );
7872 if( ( registerB
& 0x60 ) != 0 ) {
7873 if( ( registerC
& 0x20 ) != 0 ) {
7874 // Handle Alarm Interrupt.
7881 if( ( registerC
& 0x40 ) != 0 ) {
7882 // Handle Periodic Interrupt.
7884 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7885 // Wait Interval (Int 15, AH=83) active.
7886 Bit32u time
, toggle
;
7888 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
7889 if( time
< 0x3D1 ) {
7891 Bit16u segment
, offset
;
7893 segment
= read_word( 0x40, 0x98 );
7894 offset
= read_word( 0x40, 0x9A );
7895 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7896 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
7897 write_byte(segment
, offset
, read_byte(segment
, offset
) | 0x80 ); // Write to specified flag byte.
7899 // Continue waiting.
7901 write_dword( 0x40, 0x9C, time
);
7914 ;------------------------------------------
7915 ;- INT74h
: PS
/2 mouse hardware interrupt
-
7916 ;------------------------------------------
7921 push
#0x00 ;; placeholder for status
7922 push
#0x00 ;; placeholder for X
7923 push
#0x00 ;; placeholder for Y
7924 push
#0x00 ;; placeholder for Z
7925 push
#0x00 ;; placeholder for make_far_call boolean
7926 call _int74_function
7927 pop cx
;; remove make_far_call from stack
7930 ;; make far call to EBDA
:0022
7933 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
7935 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7940 add sp
, #8 ;; pop status, x, y, z
7942 pop ds
;; restore DS
7947 ;; This will perform an IRET
, but will retain value of current CF
7948 ;; by altering flags on stack
. Better than RETF
#02.
7953 and BYTE
[bp
+ 0x06], #0xfe
7959 or BYTE
[bp
+ 0x06], #0x01
7964 ;----------------------
7965 ;- INT13h (relocated
) -
7966 ;----------------------
7968 ; int13_relocated is a little bit messed up since I played with it
7969 ; I have to rewrite it
:
7970 ; - call a function that detect which function to call
7971 ; - make all called C function get the same parameters list
7975 #if BX_ELTORITO_BOOT
7976 ;; check
for an eltorito function
7978 jb int13_not_eltorito
7980 ja int13_not_eltorito
7989 jmp _int13_eltorito
;; ELDX
not used
7997 ;; check
if emulation active
7998 call _cdemu_isactive
8000 je int13_cdemu_inactive
8002 ;; check
if access to the emulated drive
8003 call _cdemu_emulated_drive
8006 cmp al
,dl
;; int13 on emulated drive
8021 jmp _int13_cdemu
;; ELDX
not used
8024 and dl
,#0xE0 ;; mask to get device class, including cdroms
8025 cmp al
,dl
;; al is
0x00 or 0x80
8026 jne int13_cdemu_inactive
;; inactive
for device
class
8038 dec dl
;; real drive is dl
- 1
8041 int13_cdemu_inactive
:
8047 #endif // BX_ELTORITO_BOOT
8058 push dx
;; push eltorito value of dx instead of sp
8069 ;; now the
16-bit registers can be restored with
:
8070 ;; pop ds
; pop es
; popa
; iret
8071 ;; arguments passed to functions should be
8072 ;; DS
, ES
, DI
, SI
, BP
, ELDX
, BX
, DX
, CX
, AX
, IP
, CS
, FLAGS
8078 jmp _int13_diskette_function
8087 // ebx is modified: BSD 5.2.1 boot loader problem
8088 // someone should figure out which 32 bit register that actually are used
8105 call _int13_harddisk
8117 int18_handler
: ;; Boot Failure routing
8118 call _int18_panic_msg
8125 int19_relocated
: ;; Boot function
, relocated
8127 ;; int19 was beginning to be really
complex, so now it
8128 ;; just calls an C function
, that does the work
8129 ;; it returns in BL the boot drive
, and in AX the boot segment
8130 ;; the boot segment will be
0x0000 if something has failed
8142 call _int19_function
8145 ;; bl contains the boot drive
8146 ;; ax contains the boot segment
or 0 if failure
8148 test ax
, ax
;; if ax is
0 try next boot device
8154 call _int19_function
8157 test ax
, ax
;; if ax is
0 try next boot device
8163 call _int19_function
8166 test ax
, ax
;; if ax is
0 call int18
8170 mov dl
, bl
;; set drive so guest os find it
8171 shl eax
, #0x04 ;; convert seg to ip
8172 mov
2[bp
], ax
;; set ip
8174 shr eax
, #0x04 ;; get cs back
8175 and ax
, #0xF000 ;; remove what went in ip
8176 mov
4[bp
], ax
;; set cs
8178 mov es
, ax
;; set es to zero fixes
[ 549815 ]
8179 mov
[bp
], ax
;; set bp to zero
8180 mov ax
, #0xaa55 ;; set ok flag
8183 iret
;; Beam me up Scotty
8188 int1c_handler
: ;; User Timer Tick
8192 ;----------------------
8193 ;- POST
: Floppy Drive
-
8194 ;----------------------
8200 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
8202 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
8204 mov
0x0440, al
;; diskette motor timeout counter
: not active
8205 mov
0x0441, al
;; diskette controller status
return code
8207 mov
0x0442, al
;; disk
& diskette controller status
register 0
8208 mov
0x0443, al
;; diskette controller status
register 1
8209 mov
0x0444, al
;; diskette controller status
register 2
8210 mov
0x0445, al
;; diskette controller cylinder number
8211 mov
0x0446, al
;; diskette controller head number
8212 mov
0x0447, al
;; diskette controller sector number
8213 mov
0x0448, al
;; diskette controller bytes written
8215 mov
0x048b, al
;; diskette configuration data
8217 ;; -----------------------------------------------------------------
8218 ;; (048F
) diskette controller information
8220 mov al
, #0x10 ;; get CMOS diskette drive type
8223 mov ah
, al
;; save byte to AH
8226 shr al
, #4 ;; look at top 4 bits for drive 0
8227 jz f0_missing
;; jump
if no drive0
8228 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
8231 mov bl
, #0x00 ;; no drive0
8234 mov al
, ah
;; restore from AH
8235 and al
, #0x0f ;; look at bottom 4 bits for drive 1
8236 jz f1_missing
;; jump
if no drive1
8237 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
8239 ;; leave high bits in BL zerod
8240 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
8241 ;; -----------------------------------------------------------------
8244 mov
0x0490, al
;; diskette
0 media state
8245 mov
0x0491, al
;; diskette
1 media state
8247 ;; diskette
0,1 operational starting state
8248 ;; drive type has
not been determined
,
8249 ;; has no changed detection line
8253 mov
0x0494, al
;; diskette
0 current cylinder
8254 mov
0x0495, al
;; diskette
1 current cylinder
8257 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8259 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8260 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8261 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8266 ;--------------------
8267 ;- POST
: HARD DRIVE
-
8268 ;--------------------
8269 ; relocated here because the primary POST area isnt big enough
.
8272 // INT 76h calls INT 15h function ax=9100
8274 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8280 mov
0x0474, al
/* hard disk status of last operation */
8281 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8282 mov
0x048c, al
/* hard disk status register */
8283 mov
0x048d, al
/* hard disk error register */
8284 mov
0x048e, al
/* hard disk task complete flag */
8286 mov
0x0475, al
/* hard disk number attached */
8288 mov
0x0476, al
/* hard disk control byte */
8289 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8290 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8291 ;; INT
41h
: hard disk
0 configuration pointer
8292 ;; INT
46h
: hard disk
1 configuration pointer
8293 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8294 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8296 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8308 cmp al
, #47 ;; decimal 47 - user definable
8312 ;; CMOS purpose param table offset
8313 ;; 1b cylinders low
0
8314 ;; 1c cylinders high
1
8316 ;; 1e write pre
-comp low
5
8317 ;; 1f write pre
-comp high
6
8318 ;; 20 retries
/bad map
/heads
>8 8
8319 ;; 21 landing zone low C
8320 ;; 22 landing zone high D
8321 ;; 23 sectors
/track E
8326 ;;; Filling EBDA table
for hard disk
0.
8334 mov (0x003d + 0x05), ax
;; write precomp word
8339 mov (0x003d + 0x08), al
;; drive control byte
8348 mov (0x003d + 0x0C), ax
;; landing zone word
8350 mov al
, #0x1c ;; get cylinders word in AX
8352 in al
, #0x71 ;; high byte
8356 in al
, #0x71 ;; low byte
8357 mov bx
, ax
;; BX
= cylinders
8362 mov cl
, al
;; CL
= heads
8367 mov dl
, al
;; DL
= sectors
8370 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8372 hd0_post_physical_chs
:
8373 ;; no logical CHS mapping used
, just physical CHS
8374 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8375 mov (0x003d + 0x00), bx
;; number of physical cylinders
8376 mov (0x003d + 0x02), cl
;; number of physical heads
8377 mov (0x003d + 0x0E), dl
;; number of physical sectors
8380 hd0_post_logical_chs
:
8381 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8382 mov (0x003d + 0x09), bx
;; number of physical cylinders
8383 mov (0x003d + 0x0b), cl
;; number of physical heads
8384 mov (0x003d + 0x04), dl
;; number of physical sectors
8385 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8387 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8390 jnbe hd0_post_above_2048
8391 ;; 1024 < c
<= 2048 cylinders
8394 jmp hd0_post_store_logical
8396 hd0_post_above_2048
:
8398 jnbe hd0_post_above_4096
8399 ;; 2048 < c
<= 4096 cylinders
8402 jmp hd0_post_store_logical
8404 hd0_post_above_4096
:
8406 jnbe hd0_post_above_8192
8407 ;; 4096 < c
<= 8192 cylinders
8410 jmp hd0_post_store_logical
8412 hd0_post_above_8192
:
8413 ;; 8192 < c
<= 16384 cylinders
8417 hd0_post_store_logical
:
8418 mov (0x003d + 0x00), bx
;; number of physical cylinders
8419 mov (0x003d + 0x02), cl
;; number of physical heads
8421 mov cl
, #0x0f ;; repeat count
8422 mov si
, #0x003d ;; offset to disk0 FDPT
8423 mov al
, #0x00 ;; sum
8424 hd0_post_checksum_loop
:
8428 jnz hd0_post_checksum_loop
8429 not al
;; now take
2s complement
8432 ;;; Done filling EBDA table
for hard disk
0.
8436 ;; is there really a second hard disk
? if not, return now
8444 ;; check that the hd type is really
0x0f.
8449 ;; check that the extended type is
47 - user definable
8453 cmp al
, #47 ;; decimal 47 - user definable
8458 ;; CMOS purpose param table offset
8459 ;; 0x24 cylinders low
0
8460 ;; 0x25 cylinders high
1
8462 ;; 0x27 write pre
-comp low
5
8463 ;; 0x28 write pre
-comp high
6
8465 ;; 0x2a landing zone low C
8466 ;; 0x2b landing zone high D
8467 ;; 0x2c sectors
/track E
8468 ;;; Fill EBDA table
for hard disk
1.
8478 mov (0x004d + 0x05), ax
;; write precomp word
8483 mov (0x004d + 0x08), al
;; drive control byte
8492 mov (0x004d + 0x0C), ax
;; landing zone word
8494 mov al
, #0x25 ;; get cylinders word in AX
8496 in al
, #0x71 ;; high byte
8500 in al
, #0x71 ;; low byte
8501 mov bx
, ax
;; BX
= cylinders
8506 mov cl
, al
;; CL
= heads
8511 mov dl
, al
;; DL
= sectors
8514 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8516 hd1_post_physical_chs
:
8517 ;; no logical CHS mapping used
, just physical CHS
8518 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8519 mov (0x004d + 0x00), bx
;; number of physical cylinders
8520 mov (0x004d + 0x02), cl
;; number of physical heads
8521 mov (0x004d + 0x0E), dl
;; number of physical sectors
8524 hd1_post_logical_chs
:
8525 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8526 mov (0x004d + 0x09), bx
;; number of physical cylinders
8527 mov (0x004d + 0x0b), cl
;; number of physical heads
8528 mov (0x004d + 0x04), dl
;; number of physical sectors
8529 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8531 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8534 jnbe hd1_post_above_2048
8535 ;; 1024 < c
<= 2048 cylinders
8538 jmp hd1_post_store_logical
8540 hd1_post_above_2048
:
8542 jnbe hd1_post_above_4096
8543 ;; 2048 < c
<= 4096 cylinders
8546 jmp hd1_post_store_logical
8548 hd1_post_above_4096
:
8550 jnbe hd1_post_above_8192
8551 ;; 4096 < c
<= 8192 cylinders
8554 jmp hd1_post_store_logical
8556 hd1_post_above_8192
:
8557 ;; 8192 < c
<= 16384 cylinders
8561 hd1_post_store_logical
:
8562 mov (0x004d + 0x00), bx
;; number of physical cylinders
8563 mov (0x004d + 0x02), cl
;; number of physical heads
8565 mov cl
, #0x0f ;; repeat count
8566 mov si
, #0x004d ;; offset to disk0 FDPT
8567 mov al
, #0x00 ;; sum
8568 hd1_post_checksum_loop
:
8572 jnz hd1_post_checksum_loop
8573 not al
;; now take
2s complement
8576 ;;; Done filling EBDA table
for hard disk
1.
8580 ;--------------------
8581 ;- POST
: EBDA segment
8582 ;--------------------
8583 ; relocated here because the primary POST area isnt big enough
.
8588 mov byte ptr
[0x0], #EBDA_SIZE
8590 xor ax
, ax
; mov EBDA seg into
40E
8592 mov word ptr
[0x40E], #EBDA_SEG
8595 ;--------------------
8596 ;- POST
: EOI
+ jmp via
[0x40:67)
8597 ;--------------------
8598 ; relocated here because the primary POST area isnt big enough
.
8608 ;--------------------
8611 out
#0xA0, al ;; slave PIC EOI
8614 out
#0x20, al ;; master PIC EOI
8617 ;--------------------
8619 ;; in
: AL in BCD format
8620 ;; out
: AL in binary format
, AH will always be
0
8623 and bl
, #0x0f ;; bl has low digit
8624 shr al
, #4 ;; al has high digit
8626 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8627 add al
, bl
;; then add low digit
8630 ;--------------------
8632 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8633 ;; Timer Ticks Roller
Flag (0x470:byte
)
8634 ;; The Timer Ticks Count needs to be set according to
8635 ;; the current CMOS time
, as
if ticks have been occurring
8636 ;; at
18.2hz since midnight up to
this point
. Calculating
8637 ;; this is a little complicated
. Here are the factors I gather
8638 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8639 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8640 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8641 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8642 ;; the timer
. With a maximum
16bit timer count
, this is again
8643 ;; divided down by
65536 to
18.2hz
.
8645 ;; 14,318,180 Hz clock
8646 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8647 ;; /4 = 1,193,181 Hz fed to timer
8648 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8649 ;; 1 second
= 18.20650736 ticks
8650 ;; 1 minute
= 1092.390442 ticks
8651 ;; 1 hour
= 65543.42651 ticks
8653 ;; Given the values in the CMOS clock
, one could calculate
8654 ;; the number of ticks by the following
:
8655 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8656 ;; (BcdToBin(minutes
) * 1092.3904)
8657 ;; (BcdToBin(hours
) * 65543.427)
8658 ;; To get a little more accuracy
, since Im
using integer
8659 ;; arithmatic
, I use
:
8660 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8661 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8662 ;; (BcdToBin(hours
) * 65543427) / 1000
8667 xor eax
, eax
;; clear EAX
8670 in al
, #0x71 ;; AL has CMOS seconds in BCD
8671 call BcdToBin
;; EAX now has seconds in binary
8677 mov ecx
, eax
;; ECX will accumulate total ticks
8680 xor eax
, eax
;; clear EAX
8683 in al
, #0x71 ;; AL has CMOS minutes in BCD
8684 call BcdToBin
;; EAX now has minutes in binary
8690 add ecx
, eax
;; add to total ticks
8693 xor eax
, eax
;; clear EAX
8696 in al
, #0x71 ;; AL has CMOS hours in BCD
8697 call BcdToBin
;; EAX now has hours in binary
8703 add ecx
, eax
;; add to total ticks
8705 mov
0x46C, ecx
;; Timer Ticks Count
8707 mov
0x470, al
;; Timer Ticks Rollover Flag
8710 ;--------------------
8712 ;; record completion in BIOS task complete flag
8724 ;--------------------
8729 #include "apmbios.S"
8733 #include "apmbios.S"
8736 #include "apmbios.S"
8740 ;--------------------
8745 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8746 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8747 db
0 ;; revision level
8748 ;; length in paragraphs
and checksum stored in a word to prevent errors
8749 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8750 & 0xff) << 8) + 0x01
8751 db
0,0,0,0,0 ;; reserved
8756 cmp eax
, #0x49435024 ;; "$PCI"
8758 mov eax
, #0x80000000
8763 #ifdef PCI_FIXED_HOST_BRIDGE
8764 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8767 ;; say ok
if a device is present
8768 cmp eax
, #0xffffffff
8771 mov ebx
, #0x000f0000
8773 mov edx
, #pcibios_protected
8780 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
8791 cmp al
, #0x01 ;; installation check
8795 mov edx
, #0x20494350 ;; "PCI "
8798 pci_pro_f02
: ;; find pci device
8806 call pci_pro_select_reg
8820 pci_pro_f08
: ;; read configuration byte
8823 call pci_pro_select_reg
8832 pci_pro_f09
: ;; read configuration word
8835 call pci_pro_select_reg
8844 pci_pro_f0a
: ;; read configuration dword
8847 call pci_pro_select_reg
8854 pci_pro_f0b
: ;; write configuration byte
8857 call pci_pro_select_reg
8866 pci_pro_f0c
: ;; write configuration word
8869 call pci_pro_select_reg
8878 pci_pro_f0d
: ;; write configuration dword
8881 call pci_pro_select_reg
8894 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
8904 and dword ptr
[esp
+8],0xfffffffc ;; reset CS
.RPL
for kqemu
8928 mov eax
, #0x80000000
8933 #ifdef PCI_FIXED_HOST_BRIDGE
8934 cmp eax
, #PCI_FIXED_HOST_BRIDGE
8937 ;; say ok
if a device is present
8938 cmp eax
, #0xffffffff
8949 cmp al
, #0x01 ;; installation check
8954 mov edx
, #0x20494350 ;; "PCI "
8956 mov di
, #pcibios_protected
8959 pci_real_f02
: ;; find pci device
8969 call pci_real_select_reg
8973 jne pci_real_nextdev
8980 jne pci_real_devloop
8985 pci_real_f08
: ;; read configuration byte
8988 call pci_real_select_reg
8997 pci_real_f09
: ;; read configuration word
9000 call pci_real_select_reg
9009 pci_real_f0a
: ;; read configuration dword
9012 call pci_real_select_reg
9019 pci_real_f0b
: ;; write configuration byte
9022 call pci_real_select_reg
9031 pci_real_f0c
: ;; write configuration word
9034 call pci_real_select_reg
9043 pci_real_f0d
: ;; write configuration dword
9046 call pci_real_select_reg
9053 pci_real_f0e
: ;; get irq routing options
9055 jne pci_real_unknown
9057 cmp word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9058 jb pci_real_too_small
9060 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9068 mov si
, #pci_routing_table_structure_start
9076 mov cx
, #pci_routing_table_structure_end - pci_routing_table_structure_start
9085 mov bx
, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9089 mov word ptr
[di
], #pci_routing_table_structure_end - pci_routing_table_structure_start
9107 pci_real_select_reg
:
9121 pci_routing_table_structure
:
9122 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9124 dw
32 + (6 * 16) ;; table size
9125 db
0 ;; PCI interrupt router bus
9126 db
0x08 ;; PCI interrupt router DevFunc
9127 dw
0x0000 ;; PCI exclusive IRQs
9128 dw
0x8086 ;; compatible PCI interrupt router vendor ID
9129 dw
0x7000 ;; compatible PCI interrupt router device ID
9130 dw
0,0 ;; Miniport data
9131 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9133 pci_routing_table_structure_start
:
9134 ;; first slot entry PCI
-to
-ISA (embedded
)
9135 db
0 ;; pci bus number
9136 db
0x08 ;; pci device
number (bit
7-3)
9137 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
9138 dw
0xdef8 ;; IRQ bitmap INTA
#
9139 db
0x61 ;; link value INTB
#
9140 dw
0xdef8 ;; IRQ bitmap INTB
#
9141 db
0x62 ;; link value INTC
#
9142 dw
0xdef8 ;; IRQ bitmap INTC
#
9143 db
0x63 ;; link value INTD
#
9144 dw
0xdef8 ;; IRQ bitmap INTD
#
9145 db
0 ;; physical
slot (0 = embedded
)
9147 ;; second slot entry
: 1st PCI slot
9148 db
0 ;; pci bus number
9149 db
0x10 ;; pci device
number (bit
7-3)
9150 db
0x61 ;; link value INTA
#
9151 dw
0xdef8 ;; IRQ bitmap INTA
#
9152 db
0x62 ;; link value INTB
#
9153 dw
0xdef8 ;; IRQ bitmap INTB
#
9154 db
0x63 ;; link value INTC
#
9155 dw
0xdef8 ;; IRQ bitmap INTC
#
9156 db
0x60 ;; link value INTD
#
9157 dw
0xdef8 ;; IRQ bitmap INTD
#
9158 db
1 ;; physical
slot (0 = embedded
)
9160 ;; third slot entry
: 2nd PCI slot
9161 db
0 ;; pci bus number
9162 db
0x18 ;; pci device
number (bit
7-3)
9163 db
0x62 ;; link value INTA
#
9164 dw
0xdef8 ;; IRQ bitmap INTA
#
9165 db
0x63 ;; link value INTB
#
9166 dw
0xdef8 ;; IRQ bitmap INTB
#
9167 db
0x60 ;; link value INTC
#
9168 dw
0xdef8 ;; IRQ bitmap INTC
#
9169 db
0x61 ;; link value INTD
#
9170 dw
0xdef8 ;; IRQ bitmap INTD
#
9171 db
2 ;; physical
slot (0 = embedded
)
9173 ;; 4th slot entry
: 3rd PCI slot
9174 db
0 ;; pci bus number
9175 db
0x20 ;; pci device
number (bit
7-3)
9176 db
0x63 ;; link value INTA
#
9177 dw
0xdef8 ;; IRQ bitmap INTA
#
9178 db
0x60 ;; link value INTB
#
9179 dw
0xdef8 ;; IRQ bitmap INTB
#
9180 db
0x61 ;; link value INTC
#
9181 dw
0xdef8 ;; IRQ bitmap INTC
#
9182 db
0x62 ;; link value INTD
#
9183 dw
0xdef8 ;; IRQ bitmap INTD
#
9184 db
3 ;; physical
slot (0 = embedded
)
9186 ;; 5th slot entry
: 4rd PCI slot
9187 db
0 ;; pci bus number
9188 db
0x28 ;; pci device
number (bit
7-3)
9189 db
0x60 ;; link value INTA
#
9190 dw
0xdef8 ;; IRQ bitmap INTA
#
9191 db
0x61 ;; link value INTB
#
9192 dw
0xdef8 ;; IRQ bitmap INTB
#
9193 db
0x62 ;; link value INTC
#
9194 dw
0xdef8 ;; IRQ bitmap INTC
#
9195 db
0x63 ;; link value INTD
#
9196 dw
0xdef8 ;; IRQ bitmap INTD
#
9197 db
4 ;; physical
slot (0 = embedded
)
9199 ;; 6th slot entry
: 5rd PCI slot
9200 db
0 ;; pci bus number
9201 db
0x30 ;; pci device
number (bit
7-3)
9202 db
0x61 ;; link value INTA
#
9203 dw
0xdef8 ;; IRQ bitmap INTA
#
9204 db
0x62 ;; link value INTB
#
9205 dw
0xdef8 ;; IRQ bitmap INTB
#
9206 db
0x63 ;; link value INTC
#
9207 dw
0xdef8 ;; IRQ bitmap INTC
#
9208 db
0x60 ;; link value INTD
#
9209 dw
0xdef8 ;; IRQ bitmap INTD
#
9210 db
5 ;; physical
slot (0 = embedded
)
9212 pci_routing_table_structure_end
:
9218 pcibios_init_sel_reg
:
9230 pcibios_init_iomem_bases
:
9233 mov eax
, #0xe0000000 ;; base for memory init
9235 mov ax
, #0xc000 ;; base for i/o init
9237 mov ax
, #0x0010 ;; start at base address #0
9242 call pcibios_init_sel_reg
9247 mov dl
, #0x04 ;; disable i/o and memory space access
9248 call pcibios_init_sel_reg
9255 call pcibios_init_sel_reg
9261 mov eax
, #0xffffffff
9266 xor eax
, #0xffffffff
9270 add eax
, ecx
;; calculate next free mem base
9271 add eax
, #0x01000000
9272 and eax
, #0xff000000
9286 add ax
, cx
;; calculate next free i
/o base
9294 je enable_iomem_space
9295 mov byte ptr
[bp
-8], al
9296 jmp pci_init_io_loop2
9298 mov dl
, #0x04 ;; enable i/o and memory space access if available
9299 call pcibios_init_sel_reg
9305 mov byte ptr
[bp
-8], #0x10
9308 jne pci_init_io_loop1
9313 pcibios_init_set_elcr
:
9337 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
9342 mov si
, #pci_routing_table_structure
9346 call pcibios_init_sel_reg
9349 cmp eax
, [si
+12] ;; check irq router
9352 call pcibios_init_sel_reg
9353 push bx
;; save irq router bus
+ devfunc
9356 out dx
, ax
;; reset PIRQ route control
9364 add si
, #0x20 ;; set pointer to 1st entry
9366 mov ax
, #pci_irq_list
9375 call pcibios_init_sel_reg
9379 jnz pci_test_int_pin
9385 call pcibios_init_sel_reg
9390 dec al
;; determine pirq reg
9399 call pcibios_init_sel_reg
9406 mov bx
, [bp
-2] ;; pci irq list pointer
9411 call pcibios_init_set_elcr
9415 add bl
, [bp
-3] ;; pci function number
9417 call pcibios_init_sel_reg
9424 jnz pci_init_irq_loop2
9427 mov byte ptr
[bp
-3], #0x00
9428 loop pci_init_irq_loop1
9435 #endif // BX_ROMBIOS32
9436 #endif // BX_PCIBIOS
9440 ;; save a20
and enable it
9446 ;; save SS
:SP to the BDA
9453 lidt
[pmode_IDT_info
]
9455 lgdt
[rombios32_gdt_48
]
9456 ;; set PE bit in CR0
9460 ;; start
protected mode code
: ljmpl
0x10:rombios32_init1
9463 dw
0x000f ;; high
16 bit address
9468 ;; init data segments
9478 ;; copy rombios32 code to
ram (ram offset
= 1MB
)
9479 mov esi
, #0xfffe0000
9480 mov edi
, #0x00040000
9481 mov ecx
, #0x10000 / 4
9485 ;; init the stack pointer
9486 mov esp
, #0x00080000
9488 ;; call rombios32 code
9489 mov eax
, #0x00040000
9492 ;; return to
16 bit
protected mode first
9499 ;; restore data segment limits to
0xffff
9507 ;; reset PE bit in CR0
9512 ;; far jump to flush CPU queue after transition to real mode
9513 JMP_AP(0xf000, rombios32_real_mode
)
9515 rombios32_real_mode
:
9516 ;; restore IDT to normal real
-mode defaults
9518 lidt
[rmode_IDT_info
]
9526 ;; restore SS
:SP from the BDA
9542 dw
0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code
segment (0x10)
9543 dw
0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data
segment (0x18)
9544 dw
0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base
=0xf0000 limit
=0xffff
9545 dw
0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base
=0x0 limit
=0xffff
9549 ; parallel port detection
: base address in DX
, index in BX
, timeout in CL
9554 and al
, #0xdf ; clear input mode
9564 mov
[bx
+0x408], dx
; Parallel I
/O address
9566 mov
[bx
+0x478], cl
; Parallel printer timeout
9571 ; serial port detection
: base address in DX
, index in BX
, timeout in CL
9590 mov
[bx
+0x400], dx
; Serial I
/O address
9592 mov
[bx
+0x47c], cl
; Serial timeout
9619 ;; Scan
for existence of valid expansion ROMS
.
9620 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9621 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9622 ;; System ROM
: only
0xE0000
9628 ;; 2 ROM length in
512-byte blocks
9629 ;; 3 ROM initialization entry
point (FAR CALL
)
9634 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9635 cmp
[0], #0xAA55 ;; look for signature
9636 jne rom_scan_increment
9638 jnz rom_scan_increment
9639 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9641 ;; We want our increment in
512-byte quantities
, rounded to
9642 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9644 jz block_count_rounded
9645 and al
, #0xfc ;; needs rounding up
9647 block_count_rounded
:
9649 xor bx
, bx
;; Restore DS back to
0000:
9652 ;; Push addr of ROM entry point
9654 push
#0x0003 ;; Push offset
9655 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9656 db
0xff ;; call_far ss
:[bp
+0]
9659 cli
;; In
case expansion ROM BIOS turns IF on
9660 add sp
, #2 ;; Pop offset value
9661 pop cx
;; Pop seg
value (restore CX
)
9662 pop ax
;; Restore AX
9664 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
9665 ;; because the segment selector is shifted left
4 bits
.
9670 xor ax
, ax
;; Restore DS back to
0000:
9674 ;; for 'C' strings
and other data
, insert them here with
9675 ;; a the following hack
:
9676 ;; DATA_SEG_DEFS_HERE
9679 ;; the following area can be used to write dynamically generated tables
9681 bios_table_area_start
:
9683 dd bios_table_area_end
- bios_table_area_start
- 8;
9688 .org
0xe05b ; POST Entry Point
9689 bios_table_area_end
:
9694 ;; first reset the DMA controllers
9698 ;; then initialize the DMA controllers
9700 out
0xD6, al
; cascade mode of channel
4 enabled
9702 out
0xD4, al
; unmask channel
4
9704 ;; Examine CMOS shutdown status
.
9712 ;; Reset CMOS shutdown status
.
9714 out
0x70, AL
; select CMOS
register Fh
9716 out
0x71, AL
; set shutdown action to normal
9718 ;; Examine CMOS shutdown status
.
9721 ;; 0x00, 0x09, 0x0D+ = normal startup
9729 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
9733 ;; Examine CMOS shutdown status
.
9734 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
9736 call _shutdown_status_panic
9742 ; 0xb0, 0x20, /* mov al, #0x20 */
9743 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9753 ; case 0: normal startup
9762 ;; zero out BIOS data
area (40:00..40:ff
)
9764 mov cx
, #0x0080 ;; 128 words
9770 call _log_bios_start
9772 ;; set all interrupts to
default handler
9773 mov bx
, #0x0000 ;; offset index
9774 mov cx
, #0x0100 ;; counter (256 interrupts)
9775 mov ax
, #dummy_iret_handler
9785 loop post_default_ints
9787 ;; set vector
0x79 to zero
9788 ;; this is used by
'gardian angel' protection system
9789 SET_INT_VECTOR(0x79, #0, #0)
9791 ;; base memory in K
40:13 (word
)
9792 mov ax
, #BASE_MEM_IN_K
9796 ;; Manufacturing Test
40:12
9799 ;; Warm Boot Flag
0040:0072
9800 ;; value of
1234h
= skip memory checks
9804 ;; Printer Services vector
9805 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9807 ;; Bootstrap failure vector
9808 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9810 ;; Bootstrap Loader vector
9811 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9813 ;; User Timer Tick vector
9814 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9816 ;; Memory Size Check vector
9817 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9819 ;; Equipment Configuration Check vector
9820 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9823 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9829 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9830 ;; int 1C already points at
dummy_iret_handler (above
)
9831 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
9833 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
9838 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9839 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9843 mov
0x0417, al
/* keyboard shift flags, set 1 */
9844 mov
0x0418, al
/* keyboard shift flags, set 2 */
9845 mov
0x0419, al
/* keyboard alt-numpad work area */
9846 mov
0x0471, al
/* keyboard ctrl-break flag */
9847 mov
0x0497, al
/* keyboard status flags 4 */
9849 mov
0x0496, al
/* keyboard status flags 3 */
9852 /* keyboard head of buffer pointer */
9856 /* keyboard end of buffer pointer */
9859 /* keyboard pointer to start of buffer */
9863 /* keyboard pointer to end of buffer */
9867 /* init the keyboard */
9870 ;; mov CMOS Equipment Byte to BDA Equipment Word
9879 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9883 mov cl
, #0x14 ; timeout value
9884 mov dx
, #0x378 ; Parallel I/O address, port 1
9886 mov dx
, #0x278 ; Parallel I/O address, port 2
9889 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
9891 or ax
, bx
; set number of parallel ports
9895 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9896 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9898 mov cl
, #0x0a ; timeout value
9899 mov dx
, #0x03f8 ; Serial I/O address, port 1
9901 mov dx
, #0x02f8 ; Serial I/O address, port 2
9903 mov dx
, #0x03e8 ; Serial I/O address, port 3
9905 mov dx
, #0x02e8 ; Serial I/O address, port 4
9908 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
9910 or ax
, bx
; set number of serial port
9914 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9915 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9916 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9917 ;; BIOS DATA AREA
0x4CE ???
9918 call timer_tick_post
9921 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9923 ;; IRQ13 (FPU exception
) setup
9924 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9927 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9930 mov al
, #0x11 ; send initialisation commands
9945 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
9946 #if BX_USE_PS2_MOUSE
9951 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
9956 call pcibios_init_iomem_bases
9957 call pcibios_init_irqs
9961 call _print_bios_banner
9966 call floppy_drive_post
9973 call hard_drive_post
9976 ;; ATA
/ATAPI driver setup
9981 #else // BX_USE_ATADRV
9986 call hard_drive_post
9988 #endif // BX_USE_ATADRV
9990 #if BX_ELTORITO_BOOT
9992 ;; eltorito floppy
/harddisk emulation from cd
9996 #endif // BX_ELTORITO_BOOT
9998 sti
;; enable interrupts
10002 .org
0xe2c3 ; NMI Handler Entry Point
10004 ;; FIXME the NMI handler should
not panic
10005 ;; but iret when called from
int75 (fpu exception
)
10006 call _nmi_handler_msg
10010 out
0xf0, al
// clear irq13
10011 call eoi_both_pics
// clear interrupt
10012 int 2 // legacy nmi call
10015 ;-------------------------------------------
10016 ;- INT
13h Fixed Disk Services Entry Point
-
10017 ;-------------------------------------------
10018 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
10020 //JMPL(int13_relocated)
10021 jmp int13_relocated
10023 .org
0xe401 ; Fixed Disk Parameter Table
10028 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
10031 jmp int19_relocated
10032 ;-------------------------------------------
10033 ;- System BIOS Configuration Data Table
10034 ;-------------------------------------------
10035 .org BIOS_CONFIG_TABLE
10036 db
0x08 ; Table
size (bytes
) -Lo
10037 db
0x00 ; Table
size (bytes
) -Hi
10042 ; b7
: 1=DMA channel
3 used by hard disk
10043 ; b6
: 1=2 interrupt controllers present
10044 ; b5
: 1=RTC present
10045 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
10046 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
10047 ; b2
: 1=extended BIOS data area used
10048 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
10049 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
10053 (BX_CALL_INT15_4F
<< 4) | \
10055 (BX_USE_EBDA
<< 2) | \
10059 ; b7
: 1=32-bit DMA supported
10060 ; b6
: 1=int16h
, function
9 supported
10061 ; b5
: 1=int15h
/C6h (get POS data
) supported
10062 ; b4
: 1=int15h
/C7h (get mem map info
) supported
10063 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
10064 ; b2
: 1=non
-8042 kb controller
10065 ; b1
: 1=data streaming supported
10079 ; b4
: POST supports ROM
-to
-RAM enable
/disable
10080 ; b3
: SCSI on system board
10081 ; b2
: info panel installed
10082 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
10083 ; b0
: SCSI supported in IML
10087 ; b6
: EEPROM present
10088 ; b5
-3: ABIOS
presence (011 = not supported
)
10090 ; b1
: memory split above
16Mb supported
10091 ; b0
: POSTEXT directly supported by POST
10093 ; Feature byte
5 (IBM
)
10094 ; b1
: enhanced mouse
10100 .org
0xe729 ; Baud Rate Generator Table
10105 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
10111 call _int14_function
10117 ;----------------------------------------
10118 ;- INT
16h Keyboard Service Entry Point
-
10119 ;----------------------------------------
10135 call _int16_function
10145 and BYTE
[bp
+ 0x06], #0xbf
10153 or BYTE
[bp
+ 0x06], #0x40
10161 int16_wait_for_key
:
10165 jne int16_key_found
10169 /* no key yet, call int 15h, function AX=9002 */
10170 0x50, /* push AX */
10171 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10172 0xcd, 0x15, /* int 15h */
10174 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10176 jmp int16_wait_for_key
10181 call _int16_function
10186 /* notify int16 complete w/ int 15h, function AX=9102 */
10187 0x50, /* push AX */
10188 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10189 0xcd, 0x15, /* int 15h */
10196 ;-------------------------------------------------
10197 ;- INT09h
: Keyboard Hardware Service Entry Point
-
10198 ;-------------------------------------------------
10204 mov al
, #0xAD ;;disable keyboard
10213 in al
, #0x60 ;;read key from keyboard controller
10217 #ifdef BX_CALL_INT15_4F
10218 mov ah
, #0x4f ;; allow for keyboard intercept
10224 ;; check
for extended key
10226 jne int09_check_pause
10229 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x02
10231 mov BYTE
[0x496], al
10234 int09_check_pause
: ;; check
for pause key
10236 jne int09_process_key
10239 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
10241 mov BYTE
[0x496], al
10247 call _int09_function
10253 call eoi_master_pic
10256 mov al
, #0xAE ;;enable keyboard
10262 ;----------------------------------------
10263 ;- INT
13h Diskette Service Entry Point
-
10264 ;----------------------------------------
10267 jmp int13_noeltorito
10269 ;---------------------------------------------
10270 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
10271 ;---------------------------------------------
10272 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
10282 mov al
, #0x08 ; sense interrupt status
10300 mov ax
, #0x0000 ;; segment 0000
10302 call eoi_master_pic
10304 or al
, #0x80 ;; diskette interrupt has occurred
10312 .org
0xefc7 ; Diskette Controller Parameter Table
10313 diskette_param_table
:
10314 ;; Since no provisions are made
for multiple drive types
, most
10315 ;; values in
this table are ignored
. I set parameters
for 1.44M
10318 db
0x02 ;; head load time
0000001, DMA used
10330 ;----------------------------------------
10331 ;- INT17h
: Printer Service Entry Point
-
10332 ;----------------------------------------
10339 call _int17_function
10344 diskette_param_table2
:
10345 ;; New diskette parameter table adding
3 parameters from IBM
10346 ;; Since no provisions are made
for multiple drive types
, most
10347 ;; values in
this table are ignored
. I set parameters
for 1.44M
10350 db
0x02 ;; head load time
0000001, DMA used
10360 db
79 ;; maximum track
10361 db
0 ;; data transfer rate
10362 db
4 ;; drive type in cmos
10364 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
10371 .org
0xf065 ; INT
10h Video Support Service Entry Point
10373 ;; dont
do anything
, since the VGA BIOS handles int10h requests
10376 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
10381 .org
0xf841 ; INT
12h Memory Size Service Entry Point
10382 ; ??? different
for Pentium (machine check
)?
10394 .org
0xf84d ; INT
11h Equipment List Service Entry Point
10406 .org
0xf859 ; INT
15h System Services Entry Point
10420 #if BX_USE_PS2_MOUSE
10422 je int15_handler_mouse
10424 call _int15_function
10425 int15_handler_mouse_ret
:
10427 int15_handler32_ret
:
10437 #if BX_USE_PS2_MOUSE
10438 int15_handler_mouse
:
10439 call _int15_function_mouse
10440 jmp int15_handler_mouse_ret
10445 call _int15_function32
10447 jmp int15_handler32_ret
10449 ;; Protected mode IDT descriptor
10451 ;; I just make the limit
0, so the machine will shutdown
10452 ;; if an exception occurs during
protected mode memory
10455 ;; Set base to f0000 to correspond to beginning of BIOS
,
10456 ;; in
case I actually define an IDT later
10460 dw
0x0000 ;; limit
15:00
10461 dw
0x0000 ;; base
15:00
10462 db
0x0f ;; base
23:16
10464 ;; Real mode IDT descriptor
10466 ;; Set to typical real
-mode values
.
10471 dw
0x03ff ;; limit
15:00
10472 dw
0x0000 ;; base
15:00
10473 db
0x00 ;; base
23:16
10479 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10492 mov ax
, ss
; set readable descriptor to ds
, for calling pcibios
10493 mov ds
, ax
; on
16bit
protected mode
.
10494 jmp int1a_callfunction
10501 int1a_callfunction
:
10502 call _int1a_function
10508 ;; int70h
: IRQ8
- CMOS RTC
10515 call _int70_function
10523 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10531 ;; time to turn off
drive(s
)?
10534 jz int08_floppy_off
10537 jnz int08_floppy_off
10538 ;; turn
motor(s
) off
10547 mov eax
, 0x046c ;; get ticks dword
10550 ;; compare eax to one days worth of timer ticks at
18.2 hz
10551 cmp eax
, #0x001800B0
10552 jb int08_store_ticks
10553 ;; there has been a midnight rollover at
this point
10554 xor eax
, eax
;; zero out counter
10555 inc BYTE
0x0470 ;; increment rollover flag
10558 mov
0x046c, eax
;; store
new ticks dword
10559 ;; chain to user timer tick INT
#0x1c
10561 //;; call_ep [ds:loc]
10562 //CALL_EP( 0x1c << 2 )
10565 call eoi_master_pic
10570 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10574 .ascii BIOS_COPYRIGHT_STRING
10576 ;------------------------------------------------
10577 ;- IRET Instruction
for Dummy Interrupt Handler
-
10578 ;------------------------------------------------
10579 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10580 dummy_iret_handler
:
10583 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10587 .org
0xfff0 ; Power
-up Entry Point
10590 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10591 .ascii BIOS_BUILD_DATE
10593 .org
0xfffe ; System Model ID
10597 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10600 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10601 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10602 * This font is public domain
10604 static Bit8u vgafont8
[128*8]=
10606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10607 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10608 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10609 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10610 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10611 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10612 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10613 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10614 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10615 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10616 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10617 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10618 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10619 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10620 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10621 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10622 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10623 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10624 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10625 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10626 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10627 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10628 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10629 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10630 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10631 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10632 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10633 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10634 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10635 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10636 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10637 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10638 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10639 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10640 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10641 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10642 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10643 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10644 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10645 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10646 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10647 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10648 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10649 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10650 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10651 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10652 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10653 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10654 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10655 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10656 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10657 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10658 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10659 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10660 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10661 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10662 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10663 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10664 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10665 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10666 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10667 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10668 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10669 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10670 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10671 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10672 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10673 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10674 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10675 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10676 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10677 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10678 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10679 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10680 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10681 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10682 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10683 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10684 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10685 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10686 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10687 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10688 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10689 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10690 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10691 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10692 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10693 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10694 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10695 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10696 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10697 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10698 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10699 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10700 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10702 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10703 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10704 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10705 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10706 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10707 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10708 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10709 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10710 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10711 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10712 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10713 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10714 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10715 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10716 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10717 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10718 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10719 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10720 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10721 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10722 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10723 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10724 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10725 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10726 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10727 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10728 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10729 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10730 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10731 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10732 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10733 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10738 // bcc-generated data will be placed here