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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 // ROM BIOS for use with Bochs/Plex x86 emulation environment
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
108 // - NMI access (bit7 of addr written to 70h)
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
124 // - the bios should try to boot from different devices.
125 // Use cmos regs 0x3d & high nibble of 0x38 to store up to 3 boot devices from 16
127 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
129 #define DEBUG_ROMBIOS 0
132 #define DEBUG_INT13_HD 0
133 #define DEBUG_INT13_CD 0
134 #define DEBUG_INT13_ET 0
135 #define DEBUG_INT13_FL 0
136 #define DEBUG_INT15 0
137 #define DEBUG_INT16 0
138 #define DEBUG_INT1A 0
139 #define DEBUG_INT74 0
143 #define BX_USE_PS2_MOUSE 1
144 #define BX_CALL_INT15_4F 1
145 #define BX_USE_EBDA 1
146 #define BX_SUPPORT_FLOPPY 1
147 #define BX_FLOPPY_ON_CNT 37 // 2 seconds
151 #define BX_USE_ATADRV 1
152 #define BX_ELTORITO_BOOT 1
154 #define BX_MAX_ATA_INTERFACES 4
155 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
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 // 1K of base memory used for Extended Bios Data Area (EBDA)
164 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
165 #define EBDA_SEG 0x9FC0
166 #define EBDA_SIZE 1 // In KiB
167 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
169 // Define the application NAME
171 # define BX_APPNAME "Plex86"
173 # define BX_APPNAME "Bochs"
177 #if BX_USE_ATADRV && BX_CPU<3
178 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
180 #if BX_USE_ATADRV && !BX_USE_EBDA
181 # error ATA/ATAPI Driver can only be used if EBDA is available
183 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
184 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
186 #if BX_PCIBIOS && BX_CPU<3
187 # error PCI BIOS can only be used with 386+ cpu
191 #define PANIC_PORT 0x400
192 #define PANIC_PORT2 0x401
193 #define INFO_PORT 0x402
194 #define DEBUG_PORT 0x403
197 // #$20 is hex 20 = 32
204 // all hex literals should be prefixed with '0x'
205 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
206 // no mov SEG-REG, #value, must mov register into seg-reg
207 // grep -i "mov[ ]*.s" rombios.c
209 // This is for compiling with gcc2 and gcc3
210 #define ASM_START #asm
211 #define ASM_END #endasm
225 ;; the HALT macro is called with the line number of the HALT call
.
226 ;; The line number is then sent to the PANIC_PORT
, causing Bochs
/Plex
227 ;; to print a BX_PANIC message
. This will normally halt the simulation
228 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
229 ;; However
, users can choose to make panics non
-fatal
and continue.
250 typedef unsigned char Bit8u
;
251 typedef unsigned short Bit16u
;
252 typedef unsigned short bx_bool
;
253 typedef unsigned long Bit32u
;
257 void memsetb(seg
,offset
,value
,count
);
258 void memcpyb(dseg
,doffset
,sseg
,soffset
,count
);
259 void memcpyd(dseg
,doffset
,sseg
,soffset
,count
);
261 // memset of count bytes
263 memsetb(seg
,offset
,value
,count
)
278 mov cx
, 10[bp
] ; count
281 mov ax
, 4[bp
] ; segment
283 mov ax
, 6[bp
] ; offset
285 mov al
, 8[bp
] ; value
301 // memcpy of count bytes
303 memcpyb(dseg
,doffset
,sseg
,soffset
,count
)
321 mov cx
, 12[bp
] ; count
324 mov ax
, 4[bp
] ; dsegment
326 mov ax
, 6[bp
] ; doffset
328 mov ax
, 8[bp
] ; ssegment
330 mov ax
, 10[bp
] ; soffset
348 // memcpy of count dword
350 memcpyd(dseg
,doffset
,sseg
,soffset
,count
)
368 mov cx
, 12[bp
] ; count
371 mov ax
, 4[bp
] ; dsegment
373 mov ax
, 6[bp
] ; doffset
375 mov ax
, 8[bp
] ; ssegment
377 mov ax
, 10[bp
] ; soffset
395 #endif //BX_USE_ATADRV
397 // read_dword and write_dword functions
398 static Bit32u
read_dword();
399 static void write_dword();
402 read_dword(seg
, offset
)
412 mov ax
, 4[bp
] ; segment
414 mov bx
, 6[bp
] ; offset
419 ;; ax
= return value (word
)
420 ;; dx
= return value (word
)
429 write_dword(seg
, offset
, data
)
441 mov ax
, 4[bp
] ; segment
443 mov bx
, 6[bp
] ; offset
444 mov ax
, 8[bp
] ; data word
445 mov
[bx
], ax
; write data word
448 mov ax
, 10[bp
] ; data word
449 mov
[bx
], ax
; write data word
458 // Bit32u (unsigned long) and long helper functions
487 cmp eax
, dword ptr
[di
]
506 mul eax
, dword ptr
[di
]
602 // for access to RAM area which is used by interrupt vectors
603 // and BIOS Data Area
606 unsigned char filler1
[0x400];
607 unsigned char filler2
[0x6c];
613 #define BiosData ((bios_data_t *) 0)
617 Bit16u heads
; // # heads
618 Bit16u cylinders
; // # cylinders
619 Bit16u spt
; // # sectors / track
639 Bit8u iface
; // ISA or PCI
640 Bit16u iobase1
; // IO Base 1
641 Bit16u iobase2
; // IO Base 2
646 Bit8u type
; // Detected type of ata (ata/atapi/none/unknown)
647 Bit8u device
; // Detected type of attached devices (hd/cd/none)
648 Bit8u removable
; // Removable device flag
649 Bit8u lock
; // Locks for removable devices
650 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
651 Bit8u mode
; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
652 Bit16u blksize
; // block size
654 Bit8u translation
; // type of translation
655 chs_t lchs
; // Logical CHS
656 chs_t pchs
; // Physical CHS
658 Bit32u sectors
; // Total sectors count
663 ata_channel_t channels
[BX_MAX_ATA_INTERFACES
];
666 ata_device_t devices
[BX_MAX_ATA_DEVICES
];
668 // map between (bios hd id - 0x80) and ata channels
669 Bit8u hdcount
, hdidmap
[BX_MAX_ATA_DEVICES
];
671 // map between (bios cd id - 0xE0) and ata channels
672 Bit8u cdcount
, cdidmap
[BX_MAX_ATA_DEVICES
];
674 // Buffer for DPTE table
677 // Count of transferred sectors and bytes
684 // ElTorito Device Emulation data
688 Bit8u emulated_drive
;
689 Bit8u controller_index
;
692 Bit16u buffer_segment
;
699 #endif // BX_ELTORITO_BOOT
701 // for access to EBDA area
702 // The EBDA structure should conform to
703 // http://www.cybertrails.com/~fys/rombios.htm document
704 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
706 unsigned char filler1
[0x3D];
708 // FDPT - Can be splitted in data members if needed
709 unsigned char fdpt0
[0x10];
710 unsigned char fdpt1
[0x10];
712 unsigned char filler2
[0xC4];
718 // El Torito Emulation data
720 #endif // BX_ELTORITO_BOOT
724 #define EbdaData ((ebda_data_t *) 0)
726 // for access to the int13ext structure
737 #define Int13Ext ((int13ext_t *) 0)
739 // Disk Physical Table definition
746 Bit32u sector_count1
;
747 Bit32u sector_count2
;
758 Bit8u device_path
[8];
763 #define Int13DPT ((dpt_t *) 0)
765 #endif // BX_USE_ATADRV
770 Bit16u di
, si
, bp
, sp
;
771 Bit16u bx
, dx
, cx
, ax
;
775 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
783 Bit32u edi
, esi
, ebp
, esp
;
784 Bit32u ebx
, edx
, ecx
, eax
;
787 Bit16u di
, filler1
, si
, filler2
, bp
, filler3
, sp
, filler4
;
788 Bit16u bx
, filler5
, dx
, filler6
, cx
, filler7
, ax
, filler8
;
816 #define SetCF(x) x.u.r8.flagsl |= 0x01
817 #define SetZF(x) x.u.r8.flagsl |= 0x40
818 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
819 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
820 #define GetCF(x) (x.u.r8.flagsl & 0x01)
831 static Bit8u
inb_cmos();
833 static void outb_cmos();
836 static void init_rtc();
837 static bx_bool
rtc_updating();
839 static Bit8u
read_byte();
840 static Bit16u
read_word();
841 static void write_byte();
842 static void write_word();
843 static void bios_printf();
845 static Bit8u
inhibit_mouse_int_and_events();
846 static void enable_mouse_int_and_events();
847 static Bit8u
send_to_mouse_ctrl();
848 static Bit8u
get_mouse_data();
849 static void set_kbd_command_byte();
851 static void int09_function();
852 static void int13_harddisk();
853 static void int13_cdrom();
854 static void int13_cdemu();
855 static void int13_eltorito();
856 static void int13_diskette_function();
857 static void int14_function();
858 static void int15_function();
859 static void int16_function();
860 static void int17_function();
861 static Bit32u
int19_function();
862 static void int1a_function();
863 static void int70_function();
864 static void int74_function();
865 //static Bit16u get_DS();
866 //static void set_DS();
867 static Bit16u
get_SS();
868 static unsigned int enqueue_key();
869 static unsigned int dequeue_key();
870 static void get_hd_geometry();
871 static void set_diskette_ret_status();
872 static void set_diskette_current_cyl();
873 static void determine_floppy_media();
874 static bx_bool
floppy_drive_exists();
875 static bx_bool
floppy_drive_recal();
876 static bx_bool
floppy_media_known();
877 static bx_bool
floppy_media_sense();
878 static bx_bool
set_enable_a20();
879 static void debugger_on();
880 static void debugger_off();
881 static void keyboard_init();
882 static void keyboard_panic();
883 static void shutdown_status_panic();
884 static void nmi_handler_msg();
886 static void print_bios_banner();
887 static void print_boot_device();
888 static void print_boot_failure();
889 static void print_cdromboot_failure();
893 // ATA / ATAPI driver
898 Bit16u
ata_cmd_non_data();
899 Bit16u
ata_cmd_data_in();
900 Bit16u
ata_cmd_data_out();
901 Bit16u
ata_cmd_packet();
903 Bit16u
atapi_get_sense();
904 Bit16u
atapi_is_ready();
905 Bit16u
atapi_is_cdrom();
907 #endif // BX_USE_ATADRV
912 Bit8u
cdemu_isactive();
913 Bit8u
cdemu_emulated_drive();
917 #endif // BX_ELTORITO_BOOT
919 static char bios_cvs_version_string
[] = "$Revision$";
920 static char bios_date_string
[] = "$Date$";
922 static char CVSID
[] = "$Id$";
924 /* Offset to skip the CVS $Id: prefix */
925 #define bios_version_string (CVSID + 4)
927 #define BIOS_PRINTF_HALT 1
928 #define BIOS_PRINTF_SCREEN 2
929 #define BIOS_PRINTF_INFO 4
930 #define BIOS_PRINTF_DEBUG 8
931 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
932 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
934 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
936 // Defines the output macros.
937 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
938 // per-device basis. Debug info are sent only in debug mode
940 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
942 # define BX_DEBUG(format, p...)
944 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
945 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
948 # define BX_DEBUG_ATA(a...) BX_DEBUG(##a)
950 # define BX_DEBUG_ATA(a...)
953 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(##a)
955 # define BX_DEBUG_INT13_HD(a...)
958 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(##a)
960 # define BX_DEBUG_INT13_CD(a...)
963 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(##a)
965 # define BX_DEBUG_INT13_ET(a...)
968 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(##a)
970 # define BX_DEBUG_INT13_FL(a...)
973 # define BX_DEBUG_INT15(a...) BX_DEBUG(##a)
975 # define BX_DEBUG_INT15(a...)
978 # define BX_DEBUG_INT16(a...) BX_DEBUG(##a)
980 # define BX_DEBUG_INT16(a...)
983 # define BX_DEBUG_INT1A(a...) BX_DEBUG(##a)
985 # define BX_DEBUG_INT1A(a...)
988 # define BX_DEBUG_INT74(a...) BX_DEBUG(##a)
990 # define BX_DEBUG_INT74(a...)
993 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
994 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
995 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
996 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
997 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
998 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
999 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1000 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1002 #define GET_AL() ( AX & 0x00ff )
1003 #define GET_BL() ( BX & 0x00ff )
1004 #define GET_CL() ( CX & 0x00ff )
1005 #define GET_DL() ( DX & 0x00ff )
1006 #define GET_AH() ( AX >> 8 )
1007 #define GET_BH() ( BX >> 8 )
1008 #define GET_CH() ( CX >> 8 )
1009 #define GET_DH() ( DX >> 8 )
1012 #define SET_CF() FLAGS |= 0x0001
1013 #define CLEAR_CF() FLAGS &= 0xfffe
1014 #define GET_CF() (FLAGS & 0x0001)
1016 #define SET_ZF() FLAGS |= 0x0040
1017 #define CLEAR_ZF() FLAGS &= 0xffbf
1018 #define GET_ZF() (FLAGS & 0x0040)
1020 #define UNSUPPORTED_FUNCTION 0x86
1023 #define MAX_SCAN_CODE 0x53
1031 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
1032 { none
, none
, none
, none
, none
},
1033 { 0x011b, 0x011b, 0x011b, 0x0100, none
}, /* escape */
1034 { 0x0231, 0x0221, none
, 0x7800, none
}, /* 1! */
1035 { 0x0332, 0x0340, 0x0300, 0x7900, none
}, /* 2@ */
1036 { 0x0433, 0x0423, none
, 0x7a00, none
}, /* 3# */
1037 { 0x0534, 0x0524, none
, 0x7b00, none
}, /* 4$ */
1038 { 0x0635, 0x0625, none
, 0x7c00, none
}, /* 5% */
1039 { 0x0736, 0x075e, 0x071e, 0x7d00, none
}, /* 6^ */
1040 { 0x0837, 0x0826, none
, 0x7e00, none
}, /* 7& */
1041 { 0x0938, 0x092a, none
, 0x7f00, none
}, /* 8* */
1042 { 0x0a39, 0x0a28, none
, 0x8000, none
}, /* 9( */
1043 { 0x0b30, 0x0b29, none
, 0x8100, none
}, /* 0) */
1044 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none
}, /* -_ */
1045 { 0x0d3d, 0x0d2b, none
, 0x8300, none
}, /* =+ */
1046 { 0x0e08, 0x0e08, 0x0e7f, none
, none
}, /* backspace */
1047 { 0x0f09, 0x0f00, none
, none
, none
}, /* tab */
1048 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1049 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1050 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1051 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1052 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1053 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1054 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1055 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1056 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1057 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1058 { 0x1a5b, 0x1a7b, 0x1a1b, none
, none
}, /* [{ */
1059 { 0x1b5d, 0x1b7d, 0x1b1d, none
, none
}, /* ]} */
1060 { 0x1c0d, 0x1c0d, 0x1c0a, none
, none
}, /* Enter */
1061 { none
, none
, none
, none
, none
}, /* L Ctrl */
1062 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1063 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1064 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1065 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1066 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1067 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1068 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1069 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1070 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1071 { 0x273b, 0x273a, none
, none
, none
}, /* ;: */
1072 { 0x2827, 0x2822, none
, none
, none
}, /* '" */
1073 { 0x2960, 0x297e, none
, none
, none
}, /* `~ */
1074 { none
, none
, none
, none
, none
}, /* L shift */
1075 { 0x2b5c, 0x2b7c, 0x2b1c, none
, none
}, /* |\ */
1076 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1077 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1078 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1079 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1080 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1081 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1082 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1083 { 0x332c, 0x333c, none
, none
, none
}, /* ,< */
1084 { 0x342e, 0x343e, none
, none
, none
}, /* .> */
1085 { 0x352f, 0x353f, none
, none
, none
}, /* /? */
1086 { none
, none
, none
, none
, none
}, /* R Shift */
1087 { 0x372a, 0x372a, none
, none
, none
}, /* * */
1088 { none
, none
, none
, none
, none
}, /* L Alt */
1089 { 0x3920, 0x3920, 0x3920, 0x3920, none
}, /* space */
1090 { none
, none
, none
, none
, none
}, /* caps lock */
1091 { 0x3b00, 0x5400, 0x5e00, 0x6800, none
}, /* F1 */
1092 { 0x3c00, 0x5500, 0x5f00, 0x6900, none
}, /* F2 */
1093 { 0x3d00, 0x5600, 0x6000, 0x6a00, none
}, /* F3 */
1094 { 0x3e00, 0x5700, 0x6100, 0x6b00, none
}, /* F4 */
1095 { 0x3f00, 0x5800, 0x6200, 0x6c00, none
}, /* F5 */
1096 { 0x4000, 0x5900, 0x6300, 0x6d00, none
}, /* F6 */
1097 { 0x4100, 0x5a00, 0x6400, 0x6e00, none
}, /* F7 */
1098 { 0x4200, 0x5b00, 0x6500, 0x6f00, none
}, /* F8 */
1099 { 0x4300, 0x5c00, 0x6600, 0x7000, none
}, /* F9 */
1100 { 0x4400, 0x5d00, 0x6700, 0x7100, none
}, /* F10 */
1101 { none
, none
, none
, none
, none
}, /* Num Lock */
1102 { none
, none
, none
, none
, none
}, /* Scroll Lock */
1103 { 0x4700, 0x4737, 0x7700, none
, 0x20 }, /* 7 Home */
1104 { 0x4800, 0x4838, none
, none
, 0x20 }, /* 8 UP */
1105 { 0x4900, 0x4939, 0x8400, none
, 0x20 }, /* 9 PgUp */
1106 { 0x4a2d, 0x4a2d, none
, none
, none
}, /* - */
1107 { 0x4b00, 0x4b34, 0x7300, none
, 0x20 }, /* 4 Left */
1108 { 0x4c00, 0x4c35, none
, none
, 0x20 }, /* 5 */
1109 { 0x4d00, 0x4d36, 0x7400, none
, 0x20 }, /* 6 Right */
1110 { 0x4e2b, 0x4e2b, none
, none
, none
}, /* + */
1111 { 0x4f00, 0x4f31, 0x7500, none
, 0x20 }, /* 1 End */
1112 { 0x5000, 0x5032, none
, none
, 0x20 }, /* 2 Down */
1113 { 0x5100, 0x5133, 0x7600, none
, 0x20 }, /* 3 PgDn */
1114 { 0x5200, 0x5230, none
, none
, 0x20 }, /* 0 Ins */
1115 { 0x5300, 0x532e, none
, none
, 0x20 } /* Del */
1199 outb_cmos(cmos_reg
, val
)
1207 mov al
, 4[bp
] ;; cmos_reg
1209 mov al
, 6[bp
] ;; val
1224 mov al
, 4[bp
] ;; cmos_reg
1235 outb_cmos(0x0a, 0x26);
1236 outb_cmos(0x0b, 0x02);
1244 // This function checks to see if the update-in-progress bit
1245 // is set in CMOS Status Register A. If not, it returns 0.
1246 // If it is set, it tries to wait until there is a transition
1247 // to 0, and will return 0 if such a transition occurs. A 1
1248 // is returned only after timing out. The maximum period
1249 // that this bit should be set is constrained to 244useconds.
1250 // The count I use below guarantees coverage or more than
1251 // this time, with any reasonable IPS setting.
1256 while (--count
!= 0) {
1257 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1260 return(1); // update-in-progress never transitioned to 0
1265 read_byte(seg
, offset
)
1275 mov ax
, 4[bp
] ; segment
1277 mov bx
, 6[bp
] ; offset
1279 ;; al
= return value (byte
)
1288 read_word(seg
, offset
)
1298 mov ax
, 4[bp
] ; segment
1300 mov bx
, 6[bp
] ; offset
1302 ;; ax
= return value (word
)
1311 write_byte(seg
, offset
, data
)
1323 mov ax
, 4[bp
] ; segment
1325 mov bx
, 6[bp
] ; offset
1326 mov al
, 8[bp
] ; data byte
1327 mov
[bx
], al
; write data byte
1337 write_word(seg
, offset
, data
)
1349 mov ax
, 4[bp
] ; segment
1351 mov bx
, 6[bp
] ; offset
1352 mov ax
, 8[bp
] ; data word
1353 mov
[bx
], ax
; write data word
1371 //set_DS(ds_selector)
1372 // Bit16u ds_selector;
1379 // mov ax, 4[bp] ; ds_selector
1419 if (action
& BIOS_PRINTF_DEBUG
) outb(DEBUG_PORT
, c
);
1420 if (action
& BIOS_PRINTF_INFO
) outb(INFO_PORT
, c
);
1421 if (action
& BIOS_PRINTF_SCREEN
) {
1422 if (c
== '\n') wrch('\r');
1428 put_int(action
, val
, width
, neg
)
1433 short nval
= val
/ 10;
1435 put_int(action
, nval
, width
- 1, neg
);
1437 while (--width
> 0) send(action
, ' ');
1438 if (neg
) send(action
, '-');
1440 send(action
, val
- (nval
* 10) + '0');
1444 put_uint(action
, val
, width
, neg
)
1450 unsigned short nval
= val
/ 10;
1452 put_uint(action
, nval
, width
- 1, neg
);
1454 while (--width
> 0) send(action
, ' ');
1455 if (neg
) send(action
, '-');
1457 send(action
, val
- (nval
* 10) + '0');
1460 //--------------------------------------------------------------------------
1462 // A compact variable argument printf function which prints its output via
1463 // an I/O port so that it can be logged by Bochs/Plex.
1464 // Currently, only %x is supported (or %02x, %04x, etc).
1466 // Supports %[format_width][format]
1467 // where format can be d,x,c,s
1468 //--------------------------------------------------------------------------
1470 bios_printf(action
, s
)
1474 Bit8u c
, format_char
;
1478 Bit16u arg_seg
, arg
, nibble
, shift_count
, format_width
;
1486 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
1487 outb(PANIC_PORT2
, 0x00);
1488 bios_printf (BIOS_PRINTF_SCREEN
, "FATAL: ");
1491 while (c
= read_byte(0xf000, s
)) {
1496 else if (in_format
) {
1497 if ( (c
>='0') && (c
<='9') ) {
1498 format_width
= (format_width
* 10) + (c
- '0');
1501 arg_ptr
++; // increment to next arg
1502 arg
= read_word(arg_seg
, arg_ptr
);
1504 if (format_width
== 0)
1506 for (i
=format_width
-1; i
>=0; i
--) {
1507 nibble
= (arg
>> (4 * i
)) & 0x000f;
1508 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+'A'));
1511 else if (c
== 'u') {
1512 put_uint(action
, arg
, format_width
, 0);
1514 else if (c
== 'd') {
1516 put_int(action
, -arg
, format_width
- 1, 1);
1518 put_int(action
, arg
, format_width
, 0);
1520 else if (c
== 's') {
1521 bios_printf(action
& (~BIOS_PRINTF_HALT
), arg
);
1523 else if (c
== 'c') {
1527 BX_PANIC("bios_printf: unknown format\n");
1537 if (action
& BIOS_PRINTF_HALT
) {
1538 // freeze in a busy loop.
1548 //--------------------------------------------------------------------------
1550 //--------------------------------------------------------------------------
1551 // this file is based on LinuxBIOS implementation of keyboard.c
1552 // could convert to #asm to gain space
1558 /* ------------------- Flush buffers ------------------------*/
1559 /* Wait until buffer is empty */
1561 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1563 /* flush incoming keys */
1567 if (inb(0x64) & 0x01) {
1573 // Due to timer issues, and if the IPS setting is > 15000000,
1574 // the incoming keys might not be flushed here. That will
1575 // cause a panic a few lines below. See sourceforge bug report :
1576 // [ 642031 ] FATAL: Keyboard RESET error:993
1578 /* ------------------- controller side ----------------------*/
1579 /* send cmd = 0xAA, self test 8042 */
1582 /* Wait until buffer is empty */
1584 while ( (inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x00);
1585 if (max
==0x0) keyboard_panic(00);
1589 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x01);
1590 if (max
==0x0) keyboard_panic(01);
1592 /* read self-test result, 0x55 should be returned from 0x60 */
1593 if ((inb(0x60) != 0x55)){
1594 keyboard_panic(991);
1597 /* send cmd = 0xAB, keyboard interface test */
1600 /* Wait until buffer is empty */
1602 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x10);
1603 if (max
==0x0) keyboard_panic(10);
1607 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x11);
1608 if (max
==0x0) keyboard_panic(11);
1610 /* read keyboard interface test result, */
1611 /* 0x00 should be returned form 0x60 */
1612 if ((inb(0x60) != 0x00)) {
1613 keyboard_panic(992);
1616 /* Enable Keyboard clock */
1620 /* ------------------- keyboard side ------------------------*/
1621 /* reset kerboard and self test (keyboard side) */
1624 /* Wait until buffer is empty */
1626 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x20);
1627 if (max
==0x0) keyboard_panic(20);
1631 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x21);
1632 if (max
==0x0) keyboard_panic(21);
1634 /* keyboard should return ACK */
1635 if ((inb(0x60) != 0xfa)) {
1636 keyboard_panic(993);
1641 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x31);
1642 if (max
==0x0) keyboard_panic(31);
1644 if ((inb(0x60) != 0xaa)) {
1645 keyboard_panic(994);
1648 /* Disable keyboard */
1651 /* Wait until buffer is empty */
1653 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x40);
1654 if (max
==0x0) keyboard_panic(40);
1658 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x41);
1659 if (max
==0x0) keyboard_panic(41);
1661 /* keyboard should return ACK */
1662 if ((inb(0x60) != 0xfa)) {
1663 keyboard_panic(995);
1666 /* Write Keyboard Mode */
1669 /* Wait until buffer is empty */
1671 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x50);
1672 if (max
==0x0) keyboard_panic(50);
1674 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1677 /* Wait until buffer is empty */
1679 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x60);
1680 if (max
==0x0) keyboard_panic(60);
1682 /* Enable keyboard */
1685 /* Wait until buffer is empty */
1687 while ((inb(0x64) & 0x02) && (--max
>0)) outb(0x80, 0x70);
1688 if (max
==0x0) keyboard_panic(70);
1692 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x71);
1693 if (max
==0x0) keyboard_panic(70);
1695 /* keyboard should return ACK */
1696 if ((inb(0x60) != 0xfa)) {
1697 keyboard_panic(996);
1703 //--------------------------------------------------------------------------
1705 //--------------------------------------------------------------------------
1707 keyboard_panic(status
)
1710 // If you're getting a 993 keyboard panic here,
1711 // please see the comment in keyboard_init
1713 BX_PANIC("Keyboard error:%u\n",status
);
1716 //--------------------------------------------------------------------------
1717 // shutdown_status_panic
1718 // called when the shutdown statsu is not implemented, displays the status
1719 //--------------------------------------------------------------------------
1721 shutdown_status_panic(status
)
1724 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u
)status
);
1727 //--------------------------------------------------------------------------
1728 // print_bios_banner
1729 // displays a the bios version
1730 //--------------------------------------------------------------------------
1734 printf(BX_APPNAME
" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS
, BX_SMP_PROCESSORS
>1?"s":"");
1735 printf("%s %s\n", bios_cvs_version_string
, bios_date_string
);
1739 //--------------------------------------------------------------------------
1740 // print_boot_device
1741 // displays the boot device
1742 //--------------------------------------------------------------------------
1744 static char drivetypes
[][10]={"Floppy","Hard Disk","CD-Rom"};
1747 print_boot_device(cdboot
, drive
)
1748 Bit8u cdboot
; Bit16u drive
;
1752 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1753 // drive contains real/emulated boot drive
1755 if(cdboot
)i
=2; // CD-Rom
1756 else if((drive
&0x0080)==0x00)i
=0; // Floppy
1757 else if((drive
&0x0080)==0x80)i
=1; // Hard drive
1760 printf("Booting from %s...\n",drivetypes
[i
]);
1763 //--------------------------------------------------------------------------
1764 // print_boot_failure
1765 // displays the reason why boot failed
1766 //--------------------------------------------------------------------------
1768 print_boot_failure(cdboot
, drive
, reason
)
1769 Bit8u cdboot
; Bit8u drive
;
1771 Bit16u drivenum
= drive
&0x7f;
1773 // cdboot: 1 if boot from cd, 0 otherwise
1774 // drive : drive number
1775 // reason: 0 signature check failed, 1 read error
1778 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s failed\n",drivetypes
[2]);
1779 else if (drive
& 0x80)
1780 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[1],drivenum
);
1782 bios_printf(BIOS_PRINTF_INFO
| BIOS_PRINTF_SCREEN
, "Boot from %s %d failed\n", drivetypes
[0],drivenum
);
1785 BX_PANIC("Not a bootable disk\n");
1787 BX_PANIC("Could not read the boot disk\n");
1790 //--------------------------------------------------------------------------
1791 // print_cdromboot_failure
1792 // displays the reason why boot failed
1793 //--------------------------------------------------------------------------
1795 print_cdromboot_failure( code
)
1798 bios_printf(BIOS_PRINTF_SCREEN
| BIOS_PRINTF_INFO
, "CDROM boot failure code : %04x\n",code
);
1806 BX_PANIC("NMI Handler called\n");
1812 BX_PANIC("INT18: BOOT FAILURE\n");
1818 BX_INFO("%s\n", bios_version_string
);
1827 // Use PS2 System Control port A to set A20 enable
1829 // get current setting first
1832 // change A20 status
1834 outb(0x92, oldval
| 0x02);
1836 outb(0x92, oldval
& 0xfd);
1838 return((oldval
& 0x02) != 0);
1855 // ---------------------------------------------------------------------------
1856 // Start of ATA/ATAPI Driver
1857 // ---------------------------------------------------------------------------
1859 // Global defines -- ATA register and register bits.
1860 // command block & control block regs
1861 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1862 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1863 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1864 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1865 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1866 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1867 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1868 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1869 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1870 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1871 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1872 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1873 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1875 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1876 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1877 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1878 #define ATA_CB_ER_MC 0x20 // ATA media change
1879 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1880 #define ATA_CB_ER_MCR 0x08 // ATA media change request
1881 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
1882 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
1883 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
1885 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
1886 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
1887 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
1888 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
1889 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
1891 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
1892 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
1893 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
1894 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
1895 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
1897 // bits 7-4 of the device/head (CB_DH) reg
1898 #define ATA_CB_DH_DEV0 0xa0 // select device 0
1899 #define ATA_CB_DH_DEV1 0xb0 // select device 1
1901 // status reg (CB_STAT and CB_ASTAT) bits
1902 #define ATA_CB_STAT_BSY 0x80 // busy
1903 #define ATA_CB_STAT_RDY 0x40 // ready
1904 #define ATA_CB_STAT_DF 0x20 // device fault
1905 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
1906 #define ATA_CB_STAT_SKC 0x10 // seek complete
1907 #define ATA_CB_STAT_SERV 0x10 // service
1908 #define ATA_CB_STAT_DRQ 0x08 // data request
1909 #define ATA_CB_STAT_CORR 0x04 // corrected
1910 #define ATA_CB_STAT_IDX 0x02 // index
1911 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
1912 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
1914 // device control reg (CB_DC) bits
1915 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
1916 #define ATA_CB_DC_SRST 0x04 // soft reset
1917 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
1919 // Most mandtory and optional ATA commands (from ATA-3),
1920 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
1921 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
1922 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
1923 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
1924 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
1925 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
1926 #define ATA_CMD_CHECK_POWER_MODE2 0x98
1927 #define ATA_CMD_DEVICE_RESET 0x08
1928 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
1929 #define ATA_CMD_FLUSH_CACHE 0xE7
1930 #define ATA_CMD_FORMAT_TRACK 0x50
1931 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
1932 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
1933 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
1934 #define ATA_CMD_IDLE1 0xE3
1935 #define ATA_CMD_IDLE2 0x97
1936 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
1937 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
1938 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
1939 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
1940 #define ATA_CMD_NOP 0x00
1941 #define ATA_CMD_PACKET 0xA0
1942 #define ATA_CMD_READ_BUFFER 0xE4
1943 #define ATA_CMD_READ_DMA 0xC8
1944 #define ATA_CMD_READ_DMA_QUEUED 0xC7
1945 #define ATA_CMD_READ_MULTIPLE 0xC4
1946 #define ATA_CMD_READ_SECTORS 0x20
1947 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
1948 #define ATA_CMD_RECALIBRATE 0x10
1949 #define ATA_CMD_SEEK 0x70
1950 #define ATA_CMD_SET_FEATURES 0xEF
1951 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
1952 #define ATA_CMD_SLEEP1 0xE6
1953 #define ATA_CMD_SLEEP2 0x99
1954 #define ATA_CMD_STANDBY1 0xE2
1955 #define ATA_CMD_STANDBY2 0x96
1956 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
1957 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
1958 #define ATA_CMD_WRITE_BUFFER 0xE8
1959 #define ATA_CMD_WRITE_DMA 0xCA
1960 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
1961 #define ATA_CMD_WRITE_MULTIPLE 0xC5
1962 #define ATA_CMD_WRITE_SECTORS 0x30
1963 #define ATA_CMD_WRITE_VERIFY 0x3C
1965 #define ATA_IFACE_NONE 0x00
1966 #define ATA_IFACE_ISA 0x00
1967 #define ATA_IFACE_PCI 0x01
1969 #define ATA_TYPE_NONE 0x00
1970 #define ATA_TYPE_UNKNOWN 0x01
1971 #define ATA_TYPE_ATA 0x02
1972 #define ATA_TYPE_ATAPI 0x03
1974 #define ATA_DEVICE_NONE 0x00
1975 #define ATA_DEVICE_HD 0xFF
1976 #define ATA_DEVICE_CDROM 0x05
1978 #define ATA_MODE_NONE 0x00
1979 #define ATA_MODE_PIO16 0x00
1980 #define ATA_MODE_PIO32 0x01
1981 #define ATA_MODE_ISADMA 0x02
1982 #define ATA_MODE_PCIDMA 0x03
1983 #define ATA_MODE_USEIRQ 0x10
1985 #define ATA_TRANSLATION_NONE 0
1986 #define ATA_TRANSLATION_LBA 1
1987 #define ATA_TRANSLATION_LARGE 2
1988 #define ATA_TRANSLATION_RECHS 3
1990 #define ATA_DATA_NO 0x00
1991 #define ATA_DATA_IN 0x01
1992 #define ATA_DATA_OUT 0x02
1994 // ---------------------------------------------------------------------------
1995 // ATA/ATAPI driver : initialization
1996 // ---------------------------------------------------------------------------
1999 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2000 Bit8u channel
, device
;
2002 // Channels info init.
2003 for (channel
=0; channel
<BX_MAX_ATA_INTERFACES
; channel
++) {
2004 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iface
,ATA_IFACE_NONE
);
2005 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
,0x0);
2006 write_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
,0x0);
2007 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[channel
].irq
,0);
2010 // Devices info init.
2011 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2012 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_NONE
);
2013 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_NONE
);
2014 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
,0);
2015 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].lock
,0);
2016 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
,ATA_MODE_NONE
);
2017 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
,0);
2018 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
,ATA_TRANSLATION_NONE
);
2019 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
,0);
2020 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
,0);
2021 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
,0);
2022 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
,0);
2023 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
,0);
2024 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
,0);
2026 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
,0L);
2029 // hdidmap and cdidmap init.
2030 for (device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2031 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[device
],BX_MAX_ATA_DEVICES
);
2032 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[device
],BX_MAX_ATA_DEVICES
);
2035 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
,0);
2036 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
,0);
2039 // ---------------------------------------------------------------------------
2040 // ATA/ATAPI driver : device detection
2041 // ---------------------------------------------------------------------------
2045 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2046 Bit8u hdcount
, cdcount
, device
, type
;
2047 Bit8u buffer
[0x0200];
2049 #if BX_MAX_ATA_INTERFACES > 0
2050 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].iface
,ATA_IFACE_ISA
);
2051 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase1
,0x1f0);
2052 write_word(ebda_seg
,&EbdaData
->ata
.channels
[0].iobase2
,0x3f0);
2053 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[0].irq
,14);
2055 #if BX_MAX_ATA_INTERFACES > 1
2056 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].iface
,ATA_IFACE_ISA
);
2057 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase1
,0x170);
2058 write_word(ebda_seg
,&EbdaData
->ata
.channels
[1].iobase2
,0x370);
2059 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[1].irq
,15);
2061 #if BX_MAX_ATA_INTERFACES > 2
2062 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].iface
,ATA_IFACE_ISA
);
2063 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase1
,0x1e8);
2064 write_word(ebda_seg
,&EbdaData
->ata
.channels
[2].iobase2
,0x3e0);
2065 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[2].irq
,12);
2067 #if BX_MAX_ATA_INTERFACES > 3
2068 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].iface
,ATA_IFACE_ISA
);
2069 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase1
,0x168);
2070 write_word(ebda_seg
,&EbdaData
->ata
.channels
[3].iobase2
,0x360);
2071 write_byte(ebda_seg
,&EbdaData
->ata
.channels
[3].irq
,11);
2073 #if BX_MAX_ATA_INTERFACES > 4
2074 #error Please fill the ATA interface informations
2080 for(device
=0; device
<BX_MAX_ATA_DEVICES
; device
++) {
2081 Bit16u iobase1
, iobase2
;
2082 Bit8u channel
, slave
, shift
;
2083 Bit8u sc
, sn
, cl
, ch
, st
;
2085 channel
= device
/ 2;
2088 iobase1
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase1
);
2089 iobase2
=read_word(ebda_seg
,&EbdaData
->ata
.channels
[channel
].iobase2
);
2091 // Disable interrupts
2092 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2095 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2096 outb(iobase1
+ATA_CB_SC
, 0x55);
2097 outb(iobase1
+ATA_CB_SN
, 0xaa);
2098 outb(iobase1
+ATA_CB_SC
, 0xaa);
2099 outb(iobase1
+ATA_CB_SN
, 0x55);
2100 outb(iobase1
+ATA_CB_SC
, 0x55);
2101 outb(iobase1
+ATA_CB_SN
, 0xaa);
2103 // If we found something
2104 sc
= inb(iobase1
+ATA_CB_SC
);
2105 sn
= inb(iobase1
+ATA_CB_SN
);
2107 if ( (sc
== 0x55) && (sn
== 0xaa) ) {
2108 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_UNKNOWN
);
2110 // reset the channel
2113 // check for ATA or ATAPI
2114 outb(iobase1
+ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2115 sc
= inb(iobase1
+ATA_CB_SC
);
2116 sn
= inb(iobase1
+ATA_CB_SN
);
2117 if ( (sc
==0x01) && (sn
==0x01) ) {
2118 cl
= inb(iobase1
+ATA_CB_CL
);
2119 ch
= inb(iobase1
+ATA_CB_CH
);
2120 st
= inb(iobase1
+ATA_CB_STAT
);
2122 if ( (cl
==0x14) && (ch
==0xeb) ) {
2123 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATAPI
);
2125 else if ( (cl
==0x00) && (ch
==0x00) && (st
!=0x00) ) {
2126 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
,ATA_TYPE_ATA
);
2131 type
=read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
);
2133 // Now we send a IDENTIFY command to ATA device
2134 if(type
== ATA_TYPE_ATA
) {
2136 Bit16u cylinders
, heads
, spt
, blksize
;
2137 Bit8u translation
, removable
, mode
;
2139 //Temporary values to do the transfer
2140 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2141 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2143 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE
, 1, 0, 0, 0, 0L, get_SS(),buffer
) !=0 )
2144 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2146 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2147 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2148 blksize
= read_word(get_SS(),buffer
+10);
2150 cylinders
= read_word(get_SS(),buffer
+(1*2)); // word 1
2151 heads
= read_word(get_SS(),buffer
+(3*2)); // word 3
2152 spt
= read_word(get_SS(),buffer
+(6*2)); // word 6
2154 sectors
= read_dword(get_SS(),buffer
+(60*2)); // word 60 and word 61
2156 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_HD
);
2157 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2158 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2159 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2160 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.heads
, heads
);
2161 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.cylinders
, cylinders
);
2162 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].pchs
.spt
, spt
);
2163 write_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
, sectors
);
2164 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel
, slave
,cylinders
, heads
, spt
);
2166 translation
= inb_cmos(0x39 + channel
/2);
2167 for (shift
=device
%4; shift
>0; shift
--) translation
>>= 2;
2168 translation
&= 0x03;
2170 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].translation
, translation
);
2172 switch (translation
) {
2173 case ATA_TRANSLATION_NONE
:
2176 case ATA_TRANSLATION_LBA
:
2179 case ATA_TRANSLATION_LARGE
:
2182 case ATA_TRANSLATION_RECHS
:
2186 switch (translation
) {
2187 case ATA_TRANSLATION_NONE
:
2189 case ATA_TRANSLATION_LBA
:
2192 heads
= sectors
/ 1024;
2193 if (heads
>128) heads
= 255;
2194 else if (heads
>64) heads
= 128;
2195 else if (heads
>32) heads
= 64;
2196 else if (heads
>16) heads
= 32;
2198 cylinders
= sectors
/ heads
;
2200 case ATA_TRANSLATION_RECHS
:
2201 // Take care not to overflow
2203 if(cylinders
>61439) cylinders
=61439;
2205 cylinders
= (Bit16u
)((Bit32u
)(cylinders
)*16/15);
2207 // then go through the large bitshift process
2208 case ATA_TRANSLATION_LARGE
:
2209 while(cylinders
> 1024) {
2213 // If we max out the head count
2214 if (heads
> 127) break;
2218 // clip to 1024 cylinders in lchs
2219 if (cylinders
> 1024) cylinders
=1024;
2220 BX_INFO(" LCHS=%d/%d/%d\n", cylinders
, heads
, spt
);
2222 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.heads
, heads
);
2223 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.cylinders
, cylinders
);
2224 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].lchs
.spt
, spt
);
2227 write_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[hdcount
], device
);
2231 // Now we send a IDENTIFY command to ATAPI device
2232 if(type
== ATA_TYPE_ATAPI
) {
2234 Bit8u type
, removable
, mode
;
2237 //Temporary values to do the transfer
2238 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
,ATA_DEVICE_CDROM
);
2239 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, ATA_MODE_PIO16
);
2241 if (ata_cmd_data_in(device
,ATA_CMD_IDENTIFY_DEVICE_PACKET
, 1, 0, 0, 0, 0L, get_SS(),buffer
) != 0)
2242 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2244 type
= read_byte(get_SS(),buffer
+1) & 0x1f;
2245 removable
= (read_byte(get_SS(),buffer
+0) & 0x80) ? 1 : 0;
2246 mode
= read_byte(get_SS(),buffer
+96) ? ATA_MODE_PIO32
: ATA_MODE_PIO16
;
2249 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
, type
);
2250 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].removable
, removable
);
2251 write_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].mode
, mode
);
2252 write_word(ebda_seg
,&EbdaData
->ata
.devices
[device
].blksize
, blksize
);
2255 write_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[cdcount
], device
);
2262 Bit8u c
, i
, version
, model
[41];
2266 sizeinmb
= read_dword(ebda_seg
,&EbdaData
->ata
.devices
[device
].sectors
);
2268 case ATA_TYPE_ATAPI
:
2269 // Read ATA/ATAPI version
2270 ataversion
=((Bit16u
)(read_byte(get_SS(),buffer
+161))<<8)|read_byte(get_SS(),buffer
+160);
2271 for(version
=15;version
>0;version
--) {
2272 if((ataversion
&(1<<version
))!=0)
2278 write_byte(get_SS(),model
+(i
*2),read_byte(get_SS(),buffer
+(i
*2)+54+1));
2279 write_byte(get_SS(),model
+(i
*2)+1,read_byte(get_SS(),buffer
+(i
*2)+54));
2283 write_byte(get_SS(),model
+40,0x00);
2285 if(read_byte(get_SS(),model
+i
)==0x20)
2286 write_byte(get_SS(),model
+i
,0x00);
2294 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2295 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2296 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version
,(Bit16u
)sizeinmb
);
2298 case ATA_TYPE_ATAPI
:
2299 printf("ata%d %s: ",channel
,slave
?" slave":"master");
2300 i
=0; while(c
=read_byte(get_SS(),model
+i
++)) printf("%c",c
);
2301 if(read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
)==ATA_DEVICE_CDROM
)
2302 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version
);
2304 printf(" ATAPI-%d Device\n",version
);
2306 case ATA_TYPE_UNKNOWN
:
2307 printf("ata%d %s: Unknown device\n",channel
,slave
?" slave":"master");
2313 // Store the devices counts
2314 write_byte(ebda_seg
,&EbdaData
->ata
.hdcount
, hdcount
);
2315 write_byte(ebda_seg
,&EbdaData
->ata
.cdcount
, cdcount
);
2316 write_byte(0x40,0x75, hdcount
);
2320 // FIXME : should use bios=cmos|auto|disable bits
2321 // FIXME : should know about translation bits
2322 // FIXME : move hard_drive_post here
2326 // ---------------------------------------------------------------------------
2327 // ATA/ATAPI driver : software reset
2328 // ---------------------------------------------------------------------------
2330 // 8.2.1 Software reset - Device 0
2332 void ata_reset(device
)
2335 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2336 Bit16u iobase1
, iobase2
;
2337 Bit8u channel
, slave
, sn
, sc
;
2340 channel
= device
/ 2;
2343 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2344 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2348 // 8.2.1 (a) -- set SRST in DC
2349 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
| ATA_CB_DC_SRST
);
2351 // 8.2.1 (b) -- wait for BSY
2354 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2355 if ((status
& ATA_CB_STAT_BSY
) != 0) break;
2358 // 8.2.1 (f) -- clear SRST
2359 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2361 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_NONE
) {
2363 // 8.2.1 (g) -- check for sc==sn==0x01
2365 outb(iobase1
+ATA_CB_DH
, slave
?ATA_CB_DH_DEV1
:ATA_CB_DH_DEV0
);
2366 sc
= inb(iobase1
+ATA_CB_SC
);
2367 sn
= inb(iobase1
+ATA_CB_SN
);
2369 if ( (sc
==0x01) && (sn
==0x01) ) {
2371 // 8.2.1 (h) -- wait for not BSY
2374 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2375 if ((status
& ATA_CB_STAT_BSY
) == 0) break;
2380 // 8.2.1 (i) -- wait for DRDY
2383 Bit8u status
= inb(iobase1
+ATA_CB_STAT
);
2384 if ((status
& ATA_CB_STAT_RDY
) != 0) break;
2387 // Enable interrupts
2388 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2391 // ---------------------------------------------------------------------------
2392 // ATA/ATAPI driver : execute a non data command
2393 // ---------------------------------------------------------------------------
2395 Bit16u
ata_cmd_non_data()
2398 // ---------------------------------------------------------------------------
2399 // ATA/ATAPI driver : execute a data-in command
2400 // ---------------------------------------------------------------------------
2405 // 3 : expected DRQ=1
2406 // 4 : no sectors left to read/verify
2407 // 5 : more sectors to read/verify
2408 // 6 : no sectors left to write
2409 // 7 : more sectors to write
2410 Bit16u
ata_cmd_data_in(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2411 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2414 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2415 Bit16u iobase1
, iobase2
, blksize
;
2416 Bit8u channel
, slave
;
2417 Bit8u status
, current
, mode
;
2419 channel
= device
/ 2;
2422 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2423 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2424 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2425 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2426 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2429 // sector will be 0 only on lba access. Convert to lba-chs
2431 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2433 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2435 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2438 // Reset count of transferred data
2439 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2440 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2443 status
= inb(iobase1
+ ATA_CB_STAT
);
2444 if (status
& ATA_CB_STAT_BSY
) return 1;
2446 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2447 outb(iobase1
+ ATA_CB_FR
, 0x00);
2448 outb(iobase1
+ ATA_CB_SC
, count
);
2449 outb(iobase1
+ ATA_CB_SN
, sector
);
2450 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2451 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2452 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2453 outb(iobase1
+ ATA_CB_CMD
, command
);
2456 status
= inb(iobase1
+ ATA_CB_STAT
);
2457 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2460 if (status
& ATA_CB_STAT_ERR
) {
2461 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2463 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2464 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status
);
2468 // FIXME : move seg/off translation here
2471 sti
;; enable higher priority interrupts
2479 mov di
, _ata_cmd_data_in
.offset
+ 2[bp
]
2480 mov ax
, _ata_cmd_data_in
.segment
+ 2[bp
]
2481 mov cx
, _ata_cmd_data_in
.blksize
+ 2[bp
]
2483 ;; adjust
if there will be an overrun
. 2K max sector size
2485 jbe ata_in_no_adjust
2488 sub di
, #0x0800 ;; sub 2 kbytes from offset
2489 add ax
, #0x0080 ;; add 2 Kbytes to segment
2492 mov es
, ax
;; segment in es
2494 mov dx
, _ata_cmd_data_in
.iobase1
+ 2[bp
] ;; ATA data read port
2496 mov ah
, _ata_cmd_data_in
.mode
+ 2[bp
]
2497 cmp ah
, #ATA_MODE_PIO32
2502 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2507 insd
;; CX dwords transfered from
port(DX
) to ES
:[DI
]
2510 mov _ata_cmd_data_in
.offset
+ 2[bp
], di
2511 mov _ata_cmd_data_in
.segment
+ 2[bp
], es
2516 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2518 status
= inb(iobase1
+ ATA_CB_STAT
);
2520 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2521 != ATA_CB_STAT_RDY
) {
2522 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status
);
2528 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2529 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2530 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status
);
2536 // Enable interrupts
2537 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2541 // ---------------------------------------------------------------------------
2542 // ATA/ATAPI driver : execute a data-out command
2543 // ---------------------------------------------------------------------------
2548 // 3 : expected DRQ=1
2549 // 4 : no sectors left to read/verify
2550 // 5 : more sectors to read/verify
2551 // 6 : no sectors left to write
2552 // 7 : more sectors to write
2553 Bit16u
ata_cmd_data_out(device
, command
, count
, cylinder
, head
, sector
, lba
, segment
, offset
)
2554 Bit16u device
, command
, count
, cylinder
, head
, sector
, segment
, offset
;
2557 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2558 Bit16u iobase1
, iobase2
, blksize
;
2559 Bit8u channel
, slave
;
2560 Bit8u status
, current
, mode
;
2562 channel
= device
/ 2;
2565 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2566 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2567 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2568 blksize
= 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2569 if (mode
== ATA_MODE_PIO32
) blksize
>>=2;
2572 // sector will be 0 only on lba access. Convert to lba-chs
2574 sector
= (Bit16u
) (lba
& 0x000000ffL
);
2576 cylinder
= (Bit16u
) (lba
& 0x0000ffffL
);
2578 head
= ((Bit16u
) (lba
& 0x0000000fL
)) | 0x40;
2581 // Reset count of transferred data
2582 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2583 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2586 status
= inb(iobase1
+ ATA_CB_STAT
);
2587 if (status
& ATA_CB_STAT_BSY
) return 1;
2589 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2590 outb(iobase1
+ ATA_CB_FR
, 0x00);
2591 outb(iobase1
+ ATA_CB_SC
, count
);
2592 outb(iobase1
+ ATA_CB_SN
, sector
);
2593 outb(iobase1
+ ATA_CB_CL
, cylinder
& 0x00ff);
2594 outb(iobase1
+ ATA_CB_CH
, cylinder
>> 8);
2595 outb(iobase1
+ ATA_CB_DH
, (slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
) | (Bit8u
) head
);
2596 outb(iobase1
+ ATA_CB_CMD
, command
);
2599 status
= inb(iobase1
+ ATA_CB_STAT
);
2600 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2603 if (status
& ATA_CB_STAT_ERR
) {
2604 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2606 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2607 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status
);
2611 // FIXME : move seg/off translation here
2614 sti
;; enable higher priority interrupts
2622 mov si
, _ata_cmd_data_out
.offset
+ 2[bp
]
2623 mov ax
, _ata_cmd_data_out
.segment
+ 2[bp
]
2624 mov cx
, _ata_cmd_data_out
.blksize
+ 2[bp
]
2626 ;; adjust
if there will be an overrun
. 2K max sector size
2628 jbe ata_out_no_adjust
2631 sub si
, #0x0800 ;; sub 2 kbytes from offset
2632 add ax
, #0x0080 ;; add 2 Kbytes to segment
2635 mov es
, ax
;; segment in es
2637 mov dx
, _ata_cmd_data_out
.iobase1
+ 2[bp
] ;; ATA data write port
2639 mov ah
, _ata_cmd_data_out
.mode
+ 2[bp
]
2640 cmp ah
, #ATA_MODE_PIO32
2646 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2652 outsd
;; CX dwords transfered from
port(DX
) to ES
:[SI
]
2655 mov _ata_cmd_data_out
.offset
+ 2[bp
], si
2656 mov _ata_cmd_data_out
.segment
+ 2[bp
], es
2661 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,current
);
2663 status
= inb(iobase1
+ ATA_CB_STAT
);
2665 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2666 != ATA_CB_STAT_RDY
) {
2667 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status
);
2673 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2674 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2675 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status
);
2681 // Enable interrupts
2682 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2686 // ---------------------------------------------------------------------------
2687 // ATA/ATAPI driver : execute a packet command
2688 // ---------------------------------------------------------------------------
2691 // 1 : error in parameters
2695 Bit16u
ata_cmd_packet(device
, cmdlen
, cmdseg
, cmdoff
, header
, length
, inout
, bufseg
, bufoff
)
2697 Bit16u device
,cmdseg
, cmdoff
, bufseg
, bufoff
;
2701 Bit16u ebda_seg
=read_word(0x0040,0x000E);
2702 Bit16u iobase1
, iobase2
;
2703 Bit16u lcount
, lbefore
, lafter
, count
;
2704 Bit8u channel
, slave
;
2705 Bit8u status
, mode
, lmode
;
2706 Bit32u total
, transfer
;
2708 channel
= device
/ 2;
2711 // Data out is not supported yet
2712 if (inout
== ATA_DATA_OUT
) {
2713 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet");
2717 // The header length must be even
2719 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header
);
2723 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
2724 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
2725 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
2728 if (cmdlen
< 12) cmdlen
=12;
2729 if (cmdlen
> 12) cmdlen
=16;
2732 // Reset count of transferred data
2733 write_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
,0);
2734 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,0L);
2736 status
= inb(iobase1
+ ATA_CB_STAT
);
2737 if (status
& ATA_CB_STAT_BSY
) return 2;
2739 outb(iobase2
+ ATA_CB_DC
, ATA_CB_DC_HD15
| ATA_CB_DC_NIEN
);
2740 // outb(iobase1 + ATA_CB_FR, 0x00);
2741 // outb(iobase1 + ATA_CB_SC, 0x00);
2742 // outb(iobase1 + ATA_CB_SN, 0x00);
2743 outb(iobase1
+ ATA_CB_CL
, 0xfff0 & 0x00ff);
2744 outb(iobase1
+ ATA_CB_CH
, 0xfff0 >> 8);
2745 outb(iobase1
+ ATA_CB_DH
, slave
? ATA_CB_DH_DEV1
: ATA_CB_DH_DEV0
);
2746 outb(iobase1
+ ATA_CB_CMD
, ATA_CMD_PACKET
);
2748 // Device should ok to receive command
2750 status
= inb(iobase1
+ ATA_CB_STAT
);
2751 if ( !(status
& ATA_CB_STAT_BSY
) ) break;
2754 if (status
& ATA_CB_STAT_ERR
) {
2755 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status
);
2757 } else if ( !(status
& ATA_CB_STAT_DRQ
) ) {
2758 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status
);
2762 // Normalize address
2763 cmdseg
+= (cmdoff
/ 16);
2766 // Send command to device
2768 sti
;; enable higher priority interrupts
2773 mov si
, _ata_cmd_packet
.cmdoff
+ 2[bp
]
2774 mov ax
, _ata_cmd_packet
.cmdseg
+ 2[bp
]
2775 mov cx
, _ata_cmd_packet
.cmdlen
+ 2[bp
]
2776 mov es
, ax
;; segment in es
2778 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data write port
2782 outsw
;; CX words transfered from
port(DX
) to ES
:[SI
]
2787 if (inout
== ATA_DATA_NO
) {
2788 status
= inb(iobase1
+ ATA_CB_STAT
);
2793 status
= inb(iobase1
+ ATA_CB_STAT
);
2795 // Check if command completed
2796 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_DRQ
) ) ==0 ) break;
2798 if (status
& ATA_CB_STAT_ERR
) {
2799 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status
);
2803 // Device must be ready to send data
2804 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2805 != (ATA_CB_STAT_RDY
| ATA_CB_STAT_DRQ
) ) {
2806 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status
);
2810 // Normalize address
2811 bufseg
+= (bufoff
/ 16);
2814 // Get the byte count
2815 lcount
= ((Bit16u
)(inb(iobase1
+ ATA_CB_CH
))<<8)+inb(iobase1
+ ATA_CB_CL
);
2817 // adjust to read what we want
2830 lafter
=lcount
-length
;
2842 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore
+lcount
+lafter
,lbefore
,lcount
,lafter
);
2843 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg
,bufoff
);
2845 // If counts not dividable by 4, use 16bits mode
2847 if (lbefore
& 0x03) lmode
=ATA_MODE_PIO16
;
2848 if (lcount
& 0x03) lmode
=ATA_MODE_PIO16
;
2849 if (lafter
& 0x03) lmode
=ATA_MODE_PIO16
;
2851 // adds an extra byte if count are odd. before is always even
2852 if (lcount
& 0x01) {
2854 if ((lafter
> 0) && (lafter
& 0x01)) {
2859 if (lmode
== ATA_MODE_PIO32
) {
2860 lcount
>>=2; lbefore
>>=2; lafter
>>=2;
2863 lcount
>>=1; lbefore
>>=1; lafter
>>=1;
2872 mov dx
, _ata_cmd_packet
.iobase1
+ 2[bp
] ;; ATA data read port
2874 mov cx
, _ata_cmd_packet
.lbefore
+ 2[bp
]
2875 jcxz ata_packet_no_before
2877 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
2878 cmp ah
, #ATA_MODE_PIO32
2879 je ata_packet_in_before_32
2881 ata_packet_in_before_16
:
2883 loop ata_packet_in_before_16
2884 jmp ata_packet_no_before
2886 ata_packet_in_before_32
:
2888 loop ata_packet_in_before_32
2890 ata_packet_no_before
:
2891 mov cx
, _ata_cmd_packet
.lcount
+ 2[bp
]
2892 jcxz ata_packet_after
2894 mov di
, _ata_cmd_packet
.bufoff
+ 2[bp
]
2895 mov ax
, _ata_cmd_packet
.bufseg
+ 2[bp
]
2898 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
2899 cmp ah
, #ATA_MODE_PIO32
2904 insw
;; CX words transfered tp
port(DX
) to ES
:[DI
]
2905 jmp ata_packet_after
2909 insd
;; CX dwords transfered to
port(DX
) to ES
:[DI
]
2912 mov cx
, _ata_cmd_packet
.lafter
+ 2[bp
]
2913 jcxz ata_packet_done
2915 mov ah
, _ata_cmd_packet
.lmode
+ 2[bp
]
2916 cmp ah
, #ATA_MODE_PIO32
2917 je ata_packet_in_after_32
2919 ata_packet_in_after_16
:
2921 loop ata_packet_in_after_16
2924 ata_packet_in_after_32
:
2926 loop ata_packet_in_after_32
2932 // Compute new buffer address
2935 // Save transferred bytes count
2937 write_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
,transfer
);
2941 // Final check, device must be ready
2942 if ( (status
& (ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
| ATA_CB_STAT_DF
| ATA_CB_STAT_DRQ
| ATA_CB_STAT_ERR
) )
2943 != ATA_CB_STAT_RDY
) {
2944 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status
);
2948 // Enable interrupts
2949 outb(iobase2
+ATA_CB_DC
, ATA_CB_DC_HD15
);
2953 // ---------------------------------------------------------------------------
2954 // End of ATA/ATAPI Driver
2955 // ---------------------------------------------------------------------------
2957 // ---------------------------------------------------------------------------
2958 // Start of ATA/ATAPI generic functions
2959 // ---------------------------------------------------------------------------
2962 atapi_get_sense(device
)
2969 memsetb(get_SS(),atacmd
,0,12);
2974 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 16L, ATA_DATA_IN
, get_SS(), buffer
) != 0)
2977 if ((buffer
[0] & 0x7e) == 0x70) {
2978 return (((Bit16u
)buffer
[2]&0x0f)*0x100)+buffer
[12];
2985 atapi_is_ready(device
)
2991 memsetb(get_SS(),atacmd
,0,12);
2994 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
2997 if (atapi_get_sense(device
) !=0 ) {
2998 memsetb(get_SS(),atacmd
,0,12);
3000 // try to send Test Unit Ready again
3001 if (ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 0L, ATA_DATA_NO
, get_SS(), buffer
) != 0)
3004 return atapi_get_sense(device
);
3010 atapi_is_cdrom(device
)
3013 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3015 if (device
>= BX_MAX_ATA_DEVICES
)
3018 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].type
) != ATA_TYPE_ATAPI
)
3021 if (read_byte(ebda_seg
,&EbdaData
->ata
.devices
[device
].device
) != ATA_DEVICE_CDROM
)
3027 // ---------------------------------------------------------------------------
3028 // End of ATA/ATAPI generic functions
3029 // ---------------------------------------------------------------------------
3031 #endif // BX_USE_ATADRV
3033 #if BX_ELTORITO_BOOT
3035 // ---------------------------------------------------------------------------
3036 // Start of El-Torito boot functions
3037 // ---------------------------------------------------------------------------
3042 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3044 // the only important data is this one for now
3045 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x00);
3051 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3053 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.active
));
3057 cdemu_emulated_drive()
3059 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3061 return(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
3064 static char isotag
[6]="CD001";
3065 static char eltorito
[24]="EL TORITO SPECIFICATION";
3067 // Returns ah: emulated drive, al: error code
3072 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3073 Bit8u atacmd
[12], buffer
[2048];
3075 Bit16u boot_segment
, nbsectors
, i
, error
;
3078 // Find out the first cdrom
3079 for (device
=0; device
<BX_MAX_ATA_DEVICES
;device
++) {
3080 if (atapi_is_cdrom(device
)) break;
3084 if(device
>= BX_MAX_ATA_DEVICES
) return 2;
3086 // Read the Boot Record Volume Descriptor
3087 memsetb(get_SS(),atacmd
,0,12);
3088 atacmd
[0]=0x28; // READ command
3089 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3090 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3091 atacmd
[2]=(0x11 & 0xff000000) >> 24; // LBA
3092 atacmd
[3]=(0x11 & 0x00ff0000) >> 16;
3093 atacmd
[4]=(0x11 & 0x0000ff00) >> 8;
3094 atacmd
[5]=(0x11 & 0x000000ff);
3095 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3099 if(buffer
[0]!=0)return 4;
3101 if(buffer
[1+i
]!=read_byte(0xf000,&isotag
[i
]))return 5;
3104 if(buffer
[7+i
]!=read_byte(0xf000,&eltorito
[i
]))return 6;
3106 // ok, now we calculate the Boot catalog address
3107 lba
=buffer
[0x4A]*0x1000000+buffer
[0x49]*0x10000+buffer
[0x48]*0x100+buffer
[0x47];
3109 // And we read the Boot Catalog
3110 memsetb(get_SS(),atacmd
,0,12);
3111 atacmd
[0]=0x28; // READ command
3112 atacmd
[7]=(0x01 & 0xff00) >> 8; // Sectors
3113 atacmd
[8]=(0x01 & 0x00ff); // Sectors
3114 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3115 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3116 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3117 atacmd
[5]=(lba
& 0x000000ff);
3118 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, 2048L, ATA_DATA_IN
, get_SS(), buffer
)) != 0)
3122 if(buffer
[0x00]!=0x01)return 8; // Header
3123 if(buffer
[0x01]!=0x00)return 9; // Platform
3124 if(buffer
[0x1E]!=0x55)return 10; // key 1
3125 if(buffer
[0x1F]!=0xAA)return 10; // key 2
3127 // Initial/Default Entry
3128 if(buffer
[0x20]!=0x88)return 11; // Bootable
3130 write_byte(ebda_seg
,&EbdaData
->cdemu
.media
,buffer
[0x21]);
3131 if(buffer
[0x21]==0){
3132 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3133 // Win2000 cd boot needs to know it booted from cd
3134 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0xE0);
3136 else if(buffer
[0x21]<4)
3137 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x00);
3139 write_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
,0x80);
3141 write_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
,device
/2);
3142 write_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
,device
%2);
3144 boot_segment
=buffer
[0x23]*0x100+buffer
[0x22];
3145 if(boot_segment
==0x0000)boot_segment
=0x07C0;
3147 write_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
,boot_segment
);
3148 write_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
,0x0000);
3150 nbsectors
=buffer
[0x27]*0x100+buffer
[0x26];
3151 write_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
,nbsectors
);
3153 lba
=buffer
[0x2B]*0x1000000+buffer
[0x2A]*0x10000+buffer
[0x29]*0x100+buffer
[0x28];
3154 write_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
,lba
);
3156 // And we read the image in memory
3157 memsetb(get_SS(),atacmd
,0,12);
3158 atacmd
[0]=0x28; // READ command
3159 atacmd
[7]=((1+(nbsectors
-1)/4) & 0xff00) >> 8; // Sectors
3160 atacmd
[8]=((1+(nbsectors
-1)/4) & 0x00ff); // Sectors
3161 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
3162 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
3163 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
3164 atacmd
[5]=(lba
& 0x000000ff);
3165 if((error
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, nbsectors
*512L, ATA_DATA_IN
, boot_segment
,0)) != 0)
3168 // Remember the media type
3169 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
3170 case 0x01: // 1.2M floppy
3171 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,15);
3172 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3173 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3175 case 0x02: // 1.44M floppy
3176 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,18);
3177 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3178 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3180 case 0x03: // 2.88M floppy
3181 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,36);
3182 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,80);
3183 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,2);
3185 case 0x04: // Harddrive
3186 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
,read_byte(boot_segment
,446+6)&0x3f);
3187 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
,
3188 (read_byte(boot_segment
,446+6)<<2) + read_byte(boot_segment
,446+7) + 1);
3189 write_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
,read_byte(boot_segment
,446+5) + 1);
3193 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0) {
3194 // Increase bios installed hardware number of devices
3195 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)==0x00)
3196 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3198 write_byte(ebda_seg
, &EbdaData
->ata
.hdcount
, read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
) + 1);
3202 // everything is ok, so from now on, the emulation is active
3203 if(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)!=0)
3204 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
,0x01);
3206 // return the boot drive + no error
3207 return (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
)*0x100)+0;
3210 // ---------------------------------------------------------------------------
3211 // End of El-Torito boot functions
3212 // ---------------------------------------------------------------------------
3213 #endif // BX_ELTORITO_BOOT
3216 int14_function(regs
, ds
, iret_addr
)
3217 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3218 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3219 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3221 Bit16u addr
,timer
,val16
;
3228 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1));
3229 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
3230 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
3231 switch (regs
.u
.r8
.ah
) {
3233 outb(addr
+3, inb(addr
+3) | 0x80);
3234 if (regs
.u
.r8
.al
& 0xE0 == 0) {
3238 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
3239 outb(addr
, val16
& 0xFF);
3240 outb(addr
+1, val16
>> 8);
3242 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
3243 regs
.u
.r8
.ah
= inb(addr
+5);
3244 regs
.u
.r8
.al
= inb(addr
+6);
3245 ClearCF(iret_addr
.flags
);
3248 timer
= read_word(0x0040, 0x006C);
3249 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
3250 val16
= read_word(0x0040, 0x006C);
3251 if (val16
!= timer
) {
3256 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
3257 regs
.u
.r8
.ah
= inb(addr
+5);
3258 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
3259 ClearCF(iret_addr
.flags
);
3262 timer
= read_word(0x0040, 0x006C);
3263 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
3264 val16
= read_word(0x0040, 0x006C);
3265 if (val16
!= timer
) {
3272 regs
.u
.r8
.al
= inb(addr
);
3274 regs
.u
.r8
.ah
= inb(addr
+5);
3276 ClearCF(iret_addr
.flags
);
3279 regs
.u
.r8
.ah
= inb(addr
+5);
3280 regs
.u
.r8
.al
= inb(addr
+6);
3281 ClearCF(iret_addr
.flags
);
3284 SetCF(iret_addr
.flags
); // Unsupported
3287 SetCF(iret_addr
.flags
); // Unsupported
3292 int15_function(regs
, ES
, DS
, FLAGS
)
3293 pusha_regs_t regs
; // REGS pushed via pusha
3294 Bit16u ES
, DS
, FLAGS
;
3296 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3297 bx_bool prev_a20_enable
;
3306 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3308 switch (regs
.u
.r8
.ah
) {
3309 case 0x24: /* A20 Control */
3310 switch (regs
.u
.r8
.al
) {
3322 regs
.u
.r8
.al
= (inb(0x92) >> 1) & 0x01;
3332 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs
.u
.r8
.al
);
3334 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3340 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3344 /* keyboard intercept */
3346 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3353 case 0x52: // removable media eject
3355 regs
.u
.r8
.ah
= 0; // "ok ejection may proceed"
3359 if( regs
.u
.r8
.al
== 0 ) {
3360 // Set Interval requested.
3361 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3362 // Interval not already set.
3363 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3364 write_word( 0x40, 0x98, ES
); // Byte location, segment
3365 write_word( 0x40, 0x9A, regs
.u
.r16
.bx
); // Byte location, offset
3366 write_word( 0x40, 0x9C, regs
.u
.r16
.dx
); // Low word, delay
3367 write_word( 0x40, 0x9E, regs
.u
.r16
.cx
); // High word, delay.
3369 irqDisable
= inb( 0xA1 );
3370 outb( 0xA1, irqDisable
& 0xFE );
3371 bRegister
= inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3372 outb_cmos( 0xB, bRegister
| 0x40 ); // Turn on the Periodic Interrupt timer
3374 // Interval already set.
3375 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3377 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3379 } else if( regs
.u
.r8
.al
== 1 ) {
3380 // Clear Interval requested
3381 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3383 bRegister
= inb_cmos( 0xB );
3384 outb_cmos( 0xB, bRegister
& ~0x40 ); // Turn off the Periodic Interrupt timer
3386 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3388 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3397 # error "Int15 function 87h not supported on < 80386"
3399 // +++ should probably have descriptor checks
3400 // +++ should have exception handlers
3402 // turn off interrupts
3407 prev_a20_enable
= set_enable_a20(1); // enable A20 line
3409 // 128K max of transfer on 386+ ???
3410 // source == destination ???
3412 // ES:SI points to descriptor table
3413 // offset use initially comments
3414 // ==============================================
3415 // 00..07 Unused zeros Null descriptor
3416 // 08..0f GDT zeros filled in by BIOS
3417 // 10..17 source ssssssss source of data
3418 // 18..1f dest dddddddd destination of data
3419 // 20..27 CS zeros filled in by BIOS
3420 // 28..2f SS zeros filled in by BIOS
3427 // check for access rights of source & dest here
3429 // Initialize GDT descriptor
3430 base15_00
= (ES
<< 4) + regs
.u
.r16
.si
;
3431 base23_16
= ES
>> 12;
3432 if (base15_00
< (ES
<<4))
3434 write_word(ES
, regs
.u
.r16
.si
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3435 write_word(ES
, regs
.u
.r16
.si
+0x08+2, base15_00
);// base 15:00
3436 write_byte(ES
, regs
.u
.r16
.si
+0x08+4, base23_16
);// base 23:16
3437 write_byte(ES
, regs
.u
.r16
.si
+0x08+5, 0x93); // access
3438 write_word(ES
, regs
.u
.r16
.si
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3440 // Initialize CS descriptor
3441 write_word(ES
, regs
.u
.r16
.si
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3442 write_word(ES
, regs
.u
.r16
.si
+0x20+2, 0x0000);// base 15:00
3443 write_byte(ES
, regs
.u
.r16
.si
+0x20+4, 0x000f);// base 23:16
3444 write_byte(ES
, regs
.u
.r16
.si
+0x20+5, 0x9b); // access
3445 write_word(ES
, regs
.u
.r16
.si
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3447 // Initialize SS descriptor
3449 base15_00
= ss
<< 4;
3450 base23_16
= ss
>> 12;
3451 write_word(ES
, regs
.u
.r16
.si
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3452 write_word(ES
, regs
.u
.r16
.si
+0x28+2, base15_00
);// base 15:00
3453 write_byte(ES
, regs
.u
.r16
.si
+0x28+4, base23_16
);// base 23:16
3454 write_byte(ES
, regs
.u
.r16
.si
+0x28+5, 0x93); // access
3455 write_word(ES
, regs
.u
.r16
.si
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3459 // Compile generates locals offset info relative to SP.
3460 // Get CX (word count) from stack.
3463 mov cx
, _int15_function
.CX
[bx
]
3465 // since we need to set SS:SP, save them to the BDA
3466 // for future restore
3476 lidt
[pmode_IDT_info
]
3477 ;; perhaps
do something with IDT here
3479 ;; set PE bit in CR0
3483 ;; far jump to flush CPU queue after transition to
protected mode
3484 JMP_AP(0x0020, protected_mode
)
3487 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
3488 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3490 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3492 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3498 movsw
;; move CX words from DS
:SI to ES
:DI
3500 ;; make sure DS
and ES limits are
64KB
3505 ;; reset PG bit in CR0
???
3510 ;; far jump to flush CPU queue after transition to real mode
3511 JMP_AP(0xf000, real_mode
)
3514 ;; restore IDT to normal real
-mode defaults
3516 lidt
[rmode_IDT_info
]
3518 // restore SS:SP from the BDA
3526 set_enable_a20(prev_a20_enable
);
3528 // turn back on interrupts
3538 case 0x88: /* extended memory size */
3540 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3543 /* ??? change this back later... */
3544 /* number of 1K blocks of extended memory, subtract off 1st 1Meg */
3545 // AX = bx_mem.get_memory_in_k() - 1024;
3546 regs
.u
.r8
.al
= inb_cmos(0x30);
3547 regs
.u
.r8
.ah
= inb_cmos(0x31);
3553 /* Device busy interrupt. Called by Int 16h when no key available */
3557 /* Interrupt complete. Called by Int 16h when key becomes available */
3561 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3563 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3569 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3574 regs
.u
.r16
.bx
= BIOS_CONFIG_TABLE
;
3579 #if BX_USE_PS2_MOUSE
3580 ES
= read_word(0x0040, 0x000E);
3584 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3589 bios_printf(BIOS_PRINTF_DEBUG
, "EISA BIOS not present\n");
3591 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3595 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3596 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3598 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3603 #if BX_USE_PS2_MOUSE
3605 int15_function_mouse(regs
, ES
, DS
, FLAGS
)
3606 pusha_regs_t regs
; // REGS pushed via pusha
3607 Bit16u ES
, DS
, FLAGS
;
3609 Bit16u ebda_seg
=read_word(0x0040,0x000E);
3610 Bit8u mouse_flags_1
, mouse_flags_2
;
3611 Bit16u mouse_driver_seg
;
3612 Bit16u mouse_driver_offset
;
3613 Bit8u response
, prev_command_byte
;
3614 bx_bool prev_a20_enable
;
3615 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
3616 Bit8u comm_byte
, mf2_state
;
3618 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3620 switch (regs
.u
.r8
.ah
) {
3622 // Return Codes status in AH
3623 // =========================
3625 // 01: invalid subfunction (AL > 7)
3626 // 02: invalid input value (out of allowable range)
3627 // 03: interface error
3628 // 04: resend command received from mouse controller,
3629 // device driver should attempt command again
3630 // 05: cannot enable mouse, since no far call has been installed
3631 // 80/86: mouse service not implemented
3633 switch (regs
.u
.r8
.al
) {
3634 case 0: // Disable/Enable Mouse
3635 BX_DEBUG_INT15("case 0:\n");
3636 switch (regs
.u
.r8
.bh
) {
3637 case 0: // Disable Mouse
3638 BX_DEBUG_INT15("case 0: disable mouse\n");
3639 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3640 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
3642 ret
= get_mouse_data(&mouse_data1
);
3643 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
3656 case 1: // Enable Mouse
3657 BX_DEBUG_INT15("case 1: enable mouse\n");
3658 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3659 if ( (mouse_flags_2
& 0x80) == 0 ) {
3660 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3662 regs
.u
.r8
.ah
= 5; // no far call installed
3665 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3666 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
3668 ret
= get_mouse_data(&mouse_data1
);
3669 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
3670 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3680 default: // invalid subfunction
3681 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3683 regs
.u
.r8
.ah
= 1; // invalid subfunction
3688 case 1: // Reset Mouse
3689 case 5: // Initialize Mouse
3690 BX_DEBUG_INT15("case 1 or 5:\n");
3691 if (regs
.u
.r8
.al
== 5) {
3692 if (regs
.u
.r8
.bh
!= 3)
3693 BX_PANIC("INT 15h C2 AL=5, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3694 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3695 mouse_flags_2
= (mouse_flags_2
& 0x00) | regs
.u
.r8
.bh
;
3696 mouse_flags_1
= 0x00;
3697 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
3698 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3701 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3702 ret
= send_to_mouse_ctrl(0xFF); // disable mouse command
3704 ret
= get_mouse_data(&mouse_data3
);
3705 if (mouse_data3
!= 0xfa)
3706 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3
);
3708 ret
= get_mouse_data(&mouse_data1
);
3710 ret
= get_mouse_data(&mouse_data2
);
3712 // turn IRQ12 and packet generation on
3713 enable_mouse_int_and_events();
3716 regs
.u
.r8
.bl
= mouse_data1
;
3717 regs
.u
.r8
.bh
= mouse_data2
;
3729 case 2: // Set Sample Rate
3730 BX_DEBUG_INT15("case 2:\n");
3731 switch (regs
.u
.r8
.bh
) {
3732 case 0: // 10 reports/sec
3733 case 1: // 20 reports/sec
3734 case 2: // 40 reports/sec
3735 case 3: // 60 reports/sec
3736 case 4: // 80 reports/sec
3737 case 5: // 100 reports/sec (default)
3738 case 6: // 200 reports/sec
3743 BX_PANIC("INT 15h C2 AL=2, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3747 case 3: // Set Resolution
3748 BX_DEBUG_INT15("case 3:\n");
3750 // 0 = 25 dpi, 1 count per millimeter
3751 // 1 = 50 dpi, 2 counts per millimeter
3752 // 2 = 100 dpi, 4 counts per millimeter
3753 // 3 = 200 dpi, 8 counts per millimeter
3758 case 4: // Get Device ID
3759 BX_DEBUG_INT15("case 4:\n");
3765 case 6: // Return Status & Set Scaling Factor...
3766 BX_DEBUG_INT15("case 6:\n");
3767 switch (regs
.u
.r8
.bh
) {
3768 case 0: // Return Status
3769 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3770 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
3772 ret
= get_mouse_data(&mouse_data1
);
3773 if (mouse_data1
!= 0xfa)
3774 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1
);
3776 ret
= get_mouse_data(&mouse_data1
);
3778 ret
= get_mouse_data(&mouse_data2
);
3780 ret
= get_mouse_data(&mouse_data3
);
3784 regs
.u
.r8
.bl
= mouse_data1
;
3785 regs
.u
.r8
.cl
= mouse_data2
;
3786 regs
.u
.r8
.dl
= mouse_data3
;
3787 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3798 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
3801 case 1: // Set Scaling Factor to 1:1
3807 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs
.u
.r8
.bh
);
3811 case 7: // Set Mouse Handler Address
3812 BX_DEBUG_INT15("case 7:\n");
3813 mouse_driver_seg
= ES
;
3814 mouse_driver_offset
= regs
.u
.r16
.bx
;
3815 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
3816 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
3817 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
3818 if (mouse_driver_offset
== 0 && mouse_driver_seg
== 0) {
3819 /* remove handler */
3820 if ( (mouse_flags_2
& 0x80) != 0 ) {
3821 mouse_flags_2
&= ~0x80;
3822 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3826 /* install handler */
3827 mouse_flags_2
|= 0x80;
3829 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
3835 BX_DEBUG_INT15("case default:\n");
3836 regs
.u
.r8
.ah
= 1; // invalid function
3842 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3843 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
3845 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
3852 int15_function32(regs
, ES
, DS
, FLAGS
)
3853 pushad_regs_t regs
; // REGS pushed via pushad
3854 Bit16u ES
, DS
, FLAGS
;
3856 Bit32u extended_memory_size
=0; // 64bits long
3859 BX_DEBUG_INT15("int15 AX=%04x\n",regs
.u
.r16
.ax
);
3861 switch (regs
.u
.r8
.ah
) {
3863 // Wait for CX:DX microseconds. currently using the
3864 // refresh request port 0x61 bit4, toggling every 15usec
3872 ;; Get the count in eax
3875 mov ax
, _int15_function
.CX
[bx
]
3878 mov ax
, _int15_function
.DX
[bx
]
3880 ;; convert to numbers of
15usec ticks
3886 ;; wait
for ecx number of refresh requests
3907 switch(regs
.u
.r8
.al
)
3909 case 0x20: // coded by osmaker aka K.J.
3910 if(regs
.u
.r32
.edx
== 0x534D4150)
3912 switch(regs
.u
.r16
.bx
)
3915 write_word(ES
, regs
.u
.r16
.di
, 0x00);
3916 write_word(ES
, regs
.u
.r16
.di
+2, 0x00);
3917 write_word(ES
, regs
.u
.r16
.di
+4, 0x00);
3918 write_word(ES
, regs
.u
.r16
.di
+6, 0x00);
3920 write_word(ES
, regs
.u
.r16
.di
+8, 0xFC00);
3921 write_word(ES
, regs
.u
.r16
.di
+10, 0x0009);
3922 write_word(ES
, regs
.u
.r16
.di
+12, 0x0000);
3923 write_word(ES
, regs
.u
.r16
.di
+14, 0x0000);
3925 write_word(ES
, regs
.u
.r16
.di
+16, 0x1);
3926 write_word(ES
, regs
.u
.r16
.di
+18, 0x0);
3929 regs
.u
.r32
.eax
= 0x534D4150;
3930 regs
.u
.r32
.ecx
= 0x14;
3935 extended_memory_size
= inb_cmos(0x35);
3936 extended_memory_size
<<= 8;
3937 extended_memory_size
|= inb_cmos(0x34);
3938 extended_memory_size
*= 64;
3939 if(extended_memory_size
> 0x3bc000) // greater than EFF00000???
3941 extended_memory_size
= 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
3943 extended_memory_size
*= 1024;
3944 extended_memory_size
+= 15728640; // make up for the 16mb of memory that is chopped off
3946 if(extended_memory_size
<= 15728640)
3948 extended_memory_size
= inb_cmos(0x31);
3949 extended_memory_size
<<= 8;
3950 extended_memory_size
|= inb_cmos(0x30);
3951 extended_memory_size
*= 1024;
3954 write_word(ES
, regs
.u
.r16
.di
, 0x0000);
3955 write_word(ES
, regs
.u
.r16
.di
+2, 0x0010);
3956 write_word(ES
, regs
.u
.r16
.di
+4, 0x0000);
3957 write_word(ES
, regs
.u
.r16
.di
+6, 0x0000);
3959 write_word(ES
, regs
.u
.r16
.di
+8, extended_memory_size
);
3960 extended_memory_size
>>= 16;
3961 write_word(ES
, regs
.u
.r16
.di
+10, extended_memory_size
);
3962 extended_memory_size
>>= 16;
3963 write_word(ES
, regs
.u
.r16
.di
+12, extended_memory_size
);
3964 extended_memory_size
>>= 16;
3965 write_word(ES
, regs
.u
.r16
.di
+14, extended_memory_size
);
3967 write_word(ES
, regs
.u
.r16
.di
+16, 0x1);
3968 write_word(ES
, regs
.u
.r16
.di
+18, 0x0);
3971 regs
.u
.r32
.eax
= 0x534D4150;
3972 regs
.u
.r32
.ecx
= 0x14;
3976 default: /* AX=E820, DX=534D4150, BX unrecognized */
3977 goto int15_unimplemented
;
3981 // if DX != 0x534D4150)
3982 goto int15_unimplemented
;
3987 // do we have any reason to fail here ?
3990 // my real system sets ax and bx to 0
3991 // this is confirmed by Ralph Brown list
3992 // but syslinux v1.48 is known to behave
3993 // strangely if ax is set to 0
3994 // regs.u.r16.ax = 0;
3995 // regs.u.r16.bx = 0;
3997 // Get the amount of extended memory (above 1M)
3998 regs
.u
.r8
.cl
= inb_cmos(0x30);
3999 regs
.u
.r8
.ch
= inb_cmos(0x31);
4002 if(regs
.u
.r16
.cx
> 0x3c00)
4004 regs
.u
.r16
.cx
= 0x3c00;
4007 // Get the amount of extended memory above 16M in 64k blocs
4008 regs
.u
.r8
.dl
= inb_cmos(0x34);
4009 regs
.u
.r8
.dh
= inb_cmos(0x35);
4011 // Set configured memory equal to extended memory
4012 regs
.u
.r16
.ax
= regs
.u
.r16
.cx
;
4013 regs
.u
.r16
.bx
= regs
.u
.r16
.dx
;
4015 default: /* AH=0xE8?? but not implemented */
4016 goto int15_unimplemented
;
4019 int15_unimplemented
:
4020 // fall into the default
4022 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4023 (unsigned) regs
.u
.r16
.ax
, (unsigned) regs
.u
.r16
.bx
);
4025 regs
.u
.r8
.ah
= UNSUPPORTED_FUNCTION
;
4031 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
4032 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
4034 Bit8u scan_code
, ascii_code
, shift_flags
, count
;
4035 Bit16u kbd_code
, max
;
4037 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX
, BX
, CX
, DX
);
4040 case 0x00: /* read keyboard input */
4042 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4043 BX_PANIC("KBD: int16h: out of keyboard input\n");
4045 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4046 else if (ascii_code
== 0xE0) ascii_code
= 0;
4047 AX
= (scan_code
<< 8) | ascii_code
;
4050 case 0x01: /* check keyboard status */
4051 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4055 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4056 else if (ascii_code
== 0xE0) ascii_code
= 0;
4057 AX
= (scan_code
<< 8) | ascii_code
;
4061 case 0x02: /* get shift flag status */
4062 shift_flags
= read_byte(0x0040, 0x17);
4063 SET_AL(shift_flags
);
4066 case 0x05: /* store key-stroke into buffer */
4067 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4075 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4076 // bit Bochs Description
4078 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4079 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4080 // 4 1 INT 16/AH=0Ah supported
4081 // 3 0 INT 16/AX=0306h supported
4082 // 2 0 INT 16/AX=0305h supported
4083 // 1 0 INT 16/AX=0304h supported
4084 // 0 0 INT 16/AX=0300h supported
4089 case 0x0A: /* GET KEYBOARD ID */
4095 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4097 if ((inb(0x60) == 0xfa)) {
4100 while ( ((inb(0x64) & 0x01) == 0) && (--max
>0) ) outb(0x80, 0x00);
4103 kbd_code
|= (inb(0x60) << 8);
4105 } while (--count
>0);
4111 case 0x10: /* read MF-II keyboard input */
4113 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
4114 BX_PANIC("KBD: int16h: out of keyboard input\n");
4116 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4117 AX
= (scan_code
<< 8) | ascii_code
;
4120 case 0x11: /* check MF-II keyboard status */
4121 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
4125 if (scan_code
!=0 && ascii_code
== 0xF0) ascii_code
= 0;
4126 AX
= (scan_code
<< 8) | ascii_code
;
4130 case 0x12: /* get extended keyboard status */
4131 shift_flags
= read_byte(0x0040, 0x17);
4132 SET_AL(shift_flags
);
4133 shift_flags
= read_byte(0x0040, 0x18);
4134 SET_AH(shift_flags
);
4135 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX
);
4138 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4139 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4142 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4143 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4147 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4152 dequeue_key(scan_code
, ascii_code
, incr
)
4157 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
4162 buffer_start
= 0x001E;
4163 buffer_end
= 0x003E;
4165 buffer_start
= read_word(0x0040, 0x0080);
4166 buffer_end
= read_word(0x0040, 0x0082);
4169 buffer_head
= read_word(0x0040, 0x001a);
4170 buffer_tail
= read_word(0x0040, 0x001c);
4172 if (buffer_head
!= buffer_tail
) {
4174 acode
= read_byte(0x0040, buffer_head
);
4175 scode
= read_byte(0x0040, buffer_head
+1);
4176 write_byte(ss
, ascii_code
, acode
);
4177 write_byte(ss
, scan_code
, scode
);
4181 if (buffer_head
>= buffer_end
)
4182 buffer_head
= buffer_start
;
4183 write_word(0x0040, 0x001a, buffer_head
);
4192 static char panic_msg_keyb_buffer_full
[] = "%s: keyboard input buffer full\n";
4195 inhibit_mouse_int_and_events()
4197 Bit8u command_byte
, prev_command_byte
;
4199 // Turn off IRQ generation and aux data line
4200 if ( inb(0x64) & 0x02 )
4201 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4202 outb(0x64, 0x20); // get command byte
4203 while ( (inb(0x64) & 0x01) != 0x01 );
4204 prev_command_byte
= inb(0x60);
4205 command_byte
= prev_command_byte
;
4206 //while ( (inb(0x64) & 0x02) );
4207 if ( inb(0x64) & 0x02 )
4208 BX_PANIC(panic_msg_keyb_buffer_full
,"inhibmouse");
4209 command_byte
&= 0xfd; // turn off IRQ 12 generation
4210 command_byte
|= 0x20; // disable mouse serial clock line
4211 outb(0x64, 0x60); // write command byte
4212 outb(0x60, command_byte
);
4213 return(prev_command_byte
);
4217 enable_mouse_int_and_events()
4221 // Turn on IRQ generation and aux data line
4222 if ( inb(0x64) & 0x02 )
4223 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4224 outb(0x64, 0x20); // get command byte
4225 while ( (inb(0x64) & 0x01) != 0x01 );
4226 command_byte
= inb(0x60);
4227 //while ( (inb(0x64) & 0x02) );
4228 if ( inb(0x64) & 0x02 )
4229 BX_PANIC(panic_msg_keyb_buffer_full
,"enabmouse");
4230 command_byte
|= 0x02; // turn on IRQ 12 generation
4231 command_byte
&= 0xdf; // enable mouse serial clock line
4232 outb(0x64, 0x60); // write command byte
4233 outb(0x60, command_byte
);
4237 send_to_mouse_ctrl(sendbyte
)
4242 // wait for chance to write to ctrl
4243 if ( inb(0x64) & 0x02 )
4244 BX_PANIC(panic_msg_keyb_buffer_full
,"sendmouse");
4246 outb(0x60, sendbyte
);
4252 get_mouse_data(data
)
4258 while ( (inb(0x64) & 0x21) != 0x21 ) {
4261 response
= inb(0x60);
4264 write_byte(ss
, data
, response
);
4269 set_kbd_command_byte(command_byte
)
4272 if ( inb(0x64) & 0x02 )
4273 BX_PANIC(panic_msg_keyb_buffer_full
,"setkbdcomm");
4276 outb(0x64, 0x60); // write command byte
4277 outb(0x60, command_byte
);
4281 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
4282 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
4284 Bit8u scancode
, asciicode
, shift_flags
;
4285 Bit8u mf2_flags
, mf2_state
, led_flags
;
4288 // DS has been set to F000 before call
4292 scancode
= GET_AL();
4294 if (scancode
== 0) {
4295 BX_INFO("KBD: int09 handler: AL=0\n");
4300 shift_flags
= read_byte(0x0040, 0x17);
4301 mf2_flags
= read_byte(0x0040, 0x18);
4302 mf2_state
= read_byte(0x0040, 0x96);
4303 led_flags
= read_byte(0x0040, 0x97);
4307 case 0x3a: /* Caps Lock press */
4308 shift_flags
^= 0x40;
4309 write_byte(0x0040, 0x17, shift_flags
);
4311 write_byte(0x0040, 0x18, mf2_flags
);
4313 write_byte(0x0040, 0x97, led_flags
);
4315 case 0xba: /* Caps Lock release */
4317 write_byte(0x0040, 0x18, mf2_flags
);
4320 case 0x2a: /* L Shift press */
4321 /*shift_flags &= ~0x40;*/
4322 shift_flags
|= 0x02;
4323 write_byte(0x0040, 0x17, shift_flags
);
4325 write_byte(0x0040, 0x97, led_flags
);
4327 case 0xaa: /* L Shift release */
4328 shift_flags
&= ~0x02;
4329 write_byte(0x0040, 0x17, shift_flags
);
4332 case 0x36: /* R Shift press */
4333 /*shift_flags &= ~0x40;*/
4334 shift_flags
|= 0x01;
4335 write_byte(0x0040, 0x17, shift_flags
);
4337 write_byte(0x0040, 0x97, led_flags
);
4339 case 0xb6: /* R Shift release */
4340 shift_flags
&= ~0x01;
4341 write_byte(0x0040, 0x17, shift_flags
);
4344 case 0x1d: /* Ctrl press */
4345 shift_flags
|= 0x04;
4346 write_byte(0x0040, 0x17, shift_flags
);
4347 if (mf2_state
& 0x01) {
4352 write_byte(0x0040, 0x18, mf2_flags
);
4354 case 0x9d: /* Ctrl release */
4355 shift_flags
&= ~0x04;
4356 write_byte(0x0040, 0x17, shift_flags
);
4357 if (mf2_state
& 0x01) {
4362 write_byte(0x0040, 0x18, mf2_flags
);
4365 case 0x38: /* Alt press */
4366 shift_flags
|= 0x08;
4367 write_byte(0x0040, 0x17, shift_flags
);
4368 if (mf2_state
& 0x01) {
4373 write_byte(0x0040, 0x18, mf2_flags
);
4375 case 0xb8: /* Alt release */
4376 shift_flags
&= ~0x08;
4377 write_byte(0x0040, 0x17, shift_flags
);
4378 if (mf2_state
& 0x01) {
4383 write_byte(0x0040, 0x18, mf2_flags
);
4386 case 0x45: /* Num Lock press */
4387 if ((mf2_state
& 0x01) == 0) {
4389 write_byte(0x0040, 0x18, mf2_flags
);
4390 shift_flags
^= 0x20;
4392 write_byte(0x0040, 0x17, shift_flags
);
4393 write_byte(0x0040, 0x97, led_flags
);
4396 case 0xc5: /* Num Lock release */
4397 if ((mf2_state
& 0x01) == 0) {
4399 write_byte(0x0040, 0x18, mf2_flags
);
4403 case 0x46: /* Scroll Lock press */
4405 write_byte(0x0040, 0x18, mf2_flags
);
4406 shift_flags
^= 0x10;
4408 write_byte(0x0040, 0x17, shift_flags
);
4409 write_byte(0x0040, 0x97, led_flags
);
4412 case 0xc6: /* Scroll Lock release */
4414 write_byte(0x0040, 0x18, mf2_flags
);
4418 if (scancode
& 0x80) return; /* toss key releases ... */
4419 if (scancode
> MAX_SCAN_CODE
) {
4420 BX_INFO("KBD: int09h_handler(): unknown scancode read!");
4423 if (shift_flags
& 0x08) { /* ALT */
4424 asciicode
= scan_to_scanascii
[scancode
].alt
;
4425 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
4427 else if (shift_flags
& 0x04) { /* CONTROL */
4428 asciicode
= scan_to_scanascii
[scancode
].control
;
4429 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
4431 else if (shift_flags
& 0x03) { /* LSHIFT + RSHIFT */
4432 /* check if lock state should be ignored
4433 * because a SHIFT key are pressed */
4435 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4436 asciicode
= scan_to_scanascii
[scancode
].normal
;
4437 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4440 asciicode
= scan_to_scanascii
[scancode
].shift
;
4441 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4445 /* check if lock is on */
4446 if (shift_flags
& scan_to_scanascii
[scancode
].lock_flags
) {
4447 asciicode
= scan_to_scanascii
[scancode
].shift
;
4448 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
4451 asciicode
= scan_to_scanascii
[scancode
].normal
;
4452 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
4455 if (scancode
==0 && asciicode
==0) {
4456 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?");
4458 enqueue_key(scancode
, asciicode
);
4465 enqueue_key(scan_code
, ascii_code
)
4466 Bit8u scan_code
, ascii_code
;
4468 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
4470 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4471 // scan_code, ascii_code);
4474 buffer_start
= 0x001E;
4475 buffer_end
= 0x003E;
4477 buffer_start
= read_word(0x0040, 0x0080);
4478 buffer_end
= read_word(0x0040, 0x0082);
4481 buffer_head
= read_word(0x0040, 0x001A);
4482 buffer_tail
= read_word(0x0040, 0x001C);
4484 temp_tail
= buffer_tail
;
4486 if (buffer_tail
>= buffer_end
)
4487 buffer_tail
= buffer_start
;
4489 if (buffer_tail
== buffer_head
) {
4493 write_byte(0x0040, temp_tail
, ascii_code
);
4494 write_byte(0x0040, temp_tail
+1, scan_code
);
4495 write_word(0x0040, 0x001C, buffer_tail
);
4501 int74_function(make_farcall
, Z
, Y
, X
, status
)
4502 Bit16u make_farcall
, Z
, Y
, X
, status
;
4504 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4505 Bit8u in_byte
, index
, package_count
;
4506 Bit8u mouse_flags_1
, mouse_flags_2
;
4508 BX_DEBUG_INT74("entering int74_function\n");
4511 in_byte
= inb(0x64);
4512 if ( (in_byte
& 0x21) != 0x21 ) {
4515 in_byte
= inb(0x60);
4516 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte
);
4518 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
4519 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
4521 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
4522 // BX_PANIC("int74_function:\n");
4526 package_count
= mouse_flags_2
& 0x07;
4527 index
= mouse_flags_1
& 0x07;
4528 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
4530 if ( (index
+1) >= package_count
) {
4531 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4532 status
= read_byte(ebda_seg
, 0x0028 + 0);
4533 X
= read_byte(ebda_seg
, 0x0028 + 1);
4534 Y
= read_byte(ebda_seg
, 0x0028 + 2);
4537 // check if far call handler installed
4538 if (mouse_flags_2
& 0x80)
4544 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
4547 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4552 int13_harddisk(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, DS
, ES
, FLAGS
)
4553 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, DS
, ES
, FLAGS
;
4556 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4557 Bit16u cylinder
, head
, sector
;
4558 Bit16u segment
, offset
;
4559 Bit16u npc
, nph
, npspt
, nlc
, nlh
, nlspt
;
4561 Bit8u device
, status
;
4563 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4565 write_byte(0x0040, 0x008e, 0); // clear completion flag
4567 // basic check : device has to be defined
4568 if ( (GET_DL() < 0x80) || (GET_DL() >= 0x80 + BX_MAX_ATA_DEVICES
) ) {
4569 BX_INFO("int13_harddisk: function %02x, DL out of range %02x\n", GET_AH(), GET_DL());
4573 // Get the ata channel
4574 device
=read_byte(ebda_seg
,&EbdaData
->ata
.hdidmap
[GET_DL()-0x80]);
4576 // basic check : device has to be valid
4577 if (device
>= BX_MAX_ATA_DEVICES
) {
4578 BX_INFO("int13_harddisk: function %02x, unmapped device for DL=%02x\n", GET_AH(), GET_DL());
4584 case 0x00: /* disk controller reset */
4589 case 0x01: /* read disk status */
4590 status
= read_byte(0x0040, 0x0074);
4592 SET_DISK_RET_STATUS(0);
4593 /* set CF if error status read */
4594 if (status
) goto int13_fail_nostatus
;
4595 else goto int13_success_noah
;
4598 case 0x02: // read disk sectors
4599 case 0x03: // write disk sectors
4600 case 0x04: // verify disk sectors
4603 cylinder
= GET_CH();
4604 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
4605 sector
= (GET_CL() & 0x3f);
4611 if ( (count
> 128) || (count
== 0) ) {
4612 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4616 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4617 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4618 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4620 // sanity check on cyl heads, sec
4621 if( (cylinder
>= nlc
) || (head
>= nlh
) || (sector
> nlspt
)) {
4622 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder
, head
, sector
);
4627 if ( GET_AH() == 0x04 ) goto int13_success
;
4629 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4630 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4632 // if needed, translate lchs to lba, and execute command
4633 if ( (nph
!= nlh
) || (npspt
!= nlspt
)) {
4634 lba
= ((((Bit32u
)cylinder
* (Bit32u
)nlh
) + (Bit32u
)head
) * (Bit32u
)nlspt
) + (Bit32u
)sector
- 1;
4635 sector
= 0; // this forces the command to be lba
4638 if ( GET_AH() == 0x02 )
4639 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4641 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, cylinder
, head
, sector
, lba
, segment
, offset
);
4643 // Set nb of sector transferred
4644 SET_AL(read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
));
4647 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4649 goto int13_fail_noah
;
4655 case 0x05: /* format disk track */
4656 BX_INFO("format disk track called\n");
4661 case 0x08: /* read disk drive parameters */
4663 // Get logical geometry from table
4664 nlc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.cylinders
);
4665 nlh
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.heads
);
4666 nlspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].lchs
.spt
);
4667 count
= read_byte(ebda_seg
, &EbdaData
->ata
.hdcount
);
4669 nlc
= nlc
- 2; /* 0 based , last sector not used */
4672 SET_CL(((nlc
>> 2) & 0xc0) | (nlspt
& 0x3f));
4674 SET_DL(count
); /* FIXME returns 0, 1, or n hard drives */
4676 // FIXME should set ES & DI
4681 case 0x10: /* check drive ready */
4682 // should look at 40:8E also???
4684 // Read the status from controller
4685 status
= inb(read_word(ebda_seg
, &EbdaData
->ata
.channels
[device
/2].iobase1
) + ATA_CB_STAT
);
4686 if ( (status
& ( ATA_CB_STAT_BSY
| ATA_CB_STAT_RDY
)) == ATA_CB_STAT_RDY
) {
4691 goto int13_fail_noah
;
4695 case 0x15: /* read disk drive size */
4697 // Get physical geometry from table
4698 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
4699 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4700 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4702 // Compute sector count seen by int13
4703 lba
= (Bit32u
)(npc
- 1) * (Bit32u
)nph
* (Bit32u
)npspt
;
4707 SET_AH(3); // hard disk accessible
4708 goto int13_success_noah
;
4711 case 0x41: // IBM/MS installation check
4712 BX
=0xaa55; // install check
4713 SET_AH(0x30); // EDD 3.0
4714 CX
=0x0007; // ext disk access and edd, removable supported
4715 goto int13_success_noah
;
4718 case 0x42: // IBM/MS extended read
4719 case 0x43: // IBM/MS extended write
4720 case 0x44: // IBM/MS verify
4721 case 0x47: // IBM/MS extended seek
4723 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
4724 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
4725 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
4727 // Can't use 64 bits lba
4728 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
4730 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4734 // Get 32 bits lba and check
4735 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
4736 if (lba
>= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
) ) {
4737 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4741 // If verify or seek
4742 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4745 // Execute the command
4746 if ( GET_AH() == 0x42 )
4747 status
=ata_cmd_data_in(device
, ATA_CMD_READ_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4749 status
=ata_cmd_data_out(device
, ATA_CMD_WRITE_SECTORS
, count
, 0, 0, 0, lba
, segment
, offset
);
4751 count
=read_word(ebda_seg
, &EbdaData
->ata
.trsfsectors
);
4752 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
4755 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status
);
4757 goto int13_fail_noah
;
4763 case 0x45: // IBM/MS lock/unlock drive
4764 case 0x49: // IBM/MS extended media change
4765 goto int13_success
; // Always success for HD
4768 case 0x46: // IBM/MS eject media
4769 SET_AH(0xb2); // Volume Not Removable
4770 goto int13_fail_noah
; // Always fail for HD
4773 case 0x48: // IBM/MS get drive parameters
4774 size
=read_word(DS
,SI
+(Bit16u
)&Int13DPT
->size
);
4776 // Buffer is too small
4784 npc
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.cylinders
);
4785 nph
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.heads
);
4786 npspt
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].pchs
.spt
);
4787 lba
= read_dword(ebda_seg
, &EbdaData
->ata
.devices
[device
].sectors
);
4788 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
4790 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
4791 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x02); // geometry is valid
4792 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, (Bit32u
)npc
);
4793 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, (Bit32u
)nph
);
4794 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, (Bit32u
)npspt
);
4795 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, lba
); // FIXME should be Bit64
4796 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0L);
4797 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
4802 Bit8u channel
, dev
, irq
, mode
, checksum
, i
, translation
;
4803 Bit16u iobase1
, iobase2
, options
;
4805 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
4807 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
4808 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
4811 channel
= device
/ 2;
4812 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
4813 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
4814 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
4815 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
4816 translation
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].translation
);
4818 options
= (translation
==ATA_TRANSLATION_NONE
?0:1<<3); // chs translation
4819 options
|= (1<<4); // lba translation
4820 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
4821 options
|= (translation
==ATA_TRANSLATION_LBA
?1:0<<9);
4822 options
|= (translation
==ATA_TRANSLATION_RECHS
?3:0<<9);
4824 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
4825 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
4826 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
4827 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
4828 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
4829 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
4830 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
4831 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
4832 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
4833 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
4834 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
4837 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
4838 checksum
= ~checksum
;
4839 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
4844 Bit8u channel
, iface
, checksum
, i
;
4847 channel
= device
/ 2;
4848 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
4849 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
4851 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
4852 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
4853 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
4854 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
4855 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
4857 if (iface
==ATA_IFACE_ISA
) {
4858 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
4859 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
4860 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
4861 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
4866 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
4867 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
4868 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
4869 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
4871 if (iface
==ATA_IFACE_ISA
) {
4872 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
4873 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
4874 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
4879 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
4880 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
4881 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
4882 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
4885 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
4886 checksum
= ~checksum
;
4887 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
4893 case 0x4e: // // IBM/MS set hardware configuration
4894 // DMA, prefetch, PIO maximum not supported
4907 case 0x09: /* initialize drive parameters */
4908 case 0x0c: /* seek to specified cylinder */
4909 case 0x0d: /* alternate disk reset */
4910 case 0x11: /* recalibrate */
4911 case 0x14: /* controller internal diagnostic */
4912 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
4916 case 0x0a: /* read disk sectors with ECC */
4917 case 0x0b: /* write disk sectors with ECC */
4918 case 0x18: // set media type for format
4919 case 0x50: // IBM/MS send packet command
4921 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
4927 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
4929 SET_DISK_RET_STATUS(GET_AH());
4930 int13_fail_nostatus
:
4931 SET_CF(); // error occurred
4935 SET_AH(0x00); // no error
4937 SET_DISK_RET_STATUS(0x00);
4938 CLEAR_CF(); // no error
4942 // ---------------------------------------------------------------------------
4943 // Start of int13 for cdrom
4944 // ---------------------------------------------------------------------------
4947 int13_cdrom(DI
, DIH
, SI
, SIH
, BP
, BPH
, SP
, SPH
, BX
, BXH
, DX
, DXH
, CX
, CXH
, AX
, AXH
,
4949 Bit16u DI
, DIH
, SI
, SIH
, BP
, BPH
, SP
, SPH
, BX
, BXH
, DX
, DXH
, CX
, CXH
, AX
, AXH
,
4952 Bit16u ebda_seg
=read_word(0x0040,0x000E);
4953 Bit8u device
, status
, locks
;
4956 Bit16u count
, segment
, offset
, i
, size
;
4958 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
4959 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
4961 SET_DISK_RET_STATUS(0x00);
4963 /* basic check : device should be 0xE0+ */
4964 if( (GET_DL() < 0xE0) || (GET_DL() >= 0xE0+BX_MAX_ATA_DEVICES
) ) {
4965 BX_INFO("int13_cdrom: function %02x, DL out of range %02x\n", GET_AH(), GET_DL());
4969 // Get the ata channel
4970 device
=read_byte(ebda_seg
,&EbdaData
->ata
.cdidmap
[GET_DL()-0xE0]);
4972 /* basic check : device has to be valid */
4973 if (device
>= BX_MAX_ATA_DEVICES
) {
4974 BX_INFO("int13_cdrom: function %02x, unmapped device for DL=%02x\n", GET_AH(), GET_DL());
4980 // all those functions return SUCCESS
4981 case 0x00: /* disk controller reset */
4982 case 0x09: /* initialize drive parameters */
4983 case 0x0c: /* seek to specified cylinder */
4984 case 0x0d: /* alternate disk reset */
4985 case 0x10: /* check drive ready */
4986 case 0x11: /* recalibrate */
4987 case 0x14: /* controller internal diagnostic */
4988 case 0x16: /* detect disk change */
4992 // all those functions return disk write-protected
4993 case 0x03: /* write disk sectors */
4994 case 0x05: /* format disk track */
4995 case 0x43: // IBM/MS extended write
4997 goto int13_fail_noah
;
5000 case 0x01: /* read disk status */
5001 status
= read_byte(0x0040, 0x0074);
5003 SET_DISK_RET_STATUS(0);
5005 /* set CF if error status read */
5006 if (status
) goto int13_fail_nostatus
;
5007 else goto int13_success_noah
;
5010 case 0x15: /* read disk drive size */
5012 goto int13_fail_noah
;
5015 case 0x41: // IBM/MS installation check
5016 BX
=0xaa55; // install check
5017 SET_AH(0x30); // EDD 2.1
5018 CX
=0x0007; // ext disk access, removable and edd
5019 goto int13_success_noah
;
5022 case 0x42: // IBM/MS extended read
5023 case 0x44: // IBM/MS verify sectors
5024 case 0x47: // IBM/MS extended seek
5026 count
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
);
5027 segment
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->segment
);
5028 offset
=read_word(DS
, SI
+(Bit16u
)&Int13Ext
->offset
);
5030 // Can't use 64 bits lba
5031 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba2
);
5033 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5038 lba
=read_dword(DS
, SI
+(Bit16u
)&Int13Ext
->lba1
);
5040 // If verify or seek
5041 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5044 memsetb(get_SS(),atacmd
,0,12);
5045 atacmd
[0]=0x28; // READ command
5046 atacmd
[7]=(count
& 0xff00) >> 8; // Sectors
5047 atacmd
[8]=(count
& 0x00ff); // Sectors
5048 atacmd
[2]=(lba
& 0xff000000) >> 24; // LBA
5049 atacmd
[3]=(lba
& 0x00ff0000) >> 16;
5050 atacmd
[4]=(lba
& 0x0000ff00) >> 8;
5051 atacmd
[5]=(lba
& 0x000000ff);
5052 status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, 0, count
*2048L, ATA_DATA_IN
, segment
,offset
);
5054 count
= (Bit16u
)(read_dword(ebda_seg
, &EbdaData
->ata
.trsfbytes
) >> 11);
5055 write_word(DS
, SI
+(Bit16u
)&Int13Ext
->count
, count
);
5058 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status
);
5060 goto int13_fail_noah
;
5066 case 0x45: // IBM/MS lock/unlock drive
5067 if (GET_AL() > 2) goto int13_fail
;
5069 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5073 if (locks
== 0xff) {
5076 goto int13_fail_noah
;
5078 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, ++locks
);
5082 if (locks
== 0x00) {
5085 goto int13_fail_noah
;
5087 write_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
, --locks
);
5088 SET_AL(locks
==0?0:1);
5091 SET_AL(locks
==0?0:1);
5097 case 0x46: // IBM/MS eject media
5098 locks
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].lock
);
5101 SET_AH(0xb1); // media locked
5102 goto int13_fail_noah
;
5104 // FIXME should handle 0x31 no media in device
5105 // FIXME should handle 0xb5 valid request failed
5107 // Call removable media eject
5114 mov _int13_cdrom
.status
+ 2[bp
], ah
5115 jnc int13_cdrom_rme_end
5116 mov _int13_cdrom
.status
, #1
5117 int13_cdrom_rme_end
:
5122 SET_AH(0xb1); // media locked
5123 goto int13_fail_noah
;
5129 case 0x48: // IBM/MS get drive parameters
5130 size
= read_word(DS
,SI
+(Bit16u
)&Int13Ext
->size
);
5132 // Buffer is too small
5138 Bit16u cylinders
, heads
, spt
, blksize
;
5140 blksize
= read_word(ebda_seg
, &EbdaData
->ata
.devices
[device
].blksize
);
5142 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1a);
5143 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->infos
, 0x74); // removable, media change, lockable, max values
5144 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->cylinders
, 0xffffffff);
5145 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->heads
, 0xffffffff);
5146 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->spt
, 0xffffffff);
5147 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count1
, 0xffffffff); // FIXME should be Bit64
5148 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->sector_count2
, 0xffffffff);
5149 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->blksize
, blksize
);
5154 Bit8u channel
, dev
, irq
, mode
, checksum
, i
;
5155 Bit16u iobase1
, iobase2
, options
;
5157 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x1e);
5159 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_segment
, ebda_seg
);
5160 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->dpte_offset
, &EbdaData
->ata
.dpte
);
5163 channel
= device
/ 2;
5164 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5165 iobase2
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase2
);
5166 irq
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].irq
);
5167 mode
= read_byte(ebda_seg
, &EbdaData
->ata
.devices
[device
].mode
);
5169 // FIXME atapi device
5170 options
= (1<<4); // lba translation
5171 options
|= (1<<5); // removable device
5172 options
|= (1<<6); // atapi device
5173 options
|= (mode
==ATA_MODE_PIO32
?1:0<<7);
5175 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase1
, iobase1
);
5176 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.iobase2
, iobase2
);
5177 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.prefix
, (0xe | (device
% 2))<<4 );
5178 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.unused
, 0xcb );
5179 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.irq
, irq
);
5180 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.blkcount
, 1 );
5181 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.dma
, 0 );
5182 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.pio
, 0 );
5183 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.options
, options
);
5184 write_word(ebda_seg
, &EbdaData
->ata
.dpte
.reserved
, 0);
5185 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.revision
, 0x11);
5188 for (i
=0; i
<15; i
++) checksum
+=read_byte(ebda_seg
, (&EbdaData
->ata
.dpte
) + i
);
5189 checksum
= ~checksum
;
5190 write_byte(ebda_seg
, &EbdaData
->ata
.dpte
.checksum
, checksum
);
5195 Bit8u channel
, iface
, checksum
, i
;
5198 channel
= device
/ 2;
5199 iface
= read_byte(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iface
);
5200 iobase1
= read_word(ebda_seg
, &EbdaData
->ata
.channels
[channel
].iobase1
);
5202 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->size
, 0x42);
5203 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->key
, 0xbedd);
5204 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->dpi_length
, 0x24);
5205 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->reserved1
, 0);
5206 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->reserved2
, 0);
5208 if (iface
==ATA_IFACE_ISA
) {
5209 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[0], 'I');
5210 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[1], 'S');
5211 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[2], 'A');
5212 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->host_bus
[3], 0);
5217 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[0], 'A');
5218 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[1], 'T');
5219 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[2], 'A');
5220 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->iface_type
[3], 0);
5222 if (iface
==ATA_IFACE_ISA
) {
5223 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[0], iobase1
);
5224 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[2], 0);
5225 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->iface_path
[4], 0L);
5230 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[0], device
%2);
5231 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[1], 0);
5232 write_word(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[2], 0);
5233 write_dword(DS
, SI
+(Bit16u
)&Int13DPT
->device_path
[4], 0L);
5236 for (i
=30; i
<64; i
++) checksum
+=read_byte(DS
, SI
+ i
);
5237 checksum
= ~checksum
;
5238 write_byte(DS
, SI
+(Bit16u
)&Int13DPT
->checksum
, checksum
);
5244 case 0x49: // IBM/MS extended media change
5245 // always send changed ??
5247 goto int13_fail_nostatus
;
5250 case 0x4e: // // IBM/MS set hardware configuration
5251 // DMA, prefetch, PIO maximum not supported
5264 // all those functions return unimplemented
5265 case 0x02: /* read sectors */
5266 case 0x04: /* verify sectors */
5267 case 0x08: /* read disk drive parameters */
5268 case 0x0a: /* read disk sectors with ECC */
5269 case 0x0b: /* write disk sectors with ECC */
5270 case 0x18: /* set media type for format */
5271 case 0x50: // ? - send packet command
5273 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5279 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5281 SET_DISK_RET_STATUS(GET_AH());
5282 int13_fail_nostatus
:
5283 SET_CF(); // error occurred
5287 SET_AH(0x00); // no error
5289 SET_DISK_RET_STATUS(0x00);
5290 CLEAR_CF(); // no error
5294 // ---------------------------------------------------------------------------
5295 // End of int13 for cdrom
5296 // ---------------------------------------------------------------------------
5298 #if BX_ELTORITO_BOOT
5299 // ---------------------------------------------------------------------------
5300 // Start of int13 for eltorito functions
5301 // ---------------------------------------------------------------------------
5304 int13_eltorito(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, DS
, ES
, FLAGS
)
5305 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, DS
, ES
, FLAGS
;
5307 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5309 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5310 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5314 // FIXME ElTorito Various. Should be implemented
5315 case 0x4a: // ElTorito - Initiate disk emu
5316 case 0x4c: // ElTorito - Initiate disk emu and boot
5317 case 0x4d: // ElTorito - Return Boot catalog
5318 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX
);
5322 case 0x4b: // ElTorito - Terminate disk emu
5323 // FIXME ElTorito Hardcoded
5324 write_byte(DS
,SI
+0x00,0x13);
5325 write_byte(DS
,SI
+0x01,read_byte(ebda_seg
,&EbdaData
->cdemu
.media
));
5326 write_byte(DS
,SI
+0x02,read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
));
5327 write_byte(DS
,SI
+0x03,read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
));
5328 write_dword(DS
,SI
+0x04,read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
));
5329 write_word(DS
,SI
+0x08,read_word(ebda_seg
,&EbdaData
->cdemu
.device_spec
));
5330 write_word(DS
,SI
+0x0a,read_word(ebda_seg
,&EbdaData
->cdemu
.buffer_segment
));
5331 write_word(DS
,SI
+0x0c,read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
));
5332 write_word(DS
,SI
+0x0e,read_word(ebda_seg
,&EbdaData
->cdemu
.sector_count
));
5333 write_byte(DS
,SI
+0x10,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
));
5334 write_byte(DS
,SI
+0x11,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
));
5335 write_byte(DS
,SI
+0x12,read_byte(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
));
5337 // If we have to terminate emulation
5338 if(GET_AL() == 0x00) {
5339 // FIXME ElTorito Various. Should be handled accordingly to spec
5340 write_byte(ebda_seg
,&EbdaData
->cdemu
.active
, 0x00); // bye bye
5347 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5353 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5354 SET_DISK_RET_STATUS(GET_AH());
5355 SET_CF(); // error occurred
5359 SET_AH(0x00); // no error
5360 SET_DISK_RET_STATUS(0x00);
5361 CLEAR_CF(); // no error
5365 // ---------------------------------------------------------------------------
5366 // End of int13 for eltorito functions
5367 // ---------------------------------------------------------------------------
5369 // ---------------------------------------------------------------------------
5370 // Start of int13 when emulating a device from the cd
5371 // ---------------------------------------------------------------------------
5374 int13_cdemu(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
)
5375 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
;
5377 Bit16u ebda_seg
=read_word(0x0040,0x000E);
5378 Bit8u device
, status
;
5379 Bit16u vheads
, vspt
, vcylinders
;
5380 Bit16u head
, sector
, cylinder
, nbsectors
;
5381 Bit32u vlba
, ilba
, slba
, elba
;
5382 Bit16u before
, segment
, offset
;
5385 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5386 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5388 /* at this point, we are emulating a floppy/harddisk */
5390 // Recompute the device number
5391 device
= read_byte(ebda_seg
,&EbdaData
->cdemu
.controller_index
) * 2;
5392 device
+= read_byte(ebda_seg
,&EbdaData
->cdemu
.device_spec
);
5394 SET_DISK_RET_STATUS(0x00);
5396 /* basic checks : emulation should be active, dl should equal the emulated drive */
5397 if( (read_byte(ebda_seg
,&EbdaData
->cdemu
.active
) ==0 )
5398 || (read_byte(ebda_seg
,&EbdaData
->cdemu
.emulated_drive
) != GET_DL())) {
5399 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5405 // all those functions return SUCCESS
5406 case 0x00: /* disk controller reset */
5407 case 0x09: /* initialize drive parameters */
5408 case 0x0c: /* seek to specified cylinder */
5409 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5410 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5411 case 0x11: /* recalibrate */
5412 case 0x14: /* controller internal diagnostic */
5413 case 0x16: /* detect disk change */
5417 // all those functions return disk write-protected
5418 case 0x03: /* write disk sectors */
5419 case 0x05: /* format disk track */
5421 goto int13_fail_noah
;
5424 case 0x01: /* read disk status */
5425 status
=read_byte(0x0040, 0x0074);
5427 SET_DISK_RET_STATUS(0);
5429 /* set CF if error status read */
5430 if (status
) goto int13_fail_nostatus
;
5431 else goto int13_success_noah
;
5434 case 0x02: // read disk sectors
5435 case 0x04: // verify disk sectors
5436 vspt
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5437 vcylinders
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
);
5438 vheads
= read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
);
5440 ilba
= read_dword(ebda_seg
,&EbdaData
->cdemu
.ilba
);
5442 sector
= GET_CL() & 0x003f;
5443 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5445 nbsectors
= GET_AL();
5449 // no sector to read ?
5450 if(nbsectors
==0) goto int13_success
;
5452 // sanity checks sco openserver needs this!
5454 || (cylinder
>= vcylinders
)
5455 || (head
>= vheads
)) {
5459 // After controls, verify do nothing
5460 if (GET_AH() == 0x04) goto int13_success
;
5462 segment
= ES
+(BX
/ 16);
5465 // calculate the virtual lba inside the image
5466 vlba
=((((Bit32u
)cylinder
*(Bit32u
)vheads
)+(Bit32u
)head
)*(Bit32u
)vspt
)+((Bit32u
)(sector
-1));
5468 // In advance so we don't loose the count
5472 slba
= (Bit32u
)vlba
/4;
5473 before
= (Bit16u
)vlba
%4;
5476 elba
= (Bit32u
)(vlba
+nbsectors
-1)/4;
5478 memsetb(get_SS(),atacmd
,0,12);
5479 atacmd
[0]=0x28; // READ command
5480 atacmd
[7]=((Bit16u
)(elba
-slba
+1) & 0xff00) >> 8; // Sectors
5481 atacmd
[8]=((Bit16u
)(elba
-slba
+1) & 0x00ff); // Sectors
5482 atacmd
[2]=(ilba
+slba
& 0xff000000) >> 24; // LBA
5483 atacmd
[3]=(ilba
+slba
& 0x00ff0000) >> 16;
5484 atacmd
[4]=(ilba
+slba
& 0x0000ff00) >> 8;
5485 atacmd
[5]=(ilba
+slba
& 0x000000ff);
5486 if((status
= ata_cmd_packet(device
, 12, get_SS(), atacmd
, before
*512, nbsectors
*512L, ATA_DATA_IN
, segment
,offset
)) != 0) {
5487 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status
);
5490 goto int13_fail_noah
;
5496 case 0x08: /* read disk drive parameters */
5497 vspt
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.spt
);
5498 vcylinders
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.cylinders
) - 1;
5499 vheads
=read_word(ebda_seg
,&EbdaData
->cdemu
.vdevice
.heads
) - 1;
5503 SET_CH( vcylinders
& 0xff );
5504 SET_CL((( vcylinders
>> 2) & 0xc0) | ( vspt
& 0x3f ));
5506 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5507 // FIXME ElTorito Harddisk. should send the HD count
5509 switch(read_byte(ebda_seg
,&EbdaData
->cdemu
.media
)) {
5510 case 0x01: SET_BL( 0x02 ); break;
5511 case 0x02: SET_BL( 0x04 ); break;
5512 case 0x03: SET_BL( 0x06 ); break;
5515 DI
= read_word(0x00, 0x1e*4); // INT vector 0x1E
5516 ES
= read_word(0x00, 0x1e*4+2);
5520 case 0x15: /* read disk drive size */
5521 // FIXME ElTorito Harddisk. What geometry to send ?
5523 goto int13_success_noah
;
5526 // all those functions return unimplemented
5527 case 0x0a: /* read disk sectors with ECC */
5528 case 0x0b: /* write disk sectors with ECC */
5529 case 0x18: /* set media type for format */
5530 case 0x41: // IBM/MS installation check
5531 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5532 case 0x42: // IBM/MS extended read
5533 case 0x43: // IBM/MS extended write
5534 case 0x44: // IBM/MS verify sectors
5535 case 0x45: // IBM/MS lock/unlock drive
5536 case 0x46: // IBM/MS eject media
5537 case 0x47: // IBM/MS extended seek
5538 case 0x48: // IBM/MS get drive parameters
5539 case 0x49: // IBM/MS extended media change
5540 case 0x4e: // ? - set hardware configuration
5541 case 0x50: // ? - send packet command
5543 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5549 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5551 SET_DISK_RET_STATUS(GET_AH());
5552 int13_fail_nostatus
:
5553 SET_CF(); // error occurred
5557 SET_AH(0x00); // no error
5559 SET_DISK_RET_STATUS(0x00);
5560 CLEAR_CF(); // no error
5564 // ---------------------------------------------------------------------------
5565 // End of int13 when emulating a device from the cd
5566 // ---------------------------------------------------------------------------
5568 #endif // BX_ELTORITO_BOOT
5570 #else //BX_USE_ATADRV
5573 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
5588 mov ax
,4[bp
] // cylinder
5590 mov bl
,6[bp
] // hd_heads
5593 mov bl
,8[bp
] // head
5595 mov bl
,10[bp
] // hd_sectors
5597 mov bl
,12[bp
] // sector
5626 int13_harddisk(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, DS
, ES
, FLAGS
)
5627 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, DS
, ES
, FLAGS
;
5629 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
5633 Bit16u max_cylinder
, cylinder
, total_sectors
;
5634 Bit16u hd_cylinders
;
5635 Bit8u hd_heads
, hd_sectors
;
5642 Bit16u count
, segment
, offset
;
5646 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
5648 write_byte(0x0040, 0x008e, 0); // clear completion flag
5650 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5652 /* check how many disks first (cmos reg 0x12), return an error if
5653 drive not present */
5654 drive_map
= inb_cmos(0x12);
5655 drive_map
= (((drive_map
& 0xf0)==0) ? 0 : 1) |
5656 (((drive_map
& 0x0f)==0) ? 0 : 2);
5657 n_drives
= (drive_map
==0) ? 0 :
5658 ((drive_map
==3) ? 2 : 1);
5660 if (!(drive_map
& (1<<(GET_DL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5662 SET_DISK_RET_STATUS(0x01);
5663 SET_CF(); /* error occurred */
5669 case 0x00: /* disk controller reset */
5670 BX_DEBUG_INT13_HD("int13_f00\n");
5673 SET_DISK_RET_STATUS(0);
5674 set_diskette_ret_status(0);
5675 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5676 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5677 CLEAR_CF(); /* successful */
5681 case 0x01: /* read disk status */
5682 BX_DEBUG_INT13_HD("int13_f01\n");
5683 status
= read_byte(0x0040, 0x0074);
5685 SET_DISK_RET_STATUS(0);
5686 /* set CF if error status read */
5687 if (status
) SET_CF();
5692 case 0x04: // verify disk sectors
5693 case 0x02: // read disk sectors
5695 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
5697 num_sectors
= GET_AL();
5698 cylinder
= (GET_CL() & 0x00c0) << 2 | GET_CH();
5699 sector
= (GET_CL() & 0x3f);
5703 if (hd_cylinders
> 1024) {
5704 if (hd_cylinders
<= 2048) {
5707 else if (hd_cylinders
<= 4096) {
5710 else if (hd_cylinders
<= 8192) {
5713 else { // hd_cylinders <= 16384
5717 ax
= head
/ hd_heads
;
5718 cyl_mod
= ax
& 0xff;
5720 cylinder
|= cyl_mod
;
5723 if ( (cylinder
>= hd_cylinders
) ||
5724 (sector
> hd_sectors
) ||
5725 (head
>= hd_heads
) ) {
5727 SET_DISK_RET_STATUS(1);
5728 SET_CF(); /* error occurred */
5732 if ( (num_sectors
> 128) || (num_sectors
== 0) )
5733 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5736 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5738 if ( GET_AH() == 0x04 ) {
5740 SET_DISK_RET_STATUS(0);
5745 status
= inb(0x1f7);
5746 if (status
& 0x80) {
5747 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5749 outb(0x01f2, num_sectors
);
5750 /* activate LBA? (tomv) */
5751 if (hd_heads
> 16) {
5752 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder
, head
, sector
);
5753 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
5756 outb(0x01f3, sector
);
5757 outb(0x01f4, cylinder
& 0x00ff);
5758 outb(0x01f5, cylinder
>> 8);
5759 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
5764 status
= inb(0x1f7);
5765 if ( !(status
& 0x80) ) break;
5768 if (status
& 0x01) {
5769 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
5770 } else if ( !(status
& 0x08) ) {
5771 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
5772 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
5779 sti
;; enable higher priority interrupts
5784 ;; store temp bx in real DI
register
5787 mov di
, _int13_harddisk
.tempbx
+ 2 [bp
]
5790 ;; adjust
if there will be an overrun
5792 jbe i13_f02_no_adjust
5794 sub di
, #0x0200 ; sub 512 bytes from offset
5796 add ax
, #0x0020 ; add 512 to segment
5800 mov cx
, #0x0100 ;; counter (256 words = 512b)
5801 mov dx
, #0x01f0 ;; AT data read port
5804 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
5807 ;; store real DI
register back to temp bx
5810 mov _int13_harddisk
.tempbx
+ 2 [bp
], di
5816 if (num_sectors
== 0) {
5817 status
= inb(0x1f7);
5818 if ( (status
& 0xc9) != 0x40 )
5819 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status
);
5823 status
= inb(0x1f7);
5824 if ( (status
& 0xc9) != 0x48 )
5825 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status
);
5831 SET_DISK_RET_STATUS(0);
5832 SET_AL(sector_count
);
5833 CLEAR_CF(); /* successful */
5838 case 0x03: /* write disk sectors */
5839 BX_DEBUG_INT13_HD("int13_f03\n");
5841 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
5843 num_sectors
= GET_AL();
5844 cylinder
= GET_CH();
5845 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
5846 sector
= (GET_CL() & 0x3f);
5849 if (hd_cylinders
> 1024) {
5850 if (hd_cylinders
<= 2048) {
5853 else if (hd_cylinders
<= 4096) {
5856 else if (hd_cylinders
<= 8192) {
5859 else { // hd_cylinders <= 16384
5863 ax
= head
/ hd_heads
;
5864 cyl_mod
= ax
& 0xff;
5866 cylinder
|= cyl_mod
;
5869 if ( (cylinder
>= hd_cylinders
) ||
5870 (sector
> hd_sectors
) ||
5871 (head
>= hd_heads
) ) {
5873 SET_DISK_RET_STATUS(1);
5874 SET_CF(); /* error occurred */
5878 if ( (num_sectors
> 128) || (num_sectors
== 0) )
5879 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5882 BX_PANIC("hard drive BIOS:(read) head > 15\n");
5884 status
= inb(0x1f7);
5885 if (status
& 0x80) {
5886 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
5888 // should check for Drive Ready Bit also in status reg
5889 outb(0x01f2, num_sectors
);
5891 /* activate LBA? (tomv) */
5892 if (hd_heads
> 16) {
5893 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
5894 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_DL());
5897 outb(0x01f3, sector
);
5898 outb(0x01f4, cylinder
& 0x00ff);
5899 outb(0x01f5, cylinder
>> 8);
5900 outb(0x01f6, 0xa0 | ((GET_DL() & 0x01)<<4) | (head
& 0x0f));
5904 // wait for busy bit to turn off after seeking
5906 status
= inb(0x1f7);
5907 if ( !(status
& 0x80) ) break;
5910 if ( !(status
& 0x08) ) {
5911 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status
);
5912 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
5919 sti
;; enable higher priority interrupts
5924 ;; store temp bx in real SI
register
5927 mov si
, _int13_harddisk
.tempbx
+ 2 [bp
]
5930 ;; adjust
if there will be an overrun
5932 jbe i13_f03_no_adjust
5934 sub si
, #0x0200 ; sub 512 bytes from offset
5936 add ax
, #0x0020 ; add 512 to segment
5940 mov cx
, #0x0100 ;; counter (256 words = 512b)
5941 mov dx
, #0x01f0 ;; AT data read port
5945 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
5947 ;; store real SI
register back to temp bx
5950 mov _int13_harddisk
.tempbx
+ 2 [bp
], si
5956 if (num_sectors
== 0) {
5957 status
= inb(0x1f7);
5958 if ( (status
& 0xe9) != 0x40 )
5959 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status
);
5963 status
= inb(0x1f7);
5964 if ( (status
& 0xc9) != 0x48 )
5965 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status
);
5971 SET_DISK_RET_STATUS(0);
5972 SET_AL(sector_count
);
5973 CLEAR_CF(); /* successful */
5977 case 0x05: /* format disk track */
5978 BX_DEBUG_INT13_HD("int13_f05\n");
5979 BX_PANIC("format disk track called\n");
5982 SET_DISK_RET_STATUS(0);
5983 CLEAR_CF(); /* successful */
5987 case 0x08: /* read disk drive parameters */
5988 BX_DEBUG_INT13_HD("int13_f08\n");
5991 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
5995 if (hd_cylinders
<= 1024) {
5996 // hd_cylinders >>= 0;
5999 else if (hd_cylinders
<= 2048) {
6003 else if (hd_cylinders
<= 4096) {
6007 else if (hd_cylinders
<= 8192) {
6011 else { // hd_cylinders <= 16384
6016 max_cylinder
= hd_cylinders
- 2; /* 0 based */
6018 SET_CH(max_cylinder
& 0xff);
6019 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
6020 SET_DH(hd_heads
- 1);
6021 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
6023 SET_DISK_RET_STATUS(0);
6024 CLEAR_CF(); /* successful */
6029 case 0x09: /* initialize drive parameters */
6030 BX_DEBUG_INT13_HD("int13_f09\n");
6032 SET_DISK_RET_STATUS(0);
6033 CLEAR_CF(); /* successful */
6037 case 0x0a: /* read disk sectors with ECC */
6038 BX_DEBUG_INT13_HD("int13_f0a\n");
6039 case 0x0b: /* write disk sectors with ECC */
6040 BX_DEBUG_INT13_HD("int13_f0b\n");
6041 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6045 case 0x0c: /* seek to specified cylinder */
6046 BX_DEBUG_INT13_HD("int13_f0c\n");
6047 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6049 SET_DISK_RET_STATUS(0);
6050 CLEAR_CF(); /* successful */
6054 case 0x0d: /* alternate disk reset */
6055 BX_DEBUG_INT13_HD("int13_f0d\n");
6057 SET_DISK_RET_STATUS(0);
6058 CLEAR_CF(); /* successful */
6062 case 0x10: /* check drive ready */
6063 BX_DEBUG_INT13_HD("int13_f10\n");
6065 //SET_DISK_RET_STATUS(0);
6066 //CLEAR_CF(); /* successful */
6070 // should look at 40:8E also???
6071 status
= inb(0x01f7);
6072 if ( (status
& 0xc0) == 0x40 ) {
6074 SET_DISK_RET_STATUS(0);
6075 CLEAR_CF(); // drive ready
6080 SET_DISK_RET_STATUS(0xAA);
6081 SET_CF(); // not ready
6086 case 0x11: /* recalibrate */
6087 BX_DEBUG_INT13_HD("int13_f11\n");
6089 SET_DISK_RET_STATUS(0);
6090 CLEAR_CF(); /* successful */
6094 case 0x14: /* controller internal diagnostic */
6095 BX_DEBUG_INT13_HD("int13_f14\n");
6097 SET_DISK_RET_STATUS(0);
6098 CLEAR_CF(); /* successful */
6103 case 0x15: /* read disk drive size */
6105 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
6109 mov al
, _int13_harddisk
.hd_heads
+ 2 [bp
]
6110 mov ah
, _int13_harddisk
.hd_sectors
+ 2 [bp
]
6111 mul al
, ah
;; ax
= heads
* sectors
6112 mov bx
, _int13_harddisk
.hd_cylinders
+ 2 [bp
]
6113 dec bx
;; use (cylinders
- 1) ???
6114 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
6115 ;; now we need to move the
32bit result dx
:ax to what the
6116 ;; BIOS wants which is cx
:dx
.
6117 ;; and then into CX
:DX on the stack
6118 mov _int13_harddisk
.CX
+ 2 [bp
], dx
6119 mov _int13_harddisk
.DX
+ 2 [bp
], ax
6122 SET_AH(3); // hard disk accessible
6123 SET_DISK_RET_STATUS(0); // ??? should this be 0
6124 CLEAR_CF(); // successful
6128 case 0x18: // set media type for format
6129 case 0x41: // IBM/MS
6130 case 0x42: // IBM/MS
6131 case 0x43: // IBM/MS
6132 case 0x44: // IBM/MS
6133 case 0x45: // IBM/MS lock/unlock drive
6134 case 0x46: // IBM/MS eject media
6135 case 0x47: // IBM/MS extended seek
6136 case 0x49: // IBM/MS extended media change
6137 case 0x50: // IBM/MS send packet command
6139 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6141 SET_AH(1); // code=invalid function in AH or invalid parameter
6142 SET_DISK_RET_STATUS(1);
6143 SET_CF(); /* unsuccessful */
6149 static char panic_msg_reg12h
[] = "HD%d cmos reg 12h not type F";
6150 static char panic_msg_reg19h
[] = "HD%d cmos reg %02xh not user definable type 47";
6153 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
6155 Bit16u
*hd_cylinders
;
6165 if (drive
== 0x80) {
6166 hd_type
= inb_cmos(0x12) & 0xf0;
6167 if (hd_type
!= 0xf0)
6168 BX_INFO(panic_msg_reg12h
,0);
6169 hd_type
= inb_cmos(0x19); // HD0: extended type
6171 BX_INFO(panic_msg_reg19h
,0,0x19);
6174 hd_type
= inb_cmos(0x12) & 0x0f;
6175 if (hd_type
!= 0x0f)
6176 BX_INFO(panic_msg_reg12h
,1);
6177 hd_type
= inb_cmos(0x1a); // HD0: extended type
6179 BX_INFO(panic_msg_reg19h
,0,0x1a);
6184 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
6185 write_word(ss
, hd_cylinders
, cylinders
);
6188 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
6190 // sectors per track
6191 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
6194 #endif //else BX_USE_ATADRV
6197 //////////////////////
6198 // FLOPPY functions //
6199 //////////////////////
6202 floppy_media_known(drive
)
6206 Bit16u media_state_offset
;
6208 val8
= read_byte(0x0040, 0x003e); // diskette recal status
6215 media_state_offset
= 0x0090;
6217 media_state_offset
+= 1;
6219 val8
= read_byte(0x0040, media_state_offset
);
6220 val8
= (val8
>> 4) & 0x01;
6224 // check pass, return KNOWN
6229 floppy_media_sense(drive
)
6233 Bit16u media_state_offset
;
6234 Bit8u drive_type
, config_data
, media_state
;
6236 if (floppy_drive_recal(drive
) == 0) {
6240 // for now cheat and get drive type from CMOS,
6241 // assume media is same as drive type
6243 // ** config_data **
6244 // Bitfields for diskette media control:
6245 // Bit(s) Description (Table M0028)
6246 // 7-6 last data rate set by controller
6247 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6248 // 5-4 last diskette drive step rate selected
6249 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6250 // 3-2 {data rate at start of operation}
6253 // ** media_state **
6254 // Bitfields for diskette drive media state:
6255 // Bit(s) Description (Table M0030)
6257 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6258 // 5 double stepping required (e.g. 360kB in 1.2MB)
6259 // 4 media type established
6260 // 3 drive capable of supporting 4MB media
6261 // 2-0 on exit from BIOS, contains
6262 // 000 trying 360kB in 360kB
6263 // 001 trying 360kB in 1.2MB
6264 // 010 trying 1.2MB in 1.2MB
6265 // 011 360kB in 360kB established
6266 // 100 360kB in 1.2MB established
6267 // 101 1.2MB in 1.2MB established
6269 // 111 all other formats/drives
6271 drive_type
= inb_cmos(0x10);
6276 if ( drive_type
== 1 ) {
6278 config_data
= 0x00; // 0000 0000
6279 media_state
= 0x25; // 0010 0101
6282 else if ( drive_type
== 2 ) {
6283 // 1.2 MB 5.25" drive
6284 config_data
= 0x00; // 0000 0000
6285 media_state
= 0x25; // 0010 0101 // need double stepping??? (bit 5)
6288 else if ( drive_type
== 3 ) {
6290 config_data
= 0x00; // 0000 0000 ???
6291 media_state
= 0x17; // 0001 0111
6294 else if ( drive_type
== 4 ) {
6295 // 1.44 MB 3.5" drive
6296 config_data
= 0x00; // 0000 0000
6297 media_state
= 0x17; // 0001 0111
6300 else if ( drive_type
== 5 ) {
6301 // 2.88 MB 3.5" drive
6302 config_data
= 0xCC; // 1100 1100
6303 media_state
= 0xD7; // 1101 0111
6307 // Extended floppy size uses special cmos setting
6308 else if ( drive_type
== 6 ) {
6310 config_data
= 0x00; // 0000 0000
6311 media_state
= 0x27; // 0010 0111
6314 else if ( drive_type
== 7 ) {
6316 config_data
= 0x00; // 0000 0000
6317 media_state
= 0x27; // 0010 0111
6320 else if ( drive_type
== 8 ) {
6322 config_data
= 0x00; // 0000 0000
6323 media_state
= 0x27; // 0010 0111
6329 config_data
= 0x00; // 0000 0000
6330 media_state
= 0x00; // 0000 0000
6335 media_state_offset
= 0x90;
6337 media_state_offset
= 0x91;
6338 write_byte(0x0040, 0x008B, config_data
);
6339 write_byte(0x0040, media_state_offset
, media_state
);
6345 floppy_drive_recal(drive
)
6349 Bit16u curr_cyl_offset
;
6351 // set 40:3e bit 7 to 0
6352 val8
= read_byte(0x0000, 0x043e);
6354 write_byte(0x0000, 0x043e, val8
);
6356 // turn on motor of selected drive, DMA & int enabled, normal operation
6365 // reset the disk motor timeout value of INT 08
6366 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6368 // check port 3f4 for drive readiness
6370 if ( (val8
& 0xf0) != 0x80 )
6371 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6373 // send Recalibrate command (2 bytes) to controller
6374 outb(0x03f5, 0x07); // 07: Recalibrate
6375 outb(0x03f5, drive
); // 0=drive0, 1=drive1
6377 // turn on interrupts
6382 // wait on 40:3e bit 7 to become 1
6383 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6384 while ( val8
== 0 ) {
6385 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6388 val8
= 0; // separate asm from while() loop
6389 // turn off interrupts
6394 // set 40:3e bit 7 to 0, and calibrated bit
6395 val8
= read_byte(0x0000, 0x043e);
6398 val8
|= 0x02; // Drive 1 calibrated
6399 curr_cyl_offset
= 0x0095;
6402 val8
|= 0x01; // Drive 0 calibrated
6403 curr_cyl_offset
= 0x0094;
6405 write_byte(0x0040, 0x003e, val8
);
6406 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
6414 floppy_drive_exists(drive
)
6419 // check CMOS to see if drive exists
6420 drive_type
= inb_cmos(0x10);
6425 if ( drive_type
== 0 )
6431 #if BX_SUPPORT_FLOPPY
6433 int13_diskette_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
)
6434 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
;
6436 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
6437 Bit16u base_address
, base_count
, base_es
;
6438 Bit8u page
, mode_register
, val8
, dor
;
6439 Bit8u return_status
[7];
6440 Bit8u drive_type
, num_floppies
, ah
;
6441 Bit16u es
, last_addr
;
6443 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX
, BX
, CX
, DX
, ES
);
6444 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6449 case 0x00: // diskette controller reset
6450 BX_DEBUG_INT13_FL("floppy f00\n");
6453 SET_AH(1); // invalid param
6454 set_diskette_ret_status(1);
6458 drive_type
= inb_cmos(0x10);
6464 if (drive_type
== 0) {
6465 SET_AH(0x80); // drive not responding
6466 set_diskette_ret_status(0x80);
6471 set_diskette_ret_status(0);
6472 CLEAR_CF(); // successful
6473 set_diskette_current_cyl(drive
, 0); // current cylinder
6476 case 0x01: // Read Diskette Status
6478 val8
= read_byte(0x0000, 0x0441);
6485 case 0x02: // Read Diskette Sectors
6486 case 0x03: // Write Diskette Sectors
6487 case 0x04: // Verify Diskette Sectors
6488 num_sectors
= GET_AL();
6494 if ( (drive
> 1) || (head
> 1) ||
6495 (num_sectors
== 0) || (num_sectors
> 72) ) {
6496 BX_INFO("floppy: drive>1 || head>1 ...\n");
6498 set_diskette_ret_status(1);
6499 SET_AL(0); // no sectors read
6500 SET_CF(); // error occurred
6504 // see if drive exists
6505 if (floppy_drive_exists(drive
) == 0) {
6506 SET_AH(0x80); // not responding
6507 set_diskette_ret_status(0x80);
6508 SET_AL(0); // no sectors read
6509 SET_CF(); // error occurred
6513 // see if media in drive, and type is known
6514 if (floppy_media_known(drive
) == 0) {
6515 if (floppy_media_sense(drive
) == 0) {
6516 SET_AH(0x0C); // Media type not found
6517 set_diskette_ret_status(0x0C);
6518 SET_AL(0); // no sectors read
6519 SET_CF(); // error occurred
6525 // Read Diskette Sectors
6527 //-----------------------------------
6528 // set up DMA controller for transfer
6529 //-----------------------------------
6531 // es:bx = pointer to where to place information from diskette
6532 // port 04: DMA-1 base and current address, channel 2
6533 // port 05: DMA-1 base and current count, channel 2
6534 page
= (ES
>> 12); // upper 4 bits
6535 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6536 base_address
= base_es
+ BX
; // lower 16 bits of address
6537 // contributed by ES:BX
6538 if ( base_address
< base_es
) {
6539 // in case of carry, adjust page by 1
6542 base_count
= (num_sectors
* 512) - 1;
6544 // check for 64K boundary overrun
6545 last_addr
= base_address
+ base_count
;
6546 if (last_addr
< base_address
) {
6548 set_diskette_ret_status(0x09);
6549 SET_AL(0); // no sectors read
6550 SET_CF(); // error occurred
6554 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6557 BX_DEBUG_INT13_FL("clear flip-flop\n");
6558 outb(0x000c, 0x00); // clear flip-flop
6559 outb(0x0004, base_address
);
6560 outb(0x0004, base_address
>>8);
6561 BX_DEBUG_INT13_FL("clear flip-flop\n");
6562 outb(0x000c, 0x00); // clear flip-flop
6563 outb(0x0005, base_count
);
6564 outb(0x0005, base_count
>>8);
6566 // port 0b: DMA-1 Mode Register
6567 mode_register
= 0x46; // single mode, increment, autoinit disable,
6568 // transfer type=write, channel 2
6569 BX_DEBUG_INT13_FL("setting mode register\n");
6570 outb(0x000b, mode_register
);
6572 BX_DEBUG_INT13_FL("setting page register\n");
6573 // port 81: DMA-1 Page Register, channel 2
6576 BX_DEBUG_INT13_FL("unmask chan 2\n");
6577 outb(0x000a, 0x02); // unmask channel 2
6579 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6582 //--------------------------------------
6583 // set up floppy controller for transfer
6584 //--------------------------------------
6586 // set 40:3e bit 7 to 0
6587 val8
= read_byte(0x0000, 0x043e);
6589 write_byte(0x0000, 0x043e, val8
);
6591 // turn on motor of selected drive, DMA & int enabled, normal operation
6600 // reset the disk motor timeout value of INT 08
6601 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6603 // check port 3f4 for drive readiness
6605 if ( (val8
& 0xf0) != 0x80 )
6606 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6608 // send read-normal-data command (9 bytes) to controller
6609 outb(0x03f5, 0xe6); // e6: read normal data
6610 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6611 outb(0x03f5, track
);
6613 outb(0x03f5, sector
);
6614 outb(0x03f5, 2); // 512 byte sector size
6615 outb(0x03f5, 0); // last sector number possible on track
6616 outb(0x03f5, 0); // Gap length
6617 outb(0x03f5, 0xff); // Gap length
6619 // turn on interrupts
6624 // wait on 40:3e bit 7 to become 1
6625 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6626 while ( val8
== 0 ) {
6627 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6630 val8
= 0; // separate asm from while() loop
6631 // turn off interrupts
6636 // set 40:3e bit 7 to 0
6637 val8
= read_byte(0x0000, 0x043e);
6639 write_byte(0x0000, 0x043e, val8
);
6641 // check port 3f4 for accessibility to status bytes
6643 if ( (val8
& 0xc0) != 0xc0 )
6644 BX_PANIC("int13_diskette: ctrl not ready\n");
6646 // read 7 return status bytes from controller
6647 // using loop index broken, have to unroll...
6648 return_status
[0] = inb(0x3f5);
6649 return_status
[1] = inb(0x3f5);
6650 return_status
[2] = inb(0x3f5);
6651 return_status
[3] = inb(0x3f5);
6652 return_status
[4] = inb(0x3f5);
6653 return_status
[5] = inb(0x3f5);
6654 return_status
[6] = inb(0x3f5);
6655 // record in BIOS Data Area
6656 write_byte(0x0040, 0x0042, return_status
[0]);
6657 write_byte(0x0040, 0x0043, return_status
[1]);
6658 write_byte(0x0040, 0x0044, return_status
[2]);
6659 write_byte(0x0040, 0x0045, return_status
[3]);
6660 write_byte(0x0040, 0x0046, return_status
[4]);
6661 write_byte(0x0040, 0x0047, return_status
[5]);
6662 write_byte(0x0040, 0x0048, return_status
[6]);
6664 if ( (return_status
[0] & 0xc0) != 0 ) {
6666 set_diskette_ret_status(0x20);
6667 SET_AL(0); // no sectors read
6668 SET_CF(); // error occurred
6672 // ??? should track be new val from return_status[3] ?
6673 set_diskette_current_cyl(drive
, track
);
6674 // AL = number of sectors read (same value as passed)
6675 SET_AH(0x00); // success
6676 CLEAR_CF(); // success
6679 else if (ah
== 0x03) {
6680 // Write Diskette Sectors
6682 //-----------------------------------
6683 // set up DMA controller for transfer
6684 //-----------------------------------
6686 // es:bx = pointer to where to place information from diskette
6687 // port 04: DMA-1 base and current address, channel 2
6688 // port 05: DMA-1 base and current count, channel 2
6689 page
= (ES
>> 12); // upper 4 bits
6690 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6691 base_address
= base_es
+ BX
; // lower 16 bits of address
6692 // contributed by ES:BX
6693 if ( base_address
< base_es
) {
6694 // in case of carry, adjust page by 1
6697 base_count
= (num_sectors
* 512) - 1;
6699 // check for 64K boundary overrun
6700 last_addr
= base_address
+ base_count
;
6701 if (last_addr
< base_address
) {
6703 set_diskette_ret_status(0x09);
6704 SET_AL(0); // no sectors read
6705 SET_CF(); // error occurred
6709 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6712 outb(0x000c, 0x00); // clear flip-flop
6713 outb(0x0004, base_address
);
6714 outb(0x0004, base_address
>>8);
6715 outb(0x000c, 0x00); // clear flip-flop
6716 outb(0x0005, base_count
);
6717 outb(0x0005, base_count
>>8);
6719 // port 0b: DMA-1 Mode Register
6720 mode_register
= 0x4a; // single mode, increment, autoinit disable,
6721 // transfer type=read, channel 2
6722 outb(0x000b, mode_register
);
6724 // port 81: DMA-1 Page Register, channel 2
6727 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6730 //--------------------------------------
6731 // set up floppy controller for transfer
6732 //--------------------------------------
6734 // set 40:3e bit 7 to 0
6735 val8
= read_byte(0x0000, 0x043e);
6737 write_byte(0x0000, 0x043e, val8
);
6739 // turn on motor of selected drive, DMA & int enabled, normal operation
6748 // reset the disk motor timeout value of INT 08
6749 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6751 // check port 3f4 for drive readiness
6753 if ( (val8
& 0xf0) != 0x80 )
6754 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
6756 // send read-normal-data command (9 bytes) to controller
6757 outb(0x03f5, 0xc5); // c5: write normal data
6758 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6759 outb(0x03f5, track
);
6761 outb(0x03f5, sector
);
6762 outb(0x03f5, 2); // 512 byte sector size
6763 outb(0x03f5, 0); // last sector number possible on track
6764 outb(0x03f5, 0); // Gap length
6765 outb(0x03f5, 0xff); // Gap length
6767 // turn on interrupts
6772 // wait on 40:3e bit 7 to become 1
6773 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6774 while ( val8
== 0 ) {
6775 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6778 val8
= 0; // separate asm from while() loop
6779 // turn off interrupts
6784 // set 40:3e bit 7 to 0
6785 val8
= read_byte(0x0000, 0x043e);
6787 write_byte(0x0000, 0x043e, val8
);
6789 // check port 3f4 for accessibility to status bytes
6791 if ( (val8
& 0xc0) != 0xc0 )
6792 BX_PANIC("int13_diskette: ctrl not ready\n");
6794 // read 7 return status bytes from controller
6795 // using loop index broken, have to unroll...
6796 return_status
[0] = inb(0x3f5);
6797 return_status
[1] = inb(0x3f5);
6798 return_status
[2] = inb(0x3f5);
6799 return_status
[3] = inb(0x3f5);
6800 return_status
[4] = inb(0x3f5);
6801 return_status
[5] = inb(0x3f5);
6802 return_status
[6] = inb(0x3f5);
6803 // record in BIOS Data Area
6804 write_byte(0x0040, 0x0042, return_status
[0]);
6805 write_byte(0x0040, 0x0043, return_status
[1]);
6806 write_byte(0x0040, 0x0044, return_status
[2]);
6807 write_byte(0x0040, 0x0045, return_status
[3]);
6808 write_byte(0x0040, 0x0046, return_status
[4]);
6809 write_byte(0x0040, 0x0047, return_status
[5]);
6810 write_byte(0x0040, 0x0048, return_status
[6]);
6812 if ( (return_status
[0] & 0xc0) != 0 ) {
6813 if ( (return_status
[1] & 0x02) != 0 ) {
6814 // diskette not writable.
6815 // AH=status code=0x03 (tried to write on write-protected disk)
6816 // AL=number of sectors written=0
6821 BX_PANIC("int13_diskette_function: read error\n");
6825 // ??? should track be new val from return_status[3] ?
6826 set_diskette_current_cyl(drive
, track
);
6827 // AL = number of sectors read (same value as passed)
6828 SET_AH(0x00); // success
6829 CLEAR_CF(); // success
6832 else { // if (ah == 0x04)
6833 // Verify Diskette Sectors
6835 // ??? should track be new val from return_status[3] ?
6836 set_diskette_current_cyl(drive
, track
);
6837 // AL = number of sectors verified (same value as passed)
6838 CLEAR_CF(); // success
6839 SET_AH(0x00); // success
6844 case 0x05: // format diskette track
6845 BX_DEBUG_INT13_FL("floppy f05\n");
6847 num_sectors
= GET_AL();
6852 if ((drive
> 1) || (head
> 1) || (track
> 79) ||
6853 (num_sectors
== 0) || (num_sectors
> 18)) {
6855 set_diskette_ret_status(1);
6856 SET_CF(); // error occurred
6859 // see if drive exists
6860 if (floppy_drive_exists(drive
) == 0) {
6861 SET_AH(0x80); // drive not responding
6862 set_diskette_ret_status(0x80);
6863 SET_CF(); // error occurred
6867 // see if media in drive, and type is known
6868 if (floppy_media_known(drive
) == 0) {
6869 if (floppy_media_sense(drive
) == 0) {
6870 SET_AH(0x0C); // Media type not found
6871 set_diskette_ret_status(0x0C);
6872 SET_AL(0); // no sectors read
6873 SET_CF(); // error occurred
6878 // set up DMA controller for transfer
6879 page
= (ES
>> 12); // upper 4 bits
6880 base_es
= (ES
<< 4); // lower 16bits contributed by ES
6881 base_address
= base_es
+ BX
; // lower 16 bits of address
6882 // contributed by ES:BX
6883 if ( base_address
< base_es
) {
6884 // in case of carry, adjust page by 1
6887 base_count
= (num_sectors
* 4) - 1;
6889 // check for 64K boundary overrun
6890 last_addr
= base_address
+ base_count
;
6891 if (last_addr
< base_address
) {
6893 set_diskette_ret_status(0x09);
6894 SET_AL(0); // no sectors read
6895 SET_CF(); // error occurred
6900 outb(0x000c, 0x00); // clear flip-flop
6901 outb(0x0004, base_address
);
6902 outb(0x0004, base_address
>>8);
6903 outb(0x000c, 0x00); // clear flip-flop
6904 outb(0x0005, base_count
);
6905 outb(0x0005, base_count
>>8);
6906 mode_register
= 0x4a; // single mode, increment, autoinit disable,
6907 // transfer type=read, channel 2
6908 outb(0x000b, mode_register
);
6909 // port 81: DMA-1 Page Register, channel 2
6913 // set up floppy controller for transfer
6914 val8
= read_byte(0x0000, 0x043e);
6916 write_byte(0x0000, 0x043e, val8
);
6917 // turn on motor of selected drive, DMA & int enabled, normal operation
6926 // reset the disk motor timeout value of INT 08
6927 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT
);
6929 // check port 3f4 for drive readiness
6931 if ( (val8
& 0xf0) != 0x80 )
6932 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
6934 // send read-normal-data command (6 bytes) to controller
6935 outb(0x03f5, 0x4d); // 4d: format track
6936 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
6937 outb(0x03f5, 2); // 512 byte sector size
6938 outb(0x03f5, num_sectors
); // number of sectors per track
6939 outb(0x03f5, 0); // Gap length
6940 outb(0x03f5, 0xf6); // Fill byte
6941 // turn on interrupts
6945 // wait on 40:3e bit 7 to become 1
6946 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6947 while ( val8
== 0 ) {
6948 val8
= (read_byte(0x0000, 0x043e) & 0x80);
6950 val8
= 0; // separate asm from while() loop
6951 // turn off interrupts
6955 // set 40:3e bit 7 to 0
6956 val8
= read_byte(0x0000, 0x043e);
6958 write_byte(0x0000, 0x043e, val8
);
6959 // check port 3f4 for accessibility to status bytes
6961 if ( (val8
& 0xc0) != 0xc0 )
6962 BX_PANIC("int13_diskette: ctrl not ready\n");
6964 // read 7 return status bytes from controller
6965 // using loop index broken, have to unroll...
6966 return_status
[0] = inb(0x3f5);
6967 return_status
[1] = inb(0x3f5);
6968 return_status
[2] = inb(0x3f5);
6969 return_status
[3] = inb(0x3f5);
6970 return_status
[4] = inb(0x3f5);
6971 return_status
[5] = inb(0x3f5);
6972 return_status
[6] = inb(0x3f5);
6973 // record in BIOS Data Area
6974 write_byte(0x0040, 0x0042, return_status
[0]);
6975 write_byte(0x0040, 0x0043, return_status
[1]);
6976 write_byte(0x0040, 0x0044, return_status
[2]);
6977 write_byte(0x0040, 0x0045, return_status
[3]);
6978 write_byte(0x0040, 0x0046, return_status
[4]);
6979 write_byte(0x0040, 0x0047, return_status
[5]);
6980 write_byte(0x0040, 0x0048, return_status
[6]);
6982 if ( (return_status
[0] & 0xc0) != 0 ) {
6983 if ( (return_status
[1] & 0x02) != 0 ) {
6984 // diskette not writable.
6985 // AH=status code=0x03 (tried to write on write-protected disk)
6986 // AL=number of sectors written=0
6991 BX_PANIC("int13_diskette_function: write error\n");
6996 set_diskette_ret_status(0);
6997 set_diskette_current_cyl(drive
, 0);
6998 CLEAR_CF(); // successful
7002 case 0x08: // read diskette drive parameters
7003 BX_DEBUG_INT13_FL("floppy f08\n");
7013 SET_DL(num_floppies
);
7018 drive_type
= inb_cmos(0x10);
7020 if (drive_type
& 0xf0)
7022 if (drive_type
& 0x0f)
7034 SET_DL(num_floppies
);
7036 switch (drive_type
) {
7039 SET_DH(0); // max head #
7042 case 1: // 360KB, 5.25"
7043 CX
= 0x2709; // 40 tracks, 9 sectors
7044 SET_DH(1); // max head #
7047 case 2: // 1.2MB, 5.25"
7048 CX
= 0x4f0f; // 80 tracks, 15 sectors
7049 SET_DH(1); // max head #
7052 case 3: // 720KB, 3.5"
7053 CX
= 0x4f09; // 80 tracks, 9 sectors
7054 SET_DH(1); // max head #
7057 case 4: // 1.44MB, 3.5"
7058 CX
= 0x4f12; // 80 tracks, 18 sectors
7059 SET_DH(1); // max head #
7062 case 5: // 2.88MB, 3.5"
7063 CX
= 0x4f24; // 80 tracks, 36 sectors
7064 SET_DH(1); // max head #
7067 case 6: // 160k, 5.25"
7068 CX
= 0x2708; // 40 tracks, 8 sectors
7069 SET_DH(0); // max head #
7072 case 7: // 180k, 5.25"
7073 CX
= 0x2709; // 40 tracks, 9 sectors
7074 SET_DH(0); // max head #
7077 case 8: // 320k, 5.25"
7078 CX
= 0x2708; // 40 tracks, 8 sectors
7079 SET_DH(1); // max head #
7083 BX_PANIC("floppy: int13: bad floppy type\n");
7086 /* set es & di to point to 11 byte diskette param table in ROM */
7087 DI
= read_word(0x00, 0x1e*4); // INT vector 0x1E
7088 ES
= read_word(0x00, 0x1e*4+2);
7089 CLEAR_CF(); // success
7090 /* disk status not changed upon success */
7094 case 0x15: // read diskette drive type
7095 BX_DEBUG_INT13_FL("floppy f15\n");
7098 SET_AH(0); // only 2 drives supported
7099 // set_diskette_ret_status here ???
7103 drive_type
= inb_cmos(0x10);
7109 CLEAR_CF(); // successful, not present
7110 if (drive_type
==0) {
7111 SET_AH(0); // drive not present
7114 SET_AH(1); // drive present, does not support change line
7117 #if BX_ELTORITO_BOOT
7118 // This is mandatory. Otherwise Win98 does not boot
7119 if ((cdemu_isactive() != 00) && (cdemu_emulated_drive() == drive
))
7124 case 0x16: // get diskette change line status
7125 BX_DEBUG_INT13_FL("floppy f16\n");
7128 SET_AH(0x01); // invalid drive
7129 set_diskette_ret_status(0x01);
7134 SET_AH(0x06); // change line not supported
7135 set_diskette_ret_status(0x06);
7139 case 0x17: // set diskette type for format(old)
7140 BX_DEBUG_INT13_FL("floppy f17\n");
7141 /* not used for 1.44M floppies */
7142 SET_AH(0x01); // not supported
7143 set_diskette_ret_status(1); /* not supported */
7147 case 0x18: // set diskette type for format(new)
7148 BX_DEBUG_INT13_FL("floppy f18\n");
7149 SET_AH(0x01); // do later
7150 set_diskette_ret_status(1);
7155 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7157 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7158 SET_AH(0x01); // ???
7159 set_diskette_ret_status(1);
7165 #else // #if BX_SUPPORT_FLOPPY
7167 int13_diskette_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
)
7168 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
;
7172 switch ( GET_AH() ) {
7174 case 0x01: // Read Diskette Status
7176 val8
= read_byte(0x0000, 0x0441);
7185 write_byte(0x0000, 0x0441, 0x01);
7189 #endif // #if BX_SUPPORT_FLOPPY
7192 set_diskette_ret_status(value
)
7195 write_byte(0x0040, 0x0041, value
);
7199 set_diskette_current_cyl(drive
, cyl
)
7204 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7205 write_byte(0x0040, 0x0094+drive
, cyl
);
7209 determine_floppy_media(drive
)
7213 Bit8u val8
, DOR
, ctrl_info
;
7215 ctrl_info
= read_byte(0x0040, 0x008F);
7223 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7226 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7230 if ( (ctrl_info
& 0x04) != 0x04 ) {
7231 // Drive not determined means no drive exists, done.
7236 // check Main Status Register for readiness
7237 val8
= inb(0x03f4) & 0x80; // Main Status Register
7239 BX_PANIC("d_f_m: MRQ bit not set\n");
7243 // existing BDA values
7245 // turn on drive motor
7246 outb(0x03f2, DOR
); // Digital Output Register
7249 BX_PANIC("d_f_m: OK so far\n");
7254 int17_function(regs
, ds
, iret_addr
)
7255 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7256 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7257 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7259 Bit16u addr
,timeout
;
7266 addr
= read_word(0x0040, (regs
.u
.r16
.dx
<< 1) + 8);
7267 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
< 3) && (addr
> 0)) {
7268 timeout
= read_byte(0x0040, 0x0078 + regs
.u
.r16
.dx
) << 8;
7269 if (regs
.u
.r8
.ah
== 0) {
7270 outb(addr
, regs
.u
.r8
.al
);
7272 outb(addr
+2, val8
| 0x01); // send strobe
7276 outb(addr
+2, val8
& ~0x01);
7277 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
7281 if (regs
.u
.r8
.ah
== 1) {
7283 outb(addr
+2, val8
& ~0x04); // send init
7287 outb(addr
+2, val8
| 0x04);
7289 regs
.u
.r8
.ah
= inb(addr
+1);
7290 val8
= (~regs
.u
.r8
.ah
& 0x48);
7291 regs
.u
.r8
.ah
&= 0xB7;
7292 regs
.u
.r8
.ah
|= val8
;
7293 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
7294 ClearCF(iret_addr
.flags
);
7296 SetCF(iret_addr
.flags
); // Unsupported
7300 // returns bootsegment in ax, drive in bl
7304 Bit16u ebda_seg
=read_word(0x0040,0x000E);
7312 // if BX_ELTORITO_BOOT is not defined, old behavior
7313 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7314 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7315 // 0: system boot sequence, first drive C: then A:
7316 // 1: system boot sequence, first drive A: then C:
7317 // else BX_ELTORITO_BOOT is defined
7318 // CMOS reg 0x3D contains the boot device :
7322 // else : floppy for now.
7324 // Get the boot sequence
7325 #if BX_ELTORITO_BOOT
7326 bootseq
=inb_cmos(0x3d);
7328 bootdrv
=0x00; bootcd
=0;
7330 case 0x01: bootdrv
=0x00; bootcd
=0; break;
7331 case 0x02: bootdrv
=0x80; bootcd
=0; break;
7332 case 0x03: bootdrv
=0x00; bootcd
=1; break;
7335 bootseq
=inb_cmos(0x2d);
7337 bootdrv
=0x00; bootcd
=0;
7338 if((bootseq
&0x20)==0) bootdrv
=0x80;
7339 #endif // BX_ELTORITO_BOOT
7341 #if BX_ELTORITO_BOOT
7342 // We have to boot from cd
7344 status
= cdrom_boot();
7347 if ( (status
& 0x00ff) !=0 ) {
7348 print_cdromboot_failure(status
);
7349 print_boot_failure(bootcd
, bootdrv
, 1);
7353 bootseg
= read_word(ebda_seg
,&EbdaData
->cdemu
.load_segment
);
7354 bootdrv
= (Bit8u
)(status
>>8);
7357 #endif // BX_ELTORITO_BOOT
7359 // We have to boot from harddisk or floppy
7368 mov _int19_function
.status
+ 2[bp
], ax
7369 mov dl
, _int19_function
.bootdrv
+ 2[bp
]
7370 mov ax
, _int19_function
.bootseg
+ 2[bp
]
7371 mov es
, ax
;; segment
7372 mov bx
, #0x0000 ;; offset
7373 mov ah
, #0x02 ;; function 2, read diskette sector
7374 mov al
, #0x01 ;; read 1 sector
7375 mov ch
, #0x00 ;; track 0
7376 mov cl
, #0x01 ;; sector 1
7377 mov dh
, #0x00 ;; head 0
7378 int #0x13 ;; read sector
7381 mov _int19_function
.status
+ 2[bp
], ax
7388 print_boot_failure(bootcd
, bootdrv
, 1);
7393 // check signature if instructed by cmos reg 0x38, only for floppy
7394 // bootchk = 1 : signature check disabled
7395 // bootchk = 0 : signature check enabled
7396 if (bootdrv
!= 0) bootchk
= 0;
7397 else bootchk
= inb_cmos(0x38);
7399 #if BX_ELTORITO_BOOT
7400 // if boot from cd, no signature check
7403 #endif // BX_ELTORITO_BOOT
7406 if (read_word(bootseg
,0x1fe) != 0xaa55) {
7407 print_boot_failure(bootcd
, bootdrv
, 0);
7412 #if BX_ELTORITO_BOOT
7413 // Print out the boot string
7414 print_boot_device(bootcd
, bootdrv
);
7415 #else // BX_ELTORITO_BOOT
7416 print_boot_device(0, bootdrv
);
7417 #endif // BX_ELTORITO_BOOT
7419 // return the boot segment
7420 return (((Bit32u
)bootdrv
) << 16) + bootseg
;
7424 int1a_function(regs
, ds
, iret_addr
)
7425 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7426 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7427 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7431 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
);
7437 switch (regs
.u
.r8
.ah
) {
7438 case 0: // get current clock count
7442 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
7443 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
7444 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
7445 BiosData
->midnight_flag
= 0; // reset flag
7450 ClearCF(iret_addr
.flags
); // OK
7453 case 1: // Set Current Clock Count
7457 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
7458 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
7459 BiosData
->midnight_flag
= 0; // reset flag
7464 ClearCF(iret_addr
.flags
); // OK
7468 case 2: // Read CMOS Time
7469 if (rtc_updating()) {
7470 SetCF(iret_addr
.flags
);
7474 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
7475 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
7476 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
7477 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
7479 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7480 ClearCF(iret_addr
.flags
); // OK
7483 case 3: // Set CMOS Time
7484 // Using a debugger, I notice the following masking/setting
7485 // of bits in Status Register B, by setting Reg B to
7486 // a few values and getting its value after INT 1A was called.
7488 // try#1 try#2 try#3
7489 // before 1111 1101 0111 1101 0000 0000
7490 // after 0110 0010 0110 0010 0000 0010
7492 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7493 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7494 if (rtc_updating()) {
7496 // fall through as if an update were not in progress
7498 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
7499 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
7500 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
7501 // Set Daylight Savings time enabled bit to requested value
7502 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
7503 // (reg B already selected)
7504 outb_cmos(0x0b, val8
);
7506 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7507 ClearCF(iret_addr
.flags
); // OK
7510 case 4: // Read CMOS Date
7512 if (rtc_updating()) {
7513 SetCF(iret_addr
.flags
);
7516 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
7517 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
7518 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
7519 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
7520 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
7521 ClearCF(iret_addr
.flags
); // OK
7524 case 5: // Set CMOS Date
7525 // Using a debugger, I notice the following masking/setting
7526 // of bits in Status Register B, by setting Reg B to
7527 // a few values and getting its value after INT 1A was called.
7529 // try#1 try#2 try#3 try#4
7530 // before 1111 1101 0111 1101 0000 0010 0000 0000
7531 // after 0110 1101 0111 1101 0000 0010 0000 0000
7533 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7534 // My assumption: RegB = (RegB & 01111111b)
7535 if (rtc_updating()) {
7537 SetCF(iret_addr
.flags
);
7540 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
7541 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
7542 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
7543 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
7544 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7545 outb_cmos(0x0b, val8
);
7547 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
7548 ClearCF(iret_addr
.flags
); // OK
7551 case 6: // Set Alarm Time in CMOS
7552 // Using a debugger, I notice the following masking/setting
7553 // of bits in Status Register B, by setting Reg B to
7554 // a few values and getting its value after INT 1A was called.
7556 // try#1 try#2 try#3
7557 // before 1101 1111 0101 1111 0000 0000
7558 // after 0110 1111 0111 1111 0010 0000
7560 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7561 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7562 val8
= inb_cmos(0x0b); // Get Status Reg B
7565 // Alarm interrupt enabled already
7566 SetCF(iret_addr
.flags
); // Error: alarm in use
7569 if (rtc_updating()) {
7571 // fall through as if an update were not in progress
7573 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
7574 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
7575 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
7576 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7577 // enable Status Reg B alarm bit, clear halt clock bit
7578 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
7579 ClearCF(iret_addr
.flags
); // OK
7582 case 7: // Turn off Alarm
7583 // Using a debugger, I notice the following masking/setting
7584 // of bits in Status Register B, by setting Reg B to
7585 // a few values and getting its value after INT 1A was called.
7587 // try#1 try#2 try#3 try#4
7588 // before 1111 1101 0111 1101 0010 0000 0010 0010
7589 // after 0100 0101 0101 0101 0000 0000 0000 0010
7591 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7592 // My assumption: RegB = (RegB & 01010111b)
7593 val8
= inb_cmos(0x0b); // Get Status Reg B
7594 // clear clock-halt bit, disable alarm bit
7595 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
7597 regs
.u
.r8
.al
= val8
; // val last written to Reg B
7598 ClearCF(iret_addr
.flags
); // OK
7602 // real mode PCI BIOS functions now handled in assembler code
7603 // this C code handles the error code for information only
7604 if (regs
.u
.r8
.al
== 0xff) {
7605 BX_INFO("PCI BIOS not present\n");
7606 } else if (regs
.u
.r8
.al
== 0x81) {
7607 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
7608 } else if (regs
.u
.r8
.al
== 0x83) {
7609 BX_INFO("bad PCI vendor ID %04x\n", regs
.u
.r16
.dx
);
7610 } else if (regs
.u
.r8
.al
== 0x86) {
7611 BX_INFO("PCI device %04x:%04x not found\n", regs
.u
.r16
.dx
, regs
.u
.r16
.cx
);
7613 regs
.u
.r8
.ah
= regs
.u
.r8
.al
;
7614 SetCF(iret_addr
.flags
);
7619 SetCF(iret_addr
.flags
); // Unsupported
7624 int70_function(regs
, ds
, iret_addr
)
7625 pusha_regs_t regs
; // regs pushed from PUSHA instruction
7626 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
7627 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
7629 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7630 Bit8u registerB
= 0, registerC
= 0;
7632 // Check which modes are enabled and have occurred.
7633 registerB
= inb_cmos( 0xB );
7634 registerC
= inb_cmos( 0xC );
7636 if( ( registerB
& 0x60 ) != 0 ) {
7637 if( ( registerC
& 0x20 ) != 0 ) {
7638 // Handle Alarm Interrupt.
7645 if( ( registerC
& 0x40 ) != 0 ) {
7646 // Handle Periodic Interrupt.
7648 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7649 // Wait Interval (Int 15, AH=83) active.
7650 Bit32u time
, toggle
;
7652 time
= read_dword( 0x40, 0x9C ); // Time left in microseconds.
7653 if( time
< 0x3D1 ) {
7655 Bit16u segment
, offset
;
7657 offset
= read_word( 0x40, 0x98 );
7658 segment
= read_word( 0x40, 0x9A );
7659 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7660 outb_cmos( 0xB, registerB
& 0x37 ); // Clear the Periodic Interrupt.
7661 write_byte( segment
, offset
, 0x80 ); // Write to specified flag byte.
7663 // Continue waiting.
7665 write_dword( 0x40, 0x9C, time
);
7678 ;------------------------------------------
7679 ;- INT74h
: PS
/2 mouse hardware interrupt
-
7680 ;------------------------------------------
7685 push
#0x00 ;; placeholder for status
7686 push
#0x00 ;; placeholder for X
7687 push
#0x00 ;; placeholder for Y
7688 push
#0x00 ;; placeholder for Z
7689 push
#0x00 ;; placeholder for make_far_call boolean
7690 call _int74_function
7691 pop cx
;; remove make_far_call from stack
7694 ;; make far call to EBDA
:0022
7697 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
7699 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7704 add sp
, #8 ;; pop status, x, y, z
7706 pop ds
;; restore DS
7711 ;; This will perform an IRET
, but will retain value of current CF
7712 ;; by altering flags on stack
. Better than RETF
#02.
7717 and BYTE
[bp
+ 0x06], #0xfe
7723 or BYTE
[bp
+ 0x06], #0x01
7728 ;----------------------
7729 ;- INT13h (relocated
) -
7730 ;----------------------
7732 ; int13_relocated is a little bit messed up since I played with it
7733 ; I have to rewrite it
:
7734 ; - call a function that detect which function to call
7735 ; - make all called C function get the same parameters list
7739 #if BX_ELTORITO_BOOT
7740 ;; check
for an eltorito function
7742 jb int13_not_eltorito
7744 ja int13_not_eltorito
7753 ;; check
if emulation active
7754 call _cdemu_isactive
7756 je int13_cdemu_inactive
7758 ;; check
if access to the emulated drive
7759 call _cdemu_emulated_drive
7762 cmp al
,dl
;; int13 on emulated drive
7766 and dl
,#0xE0 ;; mask to get device class, including cdroms
7767 cmp al
,dl
;; al is
0x00 or 0x80
7768 jne int13_cdemu_inactive
;; inactive
for device
class
7775 dec dl
;; real drive is dl
- 1
7778 int13_cdemu_inactive
:
7786 #endif // BX_ELTORITO_BOOT
7794 int13_disk_or_cdrom
:
7801 ;; pushf already done
7807 call _int13_harddisk
7812 // JMPL(iret_modify_cf)
7817 // JMPL(int13_diskette)
7823 ;; pushf already done
7830 // ebx is modified: BSD 5.2.1 boot loader problem, so we save all
7831 // the 32 bit registers. It should be done in all the bios or no 32
7832 // bit register should be used without saving it first.
7840 // JMPL(iret_modify_cf)
7844 #if BX_ELTORITO_BOOT
7874 call _int13_eltorito
7887 int18_handler
: ;; Boot Failure routing
7888 call _int18_panic_msg
7895 int19_relocated
: ;; Boot function
, relocated
7897 ;; int19 was beginning to be really
complex, so now it
7898 ;; just calls an C function
, that does the work
7899 ;; it returns in BL the boot drive
, and in AX the boot segment
7900 ;; the boot segment will be
0x0000 if something has failed
7909 call _int19_function
7910 ;; bl contains the boot drive
7911 ;; ax contains the boot segment
or 0 if failure
7913 test ax
, ax
;; if ax is
0 call int18
7916 mov dl
, bl
;; set drive so guest os find it
7917 shl eax
, #0x04 ;; convert seg to ip
7918 mov
2[bp
], ax
;; set ip
7920 shr eax
, #0x04 ;; get cs back
7921 and ax
, #0xF000 ;; remove what went in ip
7922 mov
4[bp
], ax
;; set cs
7924 mov es
, ax
;; set es to zero fixes
[ 549815 ]
7925 mov
[bp
], ax
;; set bp to zero
7926 mov ax
, #0xaa55 ;; set ok flag
7929 iret
;; Beam me up Scotty
7934 int1c_handler
: ;; User Timer Tick
7938 ;----------------------
7939 ;- POST
: Floppy Drive
-
7940 ;----------------------
7946 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
7948 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
7950 mov
0x0440, al
;; diskette motor timeout counter
: not active
7951 mov
0x0441, al
;; diskette controller status
return code
7953 mov
0x0442, al
;; disk
& diskette controller status
register 0
7954 mov
0x0443, al
;; diskette controller status
register 1
7955 mov
0x0444, al
;; diskette controller status
register 2
7956 mov
0x0445, al
;; diskette controller cylinder number
7957 mov
0x0446, al
;; diskette controller head number
7958 mov
0x0447, al
;; diskette controller sector number
7959 mov
0x0448, al
;; diskette controller bytes written
7961 mov
0x048b, al
;; diskette configuration data
7963 ;; -----------------------------------------------------------------
7964 ;; (048F
) diskette controller information
7966 mov al
, #0x10 ;; get CMOS diskette drive type
7969 mov ah
, al
;; save byte to AH
7972 shr al
, #4 ;; look at top 4 bits for drive 0
7973 jz f0_missing
;; jump
if no drive0
7974 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
7977 mov bl
, #0x00 ;; no drive0
7980 mov al
, ah
;; restore from AH
7981 and al
, #0x0f ;; look at bottom 4 bits for drive 1
7982 jz f1_missing
;; jump
if no drive1
7983 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
7985 ;; leave high bits in BL zerod
7986 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
7987 ;; -----------------------------------------------------------------
7990 mov
0x0490, al
;; diskette
0 media state
7991 mov
0x0491, al
;; diskette
1 media state
7993 ;; diskette
0,1 operational starting state
7994 ;; drive type has
not been determined
,
7995 ;; has no changed detection line
7999 mov
0x0494, al
;; diskette
0 current cylinder
8000 mov
0x0495, al
;; diskette
1 current cylinder
8003 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
8005 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8006 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8007 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8012 ;--------------------
8013 ;- POST
: HARD DRIVE
-
8014 ;--------------------
8015 ; relocated here because the primary POST area isnt big enough
.
8018 // INT 76h calls INT 15h function ax=9100
8020 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8026 mov
0x0474, al
/* hard disk status of last operation */
8027 mov
0x0477, al
/* hard disk port offset (XT only ???) */
8028 mov
0x048c, al
/* hard disk status register */
8029 mov
0x048d, al
/* hard disk error register */
8030 mov
0x048e, al
/* hard disk task complete flag */
8032 mov
0x0475, al
/* hard disk number attached */
8034 mov
0x0476, al
/* hard disk control byte */
8035 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8036 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8037 ;; INT
41h
: hard disk
0 configuration pointer
8038 ;; INT
46h
: hard disk
1 configuration pointer
8039 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8040 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8042 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
8054 cmp al
, #47 ;; decimal 47 - user definable
8058 ;; CMOS purpose param table offset
8059 ;; 1b cylinders low
0
8060 ;; 1c cylinders high
1
8062 ;; 1e write pre
-comp low
5
8063 ;; 1f write pre
-comp high
6
8064 ;; 20 retries
/bad map
/heads
>8 8
8065 ;; 21 landing zone low C
8066 ;; 22 landing zone high D
8067 ;; 23 sectors
/track E
8072 ;;; Filling EBDA table
for hard disk
0.
8080 mov (0x003d + 0x05), ax
;; write precomp word
8085 mov (0x003d + 0x08), al
;; drive control byte
8094 mov (0x003d + 0x0C), ax
;; landing zone word
8096 mov al
, #0x1c ;; get cylinders word in AX
8098 in al
, #0x71 ;; high byte
8102 in al
, #0x71 ;; low byte
8103 mov bx
, ax
;; BX
= cylinders
8108 mov cl
, al
;; CL
= heads
8113 mov dl
, al
;; DL
= sectors
8116 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8118 hd0_post_physical_chs
:
8119 ;; no logical CHS mapping used
, just physical CHS
8120 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8121 mov (0x003d + 0x00), bx
;; number of physical cylinders
8122 mov (0x003d + 0x02), cl
;; number of physical heads
8123 mov (0x003d + 0x0E), dl
;; number of physical sectors
8126 hd0_post_logical_chs
:
8127 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8128 mov (0x003d + 0x09), bx
;; number of physical cylinders
8129 mov (0x003d + 0x0b), cl
;; number of physical heads
8130 mov (0x003d + 0x04), dl
;; number of physical sectors
8131 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
8133 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
8136 jnbe hd0_post_above_2048
8137 ;; 1024 < c
<= 2048 cylinders
8140 jmp hd0_post_store_logical
8142 hd0_post_above_2048
:
8144 jnbe hd0_post_above_4096
8145 ;; 2048 < c
<= 4096 cylinders
8148 jmp hd0_post_store_logical
8150 hd0_post_above_4096
:
8152 jnbe hd0_post_above_8192
8153 ;; 4096 < c
<= 8192 cylinders
8156 jmp hd0_post_store_logical
8158 hd0_post_above_8192
:
8159 ;; 8192 < c
<= 16384 cylinders
8163 hd0_post_store_logical
:
8164 mov (0x003d + 0x00), bx
;; number of physical cylinders
8165 mov (0x003d + 0x02), cl
;; number of physical heads
8167 mov cl
, #0x0f ;; repeat count
8168 mov si
, #0x003d ;; offset to disk0 FDPT
8169 mov al
, #0x00 ;; sum
8170 hd0_post_checksum_loop
:
8174 jnz hd0_post_checksum_loop
8175 not al
;; now take
2s complement
8178 ;;; Done filling EBDA table
for hard disk
0.
8182 ;; is there really a second hard disk
? if not, return now
8190 ;; check that the hd type is really
0x0f.
8195 ;; check that the extended type is
47 - user definable
8199 cmp al
, #47 ;; decimal 47 - user definable
8204 ;; CMOS purpose param table offset
8205 ;; 0x24 cylinders low
0
8206 ;; 0x25 cylinders high
1
8208 ;; 0x27 write pre
-comp low
5
8209 ;; 0x28 write pre
-comp high
6
8211 ;; 0x2a landing zone low C
8212 ;; 0x2b landing zone high D
8213 ;; 0x2c sectors
/track E
8214 ;;; Fill EBDA table
for hard disk
1.
8224 mov (0x004d + 0x05), ax
;; write precomp word
8229 mov (0x004d + 0x08), al
;; drive control byte
8238 mov (0x004d + 0x0C), ax
;; landing zone word
8240 mov al
, #0x25 ;; get cylinders word in AX
8242 in al
, #0x71 ;; high byte
8246 in al
, #0x71 ;; low byte
8247 mov bx
, ax
;; BX
= cylinders
8252 mov cl
, al
;; CL
= heads
8257 mov dl
, al
;; DL
= sectors
8260 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
8262 hd1_post_physical_chs
:
8263 ;; no logical CHS mapping used
, just physical CHS
8264 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
8265 mov (0x004d + 0x00), bx
;; number of physical cylinders
8266 mov (0x004d + 0x02), cl
;; number of physical heads
8267 mov (0x004d + 0x0E), dl
;; number of physical sectors
8270 hd1_post_logical_chs
:
8271 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
8272 mov (0x004d + 0x09), bx
;; number of physical cylinders
8273 mov (0x004d + 0x0b), cl
;; number of physical heads
8274 mov (0x004d + 0x04), dl
;; number of physical sectors
8275 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
8277 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
8280 jnbe hd1_post_above_2048
8281 ;; 1024 < c
<= 2048 cylinders
8284 jmp hd1_post_store_logical
8286 hd1_post_above_2048
:
8288 jnbe hd1_post_above_4096
8289 ;; 2048 < c
<= 4096 cylinders
8292 jmp hd1_post_store_logical
8294 hd1_post_above_4096
:
8296 jnbe hd1_post_above_8192
8297 ;; 4096 < c
<= 8192 cylinders
8300 jmp hd1_post_store_logical
8302 hd1_post_above_8192
:
8303 ;; 8192 < c
<= 16384 cylinders
8307 hd1_post_store_logical
:
8308 mov (0x004d + 0x00), bx
;; number of physical cylinders
8309 mov (0x004d + 0x02), cl
;; number of physical heads
8311 mov cl
, #0x0f ;; repeat count
8312 mov si
, #0x004d ;; offset to disk0 FDPT
8313 mov al
, #0x00 ;; sum
8314 hd1_post_checksum_loop
:
8318 jnz hd1_post_checksum_loop
8319 not al
;; now take
2s complement
8322 ;;; Done filling EBDA table
for hard disk
1.
8326 ;--------------------
8327 ;- POST
: EBDA segment
8328 ;--------------------
8329 ; relocated here because the primary POST area isnt big enough
.
8334 mov byte ptr
[0x0], #EBDA_SIZE
8336 xor ax
, ax
; mov EBDA seg into
40E
8338 mov word ptr
[0x40E], #EBDA_SEG
8341 ;--------------------
8342 ;- POST
: EOI
+ jmp via
[0x40:67)
8343 ;--------------------
8344 ; relocated here because the primary POST area isnt big enough
.
8354 ;--------------------
8357 out
#0xA0, al ;; slave PIC EOI
8360 out
#0x20, al ;; master PIC EOI
8363 ;--------------------
8365 ;; in
: AL in BCD format
8366 ;; out
: AL in binary format
, AH will always be
0
8369 and bl
, #0x0f ;; bl has low digit
8370 shr al
, #4 ;; al has high digit
8372 mul al
, bh
;; multiply high digit by
10 (result in AX
)
8373 add al
, bl
;; then add low digit
8376 ;--------------------
8378 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
8379 ;; Timer Ticks Roller
Flag (0x470:byte
)
8380 ;; The Timer Ticks Count needs to be set according to
8381 ;; the current CMOS time
, as
if ticks have been occurring
8382 ;; at
18.2hz since midnight up to
this point
. Calculating
8383 ;; this is a little complicated
. Here are the factors I gather
8384 ;; regarding
this. 14,318,180 hz was the original clock speed
,
8385 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
8386 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
8387 ;; source was divided again by
4 to feed a
1.193Mhz signal to
8388 ;; the timer
. With a maximum
16bit timer count
, this is again
8389 ;; divided down by
65536 to
18.2hz
.
8391 ;; 14,318,180 Hz clock
8392 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
8393 ;; /4 = 1,193,181 Hz fed to timer
8394 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
8395 ;; 1 second
= 18.20650736 ticks
8396 ;; 1 minute
= 1092.390442 ticks
8397 ;; 1 hour
= 65543.42651 ticks
8399 ;; Given the values in the CMOS clock
, one could calculate
8400 ;; the number of ticks by the following
:
8401 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
8402 ;; (BcdToBin(minutes
) * 1092.3904)
8403 ;; (BcdToBin(hours
) * 65543.427)
8404 ;; To get a little more accuracy
, since Im
using integer
8405 ;; arithmatic
, I use
:
8406 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
8407 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
8408 ;; (BcdToBin(hours
) * 65543427) / 1000
8413 xor eax
, eax
;; clear EAX
8416 in al
, #0x71 ;; AL has CMOS seconds in BCD
8417 call BcdToBin
;; EAX now has seconds in binary
8423 mov ecx
, eax
;; ECX will accumulate total ticks
8426 xor eax
, eax
;; clear EAX
8429 in al
, #0x71 ;; AL has CMOS minutes in BCD
8430 call BcdToBin
;; EAX now has minutes in binary
8436 add ecx
, eax
;; add to total ticks
8439 xor eax
, eax
;; clear EAX
8442 in al
, #0x71 ;; AL has CMOS hours in BCD
8443 call BcdToBin
;; EAX now has hours in binary
8449 add ecx
, eax
;; add to total ticks
8451 mov
0x46C, ecx
;; Timer Ticks Count
8453 mov
0x470, al
;; Timer Ticks Rollover Flag
8456 ;--------------------
8458 ;; record completion in BIOS task complete flag
8470 ;--------------------
8474 #include "apmbios.S"
8478 #include "apmbios.S"
8482 ;--------------------
8487 db
0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8488 dw bios32_entry_point
, 0xf ;; 32 bit physical address
8489 db
0 ;; revision level
8490 ;; length in paragraphs
and checksum stored in a word to prevent errors
8491 dw (~(((bios32_entry_point
>> 8) + (bios32_entry_point
& 0xff) + 0x32) \
8492 & 0xff) << 8) + 0x01
8493 db
0,0,0,0,0 ;; reserved
8498 cmp eax
, #0x49435024
8500 mov eax
, #0x80000000
8505 cmp eax
, #0x12378086
8507 mov ebx
, #0x000f0000
8509 mov edx
, #pcibios_protected
8522 cmp al
, #0x01 ;; installation check
8526 mov edx
, #0x20494350
8529 pci_pro_f02
: ;; find pci device
8537 call pci_pro_select_reg
8551 pci_pro_f08
: ;; read configuration byte
8554 call pci_pro_select_reg
8563 pci_pro_f09
: ;; read configuration word
8566 call pci_pro_select_reg
8575 pci_pro_f0a
: ;; read configuration dword
8578 call pci_pro_select_reg
8585 pci_pro_f0b
: ;; write configuration byte
8588 call pci_pro_select_reg
8597 pci_pro_f0c
: ;; write configuration word
8600 call pci_pro_select_reg
8609 pci_pro_f0d
: ;; write configuration dword
8612 call pci_pro_select_reg
8651 mov eax
, #0x80000000
8656 cmp eax
, #0x12378086
8666 cmp al
, #0x01 ;; installation check
8671 mov edx
, #0x20494350
8672 mov edi
, #pcibios_protected
8676 pci_real_f02
: ;; find pci device
8684 call pci_real_select_reg
8688 jne pci_real_nextdev
8695 jne pci_real_devloop
8700 pci_real_f08
: ;; read configuration byte
8703 call pci_real_select_reg
8712 pci_real_f09
: ;; read configuration word
8715 call pci_real_select_reg
8724 pci_real_f0a
: ;; read configuration dword
8727 call pci_real_select_reg
8734 pci_real_f0b
: ;; write configuration byte
8737 call pci_real_select_reg
8746 pci_real_f0c
: ;; write configuration word
8749 call pci_real_select_reg
8758 pci_real_f0d
: ;; write configuration dword
8760 jne pci_real_unknown
8761 call pci_real_select_reg
8778 pci_real_select_reg
:
8792 pci_routing_table_structure
:
8793 db
0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
8795 dw
32 + (6 * 16) ;; table size
8796 db
0 ;; PCI interrupt router bus
8797 db
0x08 ;; PCI interrupt router DevFunc
8798 dw
0x0000 ;; PCI exclusive IRQs
8799 dw
0x8086 ;; compatible PCI interrupt router vendor ID
8800 dw
0x7000 ;; compatible PCI interrupt router device ID
8801 dw
0,0 ;; Miniport data
8802 db
0,0,0,0,0,0,0,0,0,0,0 ;; reserved
8804 ;; first slot entry PCI
-to
-ISA (embedded
)
8805 db
0 ;; pci bus number
8806 db
0x08 ;; pci device
number (bit
7-3)
8807 db
0x60 ;; link value INTA
#: pointer into PCI2ISA config space
8808 dw
0xdef8 ;; IRQ bitmap INTA
#
8809 db
0x61 ;; link value INTB
#
8810 dw
0xdef8 ;; IRQ bitmap INTB
#
8811 db
0x62 ;; link value INTC
#
8812 dw
0xdef8 ;; IRQ bitmap INTC
#
8813 db
0x63 ;; link value INTD
#
8814 dw
0xdef8 ;; IRQ bitmap INTD
#
8815 db
0 ;; physical
slot (0 = embedded
)
8817 ;; second slot entry
: 1st PCI slot
8818 db
0 ;; pci bus number
8819 db
0x10 ;; pci device
number (bit
7-3)
8820 db
0x61 ;; link value INTA
#
8821 dw
0xdef8 ;; IRQ bitmap INTA
#
8822 db
0x62 ;; link value INTB
#
8823 dw
0xdef8 ;; IRQ bitmap INTB
#
8824 db
0x63 ;; link value INTC
#
8825 dw
0xdef8 ;; IRQ bitmap INTC
#
8826 db
0x60 ;; link value INTD
#
8827 dw
0xdef8 ;; IRQ bitmap INTD
#
8828 db
1 ;; physical
slot (0 = embedded
)
8830 ;; third slot entry
: 2nd PCI slot
8831 db
0 ;; pci bus number
8832 db
0x18 ;; pci device
number (bit
7-3)
8833 db
0x62 ;; link value INTA
#
8834 dw
0xdef8 ;; IRQ bitmap INTA
#
8835 db
0x63 ;; link value INTB
#
8836 dw
0xdef8 ;; IRQ bitmap INTB
#
8837 db
0x60 ;; link value INTC
#
8838 dw
0xdef8 ;; IRQ bitmap INTC
#
8839 db
0x61 ;; link value INTD
#
8840 dw
0xdef8 ;; IRQ bitmap INTD
#
8841 db
2 ;; physical
slot (0 = embedded
)
8843 ;; 4th slot entry
: 3rd PCI slot
8844 db
0 ;; pci bus number
8845 db
0x20 ;; pci device
number (bit
7-3)
8846 db
0x63 ;; link value INTA
#
8847 dw
0xdef8 ;; IRQ bitmap INTA
#
8848 db
0x60 ;; link value INTB
#
8849 dw
0xdef8 ;; IRQ bitmap INTB
#
8850 db
0x61 ;; link value INTC
#
8851 dw
0xdef8 ;; IRQ bitmap INTC
#
8852 db
0x62 ;; link value INTD
#
8853 dw
0xdef8 ;; IRQ bitmap INTD
#
8854 db
3 ;; physical
slot (0 = embedded
)
8856 ;; 5th slot entry
: 4rd PCI slot
8857 db
0 ;; pci bus number
8858 db
0x28 ;; pci device
number (bit
7-3)
8859 db
0x60 ;; link value INTA
#
8860 dw
0xdef8 ;; IRQ bitmap INTA
#
8861 db
0x61 ;; link value INTB
#
8862 dw
0xdef8 ;; IRQ bitmap INTB
#
8863 db
0x62 ;; link value INTC
#
8864 dw
0xdef8 ;; IRQ bitmap INTC
#
8865 db
0x63 ;; link value INTD
#
8866 dw
0xdef8 ;; IRQ bitmap INTD
#
8867 db
4 ;; physical
slot (0 = embedded
)
8869 ;; 6th slot entry
: 5rd PCI slot
8870 db
0 ;; pci bus number
8871 db
0x30 ;; pci device
number (bit
7-3)
8872 db
0x61 ;; link value INTA
#
8873 dw
0xdef8 ;; IRQ bitmap INTA
#
8874 db
0x62 ;; link value INTB
#
8875 dw
0xdef8 ;; IRQ bitmap INTB
#
8876 db
0x63 ;; link value INTC
#
8877 dw
0xdef8 ;; IRQ bitmap INTC
#
8878 db
0x60 ;; link value INTD
#
8879 dw
0xdef8 ;; IRQ bitmap INTD
#
8880 db
5 ;; physical
slot (0 = embedded
)
8886 pcibios_init_sel_reg
:
8898 pcibios_init_set_elcr
:
8922 mov dx
, #0x04d0 ;; reset ELCR1 + ELCR2
8927 mov si
, #pci_routing_table_structure
8931 call pcibios_init_sel_reg
8934 cmp eax
, [si
+12] ;; check irq router
8937 call pcibios_init_sel_reg
8938 push bx
;; save irq router bus
+ devfunc
8941 out dx
, ax
;; reset PIRQ route control
8949 add si
, #0x20 ;; set pointer to 1st entry
8951 mov ax
, #pci_irq_list
8960 call pcibios_init_sel_reg
8964 jnz pci_test_int_pin
8970 call pcibios_init_sel_reg
8975 dec al
;; determine pirq reg
8984 call pcibios_init_sel_reg
8991 mov bx
, [bp
-2] ;; pci irq list pointer
8996 call pcibios_init_set_elcr
9000 add bl
, [bp
-3] ;; pci function number
9002 call pcibios_init_sel_reg
9012 mov byte ptr
[bp
-3], #0x00
9020 #endif // BX_PCIBIOS
9026 and al
, #0xdf ; clear input mode
9036 mov
[bx
+0x408], dx
; Parallel I
/O address
9038 mov
[bx
+0x478], cl
; Parallel printer timeout
9061 mov
[bx
+0x400], dx
; Serial I
/O address
9063 mov
[bx
+0x47c], cl
; Serial timeout
9090 ;; Scan
for existence of valid expansion ROMS
.
9091 ;; Video ROM
: from
0xC0000..0xC7FFF in
2k increments
9092 ;; General ROM
: from
0xC8000..0xDFFFF in
2k increments
9093 ;; System ROM
: only
0xE0000
9099 ;; 2 ROM length in
512-byte blocks
9100 ;; 3 ROM initialization entry
point (FAR CALL
)
9105 mov ax
, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9106 cmp
[0], #0xAA55 ;; look for signature
9107 jne rom_scan_increment
9109 jnz rom_scan_increment
9110 mov al
, [2] ;; change increment to ROM length in
512-byte blocks
9112 ;; We want our increment in
512-byte quantities
, rounded to
9113 ;; the nearest
2k quantity
, since we only scan at
2k intervals
.
9115 jz block_count_rounded
9116 and al
, #0xfc ;; needs rounding up
9118 block_count_rounded
:
9120 xor bx
, bx
;; Restore DS back to
0000:
9123 ;; Push addr of ROM entry point
9125 push
#0x0003 ;; Push offset
9126 mov bp
, sp
;; Call ROM init routine
using seg
:off on stack
9127 db
0xff ;; call_far ss
:[bp
+0]
9130 cli
;; In
case expansion ROM BIOS turns IF on
9131 add sp
, #2 ;; Pop offset value
9132 pop cx
;; Pop seg
value (restore CX
)
9133 pop ax
;; Restore AX
9135 shl ax
, #5 ;; convert 512-bytes blocks to 16-byte increments
9136 ;; because the segment selector is shifted left
4 bits
.
9141 xor ax
, ax
;; Restore DS back to
0000:
9145 ;; for 'C' strings
and other data
, insert them here with
9146 ;; a the following hack
:
9147 ;; DATA_SEG_DEFS_HERE
9153 .org
0xe05b ; POST Entry Point
9158 ;; first reset the DMA controllers
9162 ;; then initialize the DMA controllers
9164 out
0xD6, al
; cascade mode of channel
4 enabled
9166 out
0xD4, al
; unmask channel
4
9168 ;; Examine CMOS shutdown status
.
9176 ;; Reset CMOS shutdown status
.
9178 out
0x70, AL
; select CMOS
register Fh
9180 out
0x71, AL
; set shutdown action to normal
9182 ;; Examine CMOS shutdown status
.
9185 ;; 0x00, 0x09, 0x0D+ = normal startup
9193 ;; 0x05 = eoi
+ jmp via
[0x40:0x67] jump
9197 ;; Examine CMOS shutdown status
.
9198 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status
.
9200 call _shutdown_status_panic
9206 ; 0xb0, 0x20, /* mov al, #0x20 */
9207 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9217 ; case 0: normal startup
9226 ;; zero out BIOS data
area (40:00..40:ff
)
9228 mov cx
, #0x0080 ;; 128 words
9234 call _log_bios_start
9236 ;; set all interrupts to
default handler
9237 mov bx
, #0x0000 ;; offset index
9238 mov cx
, #0x0100 ;; counter (256 interrupts)
9239 mov ax
, #dummy_iret_handler
9249 loop post_default_ints
9251 ;; set vector
0x79 to zero
9252 ;; this is used by
'gardian angel' protection system
9253 SET_INT_VECTOR(0x79, #0, #0)
9255 ;; base memory in K
40:13 (word
)
9256 mov ax
, #BASE_MEM_IN_K
9260 ;; Manufacturing Test
40:12
9263 ;; Warm Boot Flag
0040:0072
9264 ;; value of
1234h
= skip memory checks
9268 ;; Printer Services vector
9269 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9271 ;; Bootstrap failure vector
9272 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9274 ;; Bootstrap Loader vector
9275 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9277 ;; User Timer Tick vector
9278 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9280 ;; Memory Size Check vector
9281 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9283 ;; Equipment Configuration Check vector
9284 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9287 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9293 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9294 ;; int 1C already points at
dummy_iret_handler (above
)
9295 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
9297 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
9302 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9303 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9307 mov
0x0417, al
/* keyboard shift flags, set 1 */
9308 mov
0x0418, al
/* keyboard shift flags, set 2 */
9309 mov
0x0419, al
/* keyboard alt-numpad work area */
9310 mov
0x0471, al
/* keyboard ctrl-break flag */
9311 mov
0x0497, al
/* keyboard status flags 4 */
9313 mov
0x0496, al
/* keyboard status flags 3 */
9316 /* keyboard head of buffer pointer */
9320 /* keyboard end of buffer pointer */
9323 /* keyboard pointer to start of buffer */
9327 /* keyboard pointer to end of buffer */
9331 /* init the keyboard */
9334 ;; mov CMOS Equipment Byte to BDA Equipment Word
9343 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9347 mov cl
, #0x14 ; timeout value
9348 mov dx
, #0x378 ; Parallel I/O address, port 1
9350 mov dx
, #0x278 ; Parallel I/O address, port 2
9353 mov ax
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
9355 or ax
, bx
; set number of parallel ports
9359 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9360 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9362 mov cl
, #0x0a ; timeout value
9363 mov dx
, #0x03f8 ; Serial I/O address, port 1
9365 mov dx
, #0x02f8 ; Serial I/O address, port 2
9367 mov dx
, #0x03e8 ; Serial I/O address, port 3
9369 mov dx
, #0x02e8 ; Serial I/O address, port 4
9372 mov ax
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
9374 or ax
, bx
; set number of serial port
9378 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9379 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9380 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9381 ;; BIOS DATA AREA
0x4CE ???
9382 call timer_tick_post
9385 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9387 ;; IRQ13 (FPU exception
) setup
9388 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9391 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9394 mov al
, #0x11 ; send initialisation commands
9409 out
0x21, AL
;master pic
: unmask IRQ
0, 1, 2, 6
9410 #if BX_USE_PS2_MOUSE
9415 out
0xa1, AL
;slave pic
: unmask IRQ
12, 13, 14
9421 call _print_bios_banner
9426 call floppy_drive_post
9433 call hard_drive_post
9436 ;; ATA
/ATAPI driver setup
9441 #else // BX_USE_ATADRV
9446 call hard_drive_post
9448 #endif // BX_USE_ATADRV
9450 #if BX_ELTORITO_BOOT
9452 ;; eltorito floppy
/harddisk emulation from cd
9456 #endif // BX_ELTORITO_BOOT
9459 //JMP_EP(0x0064) ; INT 19h location
9462 .org
0xe2c3 ; NMI Handler Entry Point
9464 ;; FIXME the NMI handler should
not panic
9465 ;; but iret when called from
int75 (fpu exception
)
9466 call _nmi_handler_msg
9470 out
0xf0, al
// clear irq13
9471 call eoi_both_pics
// clear interrupt
9472 int 2 // legacy nmi call
9475 ;-------------------------------------------
9476 ;- INT
13h Fixed Disk Services Entry Point
-
9477 ;-------------------------------------------
9478 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
9480 //JMPL(int13_relocated)
9483 .org
0xe401 ; Fixed Disk Parameter Table
9488 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
9492 ;-------------------------------------------
9493 ;- System BIOS Configuration Data Table
9494 ;-------------------------------------------
9495 .org BIOS_CONFIG_TABLE
9496 db
0x08 ; Table
size (bytes
) -Lo
9497 db
0x00 ; Table
size (bytes
) -Hi
9502 ; b7
: 1=DMA channel
3 used by hard disk
9503 ; b6
: 1=2 interrupt controllers present
9505 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
9506 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
9507 ; b2
: 1=extended BIOS data area used
9508 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
9509 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
9513 (BX_CALL_INT15_4F
<< 4) | \
9515 (BX_USE_EBDA
<< 2) | \
9519 ; b7
: 1=32-bit DMA supported
9520 ; b6
: 1=int16h
, function
9 supported
9521 ; b5
: 1=int15h
/C6h (get POS data
) supported
9522 ; b4
: 1=int15h
/C7h (get mem map info
) supported
9523 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
9524 ; b2
: 1=non
-8042 kb controller
9525 ; b1
: 1=data streaming supported
9539 ; b4
: POST supports ROM
-to
-RAM enable
/disable
9540 ; b3
: SCSI on system board
9541 ; b2
: info panel installed
9542 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
9543 ; b0
: SCSI supported in IML
9547 ; b6
: EEPROM present
9548 ; b5
-3: ABIOS
presence (011 = not supported
)
9550 ; b1
: memory split above
16Mb supported
9551 ; b0
: POSTEXT directly supported by POST
9553 ; Feature byte
5 (IBM
)
9554 ; b1
: enhanced mouse
9560 .org
0xe729 ; Baud Rate Generator Table
9565 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
9571 call _int14_function
9577 ;----------------------------------------
9578 ;- INT
16h Keyboard Service Entry Point
-
9579 ;----------------------------------------
9595 call _int16_function
9605 and BYTE
[bp
+ 0x06], #0xbf
9613 or BYTE
[bp
+ 0x06], #0x40
9629 /* no key yet, call int 15h, function AX=9002 */
9631 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9632 0xcd, 0x15, /* int 15h */
9634 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
9636 jmp int16_wait_for_key
9641 call _int16_function
9646 /* notify int16 complete w/ int 15h, function AX=9102 */
9648 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
9649 0xcd, 0x15, /* int 15h */
9656 ;-------------------------------------------------
9657 ;- INT09h
: Keyboard Hardware Service Entry Point
-
9658 ;-------------------------------------------------
9664 mov al
, #0xAD ;;disable keyboard
9673 in al
, #0x60 ;;read key from keyboard controller
9674 //test al, #0x80 ;;look for key release
9675 //jnz int09_process_key ;; dont pass releases to intercept?
9677 ;; check
for extended key
9679 jne int09_call_int15_4f
9684 mov al
, BYTE
[0x496] ;; mf2_state
|= 0x01
9686 mov BYTE
[0x496], al
9689 in al
, #0x60 ;;read another key from keyboard controller
9693 int09_call_int15_4f
:
9696 #ifdef BX_CALL_INT15_4F
9697 mov ah
, #0x4f ;; allow for keyboard intercept
9704 //int09_process_key:
9707 call _int09_function
9716 mov al
, #0xAE ;;enable keyboard
9724 ;----------------------------------------
9725 ;- INT
13h Diskette Service Entry Point
-
9726 ;----------------------------------------
9732 call _int13_diskette_function
9736 //JMPL(iret_modify_cf)
9744 ;; pushf already done
9747 call _int13_diskette_function
9751 //JMPL(iret_modify_cf)
9763 ;; ??? dont know
if this service changes the
return status
9764 //JMPL(iret_modify_cf)
9770 ;---------------------------------------------
9771 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
9772 ;---------------------------------------------
9773 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
9783 mov al
, #0x08 ; sense interrupt status
9801 mov ax
, #0x0000 ;; segment 0000
9805 or al
, #0x80 ;; diskette interrupt has occurred
9813 .org
0xefc7 ; Diskette Controller Parameter Table
9814 diskette_param_table
:
9815 ;; Since no provisions are made
for multiple drive types
, most
9816 ;; values in
this table are ignored
. I set parameters
for 1.44M
9819 db
0x02 ;; head load time
0000001, DMA used
9831 ;----------------------------------------
9832 ;- INT17h
: Printer Service Entry Point
-
9833 ;----------------------------------------
9840 call _int17_function
9845 diskette_param_table2
:
9846 ;; New diskette parameter table adding
3 parameters from IBM
9847 ;; Since no provisions are made
for multiple drive types
, most
9848 ;; values in
this table are ignored
. I set parameters
for 1.44M
9851 db
0x02 ;; head load time
0000001, DMA used
9861 db
79 ;; maximum track
9862 db
0 ;; data transfer rate
9863 db
4 ;; drive type in cmos
9865 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
9872 .org
0xf065 ; INT
10h Video Support Service Entry Point
9874 ;; dont
do anything
, since the VGA BIOS handles int10h requests
9877 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
9882 .org
0xf841 ; INT
12h Memory Size Service Entry Point
9883 ; ??? different
for Pentium (machine check
)?
9895 .org
0xf84d ; INT
11h Equipment List Service Entry Point
9907 .org
0xf859 ; INT
15h System Services Entry Point
9921 #if BX_USE_PS2_MOUSE
9923 je int15_handler_mouse
9925 call _int15_function
9926 int15_handler_mouse_ret
:
9928 int15_handler32_ret
:
9938 #if BX_USE_PS2_MOUSE
9939 int15_handler_mouse
:
9940 call _int15_function_mouse
9941 jmp int15_handler_mouse_ret
9946 call _int15_function32
9948 jmp int15_handler32_ret
9950 ;; Protected mode IDT descriptor
9952 ;; I just make the limit
0, so the machine will shutdown
9953 ;; if an exception occurs during
protected mode memory
9956 ;; Set base to f0000 to correspond to beginning of BIOS
,
9957 ;; in
case I actually define an IDT later
9961 dw
0x0000 ;; limit
15:00
9962 dw
0x0000 ;; base
15:00
9963 db
0x0f ;; base
23:16
9965 ;; Real mode IDT descriptor
9967 ;; Set to typical real
-mode values
.
9972 dw
0x03ff ;; limit
15:00
9973 dw
0x0000 ;; base
15:00
9974 db
0x00 ;; base
23:16
9980 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
10008 call _int1a_function
10014 ;; int70h
: IRQ8
- CMOS RTC
10021 call _int70_function
10029 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
10037 ;; time to turn off
drive(s
)?
10040 jz int08_floppy_off
10043 jnz int08_floppy_off
10044 ;; turn
motor(s
) off
10053 mov eax
, 0x046c ;; get ticks dword
10056 ;; compare eax to one days worth of timer ticks at
18.2 hz
10057 cmp eax
, #0x001800B0
10058 jb int08_store_ticks
10059 ;; there has been a midnight rollover at
this point
10060 xor eax
, eax
;; zero out counter
10061 inc BYTE
0x0470 ;; increment rollover flag
10064 mov
0x046c, eax
;; store
new ticks dword
10065 ;; chain to user timer tick INT
#0x1c
10067 //;; call_ep [ds:loc]
10068 //CALL_EP( 0x1c << 2 )
10071 call eoi_master_pic
10076 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10080 .ascii
"(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10082 ;------------------------------------------------
10083 ;- IRET Instruction
for Dummy Interrupt Handler
-
10084 ;------------------------------------------------
10085 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
10086 dummy_iret_handler
:
10089 .org
0xff54 ; INT
05h Print Screen Service Entry Point
10093 .org
0xfff0 ; Power
-up Entry Point
10096 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
10099 .org
0xfffe ; System Model ID
10103 .org
0xfa6e ;; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
10106 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10107 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10108 * This font is public domain
10110 static Bit8u vgafont8
[128*8]=
10112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10113 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10114 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10115 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10116 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10117 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10118 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10119 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10120 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10121 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10122 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10123 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10124 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10125 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10126 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10127 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10128 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10129 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10130 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10131 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10132 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10133 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10134 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10135 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10136 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10137 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10138 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10139 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10140 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10141 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10142 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10143 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10145 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10146 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10147 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10148 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10149 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10150 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10151 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10152 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10153 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10154 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10155 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10156 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10157 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10158 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10159 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10160 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10161 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10162 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10163 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10164 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10165 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10166 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10167 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10168 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10169 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10170 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10171 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10172 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10173 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10174 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10175 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10176 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10177 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10178 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10179 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10180 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10181 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10182 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10183 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10184 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10185 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10186 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10187 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10188 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10189 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10190 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10191 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10192 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10193 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10194 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10195 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10196 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10197 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10198 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10199 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10200 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10201 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10202 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10203 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10204 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10205 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10206 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10208 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10209 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10210 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10211 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10212 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10213 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10214 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10215 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10216 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10217 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10218 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10219 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10220 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10221 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10222 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10223 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10224 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10225 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10226 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10227 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10228 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10229 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10230 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10231 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10232 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10233 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10234 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10235 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10236 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10237 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10238 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10239 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10244 // bcc-generated data will be placed here
10246 // For documentation of this config structure, look on developer.intel.com and
10247 // search for multiprocessor specification. Note that when you change anything
10248 // you must update the checksum (a pain!). It would be better to construct this
10249 // with C structures, or at least fill in the checksum automatically.
10251 // Maybe this structs could be moved elsewhere than d000
10253 #if (BX_SMP_PROCESSORS==1)
10254 // no structure necessary.
10255 #elif (BX_SMP_PROCESSORS==2)
10256 // define the Intel MP Configuration Structure for 2 processors at
10257 // APIC ID 0,1. I/O APIC at ID=2.
10260 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10261 dw (mp_config_end
-mp_config_table
) ;; table length
10263 db
0x65 ;; checksum
10264 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10265 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10266 db
0x20, 0x20, 0x20, 0x20
10267 db
0x20, 0x20, 0x20, 0x20
10268 dw
0,0 ;; oem table ptr
10269 dw
0 ;; oem table size
10270 dw
20 ;; entry count
10271 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10272 dw
0 ;; extended table length
10273 db
0 ;; extended table checksum
10276 db
0 ;; entry type
=processor
10277 db
0 ;; local APIC id
10278 db
0x11 ;; local APIC version number
10279 db
3 ;; cpu flags
: enabled
10280 db
0,6,0,0 ;; cpu signature
10281 dw
0x201,0 ;; feature flags
10285 db
0 ;; entry type
=processor
10286 db
1 ;; local APIC id
10287 db
0x11 ;; local APIC version number
10288 db
1 ;; cpu flags
: enabled
10289 db
0,6,0,0 ;; cpu signature
10290 dw
0x201,0 ;; feature flags
10294 db
1 ;; entry type
=bus
10296 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10298 db
2 ;; entry type
=I
/O APIC
10299 db
2 ;; apic id
=2. linux will set
.
10300 db
0x11 ;; I
/O APIC version number
10301 db
1 ;; flags
=1=enabled
10302 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10304 db
3 ;; entry type
=I
/O interrupt
10305 db
0 ;; interrupt type
=vectored interrupt
10306 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10307 db
0 ;; source bus ID is ISA
10308 db
0 ;; source bus IRQ
10309 db
2 ;; destination I
/O APIC ID
10310 db
0 ;; destination I
/O APIC interrrupt in
10311 ;; repeat pattern
for interrupts
0-15
10321 db
3,0,0,0,0,10,2,10
10322 db
3,0,0,0,0,11,2,11
10323 db
3,0,0,0,0,12,2,12
10324 db
3,0,0,0,0,13,2,13
10325 db
3,0,0,0,0,14,2,14
10326 db
3,0,0,0,0,15,2,15
10327 #elif (BX_SMP_PROCESSORS==4)
10328 // define the Intel MP Configuration Structure for 4 processors at
10329 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10332 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10333 dw (mp_config_end
-mp_config_table
) ;; table length
10335 db
0xdd ;; checksum
10336 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10337 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10338 db
0x20, 0x20, 0x20, 0x20
10339 db
0x20, 0x20, 0x20, 0x20
10340 dw
0,0 ;; oem table ptr
10341 dw
0 ;; oem table size
10342 dw
22 ;; entry count
10343 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10344 dw
0 ;; extended table length
10345 db
0 ;; extended table checksum
10348 db
0 ;; entry type
=processor
10349 db
0 ;; local APIC id
10350 db
0x11 ;; local APIC version number
10351 db
1 ;; cpu flags
: enabled
10352 db
0,6,0,0 ;; cpu signature
10353 dw
0x201,0 ;; feature flags
10357 db
0 ;; entry type
=processor
10358 db
1 ;; local APIC id
10359 db
0x11 ;; local APIC version number
10360 db
1 ;; cpu flags
: enabled
10361 db
0,6,0,0 ;; cpu signature
10362 dw
0x201,0 ;; feature flags
10366 db
0 ;; entry type
=processor
10367 db
2 ;; local APIC id
10368 db
0x11 ;; local APIC version number
10369 db
3 ;; cpu flags
: enabled
, bootstrap processor
10370 db
0,6,0,0 ;; cpu signature
10371 dw
0x201,0 ;; feature flags
10375 db
0 ;; entry type
=processor
10376 db
3 ;; local APIC id
10377 db
0x11 ;; local APIC version number
10378 db
1 ;; cpu flags
: enabled
10379 db
0,6,0,0 ;; cpu signature
10380 dw
0x201,0 ;; feature flags
10384 db
1 ;; entry type
=bus
10386 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10388 db
2 ;; entry type
=I
/O APIC
10389 db
4 ;; apic id
=2. linux will set
.
10390 db
0x11 ;; I
/O APIC version number
10391 db
1 ;; flags
=1=enabled
10392 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10394 db
3 ;; entry type
=I
/O interrupt
10395 db
0 ;; interrupt type
=vectored interrupt
10396 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10397 db
0 ;; source bus ID is ISA
10398 db
0 ;; source bus IRQ
10399 db
4 ;; destination I
/O APIC ID
10400 db
0 ;; destination I
/O APIC interrrupt in
10401 ;; repeat pattern
for interrupts
0-15
10411 db
3,0,0,0,0,10,4,10
10412 db
3,0,0,0,0,11,4,11
10413 db
3,0,0,0,0,12,4,12
10414 db
3,0,0,0,0,13,4,13
10415 db
3,0,0,0,0,14,4,14
10416 db
3,0,0,0,0,15,4,15
10417 #elif (BX_SMP_PROCESSORS==8)
10418 // define the Intel MP Configuration Structure for 8 processors at
10419 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10422 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10423 dw (mp_config_end
-mp_config_table
) ;; table length
10425 db
0xc3 ;; checksum
10426 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
10427 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
10428 db
0x20, 0x20, 0x20, 0x20
10429 db
0x20, 0x20, 0x20, 0x20
10430 dw
0,0 ;; oem table ptr
10431 dw
0 ;; oem table size
10432 dw
26 ;; entry count
10433 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
10434 dw
0 ;; extended table length
10435 db
0 ;; extended table checksum
10438 db
0 ;; entry type
=processor
10439 db
0 ;; local APIC id
10440 db
0x11 ;; local APIC version number
10441 db
3 ;; cpu flags
: bootstrap cpu
10442 db
0,6,0,0 ;; cpu signature
10443 dw
0x201,0 ;; feature flags
10447 db
0 ;; entry type
=processor
10448 db
1 ;; local APIC id
10449 db
0x11 ;; local APIC version number
10450 db
1 ;; cpu flags
: enabled
10451 db
0,6,0,0 ;; cpu signature
10452 dw
0x201,0 ;; feature flags
10456 db
0 ;; entry type
=processor
10457 db
2 ;; local APIC id
10458 db
0x11 ;; local APIC version number
10459 db
1 ;; cpu flags
: enabled
10460 db
0,6,0,0 ;; cpu signature
10461 dw
0x201,0 ;; feature flags
10465 db
0 ;; entry type
=processor
10466 db
3 ;; local APIC id
10467 db
0x11 ;; local APIC version number
10468 db
1 ;; cpu flags
: enabled
10469 db
0,6,0,0 ;; cpu signature
10470 dw
0x201,0 ;; feature flags
10474 db
0 ;; entry type
=processor
10475 db
4 ;; local APIC id
10476 db
0x11 ;; local APIC version number
10477 db
1 ;; cpu flags
: enabled
10478 db
0,6,0,0 ;; cpu signature
10479 dw
0x201,0 ;; feature flags
10483 db
0 ;; entry type
=processor
10484 db
5 ;; local APIC id
10485 db
0x11 ;; local APIC version number
10486 db
1 ;; cpu flags
: enabled
10487 db
0,6,0,0 ;; cpu signature
10488 dw
0x201,0 ;; feature flags
10492 db
0 ;; entry type
=processor
10493 db
6 ;; local APIC id
10494 db
0x11 ;; local APIC version number
10495 db
1 ;; cpu flags
: enabled
10496 db
0,6,0,0 ;; cpu signature
10497 dw
0x201,0 ;; feature flags
10501 db
0 ;; entry type
=processor
10502 db
7 ;; local APIC id
10503 db
0x11 ;; local APIC version number
10504 db
1 ;; cpu flags
: enabled
10505 db
0,6,0,0 ;; cpu signature
10506 dw
0x201,0 ;; feature flags
10510 db
1 ;; entry type
=bus
10512 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
10514 db
2 ;; entry type
=I
/O APIC
10516 db
0x11 ;; I
/O APIC version number
10517 db
1 ;; flags
=1=enabled
10518 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
10520 db
3 ;; entry type
=I
/O interrupt
10521 db
0 ;; interrupt type
=vectored interrupt
10522 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
10523 db
0 ;; source bus ID is ISA
10524 db
0 ;; source bus IRQ
10525 db
8 ;; destination I
/O APIC ID
10526 db
0 ;; destination I
/O APIC interrrupt in
10527 ;; repeat pattern
for interrupts
0-15
10537 db
3,0,0,0,0,10,8,10
10538 db
3,0,0,0,0,11,8,11
10539 db
3,0,0,0,0,12,8,12
10540 db
3,0,0,0,0,13,8,13
10541 db
3,0,0,0,0,14,8,14
10542 db
3,0,0,0,0,15,8,15
10544 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
10545 #endif // if (BX_SMP_PROCESSORS==...)
10547 mp_config_end
: // this label used to find length of mp structure
10550 #if (BX_SMP_PROCESSORS>1)
10552 mp_floating_pointer_structure
:
10553 db
0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
10554 dw mp_config_table
, 0xf ;; pointer to MP configuration table
10555 db
1 ;; length of
this struct in
16-bit byte chunks
10556 db
4 ;; MP spec revision
10557 db
0xc1 ;; checksum
10558 db
0 ;; MP feature byte
1. value
0 means look at the config table
10559 db
0,0,0,0 ;; MP feature bytes
2-5.