1 /////////////////////////////////////////////////////////////////////////
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2001 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 /* includes a subset of config.h that can be compiled by bcc, and applies
29 #include "biosconfig.h"
31 // ROM BIOS for use with Bochs x86 emulation environment
34 // ROM BIOS compatability entry points:
35 // ===================================
36 // $e05b ; POST Entry Point
37 // $e2c3 ; NMI Handler Entry Point
38 // $e3fe ; INT 13h Fixed Disk Services Entry Point
39 // $e401 ; Fixed Disk Parameter Table
40 // $e6f2 ; INT 19h Boot Load Service Entry Point
41 // $e6f5 ; Configuration Data Table
42 // $e729 ; Baud Rate Generator Table
43 // $e739 ; INT 14h Serial Communications Service Entry Point
44 // $e82e ; INT 16h Keyboard Service Entry Point
45 // $e987 ; INT 09h Keyboard Service Entry Point
46 // $ec59 ; INT 13h Diskette Service Entry Point
47 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
48 // $efc7 ; Diskette Controller Parameter Table
49 // $efd2 ; INT 17h Printer Service Entry Point
50 // $f045 ; INT 10 Functions 0-Fh Entry Point
51 // $f065 ; INT 10h Video Support Service Entry Point
52 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
53 // $f841 ; INT 12h Memory Size Service Entry Point
54 // $f84d ; INT 11h Equipment List Service Entry Point
55 // $f859 ; INT 15h System Services Entry Point
56 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
57 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
58 // $fea5 ; INT 08h System Timer ISR Entry Point
59 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
60 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
61 // $ff54 ; INT 05h Print Screen Service Entry Point
62 // $fff0 ; Power-up Entry Point
63 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
64 // $fffe ; System Model ID
68 // int74 needs to be reworked. Uses direct [bp] offsets.
69 // take out int13 printf()s, or conditionally compile them
71 // f04 (verify sectors) isn't complete
72 // f02/03/04 should set current cyl,etc in BDA
75 // f03/f05 are not complete - just CLC for now
79 // - NMI access (bit7 of addr written to 70h)
80 // - timer ISR should deal with floppy counter and turn floppy motor off
83 #define BX_USE_PS2_MOUSE 1
84 #define BX_CALL_INT15_4F 1
86 #define BX_SUPPORT_FLOPPY 1
89 /* model byte 0xFC = AT */
90 #define SYS_MODEL_ID 0xFC
91 #define SYS_SUBMODEL_ID 0x00
92 #define BIOS_REVISION 1
93 #define BIOS_CONFIG_TABLE 0xe6f5
94 // 1K of base memory used for Extended Bios Data Area (EBDA)
95 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
96 #define BASE_MEM_IN_K (640 - 1)
97 #define EBDA_SEG 0x9FC0
99 #define PANIC_PORT 0x400
102 // #$20 is hex 20 = 32
109 // all hex literals should be prefixed with '0x'
110 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
111 // no mov SEG-REG, #value, must mov register into seg-reg
112 // grep -i "mov[ ]*.s" rombios.c
127 ;; the HALT macro is called with the line number of the HALT call
.
128 ;; The line number is then sent to the PANIC_PORT
, causing Bochs to
129 ;; print a BX_PANIC message
. This will normally halt the simulation
130 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
131 ;; However
, users can choose to make panics non
-fatal
and continue.
138 ;; the HALT macro is called with the line number of the HALT call
.
139 ;; The line number is then sent to the PANIC_PORT
, causing Bochs to
140 ;; print a BX_PANIC message
. This will normally halt the simulation
141 ;; with a message such as
"BIOS panic at rombios.c, line 4091".
142 ;; However
, users can choose to make panics non
-fatal
and continue.
164 typedef unsigned char Bit8u
;
165 typedef unsigned short Bit16u
;
166 typedef unsigned short Boolean
;
168 // for access to RAM area which is used by interrupt vectors
169 // and BIOS Data Area
172 unsigned char filler1
[0x400];
173 unsigned char filler2
[0x6c];
179 #define BiosData ((bios_data_t *) 0)
184 Bit16u di
, si
, bp
, sp
;
185 Bit16u bx
, dx
, cx
, ax
;
189 Bit8u bl
, bh
, dl
, dh
, cl
, ch
, al
, ah
;
206 #define SetCF(x) x.u.r8.flagsl |= 0x01
207 #define SetZF(x) x.u.r8.flagsl |= 0x40
208 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
209 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
210 #define GetCF(x) (x.u.r8.flagsl & 0x01)
221 static Bit8u
inb_cmos();
223 static void outb_cmos();
226 static void init_rtc();
227 static Boolean
rtc_updating();
229 static Bit8u
read_byte();
230 static Bit16u
read_word();
231 static void write_byte();
232 static void write_word();
233 static void bios_printf();
235 static Bit16u
UDIV();
237 static Bit8u
inhibit_mouse_int_and_events();
238 static void enable_mouse_int_and_events();
239 static Bit8u
send_to_mouse_ctrl();
240 static Bit8u
get_mouse_data();
241 static void set_kbd_command_byte();
243 static void int09_function();
244 static void int13_function();
245 static void int13_diskette_function();
246 static void int14_function();
247 static void int15_function();
248 static void int16_function();
249 static void int17_function();
250 static void int1a_function();
251 static void int70_function();
252 static void int74_function();
253 //static Bit16u get_DS();
254 //static void set_DS();
255 static Bit16u
get_SS();
256 static void enqueue_key();
257 static unsigned int dequeue_key();
258 static void set_disk_ret_status();
259 static void get_hd_geometry();
260 static void set_diskette_ret_status();
261 static void set_diskette_current_cyl();
262 static void determine_floppy_media();
263 static Boolean
floppy_drive_exists();
264 static Boolean
floppy_drive_recal();
265 static Boolean
floppy_media_known();
266 static Boolean
floppy_media_sense();
268 static Boolean
set_enable_a20();
269 static void debugger_on();
270 static void debugger_off();
271 static void keyboard_panic();
272 static void boot_failure_msg();
273 static void nmi_handler_msg();
274 static void print_bios_banner();
276 static char bios_cvs_version_string
[] = "$Revision$";
277 static char bios_date_string
[] = "$Date$";
279 static char CVSID
[] = "$Id$";
280 /* Offset to skip the CVS $Id: prefix */
281 #define bios_version_string (CVSID + 4)
283 #define BIOS_PRINTF_HALT 1
284 #define BIOS_PRINTF_SCREEN 2
285 #define BIOS_PRINTF_DEBUG 4
286 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_DEBUG)
287 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_DEBUG | BIOS_PRINTF_HALT)
289 #define DEBUG_ROMBIOS 0
292 # define printf(format, p...) bios_printf(BIOS_PRINTF_DEBUG, format, ##p)
293 # define panic(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
295 # define printf(format, p...)
296 # define panic(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
300 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
301 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
302 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
303 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
304 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
305 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
306 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
307 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
309 #define GET_AL() ( AX & 0x00ff )
310 #define GET_BL() ( BX & 0x00ff )
311 #define GET_CL() ( CX & 0x00ff )
312 #define GET_DL() ( DX & 0x00ff )
313 #define GET_AH() ( AX >> 8 )
314 #define GET_BH() ( BX >> 8 )
315 #define GET_CH() ( CX >> 8 )
316 #define GET_DH() ( DX >> 8 )
319 #define SET_CF() FLAGS |= 0x0001
320 #define CLEAR_CF() FLAGS &= 0xfffe
321 #define GET_CF() (FLAGS & 0x0001)
323 #define SET_ZF() FLAGS |= 0x0040
324 #define CLEAR_ZF() FLAGS &= 0xffbf
325 #define GET_ZF() (FLAGS & 0x0040)
327 #define UNSUPPORTED_FUNCTION 0x86
330 #define MAX_SCAN_CODE 0x53
337 } scan_to_scanascii
[MAX_SCAN_CODE
+ 1] = {
338 { none
, none
, none
, none
},
339 { 0x011b, 0x011b, 0x011b, 0x0100 }, /* escape */
340 { 0x0231, 0x0221, none
, 0x7800 }, /* 1! */
341 { 0x0332, 0x0340, 0x0300, 0x7900 }, /* 2@ */
342 { 0x0433, 0x0423, none
, 0x7a00 }, /* 3# */
343 { 0x0534, 0x0524, none
, 0x7b00 }, /* 4$ */
344 { 0x0635, 0x0625, none
, 0x7c00 }, /* 5% */
345 { 0x0736, 0x075e, 0x071e, 0x7d00 }, /* 6^ */
346 { 0x0837, 0x0826, none
, 0x7e00 }, /* 7& */
347 { 0x0938, 0x092a, none
, 0x7f00 }, /* 8* */
348 { 0x0a39, 0x0a28, none
, 0x8000 }, /* 9( */
349 { 0x0b30, 0x0b29, none
, 0x8100 }, /* 0) */
350 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* -_ */
351 { 0x0d3d, 0x0d2b, none
, 0x8300 }, /* =+ */
352 { 0x0e08, 0x0e08, 0x0e7f, none
}, /* backspace */
353 { 0x0f09, 0x0f00, none
, none
}, /* tab */
354 { 0x1071, 0x1051, 0x1011, 0x1000 }, /* Q */
355 { 0x1177, 0x1157, 0x1117, 0x1100 }, /* W */
356 { 0x1265, 0x1245, 0x1205, 0x1200 }, /* E */
357 { 0x1372, 0x1352, 0x1312, 0x1300 }, /* R */
358 { 0x1474, 0x1454, 0x1414, 0x1400 }, /* T */
359 { 0x1579, 0x1559, 0x1519, 0x1500 }, /* Y */
360 { 0x1675, 0x1655, 0x1615, 0x1600 }, /* U */
361 { 0x1769, 0x1749, 0x1709, 0x1700 }, /* I */
362 { 0x186f, 0x184f, 0x180f, 0x1800 }, /* O */
363 { 0x1970, 0x1950, 0x1910, 0x1900 }, /* P */
364 { 0x1a5b, 0x1a7b, 0x1a1b, none
}, /* [{ */
365 { 0x1b5d, 0x1b7d, 0x1b1d, none
}, /* ]} */
366 { 0x1c0d, 0x1c0d, 0x1c0a, none
}, /* Enter */
367 { none
, none
, none
, none
}, /* L Ctrl */
368 { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* A */
369 { 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* S */
370 { 0x2064, 0x2044, 0x2004, 0x2000 }, /* D */
371 { 0x2166, 0x2146, 0x2106, 0x2100 }, /* F */
372 { 0x2267, 0x2247, 0x2207, 0x2200 }, /* G */
373 { 0x2368, 0x2348, 0x2308, 0x2300 }, /* H */
374 { 0x246a, 0x244a, 0x240a, 0x2400 }, /* J */
375 { 0x256b, 0x254b, 0x250b, 0x2500 }, /* K */
376 { 0x266c, 0x264c, 0x260c, 0x2600 }, /* L */
377 { 0x273b, 0x273a, none
, none
}, /* ;: */
378 { 0x2827, 0x2822, none
, none
}, /* '" */
379 { 0x2960, 0x297e, none
, none
}, /* `~ */
380 { none
, none
, none
, none
}, /* L shift */
381 { 0x2b5c, 0x2b7c, 0x2b1c, none
}, /* |\ */
382 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* Z */
383 { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* X */
384 { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* C */
385 { 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* V */
386 { 0x3062, 0x3042, 0x3002, 0x3000 }, /* B */
387 { 0x316e, 0x314e, 0x310e, 0x3100 }, /* N */
388 { 0x326d, 0x324d, 0x320d, 0x3200 }, /* M */
389 { 0x332c, 0x333c, none
, none
}, /* ,< */
390 { 0x342e, 0x343e, none
, none
}, /* .> */
391 { 0x352f, 0x353f, none
, none
}, /* /? */
392 { none
, none
, none
, none
}, /* R Shift */
393 { 0x372a, 0x372a, none
, none
}, /* * */
394 { none
, none
, none
, none
}, /* L Alt */
395 { 0x3920, 0x3920, 0x3920, 0x3920 }, /* space */
396 { none
, none
, none
, none
}, /* caps lock */
397 { 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* F1 */
398 { 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* F2 */
399 { 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* F3 */
400 { 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* F4 */
401 { 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* F5 */
402 { 0x4000, 0x5900, 0x6300, 0x6d00 }, /* F6 */
403 { 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* F7 */
404 { 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* F8 */
405 { 0x4300, 0x5c00, 0x6600, 0x7000 }, /* F9 */
406 { 0x4400, 0x5d00, 0x6700, 0x7100 }, /* F10 */
407 { none
, none
, none
, none
}, /* Num Lock */
408 { none
, none
, none
, none
}, /* Scroll Lock */
409 { 0x4700, 0x4737, 0x7700, none
}, /* 7 Home */
410 { 0x4800, 0x4838, none
, none
}, /* 8 UP */
411 { 0x4900, 0x4939, 0x8400, none
}, /* 9 PgUp */
412 { 0x4a2d, 0x4a2d, none
, none
}, /* - */
413 { 0x4b00, 0x4b34, 0x7300, none
}, /* 4 Left */
414 { 0x4c00, 0x4c35, none
, none
}, /* 5 */
415 { 0x4d00, 0x4d36, 0x7400, none
}, /* 6 Right */
416 { 0x4e2b, 0x4e2b, none
, none
}, /* + */
417 { 0x4f00, 0x4f31, 0x7500, none
}, /* 1 End */
418 { 0x5000, 0x5032, none
, none
}, /* 2 Down */
419 { 0x5100, 0x5133, 0x7600, none
}, /* 3 PgDn */
420 { 0x5200, 0x5230, none
, none
}, /* 0 Ins */
421 { 0x5300, 0x532e, none
, none
} /* Del */
506 outb_cmos(cmos_reg
, val
)
514 mov al
, 4[bp
] ;; cmos_reg
531 mov al
, 4[bp
] ;; cmos_reg
542 outb_cmos(0x0a, 0x26);
543 outb_cmos(0x0b, 0x02);
551 // This function checks to see if the update-in-progress bit
552 // is set in CMOS Status Register A. If not, it returns 0.
553 // If it is set, it tries to wait until there is a transition
554 // to 0, and will return 0 if such a transition occurs. A 1
555 // is returned only after timing out. The maximum period
556 // that this bit should be set is constrained to 244useconds.
557 // The count I use below guarantees coverage or more than
558 // this time, with any reasonable IPS setting.
563 while (--count
!= 0) {
564 if ( (inb_cmos(0x0a) & 0x80) == 0 )
567 return(1); // update-in-progress never transitioned to 0
572 read_byte(seg
, offset
)
582 mov ax
, 4[bp
] ; segment
584 mov bx
, 6[bp
] ; offset
586 ;; al
= return value (byte
)
595 read_word(seg
, offset
)
605 mov ax
, 4[bp
] ; segment
607 mov bx
, 6[bp
] ; offset
609 ;; ax
= return value (word
)
618 write_byte(seg
, offset
, data
)
630 mov ax
, 4[bp
] ; segment
632 mov bx
, 6[bp
] ; offset
633 mov al
, 8[bp
] ; data byte
634 mov
[bx
], al
; write data byte
644 write_word(seg
, offset
, data
)
655 mov ax
, 4[bp
] ; segment
657 mov bx
, 6[bp
] ; offset
658 mov ax
, 8[bp
] ; data word
659 mov
[bx
], ax
; write data word
670 setPCIaddr(bus
, devfunc
, regnum
)
683 mov al
, 6[bp
] ;; devfunc
685 mov al
, 8[bp
] ;; regnum
701 // return value in AX is: AL=quotient, AH=remainder
708 mov bx
, 6[bp
] ;; b
: only low eight bits used
709 div bl
;; AX
/ BL
--> quotient
=AL
, remainder
=AH
720 // divide a by b, discarding remainder
730 div bx
;; DX
:AX
/ BX
-> AX
, DX
= remainder
746 //set_DS(ds_selector)
747 // Bit16u ds_selector;
754 // mov ax, 4[bp] ; ds_selector
794 if (action
& BIOS_PRINTF_DEBUG
) outb(0xfff0, c
);
795 if (action
& BIOS_PRINTF_SCREEN
) {
796 if (c
== '\n') wrch('\r');
802 put_int(action
, val
, width
, neg
)
807 short nval
= UDIV16(val
, 10);
809 put_int(action
, nval
, width
- 1, neg
);
811 while (--width
> 0) send(action
, ' ');
812 if (neg
) send(action
, '-');
814 send(action
, val
- (nval
* 10) + '0');
817 //--------------------------------------------------------------------------
819 // A compact variable argument printf function which prints its output via
820 // an I/O port so that it can be logged by Bochs. Currently, only %x is
821 // supported (or %02x, %04x, etc).
823 // Supports %[format_width][format]
824 // where format can be d,x,c,s
825 //--------------------------------------------------------------------------
827 bios_printf(action
, s
)
831 Bit8u c
, format_char
;
835 Bit16u arg_seg
, arg
, nibble
, shift_count
, format_width
;
843 if ((action
& BIOS_PRINTF_DEBHALT
) == BIOS_PRINTF_DEBHALT
) {
844 bios_printf (BIOS_PRINTF_ALL
, "FATAL: ");
847 while (c
= read_byte(0xf000, s
)) {
852 else if (in_format
) {
853 if ( (c
>='0') && (c
<='9') ) {
854 format_width
= (format_width
* 10) + (c
- '0');
857 arg_ptr
++; // increment to next arg
858 arg
= read_word(arg_seg
, arg_ptr
);
860 if (format_width
== 0)
862 for (i
=format_width
-1; i
>=0; i
--) {
863 nibble
= (arg
>> (4 * i
)) & 0x000f;
864 send (action
, (nibble
<=9)? (nibble
+'0') : (nibble
-10+'A'));
869 put_int(action
, -arg
, format_width
- 1, 1);
871 put_int(action
, arg
, format_width
, 0);
874 bios_printf(action
& (~BIOS_PRINTF_HALT
), arg
);
880 panic("bios_printf: unknown format");
890 if (action
& BIOS_PRINTF_HALT
) {
891 // freeze in a busy loop. If I do a HLT instruction, then in versions
892 // 1.3.pre1 and earlier, it will panic without ever updating the VGA
893 // display, so the panic message will not be visible. By waiting
894 // forever, you are certain to see the panic message on screen.
895 // After a few more versions have passed, we can turn this back into
896 // a halt or something.
915 panic("Keyboard RESET error");
919 This is called when the boot fails to print an appropriate message.
920 If bit 16 is 0, the disk was not readable.
921 If bit 16 is 1, the disk was readable but didn't have the boot signature.
922 If bit 15 is 0, it tried to boot a floppy disk.
923 If bit 15 is 1, it tried to boot a hard disk.
924 Bits 14-0 are the drive number, usually just a 0 or 1.
927 boot_failure_msg(drive
)
930 Bit16u drivenum
= drive
&0x7f;
931 //bios_printf(BIOS_PRINTF_SCREEN, "boot_failure_msg(%x)\n", drive);
933 bios_printf(BIOS_PRINTF_DEBUG
| BIOS_PRINTF_SCREEN
, "Boot from hard disk %d failed\n", drivenum
);
935 bios_printf(BIOS_PRINTF_DEBUG
| BIOS_PRINTF_SCREEN
, "Boot from floppy disk %d failed\n", drivenum
);
937 panic("Not a bootable disk\n");
939 panic("Could not read the boot disk\n");
945 bios_printf(BIOS_PRINTF_DEBUG
, "NMI Handler called\n");
951 bios_printf(BIOS_PRINTF_DEBUG
, "%s\n", bios_version_string
);
957 bios_printf(BIOS_PRINTF_SCREEN
, "Bochs BIOS, %s %s\n\n",
958 bios_cvs_version_string
, bios_date_string
);
960 bios_printf(BIOS_PRINTF_SCREEN, "Test: x234=%3x, d-123=%d, c=%c, s=%s\n",
961 0x1234, -123, '!', "ok");
972 // Use PS2 System Control port A to set A20 enable
974 // get current setting first
979 outb(0x92, oldval
| 0x02);
981 outb(0x92, oldval
& 0xfd);
983 return((oldval
& 0x02) != 0);
1001 int14_function(regs
, ds
, iret_addr
)
1002 pusha_regs_t regs
; // regs pushed from PUSHA instruction
1003 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
1004 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
1006 Bit16u addr
,timer
,val16
;
1013 addr
= read_word(0x0040, 2 * regs
.u
.r16
.dx
);
1014 timeout
= read_byte(0x0040, 0x007C + regs
.u
.r16
.dx
);
1015 if ((regs
.u
.r16
.dx
< 4) && (addr
> 0)) {
1016 switch (regs
.u
.r8
.ah
) {
1018 outb(addr
+3, inb(addr
+3) | 0x80);
1019 if (regs
.u
.r8
.al
& 0xE0 == 0) {
1023 val16
= 0x600 >> ((regs
.u
.r8
.al
& 0xE0) >> 5);
1024 outb(addr
, val16
& 0xFF);
1025 outb(addr
+1, val16
>> 8);
1027 outb(addr
+3, regs
.u
.r8
.al
& 0x1F);
1028 regs
.u
.r8
.ah
= inb(addr
+5);
1029 regs
.u
.r8
.al
= inb(addr
+6);
1030 ClearCF(iret_addr
.flags
);
1033 timer
= read_word(0x0040, 0x006C);
1034 while (((inb(addr
+5) & 0x60) != 0x60) && (timeout
)) {
1035 val16
= read_word(0x0040, 0x006C);
1036 if (val16
!= timer
) {
1041 if (timeout
) outb(addr
, regs
.u
.r8
.al
);
1042 regs
.u
.r8
.ah
= inb(addr
+5);
1043 if (!timeout
) regs
.u
.r8
.ah
|= 0x80;
1044 ClearCF(iret_addr
.flags
);
1047 timer
= read_word(0x0040, 0x006C);
1048 while (((inb(addr
+5) & 0x01) == 0) && (timeout
)) {
1049 val16
= read_word(0x0040, 0x006C);
1050 if (val16
!= timer
) {
1057 regs
.u
.r8
.al
= inb(addr
);
1059 regs
.u
.r8
.ah
= inb(addr
+5);
1061 ClearCF(iret_addr
.flags
);
1064 regs
.u
.r8
.ah
= inb(addr
+5);
1065 regs
.u
.r8
.al
= inb(addr
+6);
1066 ClearCF(iret_addr
.flags
);
1069 SetCF(iret_addr
.flags
); // Unsupported
1072 SetCF(iret_addr
.flags
); // Unsupported
1077 int15_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, DS
, FLAGS
)
1078 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, DS
, FLAGS
;
1081 Bit8u mouse_flags_1
, mouse_flags_2
;
1082 Bit16u mouse_driver_seg
;
1083 Bit16u mouse_driver_offset
;
1085 Bit8u response
, prev_command_byte
;
1086 Boolean prev_a20_enable
;
1090 Bit8u ret
, mouse_data1
, mouse_data2
, mouse_data3
;
1091 Bit8u comm_byte
, mf2_state
;
1094 case 0x24: /* A20 Control */
1095 printf("BIOS: int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) GET_AL());
1097 SET_AH(UNSUPPORTED_FUNCTION
);
1102 SET_AH(UNSUPPORTED_FUNCTION
);
1106 /* keyboard intercept */
1108 SET_AH(UNSUPPORTED_FUNCTION
);
1110 if (GET_AL() == 0xE0) {
1111 mf2_state
= read_byte(0x0040, 0x96);
1112 write_byte(0x0040, 0x96, mf2_state
| 0x01);
1121 # error "Int15 function 87h not supported on < 80386"
1123 // +++ should probably have descriptor checks
1124 // +++ should have exception handlers
1128 prev_a20_enable
= set_enable_a20(1); // enable A20 line
1130 // 128K max of transfer on 386+ ???
1131 // source == destination ???
1133 // ES:SI points to descriptor table
1134 // offset use initially comments
1135 // ==============================================
1136 // 00..07 Unused zeros Null descriptor
1137 // 08..0f GDT zeros filled in by BIOS
1138 // 10..17 source ssssssss source of data
1139 // 18..1f dest dddddddd destination of data
1140 // 20..27 CS zeros filled in by BIOS
1141 // 28..2f SS zeros filled in by BIOS
1148 // check for access rights of source & dest here
1150 // Initialize GDT descriptor
1151 base15_00
= (ES
<< 4) + SI
;
1152 base23_16
= ES
>> 12;
1153 if (base15_00
< (ES
<<4))
1155 write_word(ES
, SI
+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
1156 write_word(ES
, SI
+0x08+2, base15_00
);// base 15:00
1157 write_byte(ES
, SI
+0x08+4, base23_16
);// base 23:16
1158 write_byte(ES
, SI
+0x08+5, 0x93); // access
1159 write_word(ES
, SI
+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
1161 // Initialize CS descriptor
1162 write_word(ES
, SI
+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
1163 write_word(ES
, SI
+0x20+2, 0x0000);// base 15:00
1164 write_byte(ES
, SI
+0x20+4, 0x000f);// base 23:16
1165 write_byte(ES
, SI
+0x20+5, 0x9b); // access
1166 write_word(ES
, SI
+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
1168 // Initialize SS descriptor
1170 base15_00
= ss
<< 4;
1171 base23_16
= ss
>> 12;
1172 write_word(ES
, SI
+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
1173 write_word(ES
, SI
+0x28+2, base15_00
);// base 15:00
1174 write_byte(ES
, SI
+0x28+4, base23_16
);// base 23:16
1175 write_byte(ES
, SI
+0x28+5, 0x93); // access
1176 write_word(ES
, SI
+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
1179 // Compile generates locals offset info relative to SP.
1180 // Get CX (word count) from stack.
1183 mov cx
, _int15_function
.CX
[bx
]
1185 // since we need to set SS:SP, save them to the BDA
1186 // for future restore
1195 lidt
[pmode_IDT_info
]
1196 ;; perhaps
do something with IDT here
1198 ;; set PE bit in CR0
1202 ;; far jump to flush CPU queue after transition to
protected mode
1203 JMP_AP(0x0020, protected_mode
)
1206 ;; GDT points to valid descriptor table
, now load SS
, DS
, ES
1207 mov ax
, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
1209 mov ax
, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
1211 mov ax
, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
1217 movsw
;; move CX words from DS
:SI to ES
:DI
1219 ;; clear CR3
and reset PG bit in CR0
???
1223 ;; far jump to flush CPU queue after transition to real mode
1224 JMP_AP(0xf000, real_mode
)
1227 ;; restore IDT to normal real
-mode defaults
1229 lidt
[rmode_IDT_info
]
1231 // restore SS:SP from the BDA
1238 set_enable_a20(prev_a20_enable
);
1244 case 0x88: /* extended memory size */
1246 SET_AH(UNSUPPORTED_FUNCTION
);
1249 /* ??? change this back later... */
1250 /* number of 1K blocks of extended memory, subtract off 1st 1Meg */
1251 // AX = bx_mem.get_memory_in_k() - 1024;
1252 in_byte
= inb_cmos(0x30);
1254 in_byte
= inb_cmos(0x31);
1261 /* Device busy interrupt. Called by Int 16h when no key available */
1265 /* Interrupt complete. Called by Int 16h when key becomes available */
1269 printf("BIOS: *** int 15h function AH=bf not yet supported!\n");
1271 SET_AH(UNSUPPORTED_FUNCTION
);
1277 SET_AH(UNSUPPORTED_FUNCTION
);
1282 BX
= BIOS_CONFIG_TABLE
;
1287 #if BX_USE_PS2_MOUSE
1288 ES
= read_word(0x0040, 0x000E);
1292 SET_AH(UNSUPPORTED_FUNCTION
);
1297 // Return Codes status in AH
1298 // =========================
1300 // 01: invalid subfunction (AL > 7)
1301 // 02: invalid input value (out of allowable range)
1302 // 03: interface error
1303 // 04: resend command received from mouse controller,
1304 // device driver should attempt command again
1305 // 05: cannot enable mouse, since no far call has been installed
1306 // 80/86: mouse service not implemented
1308 #if BX_USE_PS2_MOUSE < 1
1310 SET_AH(UNSUPPORTED_FUNCTION
);
1312 ebda_seg
= read_word(0x0040, 0x000E);
1314 case 0: // Disable/Enable Mouse
1315 printf("case 0:\n");
1317 case 0: // Disable Mouse
1318 printf("case 0: disable mouse\n");
1319 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
1320 ret
= send_to_mouse_ctrl(0xF5); // disable mouse command
1322 ret
= get_mouse_data(&mouse_data1
);
1323 if ( (ret
== 0) || (mouse_data1
== 0xFA) ) {
1336 case 1: // Enable Mouse
1337 printf("case 1: enable mouse\n");
1338 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
1339 if ( (mouse_flags_2
& 0x80) == 0 ) {
1340 //printf("INT 15h C2 Enable Mouse, no far call handler\n");
1342 SET_AH(5); // no far call installed
1345 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
1346 ret
= send_to_mouse_ctrl(0xF4); // enable mouse command
1348 ret
= get_mouse_data(&mouse_data1
);
1349 if ( (ret
== 0) && (mouse_data1
== 0xFA) ) {
1350 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
1360 default: // invalid subfunction
1361 //printf("INT 15h C2 AL=0, BH=%02x\n", (unsigned) GET_BH());
1363 SET_AH(1); // invalid subfunction
1368 case 1: // Reset Mouse
1369 case 5: // Initialize Mouse
1370 printf("case 1 or 5:\n");
1371 if (GET_AL() == 5) {
1373 panic("INT 15h C2 AL=5, BH=%02x", (unsigned) GET_BH());
1374 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
1375 mouse_flags_2
= (mouse_flags_2
& 0x00) | GET_BH();
1376 mouse_flags_1
= 0x00;
1377 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
1378 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
1381 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
1382 ret
= send_to_mouse_ctrl(0xFF); // disable mouse command
1384 ret
= get_mouse_data(&mouse_data3
);
1385 if (mouse_data3
!= 0xfa)
1386 panic("Mouse reset returned %02x (should be ack)", (unsigned)mouse_data3
);
1388 ret
= get_mouse_data(&mouse_data1
);
1390 ret
= get_mouse_data(&mouse_data2
);
1392 // turn IRQ12 and packet generation on
1393 enable_mouse_int_and_events();
1396 SET_BL(mouse_data1
);
1397 SET_BH(mouse_data2
);
1409 case 2: // Set Sample Rate
1410 printf("case 2:\n");
1412 case 0: // 10 reports/sec
1413 case 1: // 20 reports/sec
1414 case 2: // 40 reports/sec
1415 case 3: // 60 reports/sec
1416 case 4: // 80 reports/sec
1417 case 5: // 100 reports/sec (default)
1418 case 6: // 200 reports/sec
1423 panic("INT 15h C2 AL=2, BH=%02x", (unsigned) GET_BH());
1427 case 3: // Set Resolution
1428 printf("case 3:\n");
1430 // 0 = 25 dpi, 1 count per millimeter
1431 // 1 = 50 dpi, 2 counts per millimeter
1432 // 2 = 100 dpi, 4 counts per millimeter
1433 // 3 = 200 dpi, 8 counts per millimeter
1438 case 4: // Get Device ID
1439 printf("case 4:\n");
1445 case 6: // Return Status & Set Scaling Factor...
1446 printf("case 6:\n");
1448 case 0: // Return Status
1449 comm_byte
= inhibit_mouse_int_and_events(); // disable IRQ12 and packets
1450 ret
= send_to_mouse_ctrl(0xE9); // get mouse info command
1452 ret
= get_mouse_data(&mouse_data1
);
1453 if (mouse_data1
!= 0xfa)
1454 panic("Mouse status returned %02x (should be ack)", (unsigned)mouse_data1
);
1456 ret
= get_mouse_data(&mouse_data1
);
1458 ret
= get_mouse_data(&mouse_data2
);
1460 ret
= get_mouse_data(&mouse_data3
);
1464 SET_BL(mouse_data1
);
1465 SET_CL(mouse_data2
);
1466 SET_DL(mouse_data3
);
1467 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
1478 set_kbd_command_byte(comm_byte
); // restore IRQ12 and serial enable
1481 case 1: // Set Scaling Factor to 1:1
1487 panic("INT 15h C2 AL=6, BH=%02x", (unsigned) GET_BH());
1491 case 7: // Set Mouse Handler Address
1492 printf("case 7:\n");
1493 mouse_driver_seg
= ES
;
1494 mouse_driver_offset
= BX
;
1495 write_word(ebda_seg
, 0x0022, mouse_driver_offset
);
1496 write_word(ebda_seg
, 0x0024, mouse_driver_seg
);
1497 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
1498 mouse_flags_2
|= 0x80;
1499 write_byte(ebda_seg
, 0x0027, mouse_flags_2
);
1505 printf("case default:\n");
1506 SET_AH(1); // invalid function
1513 printf("BIOS: *** int 15h function AX=%04x, BX=%04x not yet supported!\n",
1514 (unsigned) AX
, (unsigned) BX
);
1516 SET_AH(UNSUPPORTED_FUNCTION
);
1520 printf("BIOS: *** int 15h function AX=D8 not yet supported!\n");
1522 SET_AH(UNSUPPORTED_FUNCTION
);
1526 printf("BIOS: *** int 15h function AH=e0 not yet supported!\n");
1528 SET_AH(UNSUPPORTED_FUNCTION
);
1532 printf("BIOS: *** int 15h function AH=%02x not yet supported!\n",
1533 (unsigned) GET_AH());
1535 SET_AH(UNSUPPORTED_FUNCTION
);
1542 int16_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
)
1543 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, FLAGS
;
1545 Bit8u scan_code
, ascii_code
, shift_flags
;
1549 case 0x00: /* read keyboard input */
1551 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
1552 panic("KBD: int16h: out of keyboard input");
1554 AX
= (scan_code
<< 8) | ascii_code
;
1557 case 0x01: /* check keyboard status */
1558 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
1562 AX
= (scan_code
<< 8) | ascii_code
;
1566 case 0x02: /* get shift flag status */
1567 shift_flags
= read_byte(0x0040, 0x17);
1568 SET_AL(shift_flags
);
1571 case 0x10: /* read MF-II keyboard input */
1573 if ( !dequeue_key(&scan_code
, &ascii_code
, 1) ) {
1574 panic("KBD: int16h: out of keyboard input");
1576 if (ascii_code
== 0) ascii_code
= 0xE0;
1577 AX
= (scan_code
<< 8) | ascii_code
;
1580 case 0x11: /* check MF-II keyboard status */
1581 if ( !dequeue_key(&scan_code
, &ascii_code
, 0) ) {
1585 if (ascii_code
== 0) ascii_code
= 0xE0;
1586 AX
= (scan_code
<< 8) | ascii_code
;
1590 case 0x12: /* get extended keyboard status */
1591 shift_flags
= read_byte(0x0040, 0x17);
1592 SET_AL(shift_flags
);
1593 shift_flags
= read_byte(0x0040, 0x18);
1594 SET_AH(shift_flags
);
1598 printf("KBD: unsupported int 16h function %02x\n", GET_AH());
1603 dequeue_key(scan_code
, ascii_code
, incr
)
1608 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
;
1613 buffer_start
= 0x001E;
1614 buffer_end
= 0x003E;
1616 buffer_start
= read_word(0x0040, 0x0080);
1617 buffer_end
= read_word(0x0040, 0x0082);
1620 buffer_head
= read_word(0x0040, 0x001a);
1621 buffer_tail
= read_word(0x0040, 0x001c);
1623 if (buffer_head
!= buffer_tail
) {
1625 acode
= read_byte(0x0040, buffer_head
);
1626 scode
= read_byte(0x0040, buffer_head
+1);
1627 write_byte(ss
, ascii_code
, acode
);
1628 write_byte(ss
, scan_code
, scode
);
1632 if (buffer_head
>= buffer_end
)
1633 buffer_head
= buffer_start
;
1634 write_word(0x0040, 0x001a, buffer_head
);
1646 inhibit_mouse_int_and_events()
1648 Bit8u command_byte
, prev_command_byte
;
1650 // Turn off IRQ generation and aux data line
1651 if ( inb(0x64) & 0x02 )
1652 panic("inhibmouse: keyboard input buffer full");
1653 outb(0x64, 0x20); // get command byte
1654 while ( (inb(0x64) & 0x01) != 0x01 );
1655 prev_command_byte
= inb(0x60);
1656 command_byte
= prev_command_byte
;
1657 //while ( (inb(0x64) & 0x02) );
1658 if ( inb(0x64) & 0x02 )
1659 panic("inhibmouse, keyboard input buffer full");
1660 command_byte
&= 0xfd; // turn off IRQ 12 generation
1661 command_byte
|= 0x20; // disable mouse serial clock line
1662 outb(0x64, 0x60); // write command byte
1663 outb(0x60, command_byte
);
1664 return(prev_command_byte
);
1668 enable_mouse_int_and_events()
1672 // Turn on IRQ generation and aux data line
1673 if ( inb(0x64) & 0x02 )
1674 panic("enabmouse: keyboard input buffer full");
1675 outb(0x64, 0x20); // get command byte
1676 while ( (inb(0x64) & 0x01) != 0x01 );
1677 command_byte
= inb(0x60);
1678 //while ( (inb(0x64) & 0x02) );
1679 if ( inb(0x64) & 0x02 )
1680 panic("enabmouse, keyboard input buffer full");
1681 command_byte
|= 0x02; // turn on IRQ 12 generation
1682 command_byte
&= 0xdf; // enable mouse serial clock line
1683 outb(0x64, 0x60); // write command byte
1684 outb(0x60, command_byte
);
1688 send_to_mouse_ctrl(sendbyte
)
1693 // wait for chance to write to ctrl
1694 if ( inb(0x64) & 0x02 )
1695 panic("sendmouse, keyboard input buffer full");
1697 outb(0x60, sendbyte
);
1703 get_mouse_data(data
)
1709 while ( (inb(0x64) & 0x21) != 0x21 ) {
1712 response
= inb(0x60);
1715 write_byte(ss
, data
, response
);
1720 set_kbd_command_byte(command_byte
)
1723 if ( inb(0x64) & 0x02 )
1724 panic("setkbdcomm, input buffer full");
1726 outb(0x64, 0x60); // write command byte
1727 outb(0x60, command_byte
);
1731 int09_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
)
1732 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
;
1734 Bit8u scancode
, asciicode
, shift_flags
;
1735 Bit8u mf2_flags
, mf2_state
, led_flags
;
1738 // DS has been set to F000 before call
1742 scancode
= GET_AL();
1744 if (scancode
== 0) {
1745 printf("KBD: int09 handler: AL=0\n");
1750 shift_flags
= read_byte(0x0040, 0x17);
1751 mf2_flags
= read_byte(0x0040, 0x18);
1752 mf2_state
= read_byte(0x0040, 0x96);
1753 led_flags
= read_byte(0x0040, 0x97);
1757 case 0x3a: /* Caps Lock press */
1758 shift_flags
|= 0x40;
1759 write_byte(0x0040, 0x17, shift_flags
);
1761 write_byte(0x0040, 0x18, mf2_flags
);
1763 write_byte(0x0040, 0x97, led_flags
);
1765 case 0xba: /* Caps Lock release */
1767 write_byte(0x0040, 0x18, mf2_flags
);
1770 case 0x2a: /* L Shift press */
1771 shift_flags
&= ~0x40;
1772 shift_flags
|= 0x02;
1773 write_byte(0x0040, 0x17, shift_flags
);
1775 write_byte(0x0040, 0x97, led_flags
);
1777 case 0xaa: /* L Shift release */
1778 shift_flags
&= ~0x02;
1779 write_byte(0x0040, 0x17, shift_flags
);
1782 case 0x36: /* R Shift press */
1783 shift_flags
&= ~0x40;
1784 shift_flags
|= 0x01;
1785 write_byte(0x0040, 0x17, shift_flags
);
1787 write_byte(0x0040, 0x97, led_flags
);
1789 case 0xb6: /* R Shift release */
1790 shift_flags
&= ~0x01;
1791 write_byte(0x0040, 0x17, shift_flags
);
1794 case 0x1d: /* Ctrl press */
1795 shift_flags
|= 0x04;
1796 write_byte(0x0040, 0x17, shift_flags
);
1797 if (mf2_state
& 0x01) {
1802 write_byte(0x0040, 0x18, mf2_flags
);
1804 case 0x9d: /* Ctrl release */
1805 shift_flags
&= ~0x04;
1806 write_byte(0x0040, 0x17, shift_flags
);
1807 if (mf2_state
& 0x01) {
1812 write_byte(0x0040, 0x18, mf2_flags
);
1815 case 0x38: /* Alt press */
1816 shift_flags
|= 0x08;
1817 write_byte(0x0040, 0x17, shift_flags
);
1818 if (mf2_state
& 0x01) {
1823 write_byte(0x0040, 0x18, mf2_flags
);
1825 case 0xb8: /* Alt release */
1826 shift_flags
&= ~0x08;
1827 write_byte(0x0040, 0x17, shift_flags
);
1828 if (mf2_state
& 0x01) {
1833 write_byte(0x0040, 0x18, mf2_flags
);
1836 case 0x45: /* Num Lock press */
1837 if ((mf2_state
& 0x01) == 0) {
1839 write_byte(0x0040, 0x18, mf2_flags
);
1840 if (shift_flags
& 0x20) {
1841 shift_flags
&= ~0x20;
1844 shift_flags
|= 0x20;
1847 write_byte(0x0040, 0x17, shift_flags
);
1848 write_byte(0x0040, 0x97, led_flags
);
1851 case 0xc5: /* Num Lock release */
1852 if ((mf2_state
& 0x01) == 0) {
1854 write_byte(0x0040, 0x18, mf2_flags
);
1858 case 0x46: /* Scroll Lock press */
1860 write_byte(0x0040, 0x18, mf2_flags
);
1861 if (shift_flags
& 0x10) {
1862 shift_flags
&= ~0x10;
1865 shift_flags
|= 0x10;
1868 write_byte(0x0040, 0x17, shift_flags
);
1869 write_byte(0x0040, 0x97, led_flags
);
1872 case 0xc6: /* Scroll Lock release */
1874 write_byte(0x0040, 0x18, mf2_flags
);
1878 if (scancode
& 0x80) return; /* toss key releases ... */
1879 if (scancode
> MAX_SCAN_CODE
) {
1880 panic("KBD: int09h_handler(): unknown scancode read!");
1883 if (shift_flags
& 0x08) { /* ALT */
1884 asciicode
= scan_to_scanascii
[scancode
].alt
;
1885 scancode
= scan_to_scanascii
[scancode
].alt
>> 8;
1887 else if (shift_flags
& 0x04) { /* CONTROL */
1888 asciicode
= scan_to_scanascii
[scancode
].control
;
1889 scancode
= scan_to_scanascii
[scancode
].control
>> 8;
1891 else if (shift_flags
& 0x43) { /* CAPSLOCK + LSHIFT + RSHIFT */
1892 /* check if both CAPSLOCK and a SHIFT key are pressed */
1893 if ((shift_flags
& 0x03) && (shift_flags
& 0x40)) {
1894 asciicode
= scan_to_scanascii
[scancode
].normal
;
1895 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
1898 asciicode
= scan_to_scanascii
[scancode
].shift
;
1899 scancode
= scan_to_scanascii
[scancode
].shift
>> 8;
1903 asciicode
= scan_to_scanascii
[scancode
].normal
;
1904 scancode
= scan_to_scanascii
[scancode
].normal
>> 8;
1906 if (scancode
==0 && asciicode
==0) {
1907 panic("KBD: int09h_handler(): scancode & asciicode are zero?");
1909 enqueue_key(scancode
, asciicode
);
1916 enqueue_key(scan_code
, ascii_code
)
1917 Bit8u scan_code
, ascii_code
;
1919 Bit16u buffer_start
, buffer_end
, buffer_head
, buffer_tail
, temp_tail
;
1921 //printf("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
1922 // scan_code, ascii_code);
1925 buffer_start
= 0x001E;
1926 buffer_end
= 0x003E;
1928 buffer_start
= read_word(0x0040, 0x0080);
1929 buffer_end
= read_word(0x0040, 0x0082);
1932 buffer_head
= read_word(0x0040, 0x001A);
1933 buffer_tail
= read_word(0x0040, 0x001C);
1935 temp_tail
= buffer_tail
;
1937 if (buffer_tail
>= buffer_end
)
1938 buffer_tail
= buffer_start
;
1940 if (buffer_tail
== buffer_head
) {
1941 panic("KBD: dropped key scan=%02x, ascii=%02x",
1942 (int) scan_code
, (int) ascii_code
);
1946 write_byte(0x0040, temp_tail
, ascii_code
);
1947 write_byte(0x0040, temp_tail
+1, scan_code
);
1948 write_word(0x0040, 0x001C, buffer_tail
);
1953 int74_function(make_farcall
, Z
, Y
, X
, status
)
1954 Bit16u make_farcall
, Z
, Y
, X
, status
;
1956 Bit8u in_byte
, index
, package_count
;
1958 Bit8u mouse_flags_1
, mouse_flags_2
;
1960 printf("entering int74_function\n");
1963 in_byte
= inb(0x64);
1964 if ( (in_byte
& 0x21) != 0x21 ) {
1967 in_byte
= inb(0x60);
1968 printf("int74: read byte %02x\n", in_byte
);
1970 ebda_seg
= read_word(0x0040, 0x000E);
1971 mouse_flags_1
= read_byte(ebda_seg
, 0x0026);
1972 mouse_flags_2
= read_byte(ebda_seg
, 0x0027);
1974 if ( (mouse_flags_2
& 0x80) != 0x80 ) {
1975 panic("int74_function:");
1978 package_count
= mouse_flags_2
& 0x07;
1979 index
= mouse_flags_1
& 0x07;
1980 write_byte(ebda_seg
, 0x28 + index
, in_byte
);
1982 if ( (index
+1) >= package_count
) {
1983 printf("int74_function: make_farcall=1\n");
1984 status
= read_byte(ebda_seg
, 0x0028 + 0);
1985 X
= read_byte(ebda_seg
, 0x0028 + 1);
1986 Y
= read_byte(ebda_seg
, 0x0028 + 2);
1989 // check if far call handler installed
1990 if (mouse_flags_2
& 0x80)
1996 write_byte(ebda_seg
, 0x0026, mouse_flags_1
);
2002 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,dl
)
2054 int13_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
)
2055 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
;
2057 Bit8u drive
, num_sectors
, sector
, head
, status
, mod
;
2060 Bit16u max_cylinder
, cylinder
, total_sectors
;
2061 Bit16u hd_cylinders
;
2062 Bit8u hd_heads
, hd_sectors
;
2069 write_byte(0x0040, 0x008e, 0); // clear completion flag
2071 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
2073 /* check how many disks first (cmos reg 0x12), return an error if
2075 n_drives
= inb_cmos(0x12);
2076 n_drives
= ((n_drives
& 0xf0)==0) ? 0 :
2077 ((n_drives
& 0x0f) ? 2 : 1);
2079 if (!((GET_DL()&0x7f) < n_drives
)) { /* allow 0, 1, or 2 disks */
2081 set_disk_ret_status(0x01);
2082 SET_CF(); /* error occurred */
2088 case 0x00: /* disk controller reset */
2089 printf("int13_f00\n");
2092 set_disk_ret_status(0);
2093 set_diskette_ret_status(0);
2094 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
2095 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
2096 CLEAR_CF(); /* successful */
2100 case 0x01: /* read disk status */
2101 printf("int13_f01\n");
2102 status
= read_byte(0x0040, 0x0074);
2104 set_disk_ret_status(0);
2105 /* set CF if error status read */
2106 if (status
) SET_CF();
2111 case 0x04: // verify disk sectors
2112 case 0x02: // read disk sectors
2114 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
2116 num_sectors
= GET_AL();
2117 cylinder
= GET_CH();
2118 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
2119 sector
= (GET_CL() & 0x3f);
2123 if (hd_cylinders
> 1024) {
2124 if (hd_cylinders
<= 2048) {
2127 else if (hd_cylinders
<= 4096) {
2130 else if (hd_cylinders
<= 8192) {
2133 else { // hd_cylinders <= 16384
2137 ax
= UDIV(head
, hd_heads
);
2138 cyl_mod
= ax
& 0xff;
2140 cylinder
|= cyl_mod
;
2143 if ( (cylinder
>= hd_cylinders
) ||
2144 (sector
> hd_sectors
) ||
2145 (head
>= hd_heads
) ) {
2147 set_disk_ret_status(1);
2148 SET_CF(); /* error occurred */
2152 if ( (num_sectors
> 128) || (num_sectors
== 0) )
2153 panic("int13_function(): num_sectors out of range!");
2156 panic("hard drive BIOS:(read/verify) head > 15\n");
2158 if ( GET_AH() == 0x04 ) {
2160 set_disk_ret_status(0);
2165 status
= inb(0x1f7);
2166 if (status
& 0x80) {
2167 panic("hard drive BIOS:(read/verify) BUSY bit set");
2169 outb(0x01f2, num_sectors
);
2170 /* activate LBA? (tomv) */
2171 if (hd_heads
> 15) {
2172 printf("CHS: %x %x %x\n", cylinder
, head
, sector
);
2173 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,drive
);
2176 outb(0x01f3, sector
);
2177 outb(0x01f4, cylinder
& 0x00ff);
2178 outb(0x01f5, cylinder
>> 8);
2179 outb(0x01f6, 0xa0 | ((drive
& 0x01)<<4) | (head
& 0x0f));
2184 status
= inb(0x1f7);
2185 if ( !(status
& 0x80) ) break;
2188 if (status
& 0x01) {
2189 panic("hard drive BIOS:(read/verify) read error");
2190 } else if ( !(status
& 0x08) ) {
2191 printf("status was %02x\n", (unsigned) status
);
2192 panic("hard drive BIOS:(read/verify) expected DRQ=1");
2199 sti
;; enable higher priority interrupts
2204 ;; store temp bx in real DI
register
2207 mov di
, _int13_function
.tempbx
+ 2 [bp
]
2210 ;; adjust
if there will be an overrun
2212 jbe i13_f02_no_adjust
2214 sub di
, #0x0200 ; sub 512 bytes from offset
2216 add ax
, #0x0020 ; add 512 to segment
2220 mov cx
, #0x0100 ;; counter (256 words = 512b)
2221 mov dx
, #0x01f0 ;; AT data read port
2224 insw
;; CX words transfered from
port(DX
) to ES
:[DI
]
2227 ;; store real DI
register back to temp bx
2230 mov _int13_function
.tempbx
+ 2 [bp
], di
2236 if (num_sectors
== 0) {
2237 status
= inb(0x1f7);
2238 if ( (status
& 0xc9) != 0x40 )
2239 panic("no sectors left to read/verify, status is %02x", (unsigned) status
);
2243 status
= inb(0x1f7);
2244 if ( (status
& 0xc9) != 0x48 )
2245 panic("more sectors left to read/verify, status is %02x", (unsigned) status
);
2251 set_disk_ret_status(0);
2252 SET_AL(sector_count
);
2253 CLEAR_CF(); /* successful */
2258 case 0x03: /* write disk sectors */
2259 printf("int13_f03\n");
2261 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
2263 num_sectors
= GET_AL();
2264 cylinder
= GET_CH();
2265 cylinder
|= ( ((Bit16u
) GET_CL()) << 2) & 0x300;
2266 sector
= (GET_CL() & 0x3f);
2269 if (hd_cylinders
> 1024) {
2270 if (hd_cylinders
<= 2048) {
2273 else if (hd_cylinders
<= 4096) {
2276 else if (hd_cylinders
<= 8192) {
2279 else { // hd_cylinders <= 16384
2283 ax
= UDIV(head
, hd_heads
);
2284 cyl_mod
= ax
& 0xff;
2286 cylinder
|= cyl_mod
;
2289 if ( (cylinder
>= hd_cylinders
) ||
2290 (sector
> hd_sectors
) ||
2291 (head
>= hd_heads
) ) {
2293 set_disk_ret_status(1);
2294 SET_CF(); /* error occurred */
2298 if ( (num_sectors
> 128) || (num_sectors
== 0) )
2299 panic("int13_function(): num_sectors out of range!");
2302 panic("hard drive BIOS:(read) head > 15\n");
2304 status
= inb(0x1f7);
2305 if (status
& 0x80) {
2306 panic("hard drive BIOS:(read) BUSY bit set");
2308 // should check for Drive Ready Bit also in status reg
2309 outb(0x01f2, num_sectors
);
2311 /* activate LBA? (tomv) */
2312 if (hd_heads
> 15) {
2313 printf("CHS (write): %x %x %x\n", cylinder
, head
, sector
);
2314 outLBA(cylinder
,hd_heads
,head
,hd_sectors
,sector
,GET_DL());
2317 outb(0x01f3, sector
);
2318 outb(0x01f4, cylinder
& 0x00ff);
2319 outb(0x01f5, cylinder
>> 8);
2320 outb(0x01f6, 0xa0 | ((GET_DL() & 0x01)<<4) | (head
& 0x0f));
2324 // wait for busy bit to turn off after seeking
2326 status
= inb(0x1f7);
2327 if ( !(status
& 0x80) ) break;
2330 if ( !(status
& 0x08) ) {
2331 printf("status was %02x\n", (unsigned) status
);
2332 panic("hard drive BIOS:(write) data-request bit not set");
2339 sti
;; enable higher priority interrupts
2344 ;; store temp bx in real SI
register
2347 mov si
, _int13_function
.tempbx
+ 2 [bp
]
2350 ;; adjust
if there will be an overrun
2352 jbe i13_f03_no_adjust
2354 sub si
, #0x0200 ; sub 512 bytes from offset
2356 add ax
, #0x0020 ; add 512 to segment
2360 mov cx
, #0x0100 ;; counter (256 words = 512b)
2361 mov dx
, #0x01f0 ;; AT data read port
2365 outsw
;; CX words tranfered from ES
:[SI
] to
port(DX
)
2367 ;; store real SI
register back to temp bx
2370 mov _int13_function
.tempbx
+ 2 [bp
], si
2376 if (num_sectors
== 0) {
2377 status
= inb(0x1f7);
2378 if ( (status
& 0xe9) != 0x40 )
2379 panic("no sectors left to write, status is %02x", (unsigned) status
);
2383 status
= inb(0x1f7);
2384 if ( (status
& 0xc9) != 0x48 )
2385 panic("more sectors left to write, status is %02x", (unsigned) status
);
2391 set_disk_ret_status(0);
2392 SET_AL(sector_count
);
2393 CLEAR_CF(); /* successful */
2397 case 0x05: /* format disk track */
2398 printf("int13_f05\n");
2399 panic("format disk track called");
2402 set_disk_ret_status(0);
2403 CLEAR_CF(); /* successful */
2407 case 0x08: /* read disk drive parameters */
2408 printf("int13_f08\n");
2410 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
2414 if (hd_cylinders
<= 1024) {
2415 // hd_cylinders >>= 0;
2418 else if (hd_cylinders
<= 2048) {
2422 else if (hd_cylinders
<= 4096) {
2426 else if (hd_cylinders
<= 8192) {
2430 else { // hd_cylinders <= 16384
2435 max_cylinder
= hd_cylinders
- 2; /* 0 based */
2437 SET_CH(max_cylinder
& 0xff);
2438 SET_CL(((max_cylinder
>> 2) & 0xc0) | (hd_sectors
& 0x3f));
2439 SET_DH(hd_heads
- 1);
2440 SET_DL(n_drives
); /* returns 0, 1, or 2 hard drives */
2442 set_disk_ret_status(0);
2443 CLEAR_CF(); /* successful */
2447 case 0x09: /* initialize drive parameters */
2448 printf("int13_f09\n");
2450 set_disk_ret_status(0);
2451 CLEAR_CF(); /* successful */
2455 case 0x0a: /* read disk sectors with ECC */
2456 printf("int13_f0a\n");
2457 case 0x0b: /* write disk sectors with ECC */
2458 printf("int13_f0b\n");
2459 panic("int13h Functions 0Ah & 0Bh not implemented!");
2463 case 0x0c: /* seek to specified cylinder */
2464 printf("int13_f0c\n");
2465 printf("int13h function 0ch (seek) not implemented!\n");
2467 set_disk_ret_status(0);
2468 CLEAR_CF(); /* successful */
2472 case 0x0d: /* alternate disk reset */
2473 printf("int13_f0d\n");
2475 set_disk_ret_status(0);
2476 CLEAR_CF(); /* successful */
2480 case 0x10: /* check drive ready */
2481 printf("int13_f10\n");
2483 //set_disk_ret_status(0);
2484 //CLEAR_CF(); /* successful */
2488 // should look at 40:8E also???
2489 status
= inb(0x01f7);
2490 if ( (status
& 0xc0) == 0x40 ) {
2492 set_disk_ret_status(0);
2493 CLEAR_CF(); // drive ready
2498 set_disk_ret_status(0xAA);
2499 SET_CF(); // not ready
2504 case 0x11: /* recalibrate */
2505 printf("int13_f11\n");
2507 set_disk_ret_status(0);
2508 CLEAR_CF(); /* successful */
2512 case 0x14: /* controller internal diagnostic */
2513 printf("int13_f14\n");
2515 set_disk_ret_status(0);
2516 CLEAR_CF(); /* successful */
2521 case 0x15: /* read disk drive size */
2523 get_hd_geometry(drive
, &hd_cylinders
, &hd_heads
, &hd_sectors
);
2527 mov al
, _int13_function
.hd_heads
+ 2 [bp
]
2528 mov ah
, _int13_function
.hd_sectors
+ 2 [bp
]
2529 mul al
, ah
;; ax
= heads
* sectors
2530 mov bx
, _int13_function
.hd_cylinders
+ 2 [bp
]
2531 dec bx
;; use (cylinders
- 1) ???
2532 mul ax
, bx
;; dx
:ax
= (cylinders
-1) * (heads
* sectors
)
2533 ;; now we need to move the
32bit result dx
:ax to what the
2534 ;; BIOS wants which is cx
:dx
.
2535 ;; and then into CX
:DX on the stack
2536 mov _int13_function
.CX
+ 2 [bp
], dx
2537 mov _int13_function
.DX
+ 2 [bp
], ax
2540 SET_AH(3); // hard disk accessible
2541 set_disk_ret_status(0); // ??? should this be 0
2542 CLEAR_CF(); // successful
2547 case 0x41: // IBM/MS installation check
2548 case 0x42: // IBM/MS extended read
2549 case 0x43: // IBM/MS extended write
2550 case 0x44: // IBM/MS verify sectors
2551 case 0x45: // IBM/MS lock/unlock drive
2552 case 0x46: // IBM/MS eject media
2553 case 0x47: // IBM/MS extended seek
2554 case 0x48: // IBM/MS get drive parameters
2555 case 0x49: // IBM/MS extended media change
2556 printf("int13_f18,41-49\n");
2557 SET_AH(1); // code=invalid function in AH or invalid parameter
2558 set_disk_ret_status(1);
2559 SET_CF(); /* unsuccessful */
2564 panic("case 0x%x found in int13_function()", (unsigned) GET_AH());
2570 //////////////////////
2571 // FLOPPY functions //
2572 //////////////////////
2575 floppy_media_known(drive
)
2579 Bit16u media_state_offset
;
2581 val8
= read_byte(0x0040, 0x003e); // diskette recal status
2588 media_state_offset
= 0x0090;
2590 media_state_offset
+= 1;
2592 val8
= read_byte(0x0040, media_state_offset
);
2593 val8
= (val8
>> 4) & 0x01;
2597 // check pass, return KNOWN
2602 floppy_media_sense(drive
)
2606 Bit16u media_state_offset
;
2607 Bit8u drive_type
, config_data
, media_state
;
2609 if (floppy_drive_recal(drive
) == 0) {
2613 // for now cheat and get drive type from CMOS,
2614 // assume media is same as drive type
2615 drive_type
= inb_cmos(0x10);
2620 if ( drive_type
== 2 ) {
2621 // 1.2 MB 5.25" drive
2622 config_data
= 0x00; // 0000 0000
2623 media_state
= 0x25; // 0001 0101
2626 else if ( drive_type
== 3 ) {
2628 config_data
= 0x00; // 0000 0000 ???
2629 media_state
= 0x17; // 0001 0111
2632 else if ( drive_type
== 4 ) {
2633 // 1.44 MB 3.5" drive
2634 config_data
= 0x00; // 0000 0000
2635 media_state
= 0x17; // 0001 0111
2638 else if ( drive_type
== 5 ) {
2639 // 2.88 MB 3.5" drive
2640 config_data
= 0xCC; // 1100 1100
2641 media_state
= 0xD7; // 1101 0111
2646 config_data
= 0x00; // 0000 0000
2647 media_state
= 0x00; // 0000 0000
2652 media_state_offset
= 0x90;
2654 media_state_offset
= 0x91;
2655 write_byte(0x0040, 0x008B, config_data
);
2656 write_byte(0x0040, media_state_offset
, media_state
);
2662 floppy_drive_recal(drive
)
2666 Bit16u curr_cyl_offset
;
2668 // set 40:3e bit 7 to 0
2669 val8
= read_byte(0x0000, 0x043e);
2671 write_byte(0x0000, 0x043e, val8
);
2673 // turn on motor of selected drive, DMA & int enabled, normal operation
2682 // check port 3f4 for drive readiness
2684 if ( (val8
& 0xf0) != 0x80 )
2685 panic("floppy recal:f07: ctrl not ready");
2687 // send Recalibrate command (2 bytes) to controller
2688 outb(0x03f5, 0x07); // 07: Recalibrate
2689 outb(0x03f5, drive
); // 0=drive0, 1=drive1
2691 // turn on interrupts
2696 // wait on 40:3e bit 7 to become 1
2697 val8
= (read_byte(0x0000, 0x043e) & 0x80);
2698 while ( val8
== 0 ) {
2699 val8
= (read_byte(0x0000, 0x043e) & 0x80);
2702 val8
= 0; // separate asm from while() loop
2703 // turn off interrupts
2708 // set 40:3e bit 7 to 0, and calibrated bit
2709 val8
= read_byte(0x0000, 0x043e);
2712 val8
|= 0x02; // Drive 1 calibrated
2713 curr_cyl_offset
= 0x0095;
2716 val8
|= 0x01; // Drive 0 calibrated
2717 curr_cyl_offset
= 0x0094;
2719 write_byte(0x0040, 0x003e, val8
);
2720 write_byte(0x0040, curr_cyl_offset
, 0); // current cylinder is 0
2728 floppy_drive_exists(drive
)
2733 // check CMOS to see if drive exists
2734 drive_type
= inb_cmos(0x10);
2739 if ( drive_type
== 0 )
2746 #if BX_SUPPORT_FLOPPY
2748 int13_diskette_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
)
2749 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
;
2751 Bit8u drive
, num_sectors
, track
, sector
, head
, status
;
2752 Bit16u base_address
, base_count
, base_es
;
2753 Bit8u page
, mode_register
, val8
, dor
;
2754 Bit8u return_status
[7];
2755 Bit8u drive_type
, num_floppies
, ah
;
2756 Bit16u es
, last_addr
;
2758 //printf("BIOS: int13: AX=%04x BX=%04x CX=%04x DX=%04x\n", AX, BX, CX, DX);
2763 case 0x00: // diskette controller reset
2764 printf("floppy f00\n");
2767 SET_AH(1); // invalid param
2768 set_diskette_ret_status(1);
2772 drive_type
= inb_cmos(0x10);
2778 if (drive_type
== 0) {
2779 SET_AH(0x80); // drive not responding
2780 set_diskette_ret_status(0x80);
2785 set_diskette_ret_status(0);
2786 CLEAR_CF(); // successful
2787 set_diskette_current_cyl(drive
, 0); // current cylinder
2790 case 0x01: // Read Diskette Status
2792 val8
= read_byte(0x0000, 0x0441);
2799 case 0x02: // Read Diskette Sectors
2800 case 0x03: // Write Diskette Sectors
2801 case 0x04: // Verify Diskette Sectors
2802 num_sectors
= GET_AL();
2808 if ( (drive
> 1) || (head
> 1) ||
2809 (num_sectors
== 0) || (num_sectors
> 72) ) {
2810 printf("floppy: drive>1 || head>1 ...\n");
2812 set_diskette_ret_status(1);
2813 SET_AL(0); // no sectors read
2814 SET_CF(); // error occurred
2818 // see if drive exists
2819 if (floppy_drive_exists(drive
) == 0) {
2820 SET_AH(0x80); // not responding
2821 set_diskette_ret_status(0x80);
2822 SET_AL(0); // no sectors read
2823 SET_CF(); // error occurred
2827 // see if media in drive, and type is known
2828 if (floppy_media_known(drive
) == 0) {
2829 if (floppy_media_sense(drive
) == 0) {
2830 SET_AH(0x0C); // Media type not found
2831 set_diskette_ret_status(0x0C);
2832 SET_AL(0); // no sectors read
2833 SET_CF(); // error occurred
2839 // Read Diskette Sectors
2841 //-----------------------------------
2842 // set up DMA controller for transfer
2843 //-----------------------------------
2845 // es:bx = pointer to where to place information from diskette
2846 // port 04: DMA-1 base and current address, channel 2
2847 // port 05: DMA-1 base and current count, channel 2
2848 page
= (ES
>> 12); // upper 4 bits
2849 base_es
= (ES
<< 4); // lower 16bits contributed by ES
2850 base_address
= base_es
+ BX
; // lower 16 bits of address
2851 // contributed by ES:BX
2852 if ( base_address
< base_es
) {
2853 // in case of carry, adjust page by 1
2856 base_count
= (num_sectors
* 512) - 1;
2858 // check for 64K boundary overrun
2859 last_addr
= base_address
+ base_count
;
2860 if (last_addr
< base_address
) {
2862 set_diskette_ret_status(0x09);
2863 SET_AL(0); // no sectors read
2864 SET_CF(); // error occurred
2868 printf("masking DMA-1 c2\n");
2871 printf("clear flip-flop\n");
2872 outb(0x000c, 0x00); // clear flip-flop
2873 outb(0x0004, base_address
);
2874 outb(0x0004, base_address
>>8);
2875 printf("clear flip-flop\n");
2876 outb(0x000c, 0x00); // clear flip-flop
2877 outb(0x0005, base_count
);
2878 outb(0x0005, base_count
>>8);
2880 // port 0b: DMA-1 Mode Register
2881 mode_register
= 0x46; // single mode, increment, autoinit disable,
2882 // transfer type=write, channel 2
2883 printf("setting mode register\n");
2884 outb(0x000b, mode_register
);
2886 printf("setting page register\n");
2887 // port 81: DMA-1 Page Register, channel 2
2890 printf("unmask chan 2\n");
2891 outb(0x000a, 0x02); // unmask channel 2
2893 printf("unmasking DMA-1 c2\n");
2896 //--------------------------------------
2897 // set up floppy controller for transfer
2898 //--------------------------------------
2900 // set 40:3e bit 7 to 0
2901 val8
= read_byte(0x0000, 0x043e);
2903 write_byte(0x0000, 0x043e, val8
);
2905 // turn on motor of selected drive, DMA & int enabled, normal operation
2914 // check port 3f4 for drive readiness
2916 if ( (val8
& 0xf0) != 0x80 )
2917 panic("int13_diskette:f02: ctrl not ready");
2919 // send read-normal-data command (9 bytes) to controller
2920 outb(0x03f5, 0xe6); // e6: read normal data
2921 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
2922 outb(0x03f5, track
);
2924 outb(0x03f5, sector
);
2925 outb(0x03f5, 2); // 512 byte sector size
2926 outb(0x03f5, 0); // last sector number possible on track
2927 outb(0x03f5, 0); // Gap length
2928 outb(0x03f5, 0xff); // Gap length
2930 // turn on interrupts
2935 // wait on 40:3e bit 7 to become 1
2936 val8
= (read_byte(0x0000, 0x043e) & 0x80);
2937 while ( val8
== 0 ) {
2938 val8
= (read_byte(0x0000, 0x043e) & 0x80);
2941 val8
= 0; // separate asm from while() loop
2942 // turn off interrupts
2947 // set 40:3e bit 7 to 0
2948 val8
= read_byte(0x0000, 0x043e);
2950 write_byte(0x0000, 0x043e, val8
);
2952 // check port 3f4 for accessibility to status bytes
2954 if ( (val8
& 0xc0) != 0xc0 )
2955 panic("int13_diskette: ctrl not ready");
2957 // read 7 return status bytes from controller
2958 // using loop index broken, have to unroll...
2959 return_status
[0] = inb(0x3f5);
2960 return_status
[1] = inb(0x3f5);
2961 return_status
[2] = inb(0x3f5);
2962 return_status
[3] = inb(0x3f5);
2963 return_status
[4] = inb(0x3f5);
2964 return_status
[5] = inb(0x3f5);
2965 return_status
[6] = inb(0x3f5);
2966 // record in BIOS Data Area
2967 write_byte(0x0040, 0x0042, return_status
[0]);
2968 write_byte(0x0040, 0x0043, return_status
[1]);
2969 write_byte(0x0040, 0x0044, return_status
[2]);
2970 write_byte(0x0040, 0x0045, return_status
[3]);
2971 write_byte(0x0040, 0x0046, return_status
[4]);
2972 write_byte(0x0040, 0x0047, return_status
[5]);
2973 write_byte(0x0040, 0x0048, return_status
[6]);
2975 if ( (return_status
[0] & 0xc0) != 0 ) {
2977 set_diskette_ret_status(0x20);
2978 SET_AL(0); // no sectors read
2979 SET_CF(); // error occurred
2983 // ??? should track be new val from return_status[3] ?
2984 set_diskette_current_cyl(drive
, track
);
2985 // AL = number of sectors read (same value as passed)
2986 SET_AH(0x00); // success
2987 CLEAR_CF(); // success
2990 else if (ah
== 0x03) {
2991 // Write Diskette Sectors
2993 //-----------------------------------
2994 // set up DMA controller for transfer
2995 //-----------------------------------
2997 // es:bx = pointer to where to place information from diskette
2998 // port 04: DMA-1 base and current address, channel 2
2999 // port 05: DMA-1 base and current count, channel 2
3000 page
= (ES
>> 12); // upper 4 bits
3001 base_es
= (ES
<< 4); // lower 16bits contributed by ES
3002 base_address
= base_es
+ BX
; // lower 16 bits of address
3003 // contributed by ES:BX
3004 if ( base_address
< base_es
) {
3005 // in case of carry, adjust page by 1
3008 base_count
= (num_sectors
* 512) - 1;
3010 // check for 64K boundary overrun
3011 last_addr
= base_address
+ base_count
;
3012 if (last_addr
< base_address
) {
3014 set_diskette_ret_status(0x09);
3015 SET_AL(0); // no sectors read
3016 SET_CF(); // error occurred
3020 printf("masking DMA-1 c2\n");
3023 outb(0x000c, 0x00); // clear flip-flop
3024 outb(0x0004, base_address
);
3025 outb(0x0004, base_address
>>8);
3026 outb(0x000c, 0x00); // clear flip-flop
3027 outb(0x0005, base_count
);
3028 outb(0x0005, base_count
>>8);
3030 // port 0b: DMA-1 Mode Register
3031 mode_register
= 0x4a; // single mode, increment, autoinit disable,
3032 // transfer type=read, channel 2
3033 outb(0x000b, mode_register
);
3035 // port 81: DMA-1 Page Register, channel 2
3038 printf("unmasking DMA-1 c2\n");
3041 //--------------------------------------
3042 // set up floppy controller for transfer
3043 //--------------------------------------
3045 // set 40:3e bit 7 to 0
3046 val8
= read_byte(0x0000, 0x043e);
3048 write_byte(0x0000, 0x043e, val8
);
3050 // turn on motor of selected drive, DMA & int enabled, normal operation
3059 // check port 3f4 for drive readiness
3061 if ( (val8
& 0xf0) != 0x80 )
3062 panic("int13_diskette:f03: ctrl not ready");
3064 // send read-normal-data command (9 bytes) to controller
3065 outb(0x03f5, 0xc5); // c5: write normal data
3066 outb(0x03f5, (head
<< 2) | drive
); // HD DR1 DR2
3067 outb(0x03f5, track
);
3069 outb(0x03f5, sector
);
3070 outb(0x03f5, 2); // 512 byte sector size
3071 outb(0x03f5, 0); // last sector number possible on track
3072 outb(0x03f5, 0); // Gap length
3073 outb(0x03f5, 0xff); // Gap length
3075 // turn on interrupts
3080 // wait on 40:3e bit 7 to become 1
3081 val8
= (read_byte(0x0000, 0x043e) & 0x80);
3082 while ( val8
== 0 ) {
3083 val8
= (read_byte(0x0000, 0x043e) & 0x80);
3086 val8
= 0; // separate asm from while() loop
3087 // turn off interrupts
3092 // set 40:3e bit 7 to 0
3093 val8
= read_byte(0x0000, 0x043e);
3095 write_byte(0x0000, 0x043e, val8
);
3097 // check port 3f4 for accessibility to status bytes
3099 if ( (val8
& 0xc0) != 0xc0 )
3100 panic("int13_diskette: ctrl not ready");
3102 // read 7 return status bytes from controller
3103 // using loop index broken, have to unroll...
3104 return_status
[0] = inb(0x3f5);
3105 return_status
[1] = inb(0x3f5);
3106 return_status
[2] = inb(0x3f5);
3107 return_status
[3] = inb(0x3f5);
3108 return_status
[4] = inb(0x3f5);
3109 return_status
[5] = inb(0x3f5);
3110 return_status
[6] = inb(0x3f5);
3111 // record in BIOS Data Area
3112 write_byte(0x0040, 0x0042, return_status
[0]);
3113 write_byte(0x0040, 0x0043, return_status
[1]);
3114 write_byte(0x0040, 0x0044, return_status
[2]);
3115 write_byte(0x0040, 0x0045, return_status
[3]);
3116 write_byte(0x0040, 0x0046, return_status
[4]);
3117 write_byte(0x0040, 0x0047, return_status
[5]);
3118 write_byte(0x0040, 0x0048, return_status
[6]);
3120 if ( (return_status
[0] & 0xc0) != 0 ) {
3121 if ( (return_status
[1] & 0x02) != 0 ) {
3122 // diskette not writable.
3123 // AH=status code=0x03 (tried to write on write-protected disk)
3124 // AL=number of sectors written=0
3129 panic("int13_diskette_function: read error");
3133 // ??? should track be new val from return_status[3] ?
3134 set_diskette_current_cyl(drive
, track
);
3135 // AL = number of sectors read (same value as passed)
3136 SET_AH(0x00); // success
3137 CLEAR_CF(); // success
3140 else { // if (ah == 0x04)
3141 // Verify Diskette Sectors
3143 // ??? should track be new val from return_status[3] ?
3144 set_diskette_current_cyl(drive
, track
);
3145 // AL = number of sectors verified (same value as passed)
3146 CLEAR_CF(); // success
3147 SET_AH(0x00); // success
3152 case 0x05: // format diskette track
3153 printf("floppy f05\n");
3155 num_sectors
= GET_AL();
3162 set_diskette_ret_status(1);
3163 SET_CF(); // error occurred
3165 drive_type
= inb_cmos(0x10);
3170 if (drive_type
== 0) {
3171 SET_AH(0x80); // drive not responding
3172 set_diskette_ret_status(0x80);
3173 SET_CF(); // error occurred
3179 set_diskette_ret_status(0);
3180 set_diskette_current_cyl(drive
, track
);
3181 CLEAR_CF(); // successful
3185 case 0x08: // read diskette drive parameters
3186 printf("floppy f08\n");
3195 SET_DL(num_floppies
);
3196 //set_diskette_ret_status(AH=1);
3201 drive_type
= inb_cmos(0x10);
3203 if (drive_type
& 0xf0)
3205 if (drive_type
& 0x0f)
3218 SET_DL(num_floppies
);
3220 switch (drive_type
) {
3223 SET_DH(0); // max head #
3226 case 1: // 360KB, 5.25"
3227 CX
= 0x2709; // 40 tracks, 9 sectors
3228 SET_DH(1); // max head #
3231 case 2: // 1.2MB, 5.25"
3232 CX
= 0x4f0f; // 80 tracks, 15 sectors
3233 SET_DH(1); // max head #
3236 case 3: // 720KB, 3.5"
3237 CX
= 0x4f09; // 80 tracks, 9 sectors
3238 SET_DH(1); // max head #
3241 case 4: // 1.44MB, 3.5"
3242 CX
= 0x4f12; // 80 tracks, 18 sectors
3243 SET_DH(1); // max head #
3246 case 5: // 2.88MB, 3.5"
3247 CX
= 0x4f24; // 80 tracks, 36 sectors
3248 SET_DH(1); // max head #
3252 panic("floppy: int13: bad floppy type");
3255 /* set es & di to point to 11 byte diskette param table */
3256 DI
= read_word(0x0000, 0x0078);
3257 ES
= read_word(0x0000, 0x007a);
3258 CLEAR_CF(); // success
3259 /* disk status not changed upon success */
3263 case 0x15: // read diskette drive type
3264 printf("floppy f15\n");
3267 SET_AH(0); // only 2 drives supported
3268 // set_diskette_ret_status here ???
3272 drive_type
= inb_cmos(0x10);
3278 CLEAR_CF(); // successful, not present
3279 if (drive_type
==0) {
3280 SET_AH(0); // drive not present
3283 SET_AH(1); // drive present, does not support change line
3287 case 0x16: // get diskette change line status
3288 printf("floppy f16\n");
3291 SET_AH(0x01); // invalid drive
3292 set_diskette_ret_status(0x01);
3297 SET_AH(0x06); // change line not supported
3298 set_diskette_ret_status(0x06);
3302 case 0x17: // set diskette type for format(old)
3303 printf("floppy f17\n");
3304 /* not used for 1.44M floppies */
3305 SET_AH(0x01); // not supported
3306 set_diskette_ret_status(1); /* not supported */
3310 case 0x18: // set diskette type for format(new)
3311 printf("floppy f18\n");
3312 SET_AH(0x01); // do later
3313 set_diskette_ret_status(1);
3318 if ( (ah
==0x20) || ((ah
>=0x41) && (ah
<=0x49)) || (ah
==0x4e) ) {
3319 SET_AH(0x01); // ???
3320 set_diskette_ret_status(1);
3322 printf("floppy: int13: 0x%02x\n", ah
);
3325 panic("int13_diskette: AH=%02x", ah
);
3328 #else // #if BX_SUPPORT_FLOPPY
3330 int13_diskette_function(DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
)
3331 Bit16u DI
, SI
, BP
, SP
, BX
, DX
, CX
, AX
, ES
, FLAGS
;
3335 switch ( GET_AH() ) {
3337 case 0x01: // Read Diskette Status
3339 val8
= read_byte(0x0000, 0x0441);
3348 write_byte(0x0000, 0x0441, 0x01);
3352 #endif // #if BX_SUPPORT_FLOPPY
3355 set_disk_ret_status(val
)
3358 write_byte(0x0040, 0x0074, val
);
3362 set_diskette_ret_status(value
)
3365 write_byte(0x0040, 0x0041, value
);
3369 set_diskette_current_cyl(drive
, cyl
)
3374 panic("set_diskette_current_cyl(): drive > 1");
3375 write_byte(0x0040, 0x0094+drive
, cyl
);
3379 determine_floppy_media(drive
)
3383 Bit8u val8
, DOR
, ctrl_info
;
3385 ctrl_info
= read_byte(0x0040, 0x008F);
3393 DOR
= 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
3396 DOR
= 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
3400 if ( (ctrl_info
& 0x04) != 0x04 ) {
3401 // Drive not determined means no drive exists, done.
3406 // check Main Status Register for readiness
3407 val8
= inb(0x03f4) & 0x80; // Main Status Register
3409 panic("d_f_m: MRQ bit not set");
3413 // existing BDA values
3415 // turn on drive motor
3416 outb(0x03f2, DOR
); // Digital Output Register
3419 panic("d_f_m: OK so far");
3426 get_hd_geometry(drive
, hd_cylinders
, hd_heads
, hd_sectors
)
3428 Bit16u
*hd_cylinders
;
3438 if (drive
== 0x80) {
3439 hd_type
= inb_cmos(0x12) & 0xf0;
3440 if (hd_type
!= 0xf0)
3441 panic("HD0 cmos reg 12h not type F");
3442 hd_type
= inb_cmos(0x19); // HD0: extended type
3444 panic("HD0 cmos reg 19h not user definable type 47");
3447 hd_type
= inb_cmos(0x12) & 0x0f;
3448 if (hd_type
!= 0x0f)
3449 panic("HD1 cmos reg 12h not type F");
3450 hd_type
= inb_cmos(0x1a); // HD0: extended type
3452 panic("HD1 cmos reg 1ah not user definable type 47");
3457 cylinders
= inb_cmos(iobase
) | (inb_cmos(iobase
+1) << 8);
3458 write_word(ss
, hd_cylinders
, cylinders
);
3461 write_byte(ss
, hd_heads
, inb_cmos(iobase
+2));
3463 // sectors per track
3464 write_byte(ss
, hd_sectors
, inb_cmos(iobase
+8));
3468 int17_function(regs
, ds
, iret_addr
)
3469 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3470 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3471 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3473 Bit16u addr
,timeout
;
3480 if ((regs
.u
.r8
.ah
< 3) && (regs
.u
.r16
.dx
== 0)) {
3481 addr
= read_word(0x0040, 0x0008);
3482 timeout
= read_byte(0x0040, 0x0078) << 8;
3483 if (regs
.u
.r8
.ah
== 0) {
3484 outb(addr
, regs
.u
.r8
.al
);
3486 outb(addr
+2, val8
| 0x01); // send strobe
3490 outb(addr
+2, val8
& ~0x01);
3491 while (((inb(addr
+1) & 0x40) == 0x40) && (timeout
)) {
3495 if (regs
.u
.r8
.ah
== 1) {
3497 outb(addr
+2, val8
& ~0x04); // send init
3501 outb(addr
+2, val8
| 0x04);
3503 regs
.u
.r8
.ah
= inb(addr
+1);
3504 val8
= (~regs
.u
.r8
.ah
& 0x48);
3505 regs
.u
.r8
.ah
&= 0xB7;
3506 regs
.u
.r8
.ah
|= val8
;
3507 if (!timeout
) regs
.u
.r8
.ah
|= 0x01;
3508 ClearCF(iret_addr
.flags
);
3510 SetCF(iret_addr
.flags
); // Unsupported
3515 int1a_function(regs
, ds
, iret_addr
)
3516 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3517 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3518 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3526 switch (regs
.u
.r8
.ah
) {
3527 case 0: // get current clock count
3531 regs
.u
.r16
.cx
= BiosData
->ticks_high
;
3532 regs
.u
.r16
.dx
= BiosData
->ticks_low
;
3533 regs
.u
.r8
.al
= BiosData
->midnight_flag
;
3534 BiosData
->midnight_flag
= 0; // reset flag
3539 ClearCF(iret_addr
.flags
); // OK
3542 case 1: // Set Current Clock Count
3546 BiosData
->ticks_high
= regs
.u
.r16
.cx
;
3547 BiosData
->ticks_low
= regs
.u
.r16
.dx
;
3548 BiosData
->midnight_flag
= 0; // reset flag
3553 ClearCF(iret_addr
.flags
); // OK
3557 case 2: // Read CMOS Time
3558 if (rtc_updating()) {
3559 SetCF(iret_addr
.flags
);
3563 regs
.u
.r8
.dh
= inb_cmos(0x00); // Seconds
3564 regs
.u
.r8
.cl
= inb_cmos(0x02); // Minutes
3565 regs
.u
.r8
.ch
= inb_cmos(0x04); // Hours
3566 regs
.u
.r8
.dl
= inb_cmos(0x0b) & 0x01; // Stat Reg B
3568 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
3569 ClearCF(iret_addr
.flags
); // OK
3572 case 3: // Set CMOS Time
3573 // Using a debugger, I notice the following masking/setting
3574 // of bits in Status Register B, by setting Reg B to
3575 // a few values and getting its value after INT 1A was called.
3577 // try#1 try#2 try#3
3578 // before 1111 1101 0111 1101 0000 0000
3579 // after 0110 0010 0110 0010 0000 0010
3581 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
3582 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
3583 if (rtc_updating()) {
3585 // fall through as if an update were not in progress
3587 outb_cmos(0x00, regs
.u
.r8
.dh
); // Seconds
3588 outb_cmos(0x02, regs
.u
.r8
.cl
); // Minutes
3589 outb_cmos(0x04, regs
.u
.r8
.ch
); // Hours
3590 // Set Daylight Savings time enabled bit to requested value
3591 val8
= (inb_cmos(0x0b) & 0x60) | 0x02 | (regs
.u
.r8
.dl
& 0x01);
3592 // (reg B already selected)
3593 outb_cmos(0x0b, val8
);
3595 regs
.u
.r8
.al
= val8
; // val last written to Reg B
3596 ClearCF(iret_addr
.flags
); // OK
3599 case 4: // Read CMOS Date
3601 if (rtc_updating()) {
3602 SetCF(iret_addr
.flags
);
3605 regs
.u
.r8
.cl
= inb_cmos(0x09); // Year
3606 regs
.u
.r8
.dh
= inb_cmos(0x08); // Month
3607 regs
.u
.r8
.dl
= inb_cmos(0x07); // Day of Month
3608 regs
.u
.r8
.ch
= inb_cmos(0x32); // Century
3609 regs
.u
.r8
.al
= regs
.u
.r8
.ch
;
3610 ClearCF(iret_addr
.flags
); // OK
3613 case 5: // Set CMOS Date
3614 // Using a debugger, I notice the following masking/setting
3615 // of bits in Status Register B, by setting Reg B to
3616 // a few values and getting its value after INT 1A was called.
3618 // try#1 try#2 try#3 try#4
3619 // before 1111 1101 0111 1101 0000 0010 0000 0000
3620 // after 0110 1101 0111 1101 0000 0010 0000 0000
3622 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
3623 // My assumption: RegB = (RegB & 01111111b)
3624 if (rtc_updating()) {
3626 SetCF(iret_addr
.flags
);
3629 outb_cmos(0x09, regs
.u
.r8
.cl
); // Year
3630 outb_cmos(0x08, regs
.u
.r8
.dh
); // Month
3631 outb_cmos(0x07, regs
.u
.r8
.dl
); // Day of Month
3632 outb_cmos(0x32, regs
.u
.r8
.ch
); // Century
3633 val8
= inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
3634 outb_cmos(0x0b, val8
);
3636 regs
.u
.r8
.al
= val8
; // AL = val last written to Reg B
3637 ClearCF(iret_addr
.flags
); // OK
3640 case 6: // Set Alarm Time in CMOS
3641 // Using a debugger, I notice the following masking/setting
3642 // of bits in Status Register B, by setting Reg B to
3643 // a few values and getting its value after INT 1A was called.
3645 // try#1 try#2 try#3
3646 // before 1101 1111 0101 1111 0000 0000
3647 // after 0110 1111 0111 1111 0010 0000
3649 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
3650 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
3651 val8
= inb_cmos(0x0b); // Get Status Reg B
3654 // Alarm interrupt enabled already
3655 SetCF(iret_addr
.flags
); // Error: alarm in use
3658 if (rtc_updating()) {
3660 // fall through as if an update were not in progress
3662 outb_cmos(0x01, regs
.u
.r8
.dh
); // Seconds alarm
3663 outb_cmos(0x03, regs
.u
.r8
.cl
); // Minutes alarm
3664 outb_cmos(0x05, regs
.u
.r8
.ch
); // Hours alarm
3665 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
3666 // enable Status Reg B alarm bit, clear halt clock bit
3667 outb_cmos(0x0b, (val8
& 0x7f) | 0x20);
3668 ClearCF(iret_addr
.flags
); // OK
3671 case 7: // Turn off Alarm
3672 // Using a debugger, I notice the following masking/setting
3673 // of bits in Status Register B, by setting Reg B to
3674 // a few values and getting its value after INT 1A was called.
3676 // try#1 try#2 try#3 try#4
3677 // before 1111 1101 0111 1101 0010 0000 0010 0010
3678 // after 0100 0101 0101 0101 0000 0000 0000 0010
3680 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
3681 // My assumption: RegB = (RegB & 01010111b)
3682 val8
= inb_cmos(0x0b); // Get Status Reg B
3683 // clear clock-halt bit, disable alarm bit
3684 outb_cmos(0x0b, val8
& 0x57); // disable alarm bit
3686 regs
.u
.r8
.al
= val8
; // val last written to Reg B
3687 ClearCF(iret_addr
.flags
); // OK
3691 setPCIaddr(0, 0, 0);
3692 if (inw(0x0cfc) != 0x8086) {
3693 bios_printf(0, "PCI BIOS not present\n");
3694 SetCF(iret_addr
.flags
);
3696 switch (regs
.u
.r8
.al
) {
3697 case 0x01: // Installation check
3702 ClearCF(iret_addr
.flags
);
3704 case 0x09: // Read configuration word
3705 setPCIaddr(regs
.u
.r8
.bh
, regs
.u
.r8
.bl
, (Bit8u
)(regs
.u
.r16
.di
& 0xfc));
3706 regs
.u
.r16
.cx
= inw(0x0cfc + (regs
.u
.r16
.di
& 0x0002));
3708 ClearCF(iret_addr
.flags
);
3710 case 0x0c: // Write configuration word
3711 bios_printf(0, "reg: 0x%02x value: 0x%02x\n",(Bit8u
)(regs
.u
.r16
.di
& 0xff),regs
.u
.r16
.cx
);
3712 setPCIaddr(regs
.u
.r8
.bh
, regs
.u
.r8
.bl
, (Bit8u
)(regs
.u
.r16
.di
& 0xfc));
3713 outw(0x0cfc + (regs
.u
.r16
.di
& 0x0002), regs
.u
.r16
.cx
);
3715 ClearCF(iret_addr
.flags
);
3718 bios_printf(0, "unsupported PCI BIOS function 0x%02x\n", regs
.u
.r8
.al
);
3719 SetCF(iret_addr
.flags
);
3726 SetCF(iret_addr
.flags
); // Unsupported
3731 int70_function(regs
, ds
, iret_addr
)
3732 pusha_regs_t regs
; // regs pushed from PUSHA instruction
3733 Bit16u ds
; // previous DS:, DS set to 0x0000 by asm wrapper
3734 iret_addr_t iret_addr
; // CS,IP,Flags pushed from original INT call
3736 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
3739 val8
= inb_cmos(0x0c); // Status Reg C
3740 if (val8
== 0) panic("int70: regC 0");
3741 if (val8
& 0x40) panic("int70: periodic request");
3743 // Alarm Flag indicates alarm time matches current time
3744 // call user INT 4Ah alarm handler
3748 //;; call_ep [ds:loc]
3749 //CALL_EP( 0x4a << 2 )
3756 ;; send EOI to slave
& master PICs
3758 out
#0xA0, al ;; slave PIC EOI
3759 out
#0x20, al ;; master PIC EOI
3766 ;------------------------------------------
3767 ;- INT74h
: PS
/2 mouse hardware interrupt
-
3768 ;------------------------------------------
3773 push
#0x00 ;; placeholder for status
3774 push
#0x00 ;; placeholder for X
3775 push
#0x00 ;; placeholder for Y
3776 push
#0x00 ;; placeholder for Z
3777 push
#0x00 ;; placeholder for make_far_call boolean
3778 call _int74_function
3779 pop cx
;; remove make_far_call from stack
3782 ;; make far call to EBDA
:0022
3785 push
0x040E ;; push
0000:040E (opcodes
0xff, 0x36, 0x0E, 0x04)
3787 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
3792 ;; send EOI to slave
& master PICs
3793 out
#0xA0, al ;; slave PIC EOI
3794 out
#0x20, al ;; master PIC EOI
3795 add sp
, #8 ;; pop status, x, y, z
3797 pop ds
;; restore DS
3802 ;; This will perform an IRET
, but will retain value of current CF
3803 ;; by altering flags on stack
. Better than RETF
#02.
3808 and BYTE
[bp
+ 0x06], #0xfe
3814 or BYTE
[bp
+ 0x06], #0x01
3819 ;----------------------
3820 ;- INT13h (relocated
) -
3821 ;----------------------
3828 ;; pushf already done
3831 call _int13_function
3835 // JMPL(iret_modify_cf)
3839 // JMPL(int13_diskette)
3843 ;----------------------
3844 ;- INT19h (relocated
) -
3845 ;----------------------
3847 ;; check bit
5 in CMOS reg
0x2d. load either
0x00 or 0x80 into DL
3848 ;; in preparation
for the intial INT
13h (0=floppy A
:, 0x80=C
:)
3849 ;; 0: system boot sequence
, first drive C
: then A
:
3850 ;; 1: system boot sequence
, first drive A
: then C
:
3860 jmp int19_loadsector
3867 mov es
, ax
;; seg
= 0000
3868 mov bx
, #0x7c00 ;; load boot sector into 0000:7c000
3869 mov ah
, #0x02 ;; function 2, read diskette sector
3870 mov al
, #0x01 ;; read 1 sector
3871 mov ch
, #0x00 ;; track 0
3872 mov cl
, #0x01 ;; sector 1
3873 mov dh
, #0x00 ;; head 0
3875 jc int19_load_failed
3876 ;; read sector ok
. now check floppy signature
.
3878 cmp WORD
[0x7DFE], #0xAA55
3879 jne bootstrap_problem
3880 JMP_AP(0x0000, 0x7c00) ;; sig ok
. Now execute the code
.
3884 ;; if dh
=0, load failed
. if dh
=1, signature check failed
.
3886 call _boot_failure_msg
3892 int18_handler
: ;; Boot Failure routing
3900 int1c_handler
: ;; User Timer Tick
3904 ;----------------------
3905 ;- POST
: Floppy Drive
-
3906 ;----------------------
3912 mov
0x043e, al
;; drive
0 & 1 uncalibrated
, no interrupt has occurred
3914 mov
0x043f, al
;; diskette motor status
: read op
, drive0
, motors off
3916 mov
0x0440, al
;; diskette motor timeout counter
: not active
3917 mov
0x0441, al
;; diskette controller status
return code
3919 mov
0x0442, al
;; disk
& diskette controller status
register 0
3920 mov
0x0443, al
;; diskette controller status
register 1
3921 mov
0x0444, al
;; diskette controller status
register 2
3922 mov
0x0445, al
;; diskette controller cylinder number
3923 mov
0x0446, al
;; diskette controller head number
3924 mov
0x0447, al
;; diskette controller sector number
3925 mov
0x0448, al
;; diskette controller bytes written
3927 mov
0x048b, al
;; diskette configuration data
3929 ;; -----------------------------------------------------------------
3930 ;; (048F
) diskette controller information
3932 mov al
, #0x10 ;; get CMOS diskette drive type
3935 mov ah
, al
;; save byte to AH
3938 shr al
, #4 ;; look at top 4 bits for drive 0
3939 jz f0_missing
;; jump
if no drive0
3940 mov bl
, #0x07 ;; drive0 determined, multi-rate, has changed line
3943 mov bl
, #0x00 ;; no drive0
3946 mov al
, ah
;; restore from AH
3947 and al
, #0x0f ;; look at bottom 4 bits for drive 1
3948 jz f1_missing
;; jump
if no drive1
3949 or bl
, #0x70 ;; drive1 determined, multi-rate, has changed line
3951 ;; leave high bits in BL zerod
3952 mov
0x048f, bl
;; put
new val in
BDA (diskette controller information
)
3953 ;; -----------------------------------------------------------------
3956 mov
0x0490, al
;; diskette
0 media state
3957 mov
0x0491, al
;; diskette
1 media state
3959 ;; diskette
0,1 operational starting state
3960 ;; drive type has
not been determined
,
3961 ;; has no changed detection line
3965 mov
0x0494, al
;; diskette
0 current cylinder
3966 mov
0x0495, al
;; diskette
1 current cylinder
3969 out
#0x0a, al ;; clear DMA-1 channel 2 mask bit
3971 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table)
3972 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
3973 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
3979 ;--------------------
3980 ;- POST
: HARD DRIVE
-
3981 ;--------------------
3982 ; relocated here because the primary POST area isnt big enough
.
3985 // INT 76h calls INT 15h function ax=9100
3987 mov al
, #0x0a ; 0000 1010 = reserved, disable IRQ 14
3993 mov
0x0474, al
/* hard disk status of last operation */
3994 mov
0x0477, al
/* hard disk port offset (XT only ???) */
3995 mov
0x048c, al
/* hard disk status register */
3996 mov
0x048d, al
/* hard disk error register */
3997 mov
0x048e, al
/* hard disk task complete flag */
3999 mov
0x0475, al
/* hard disk number attached */
4001 mov
0x0476, al
/* hard disk control byte */
4002 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
4003 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
4004 ;; INT
41h
: hard disk
0 configuration pointer
4005 ;; INT
46h
: hard disk
1 configuration pointer
4006 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
4007 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
4009 ;; move disk geometry data from CMOS to EBDA disk parameter
table(s
)
4021 cmp al
, #47 ;; decimal 47 - user definable
4025 ;; CMOS purpose param table offset
4026 ;; 1b cylinders low
0
4027 ;; 1c cylinders high
1
4029 ;; 1e write pre
-comp low
5
4030 ;; 1f write pre
-comp high
6
4031 ;; 20 retries
/bad map
/heads
>8 8
4032 ;; 21 landing zone low C
4033 ;; 22 landing zone high D
4034 ;; 23 sectors
/track E
4039 ;;; Filling EBDA table
for hard disk
0.
4047 mov (0x003d + 0x05), ax
;; write precomp word
4052 mov (0x003d + 0x08), al
;; drive control byte
4061 mov (0x003d + 0x0C), ax
;; landing zone word
4063 mov al
, #0x1c ;; get cylinders word in AX
4065 in al
, #0x71 ;; high byte
4069 in al
, #0x71 ;; low byte
4070 mov bx
, ax
;; BX
= cylinders
4075 mov cl
, al
;; CL
= heads
4080 mov dl
, al
;; DL
= sectors
4083 jnbe hd0_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
4085 hd0_post_physical_chs
:
4086 ;; no logical CHS mapping used
, just physical CHS
4087 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
4088 mov (0x003d + 0x00), bx
;; number of physical cylinders
4089 mov (0x003d + 0x02), cl
;; number of physical heads
4090 mov (0x003d + 0x0E), dl
;; number of physical sectors
4093 hd0_post_logical_chs
:
4094 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
4095 mov (0x003d + 0x09), bx
;; number of physical cylinders
4096 mov (0x003d + 0x0b), cl
;; number of physical heads
4097 mov (0x003d + 0x04), dl
;; number of physical sectors
4098 mov (0x003d + 0x0e), dl
;; number of logical
sectors (same
)
4100 mov (0x003d + 0x03), al
;; A0h signature
, indicates translated table
4103 jnbe hd0_post_above_2048
4104 ;; 1024 < c
<= 2048 cylinders
4107 jmp hd0_post_store_logical
4109 hd0_post_above_2048
:
4111 jnbe hd0_post_above_4096
4112 ;; 2048 < c
<= 4096 cylinders
4115 jmp hd0_post_store_logical
4117 hd0_post_above_4096
:
4119 jnbe hd0_post_above_8192
4120 ;; 4096 < c
<= 8192 cylinders
4123 jmp hd0_post_store_logical
4125 hd0_post_above_8192
:
4126 ;; 8192 < c
<= 16384 cylinders
4130 hd0_post_store_logical
:
4131 mov (0x003d + 0x00), bx
;; number of physical cylinders
4132 mov (0x003d + 0x02), cl
;; number of physical heads
4134 mov cl
, #0x0f ;; repeat count
4135 mov si
, #0x003d ;; offset to disk0 FDPT
4136 mov al
, #0x00 ;; sum
4137 hd0_post_checksum_loop
:
4141 jnz hd0_post_checksum_loop
4142 not al
;; now take
2s complement
4145 ;;; Done filling EBDA table
for hard disk
0.
4149 ;; is there really a second hard disk
? if not, return now
4157 ;; check that the hd type is really
0x0f.
4162 ;; check that the extended type is
47 - user definable
4166 cmp al
, #47 ;; decimal 47 - user definable
4171 ;; CMOS purpose param table offset
4172 ;; 0x24 cylinders low
0
4173 ;; 0x25 cylinders high
1
4175 ;; 0x27 write pre
-comp low
5
4176 ;; 0x28 write pre
-comp high
6
4178 ;; 0x2a landing zone low C
4179 ;; 0x2b landing zone high D
4180 ;; 0x2c sectors
/track E
4181 ;;; Fill EBDA table
for hard disk
1.
4189 mov (0x004d + 0x05), ax
;; write precomp word
4194 mov (0x004d + 0x08), al
;; drive control byte
4203 mov (0x004d + 0x0C), ax
;; landing zone word
4205 mov al
, #0x25 ;; get cylinders word in AX
4207 in al
, #0x71 ;; high byte
4211 in al
, #0x71 ;; low byte
4212 mov bx
, ax
;; BX
= cylinders
4217 mov cl
, al
;; CL
= heads
4222 mov dl
, al
;; DL
= sectors
4225 jnbe hd1_post_logical_chs
;; if cylinders
> 1024, use translated style CHS
4227 hd1_post_physical_chs
:
4228 ;; no logical CHS mapping used
, just physical CHS
4229 ;; use Standard Fixed Disk Parameter
Table (FDPT
)
4230 mov (0x004d + 0x00), bx
;; number of physical cylinders
4231 mov (0x004d + 0x02), cl
;; number of physical heads
4232 mov (0x004d + 0x0E), dl
;; number of physical sectors
4235 hd1_post_logical_chs
:
4236 ;; complies with Phoenix style Translated Fixed Disk Parameter
Table (FDPT
)
4237 mov (0x004d + 0x09), bx
;; number of physical cylinders
4238 mov (0x004d + 0x0b), cl
;; number of physical heads
4239 mov (0x004d + 0x04), dl
;; number of physical sectors
4240 mov (0x004d + 0x0e), dl
;; number of logical
sectors (same
)
4242 mov (0x004d + 0x03), al
;; A0h signature
, indicates translated table
4245 jnbe hd1_post_above_2048
4246 ;; 1024 < c
<= 2048 cylinders
4249 jmp hd1_post_store_logical
4251 hd1_post_above_2048
:
4253 jnbe hd1_post_above_4096
4254 ;; 2048 < c
<= 4096 cylinders
4257 jmp hd1_post_store_logical
4259 hd1_post_above_4096
:
4261 jnbe hd1_post_above_8192
4262 ;; 4096 < c
<= 8192 cylinders
4265 jmp hd1_post_store_logical
4267 hd1_post_above_8192
:
4268 ;; 8192 < c
<= 16384 cylinders
4272 hd1_post_store_logical
:
4273 mov (0x004d + 0x00), bx
;; number of physical cylinders
4274 mov (0x004d + 0x02), cl
;; number of physical heads
4276 mov cl
, #0x0f ;; repeat count
4277 mov si
, #0x004d ;; offset to disk0 FDPT
4278 mov al
, #0x00 ;; sum
4279 hd1_post_checksum_loop
:
4283 jnz hd1_post_checksum_loop
4284 not al
;; now take
2s complement
4287 ;;; Done filling EBDA table
for hard disk
0.
4293 ;; in
: AL in BCD format
4294 ;; out
: AL in binary format
, AH will always be
0
4297 and bl
, #0x0f ;; bl has low digit
4298 shr al
, #4 ;; al has high digit
4300 mul al
, bh
;; multiply high digit by
10 (result in AX
)
4301 add al
, bl
;; then add low digit
4305 ;; Setup the Timer Ticks
Count (0x46C:dword
) and
4306 ;; Timer Ticks Roller
Flag (0x470:byte
)
4307 ;; The Timer Ticks Count needs to be set according to
4308 ;; the current CMOS time
, as
if ticks have been occurring
4309 ;; at
18.2hz since midnight up to
this point
. Calculating
4310 ;; this is a little complicated
. Here are the factors I gather
4311 ;; regarding
this. 14,318,180 hz was the original clock speed
,
4312 ;; chosen so it could be divided by either
3 to drive the
5Mhz CPU
4313 ;; at the time
, or 4 to drive the CGA video adapter
. The div3
4314 ;; source was divided again by
4 to feed a
1.193Mhz signal to
4315 ;; the timer
. With a maximum
16bit timer count
, this is again
4316 ;; divided down by
65536 to
18.2hz
.
4318 ;; 14,318,180 Hz clock
4319 ;; /3 = 4,772,726 Hz fed to orginal
5Mhz CPU
4320 ;; /4 = 1,193,181 Hz fed to timer
4321 ;; /65536 (maximum timer count
) = 18.20650736 ticks
/second
4322 ;; 1 second
= 18.20650736 ticks
4323 ;; 1 minute
= 1092.390442 ticks
4324 ;; 1 hour
= 65543.42651 ticks
4326 ;; Given the values in the CMOS clock
, one could calculate
4327 ;; the number of ticks by the following
:
4328 ;; ticks
= (BcdToBin(seconds
) * 18.206507) +
4329 ;; (BcdToBin(minutes
) * 1092.3904)
4330 ;; (BcdToBin(hours
) * 65543.427)
4331 ;; To get a little more accuracy
, since Im
using integer
4332 ;; arithmatic
, I use
:
4333 ;; ticks
= (BcdToBin(seconds
) * 18206507) / 1000000 +
4334 ;; (BcdToBin(minutes
) * 10923904) / 10000 +
4335 ;; (BcdToBin(hours
) * 65543427) / 1000
4340 xor eax
, eax
;; clear EAX
4343 in al
, #0x71 ;; AL has CMOS seconds in BCD
4344 call BcdToBin
;; EAX now has seconds in binary
4350 mov ecx
, eax
;; ECX will accumulate total ticks
4353 xor eax
, eax
;; clear EAX
4356 in al
, #0x71 ;; AL has CMOS minutes in BCD
4357 call BcdToBin
;; EAX now has minutes in binary
4363 add ecx
, eax
;; add to total ticks
4366 xor eax
, eax
;; clear EAX
4369 in al
, #0x71 ;; AL has CMOS hours in BCD
4370 call BcdToBin
;; EAX now has hours in binary
4376 add ecx
, eax
;; add to total ticks
4378 mov
0x46C, ecx
;; Timer Ticks Count
4380 mov
0x470, al
;; Timer Ticks Rollover Flag
4385 ;; record completion in BIOS task complete flag
4392 out
#0xA0, al ;; slave PIC EOI
4393 out
#0x20, al ;; master PIC EOI
4398 ;; for 'C' strings
and other data
, insert them here with
4399 ;; a the following hack
:
4400 ;; DATA_SEG_DEFS_HERE
4406 .org
0xe05b ; POST Entry Point
4409 ;; Examine CMOS shutdown status
.
4410 ;; 0 = normal startup
4419 out
0x70, AL
; select CMOS
register Fh
4421 out
0x71, AL
; set shutdown action to normal
4424 ; 0xb0, 0x20, /* mov al, #0x20 */
4425 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
4434 ; case 0: normal startup
4443 call _log_bios_start
4445 ;; zero out BIOS data
area (40:00..40:ff
)
4447 mov cx
, #0x0080 ;; 128 words
4453 ;; set all interrupts to
default handler
4454 mov bx
, #0x0000 ;; offset index
4455 mov cx
, #0x0100 ;; counter (256 interrupts)
4456 mov ax
, #dummy_iret_handler
4466 loop post_default_ints
4468 ;; base memory in K
40:13 (word
)
4469 mov ax
, #BASE_MEM_IN_K
4473 ;; Manufacturing Test
40:12
4476 ;; Warm Boot Flag
0040:0072
4477 ;; value of
1234h
= skip memory checks
4481 ;; Printer Services vector
4482 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
4484 ;; Bootstrap failure vector
4485 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
4487 ;; Bootstrap Loader vector
4488 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
4490 ;; User Timer Tick vector
4491 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
4493 ;; Memory Size Check vector
4494 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
4496 ;; Equipment Configuration Check vector
4497 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
4500 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
4502 mov ax
, #0x0000 ; mov EBDA seg into 40E
4504 mov
0x40E, #EBDA_SEG
4507 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
4508 ;; int 1C already points at
dummy_iret_handler (above
)
4509 mov al
, #0x34 ; timer0: binary count, 16bit count, mode 2
4511 mov al
, #0x00 ; maximum count of 0000H = 18.2Hz
4516 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
4517 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
4521 mov
0x0417, al
/* keyboard shift flags, set 1 */
4522 mov
0x0418, al
/* keyboard shift flags, set 2 */
4523 mov
0x0419, al
/* keyboard alt-numpad work area */
4524 mov
0x0471, al
/* keyboard ctrl-break flag */
4525 mov
0x0497, al
/* keyboard status flags 4 */
4527 mov
0x0496, al
/* keyboard status flags 3 */
4530 /* keyboard head of buffer pointer */
4534 /* keyboard end of buffer pointer */
4537 /* keyboard buffer */
4538 // for (i=0; i<16; i++)
4539 // bx_mem.access_physical(0x41E + i*2, 2, BX_WRITE, &zero16);
4542 /* keyboard pointer to start of buffer */
4546 /* keyboard pointer to end of buffer */
4550 /* (mch) Keyboard self-test */
4556 call _keyboard_panic
4560 #if BX_USE_PS2_MOUSE
4565 // hack to tell CMOS & BIOS data area that we have a mouse
4574 ;; mov CMOS Equipment Byte to BDA Equipment Word
4586 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
4589 mov
0x408, #0x378 ; Parallel I/O address, port 1
4590 mov
0x478, #0x14 ; Parallel printer 1 timeout
4591 mov AX
, 0x410 ; Equipment word bits
14..15 determing
# parallel ports
4593 or AX
, #0x4000 ; one parallel port
4597 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
4598 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
4599 mov
0x400, #0x03F8 ; Serial I/O address, port 1
4600 mov
0x47C, #0x0a ; Serial 1 timeout
4601 mov AX
, 0x410 ; Equipment word bits
9..11 determing
# serial ports
4603 or AX
, #0x0200 ; one serial port
4607 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
4608 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
4609 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
4610 ;; BIOS DATA AREA
0x4CE ???
4611 call timer_tick_post
4614 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
4617 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
4619 ;; Call extension ROMs
- scan C0000 to F4000 in
800 steps
4632 db
0xff ; call
0[bp
]
4646 out
0x21, AL
;master pic
: all IRQs unmasked
4647 out
0xA1, AL
;slave pic
: all IRQs unmasked
4649 call _print_bios_banner
4654 call hard_drive_post
4659 call floppy_drive_post
4662 //JMP_EP(0x0064) ; INT 19h location
4665 .org
0xe2c3 ; NMI Handler Entry Point
4666 call _nmi_handler_msg
4670 ;-------------------------------------------
4671 ;- INT
13h Fixed Disk Services Entry Point
-
4672 ;-------------------------------------------
4673 .org
0xe3fe ; INT
13h Fixed Disk Services Entry Point
4675 //JMPL(int13_relocated)
4677 .org
0xe401 ; Fixed Disk Parameter Table
4683 .org
0xe6f2 ; INT
19h Boot Load Service Entry Point
4685 //JMPL(int19_relocated)
4687 ;-------------------------------------------
4688 ;- System BIOS Configuration Data Table
4689 ;-------------------------------------------
4690 .org BIOS_CONFIG_TABLE
4691 db
0x08 ; Table
size (bytes
) -Lo
4692 db
0x00 ; Table
size (bytes
) -Hi
4697 ; b7
: 1=DMA channel
3 used by hard disk
4698 ; b6
: 1=2 interrupt controllers present
4700 ; b4
: 1=BIOS calls
int 15h
/4Fh every key
4701 ; b3
: 1=wait
for extern event
supported (Int
15h
/41h
)
4702 ; b2
: 1=extended BIOS data area used
4703 ; b1
: 0=AT
or ESDI bus
, 1=MicroChannel
4704 ; b0
: 1=Dual
bus (MicroChannel
+ ISA
)
4708 (BX_CALL_INT15_4F
<< 4) | \
4710 (BX_USE_EBDA
<< 2) | \
4714 ; b7
: 1=32-bit DMA supported
4715 ; b6
: 1=int16h
, function
9 supported
4716 ; b5
: 1=int15h
/C6h (get POS data
) supported
4717 ; b4
: 1=int15h
/C7h (get mem map info
) supported
4718 ; b3
: 1=int15h
/C8h (en
/dis CPU
) supported
4719 ; b2
: 1=non
-8042 kb controller
4720 ; b1
: 1=data streaming supported
4727 ; b4
: POST supports ROM
-to
-RAM enable
/disable
4728 ; b3
: SCSI on system board
4729 ; b2
: info panel installed
4730 ; b1
: Initial Machine
Load (IML
) system
- BIOS on disk
4731 ; b0
: SCSI supported in IML
4735 ; b6
: EEPROM present
4736 ; b5
-3: ABIOS
presence (011 = not supported
)
4738 ; b1
: memory split above
16Mb supported
4739 ; b0
: POSTEXT directly supported by POST
4741 ; Feature byte
5 (IBM
)
4742 ; b1
: enhanced mouse
4748 .org
0xe729 ; Baud Rate Generator Table
4753 .org
0xe739 ; INT
14h Serial Communications Service Entry Point
4759 call _int14_function
4765 ;----------------------------------------
4766 ;- INT
16h Keyboard Service Entry Point
-
4767 ;----------------------------------------
4780 call _int16_function
4790 and BYTE
[bp
+ 0x06], #0xbf
4798 or BYTE
[bp
+ 0x06], #0x40
4814 /* no key yet, call int 15h, function AX=9002 */
4816 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
4817 0xcd, 0x15, /* int 15h */
4819 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
4821 jmp int16_wait_for_key
4826 call _int16_function
4831 /* notify int16 complete w/ int 15h, function AX=9102 */
4833 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
4834 0xcd, 0x15, /* int 15h */
4841 ;-------------------------------------------------
4842 ;- INT09h
: Keyboard Hardware Service Entry Point
-
4843 ;-------------------------------------------------
4849 mov al
, #0xAD ;;disable keyboard
4854 ;; see
if there is really a key to read from the controller
4857 jz int09_done
;; nope
, skip processing
4859 in al
, #0x60 ;;read key from keyboard controller
4860 //test al, #0x80 ;;look for key release
4861 //jnz int09_process_key ;; dont pass releases to intercept?
4863 #ifdef BX_CALL_INT15_4F
4864 mov ah
, #0x4f ;; allow for keyboard intercept
4871 //int09_process_key:
4876 call _int09_function
4882 ;; look at PIC in
-service
-register to see
if EOI required
4886 and al
, #0x02 ;; IRQ 1 in service
4888 mov al
, #0x20 ;; send EOI to master PIC
4892 mov al
, #0xAE ;;enable keyboard
4900 ;----------------------------------------
4901 ;- INT
13h Diskette Service Entry Point
-
4902 ;----------------------------------------
4908 call _int13_diskette_function
4912 //JMPL(iret_modify_cf)
4920 ;; pushf already done
4923 call _int13_diskette_function
4927 //JMPL(iret_modify_cf)
4939 ;; ??? dont know
if this service changes the
return status
4940 //JMPL(iret_modify_cf)
4946 ;---------------------------------------------
4947 ;- INT
0Eh Diskette Hardware ISR Entry Point
-
4948 ;---------------------------------------------
4949 .org
0xef57 ; INT
0Eh Diskette Hardware ISR Entry Point
4953 mov ax
, #0x0000 ;; segment 0000
4956 out
0x20, al
;; send EOI to PIC
4958 or al
, #0x80 ;; diskette interrupt has occurred
4965 .org
0xefc7 ; Diskette Controller Parameter Table
4966 diskette_param_table
:
4967 ;; Since no provisions are made
for multiple drive types
, most
4968 ;; values in
this table are ignored
. I set parameters
for 1.44M
4971 db
0x02 ;; head load time
0000001, DMA used
4980 db
0x01 ;; most systems
default to
8
4983 ;----------------------------------------
4984 ;- INT17h
: Printer Service Entry Point
-
4985 ;----------------------------------------
4992 call _int17_function
4997 .org
0xf045 ; INT
10 Functions
0-Fh Entry Point
5004 .org
0xf065 ; INT
10h Video Support Service Entry Point
5006 ;; dont
do anything
, since the VGA BIOS handles int10h requests
5009 .org
0xf0a4 ; MDA
/CGA Video Parameter
Table (INT
1Dh
)
5014 .org
0xf841 ; INT
12h Memory Size Service Entry Point
5015 ; ??? different
for Pentium (machine check
)?
5027 .org
0xf84d ; INT
11h Equipment List Service Entry Point
5039 .org
0xf859 ; INT
15h System Services Entry Point
5045 call _int15_function
5050 //JMPL(iret_modify_cf)
5053 ;; Protected mode IDT descriptor
5055 ;; I just make the limit
0, so the machine will shutdown
5056 ;; if an exception occurs during
protected mode memory
5059 ;; Set base to f0000 to correspond to beginning of BIOS
,
5060 ;; in
case I actually define an IDT later
5064 dw
0x0000 ;; limit
15:00
5065 dw
0x0000 ;; base
15:00
5066 db
0x0f ;; base
23:16
5068 ;; Real mode IDT descriptor
5070 ;; Set to typical real
-mode values
.
5075 dw
0x03ff ;; limit
15:00
5076 dw
0x0000 ;; base
15:00
5077 db
0x00 ;; base
23:16
5079 .org
0xfa6e ; Character Font
for 320x200
& 640x200
Graphics (lower
128 characters
)
5085 .org
0xfe6e ; INT
1Ah Time
-of
-day Service Entry Point
5091 call _int1a_function
5097 ;; int70h
: IRQ8
- CMOS RTC
5104 call _int70_function
5112 .org
0xfea5 ; INT
08h System Timer ISR Entry Point
5119 mov eax
, 0x046c ;; get ticks dword
5122 ;; compare eax to one days worth of timer ticks at
18.2 hz
5123 cmp eax
, #0x001800B0
5124 jb int08_store_ticks
5125 ;; there has been a midnight rollover at
this point
5126 xor eax
, eax
;; zero out counter
5127 inc BYTE
0x0470 ;; increment rollover flag
5130 mov
0x046c, eax
;; store
new ticks dword
5131 ;; chain to user timer tick INT
#0x1c
5133 //;; call_ep [ds:loc]
5134 //CALL_EP( 0x1c << 2 )
5138 out
0x20, al
; send EOI to PIC
5143 .org
0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
5145 ;------------------------------------------------
5146 ;- IRET Instruction
for Dummy Interrupt Handler
-
5147 ;------------------------------------------------
5148 .org
0xff53 ; IRET Instruction
for Dummy Interrupt Handler
5152 .org
0xff54 ; INT
05h Print Screen Service Entry Point
5157 ; .ascii
"(c) 1994-2000 Kevin P. Lawton"
5159 .org
0xfff0 ; Power
-up Entry Point
5163 .org
0xfff5 ; ASCII Date ROM was built
- 8 characters in MM
/DD
/YY
5166 .org
0xfffe ; System Model ID
5171 // bcc-generated data will be placed here
5173 // For documentation of this config structure, look on developer.intel.com and
5174 // search for multiprocessor specification. Note that when you change anything
5175 // you must update the checksum (a pain!). It would be better to construct this
5176 // with C structures, or at least fill in the checksum automatically.
5178 #if (BX_SMP_PROCESSORS==1)
5179 // no structure necessary.
5180 #elif (BX_SMP_PROCESSORS==2)
5181 // define the Intel MP Configuration Structure for 2 processors at
5182 // APIC ID 0,1. I/O APIC at ID=2.
5185 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
5186 dw (mp_config_end
-mp_config_table
) ;; table length
5189 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
5190 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
5191 db
0x20, 0x20, 0x20, 0x20
5192 db
0x20, 0x20, 0x20, 0x20
5193 dw
0,0 ;; oem table ptr
5194 dw
0 ;; oem table size
5195 dw
20 ;; entry count
5196 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
5197 dw
0 ;; extended table length
5198 db
0 ;; extended table checksum
5201 db
0 ;; entry type
=processor
5202 db
0 ;; local APIC id
5203 db
0x11 ;; local APIC version number
5204 db
3 ;; cpu flags
: enabled
5205 db
0,6,0,0 ;; cpu signature
5206 dw
0x201,0 ;; feature flags
5210 db
0 ;; entry type
=processor
5211 db
1 ;; local APIC id
5212 db
0x11 ;; local APIC version number
5213 db
1 ;; cpu flags
: enabled
5214 db
0,6,0,0 ;; cpu signature
5215 dw
0x201,0 ;; feature flags
5219 db
1 ;; entry type
=bus
5221 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
5223 db
2 ;; entry type
=I
/O APIC
5224 db
2 ;; apic id
=2. linux will set
.
5225 db
0x11 ;; I
/O APIC version number
5226 db
1 ;; flags
=1=enabled
5227 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
5229 db
3 ;; entry type
=I
/O interrupt
5230 db
0 ;; interrupt type
=vectored interrupt
5231 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
5232 db
0 ;; source bus ID is ISA
5233 db
0 ;; source bus IRQ
5234 db
2 ;; destination I
/O APIC ID
5235 db
0 ;; destination I
/O APIC interrrupt in
5236 ;; repeat pattern
for interrupts
0-15
5246 db
3,0,0,0,0,10,2,10
5247 db
3,0,0,0,0,11,2,11
5248 db
3,0,0,0,0,12,2,12
5249 db
3,0,0,0,0,13,2,13
5250 db
3,0,0,0,0,14,2,14
5251 db
3,0,0,0,0,15,2,15
5252 #elif (BX_SMP_PROCESSORS==4)
5253 // define the Intel MP Configuration Structure for 4 processors at
5254 // APIC ID 0,1,2,3. I/O APIC at ID=4.
5257 db
0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
5258 dw (mp_config_end
-mp_config_table
) ;; table length
5261 .ascii
"BOCHSCPU" ;; OEM id
= "BOCHSCPU"
5262 db
0x30, 0x2e, 0x31, 0x20 ;; vendor id
= "0.1 "
5263 db
0x20, 0x20, 0x20, 0x20
5264 db
0x20, 0x20, 0x20, 0x20
5265 dw
0,0 ;; oem table ptr
5266 dw
0 ;; oem table size
5267 dw
22 ;; entry count
5268 dw
0x0000, 0xfee0 ;; memory mapped address of local APIC
5269 dw
0 ;; extended table length
5270 db
0 ;; extended table checksum
5273 db
0 ;; entry type
=processor
5274 db
0 ;; local APIC id
5275 db
0x11 ;; local APIC version number
5276 db
1 ;; cpu flags
: enabled
5277 db
0,6,0,0 ;; cpu signature
5278 dw
0x201,0 ;; feature flags
5282 db
0 ;; entry type
=processor
5283 db
1 ;; local APIC id
5284 db
0x11 ;; local APIC version number
5285 db
1 ;; cpu flags
: enabled
5286 db
0,6,0,0 ;; cpu signature
5287 dw
0x201,0 ;; feature flags
5291 db
0 ;; entry type
=processor
5292 db
2 ;; local APIC id
5293 db
0x11 ;; local APIC version number
5294 db
3 ;; cpu flags
: enabled
, bootstrap processor
5295 db
0,6,0,0 ;; cpu signature
5296 dw
0x201,0 ;; feature flags
5300 db
0 ;; entry type
=processor
5301 db
3 ;; local APIC id
5302 db
0x11 ;; local APIC version number
5303 db
1 ;; cpu flags
: enabled
5304 db
0,6,0,0 ;; cpu signature
5305 dw
0x201,0 ;; feature flags
5309 db
1 ;; entry type
=bus
5311 db
0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type
="ISA "
5313 db
2 ;; entry type
=I
/O APIC
5314 db
4 ;; apic id
=2. linux will set
.
5315 db
0x11 ;; I
/O APIC version number
5316 db
1 ;; flags
=1=enabled
5317 dw
0x0000, 0xfec0 ;; memory mapped address of I
/O APIC
5319 db
3 ;; entry type
=I
/O interrupt
5320 db
0 ;; interrupt type
=vectored interrupt
5321 db
0,0 ;; flags po
=0, el
=0 (linux uses as
default)
5322 db
0 ;; source bus ID is ISA
5323 db
0 ;; source bus IRQ
5324 db
4 ;; destination I
/O APIC ID
5325 db
0 ;; destination I
/O APIC interrrupt in
5326 ;; repeat pattern
for interrupts
0-15
5336 db
3,0,0,0,0,10,4,10
5337 db
3,0,0,0,0,11,4,11
5338 db
3,0,0,0,0,12,4,12
5339 db
3,0,0,0,0,13,4,13
5340 db
3,0,0,0,0,14,4,14
5341 db
3,0,0,0,0,15,4,15
5343 # error Sorry, rombios only has configurations for 1, 2, or 4 processors.
5344 #endif // if (BX_SMP_PROCESSORS==...)
5346 mp_config_end
: // this label used to find length of mp structure
5349 #if (BX_SMP_PROCESSORS>1)
5351 mp_floating_pointer_structure
:
5352 db
0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
5353 dw mp_config_table
, 0xf ;; pointer to MP configuration table
5354 db
1 ;; length of
this struct in
16-bit byte chunks
5355 db
4 ;; MP spec revision
5357 db
0 ;; MP feature byte
1. value
0 means look at the config table
5358 db
0,0,0,0 ;; MP feature bytes
2-5.