debuggers.hg

view tools/firmware/rombios/rombios.c @ 13681:c07326324f8d

[HVM] Add TCG BIOS extensions to the high memory area along with
some often-used libc utility functions. The TCG extensions are
described here:

https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf

I have tried to keep the patching with rombios.c to a minimum, but
some amount of code needs to be inserted at various locations.

The code is currently deactivated, but can be activated by setting
BX_TCGBIOS to '1'.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kaf24@localhost.localdomain
date Fri Jan 26 16:38:32 2007 +0000 (2007-01-26)
parents 480436ef6255
children edbff1762a55
line source
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
12 //
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.
17 //
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.
22 //
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 // ROM BIOS for use with Bochs/Plex x86 emulation environment
29 #define HVMASSIST
30 #undef HVMTEST
32 // Xen full virtualization does not handle unaligned IO with page crossing.
33 // Disable 32-bit PIO as a workaround.
34 #undef NO_PIO32
37 // ROM BIOS compatability entry points:
38 // ===================================
39 // $e05b ; POST Entry Point
40 // $e2c3 ; NMI Handler Entry Point
41 // $e3fe ; INT 13h Fixed Disk Services Entry Point
42 // $e401 ; Fixed Disk Parameter Table
43 // $e6f2 ; INT 19h Boot Load Service Entry Point
44 // $e6f5 ; Configuration Data Table
45 // $e729 ; Baud Rate Generator Table
46 // $e739 ; INT 14h Serial Communications Service Entry Point
47 // $e82e ; INT 16h Keyboard Service Entry Point
48 // $e987 ; INT 09h Keyboard Service Entry Point
49 // $ec59 ; INT 13h Diskette Service Entry Point
50 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
51 // $efc7 ; Diskette Controller Parameter Table
52 // $efd2 ; INT 17h Printer Service Entry Point
53 // $f045 ; INT 10 Functions 0-Fh Entry Point
54 // $f065 ; INT 10h Video Support Service Entry Point
55 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
56 // $f841 ; INT 12h Memory Size Service Entry Point
57 // $f84d ; INT 11h Equipment List Service Entry Point
58 // $f859 ; INT 15h System Services Entry Point
59 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
60 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
61 // $fea5 ; INT 08h System Timer ISR Entry Point
62 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
63 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
64 // $ff54 ; INT 05h Print Screen Service Entry Point
65 // $fff0 ; Power-up Entry Point
66 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
67 // $fffe ; System Model ID
69 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
70 // Features
71 // - supports up to 4 ATA interfaces
72 // - device/geometry detection
73 // - 16bits/32bits device access
74 // - pchs/lba access
75 // - datain/dataout/packet command support
76 //
77 // NOTES for El-Torito Boot (cbbochs@free.fr)
78 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
79 // - Current code is only able to boot mono-session cds
80 // - Current code can not boot and emulate a hard-disk
81 // the bios will panic otherwise
82 // - Current code also use memory in EBDA segement.
83 // - I used cmos byte 0x3D to store extended information on boot-device
84 // - Code has to be modified modified to handle multiple cdrom drives
85 // - Here are the cdrom boot failure codes:
86 // 1 : no atapi device found
87 // 2 : no atapi cdrom found
88 // 3 : can not read cd - BRVD
89 // 4 : cd is not eltorito (BRVD)
90 // 5 : cd is not eltorito (ISO TAG)
91 // 6 : cd is not eltorito (ELTORITO TAG)
92 // 7 : can not read cd - boot catalog
93 // 8 : boot catalog : bad header
94 // 9 : boot catalog : bad platform
95 // 10 : boot catalog : bad signature
96 // 11 : boot catalog : bootable flag not set
97 // 12 : can not read cd - boot image
98 //
99 // ATA driver
100 // - EBDA segment.
101 // I used memory starting at 0x121 in the segment
102 // - the translation policy is defined in cmos regs 0x39 & 0x3a
103 //
104 // TODO :
105 //
106 // int74
107 // - needs to be reworked. Uses direct [bp] offsets. (?)
108 //
109 // int13:
110 // - f04 (verify sectors) isn't complete (?)
111 // - f02/03/04 should set current cyl,etc in BDA (?)
112 // - rewrite int13_relocated & clean up int13 entry code
113 //
114 // NOTES:
115 // - NMI access (bit7 of addr written to 70h)
116 //
117 // ATA driver
118 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
119 // - could send the multiple-sector read/write commands
120 //
121 // El-Torito
122 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
123 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
124 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
125 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
126 // This is ok. But DL should be reincremented afterwards.
127 // - Fix all "FIXME ElTorito Various"
128 // - should be able to boot any cdrom instead of the first one
129 //
130 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
132 #define DEBUG_ROMBIOS 0
134 #define DEBUG_ATA 0
135 #define DEBUG_INT13_HD 0
136 #define DEBUG_INT13_CD 0
137 #define DEBUG_INT13_ET 0
138 #define DEBUG_INT13_FL 0
139 #define DEBUG_INT15 0
140 #define DEBUG_INT16 0
141 #define DEBUG_INT1A 0
142 #define DEBUG_INT74 0
143 #define DEBUG_APM 0
145 #define BX_CPU 3
146 #define BX_USE_PS2_MOUSE 1
147 #define BX_CALL_INT15_4F 1
148 #define BX_USE_EBDA 1
149 #define BX_SUPPORT_FLOPPY 1
150 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
151 #define BX_PCIBIOS 1
152 #define BX_APM 1
154 #define BX_USE_ATADRV 1
155 #define BX_ELTORITO_BOOT 1
157 #define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */
159 #define BX_MAX_ATA_INTERFACES 4
160 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
162 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
163 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
165 /* model byte 0xFC = AT */
166 #define SYS_MODEL_ID 0xFC
167 #define SYS_SUBMODEL_ID 0x00
168 #define BIOS_REVISION 1
169 #define BIOS_CONFIG_TABLE 0xe6f5
171 #ifndef BIOS_BUILD_DATE
172 # define BIOS_BUILD_DATE "06/23/99"
173 #endif
175 // 1K of base memory used for Extended Bios Data Area (EBDA)
176 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
177 #define EBDA_SEG 0x9FC0
178 #define EBDA_SIZE 1 // In KiB
179 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
181 // Define the application NAME
182 #ifdef HVMASSIST
183 # define BX_APPNAME "HVMAssist"
184 #elif PLEX86
185 # define BX_APPNAME "Plex86"
186 #else
187 # define BX_APPNAME "Bochs"
188 #endif
190 // Sanity Checks
191 #if BX_USE_ATADRV && BX_CPU<3
192 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
193 #endif
194 #if BX_USE_ATADRV && !BX_USE_EBDA
195 # error ATA/ATAPI Driver can only be used if EBDA is available
196 #endif
197 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
198 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
199 #endif
200 #if BX_PCIBIOS && BX_CPU<3
201 # error PCI BIOS can only be used with 386+ cpu
202 #endif
203 #if BX_APM && BX_CPU<3
204 # error APM BIOS can only be used with 386+ cpu
205 #endif
207 #ifndef BX_SMP_PROCESSORS
208 #define BX_SMP_PROCESSORS 1
209 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
210 #endif
212 #define PANIC_PORT 0x400
213 #define PANIC_PORT2 0x401
214 #define INFO_PORT 0x402
215 #define DEBUG_PORT 0x403
217 // #20 is dec 20
218 // #$20 is hex 20 = 32
219 // #0x20 is hex 20 = 32
220 // LDA #$20
221 // JSR $E820
222 // LDD .i,S
223 // JSR $C682
224 // mov al, #$20
226 // all hex literals should be prefixed with '0x'
227 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
228 // no mov SEG-REG, #value, must mov register into seg-reg
229 // grep -i "mov[ ]*.s" rombios.c
231 // This is for compiling with gcc2 and gcc3
232 #define ASM_START #asm
233 #define ASM_END #endasm
235 ASM_START
236 .rom
238 .org 0x0000
240 #if BX_CPU >= 3
241 use16 386
242 #else
243 use16 286
244 #endif
246 MACRO HALT
247 ;; the HALT macro is called with the line number of the HALT call.
248 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
249 ;; to print a BX_PANIC message. This will normally halt the simulation
250 ;; with a message such as "BIOS panic at rombios.c, line 4091".
251 ;; However, users can choose to make panics non-fatal and continue.
252 #if BX_VIRTUAL_PORTS
253 mov dx,#PANIC_PORT
254 mov ax,#?1
255 out dx,ax
256 #else
257 mov dx,#0x80
258 mov ax,#?1
259 out dx,al
260 #endif
261 MEND
263 MACRO JMP_AP
264 db 0xea
265 dw ?2
266 dw ?1
267 MEND
269 MACRO SET_INT_VECTOR
270 mov ax, ?3
271 mov ?1*4, ax
272 mov ax, ?2
273 mov ?1*4+2, ax
274 MEND
276 ASM_END
278 typedef unsigned char Bit8u;
279 typedef unsigned short Bit16u;
280 typedef unsigned short bx_bool;
281 typedef unsigned long Bit32u;
284 void memsetb(seg,offset,value,count);
285 void memcpyb(dseg,doffset,sseg,soffset,count);
286 void memcpyd(dseg,doffset,sseg,soffset,count);
288 // memset of count bytes
289 void
290 memsetb(seg,offset,value,count)
291 Bit16u seg;
292 Bit16u offset;
293 Bit16u value;
294 Bit16u count;
295 {
296 ASM_START
297 push bp
298 mov bp, sp
300 push ax
301 push cx
302 push es
303 push di
305 mov cx, 10[bp] ; count
306 cmp cx, #0x00
307 je memsetb_end
308 mov ax, 4[bp] ; segment
309 mov es, ax
310 mov ax, 6[bp] ; offset
311 mov di, ax
312 mov al, 8[bp] ; value
313 cld
314 rep
315 stosb
317 memsetb_end:
318 pop di
319 pop es
320 pop cx
321 pop ax
323 pop bp
324 ASM_END
325 }
327 // memcpy of count bytes
328 void
329 memcpyb(dseg,doffset,sseg,soffset,count)
330 Bit16u dseg;
331 Bit16u doffset;
332 Bit16u sseg;
333 Bit16u soffset;
334 Bit16u count;
335 {
336 ASM_START
337 push bp
338 mov bp, sp
340 push ax
341 push cx
342 push es
343 push di
344 push ds
345 push si
347 mov cx, 12[bp] ; count
348 cmp cx, #0x0000
349 je memcpyb_end
350 mov ax, 4[bp] ; dsegment
351 mov es, ax
352 mov ax, 6[bp] ; doffset
353 mov di, ax
354 mov ax, 8[bp] ; ssegment
355 mov ds, ax
356 mov ax, 10[bp] ; soffset
357 mov si, ax
358 cld
359 rep
360 movsb
362 memcpyb_end:
363 pop si
364 pop ds
365 pop di
366 pop es
367 pop cx
368 pop ax
370 pop bp
371 ASM_END
372 }
374 #if 0
375 // memcpy of count dword
376 void
377 memcpyd(dseg,doffset,sseg,soffset,count)
378 Bit16u dseg;
379 Bit16u doffset;
380 Bit16u sseg;
381 Bit16u soffset;
382 Bit16u count;
383 {
384 ASM_START
385 push bp
386 mov bp, sp
388 push ax
389 push cx
390 push es
391 push di
392 push ds
393 push si
395 mov cx, 12[bp] ; count
396 cmp cx, #0x0000
397 je memcpyd_end
398 mov ax, 4[bp] ; dsegment
399 mov es, ax
400 mov ax, 6[bp] ; doffset
401 mov di, ax
402 mov ax, 8[bp] ; ssegment
403 mov ds, ax
404 mov ax, 10[bp] ; soffset
405 mov si, ax
406 cld
407 rep
408 movsd
410 memcpyd_end:
411 pop si
412 pop ds
413 pop di
414 pop es
415 pop cx
416 pop ax
418 pop bp
419 ASM_END
420 }
421 #endif
423 // read_dword and write_dword functions
424 static Bit32u read_dword();
425 static void write_dword();
427 Bit32u
428 read_dword(seg, offset)
429 Bit16u seg;
430 Bit16u offset;
431 {
432 ASM_START
433 push bp
434 mov bp, sp
436 push bx
437 push ds
438 mov ax, 4[bp] ; segment
439 mov ds, ax
440 mov bx, 6[bp] ; offset
441 mov ax, [bx]
442 inc bx
443 inc bx
444 mov dx, [bx]
445 ;; ax = return value (word)
446 ;; dx = return value (word)
447 pop ds
448 pop bx
450 pop bp
451 ASM_END
452 }
454 void
455 write_dword(seg, offset, data)
456 Bit16u seg;
457 Bit16u offset;
458 Bit32u data;
459 {
460 ASM_START
461 push bp
462 mov bp, sp
464 push ax
465 push bx
466 push ds
467 mov ax, 4[bp] ; segment
468 mov ds, ax
469 mov bx, 6[bp] ; offset
470 mov ax, 8[bp] ; data word
471 mov [bx], ax ; write data word
472 inc bx
473 inc bx
474 mov ax, 10[bp] ; data word
475 mov [bx], ax ; write data word
476 pop ds
477 pop bx
478 pop ax
480 pop bp
481 ASM_END
482 }
484 // Bit32u (unsigned long) and long helper functions
485 ASM_START
487 ;; and function
488 landl:
489 landul:
490 SEG SS
491 and ax,[di]
492 SEG SS
493 and bx,2[di]
494 ret
496 ;; add function
497 laddl:
498 laddul:
499 SEG SS
500 add ax,[di]
501 SEG SS
502 adc bx,2[di]
503 ret
505 ;; cmp function
506 lcmpl:
507 lcmpul:
508 and eax, #0x0000FFFF
509 shl ebx, #16
510 add eax, ebx
511 shr ebx, #16
512 SEG SS
513 cmp eax, dword ptr [di]
514 ret
516 ;; sub function
517 lsubl:
518 lsubul:
519 SEG SS
520 sub ax,[di]
521 SEG SS
522 sbb bx,2[di]
523 ret
525 ;; mul function
526 lmull:
527 lmulul:
528 and eax, #0x0000FFFF
529 shl ebx, #16
530 add eax, ebx
531 SEG SS
532 mul eax, dword ptr [di]
533 mov ebx, eax
534 shr ebx, #16
535 ret
537 ;; dec function
538 ldecl:
539 ldecul:
540 SEG SS
541 dec dword ptr [bx]
542 ret
544 ;; or function
545 lorl:
546 lorul:
547 SEG SS
548 or ax,[di]
549 SEG SS
550 or bx,2[di]
551 ret
553 ;; inc function
554 lincl:
555 lincul:
556 SEG SS
557 inc dword ptr [bx]
558 ret
560 ;; tst function
561 ltstl:
562 ltstul:
563 and eax, #0x0000FFFF
564 shl ebx, #16
565 add eax, ebx
566 shr ebx, #16
567 test eax, eax
568 ret
570 ;; sr function
571 lsrul:
572 mov cx,di
573 jcxz lsr_exit
574 and eax, #0x0000FFFF
575 shl ebx, #16
576 add eax, ebx
577 lsr_loop:
578 shr eax, #1
579 loop lsr_loop
580 mov ebx, eax
581 shr ebx, #16
582 lsr_exit:
583 ret
585 ;; sl function
586 lsll:
587 lslul:
588 mov cx,di
589 jcxz lsl_exit
590 and eax, #0x0000FFFF
591 shl ebx, #16
592 add eax, ebx
593 lsl_loop:
594 shl eax, #1
595 loop lsl_loop
596 mov ebx, eax
597 shr ebx, #16
598 lsl_exit:
599 ret
601 idiv_:
602 cwd
603 idiv bx
604 ret
606 idiv_u:
607 xor dx,dx
608 div bx
609 ret
611 ldivul:
612 and eax, #0x0000FFFF
613 shl ebx, #16
614 add eax, ebx
615 xor edx, edx
616 SEG SS
617 mov bx, 2[di]
618 shl ebx, #16
619 SEG SS
620 mov bx, [di]
621 div ebx
622 mov ebx, eax
623 shr ebx, #16
624 ret
626 ASM_END
628 // for access to RAM area which is used by interrupt vectors
629 // and BIOS Data Area
631 typedef struct {
632 unsigned char filler1[0x400];
633 unsigned char filler2[0x6c];
634 Bit16u ticks_low;
635 Bit16u ticks_high;
636 Bit8u midnight_flag;
637 } bios_data_t;
639 #define BiosData ((bios_data_t *) 0)
641 #if BX_USE_ATADRV
642 typedef struct {
643 Bit16u heads; // # heads
644 Bit16u cylinders; // # cylinders
645 Bit16u spt; // # sectors / track
646 } chs_t;
648 // DPTE definition
649 typedef struct {
650 Bit16u iobase1;
651 Bit16u iobase2;
652 Bit8u prefix;
653 Bit8u unused;
654 Bit8u irq;
655 Bit8u blkcount;
656 Bit8u dma;
657 Bit8u pio;
658 Bit16u options;
659 Bit16u reserved;
660 Bit8u revision;
661 Bit8u checksum;
662 } dpte_t;
664 typedef struct {
665 Bit8u iface; // ISA or PCI
666 Bit16u iobase1; // IO Base 1
667 Bit16u iobase2; // IO Base 2
668 Bit8u irq; // IRQ
669 } ata_channel_t;
671 typedef struct {
672 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
673 Bit8u device; // Detected type of attached devices (hd/cd/none)
674 Bit8u removable; // Removable device flag
675 Bit8u lock; // Locks for removable devices
676 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
677 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
678 Bit16u blksize; // block size
680 Bit8u translation; // type of translation
681 chs_t lchs; // Logical CHS
682 chs_t pchs; // Physical CHS
684 Bit32u sectors; // Total sectors count
685 } ata_device_t;
687 typedef struct {
688 // ATA channels info
689 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
691 // ATA devices info
692 ata_device_t devices[BX_MAX_ATA_DEVICES];
693 //
694 // map between (bios hd id - 0x80) and ata channels
695 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
697 // map between (bios cd id - 0xE0) and ata channels
698 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
700 // Buffer for DPTE table
701 dpte_t dpte;
703 // Count of transferred sectors and bytes
704 Bit16u trsfsectors;
705 Bit32u trsfbytes;
707 } ata_t;
709 #if BX_ELTORITO_BOOT
710 // ElTorito Device Emulation data
711 typedef struct {
712 Bit8u active;
713 Bit8u media;
714 Bit8u emulated_drive;
715 Bit8u controller_index;
716 Bit16u device_spec;
717 Bit32u ilba;
718 Bit16u buffer_segment;
719 Bit16u load_segment;
720 Bit16u sector_count;
722 // Virtual device
723 chs_t vdevice;
724 } cdemu_t;
725 #endif // BX_ELTORITO_BOOT
727 #include "32bitgateway.h"
729 // for access to EBDA area
730 // The EBDA structure should conform to
731 // http://www.cybertrails.com/~fys/rombios.htm document
732 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
733 // EBDA must be at most 768 bytes; it lives at 0x9fc00, and the boot
734 // device tables are at 0x9ff00 -- 0x9ffff
735 typedef struct {
736 unsigned char filler1[0x3D];
738 // FDPT - Can be splitted in data members if needed
739 unsigned char fdpt0[0x10];
740 unsigned char fdpt1[0x10];
742 unsigned char filler2[0xC4];
744 // ATA Driver data
745 ata_t ata;
747 #if BX_ELTORITO_BOOT
748 // El Torito Emulation data
749 cdemu_t cdemu;
750 #endif // BX_ELTORITO_BOOT
752 upcall_t upcall;
753 } ebda_data_t;
755 #define EbdaData ((ebda_data_t *) 0)
757 // for access to the int13ext structure
758 typedef struct {
759 Bit8u size;
760 Bit8u reserved;
761 Bit16u count;
762 Bit16u offset;
763 Bit16u segment;
764 Bit32u lba1;
765 Bit32u lba2;
766 } int13ext_t;
768 #define Int13Ext ((int13ext_t *) 0)
770 // Disk Physical Table definition
771 typedef struct {
772 Bit16u size;
773 Bit16u infos;
774 Bit32u cylinders;
775 Bit32u heads;
776 Bit32u spt;
777 Bit32u sector_count1;
778 Bit32u sector_count2;
779 Bit16u blksize;
780 Bit16u dpte_segment;
781 Bit16u dpte_offset;
782 Bit16u key;
783 Bit8u dpi_length;
784 Bit8u reserved1;
785 Bit16u reserved2;
786 Bit8u host_bus[4];
787 Bit8u iface_type[8];
788 Bit8u iface_path[8];
789 Bit8u device_path[8];
790 Bit8u reserved3;
791 Bit8u checksum;
792 } dpt_t;
794 #define Int13DPT ((dpt_t *) 0)
796 #endif // BX_USE_ATADRV
798 typedef struct {
799 union {
800 struct {
801 Bit16u di, si, bp, sp;
802 Bit16u bx, dx, cx, ax;
803 } r16;
804 struct {
805 Bit16u filler[4];
806 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
807 } r8;
808 } u;
809 } pusha_regs_t;
811 typedef struct {
812 union {
813 struct {
814 Bit32u edi, esi, ebp, esp;
815 Bit32u ebx, edx, ecx, eax;
816 } r32;
817 struct {
818 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
819 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
820 } r16;
821 struct {
822 Bit32u filler[4];
823 Bit8u bl, bh;
824 Bit16u filler1;
825 Bit8u dl, dh;
826 Bit16u filler2;
827 Bit8u cl, ch;
828 Bit16u filler3;
829 Bit8u al, ah;
830 Bit16u filler4;
831 } r8;
832 } u;
833 } pushad_regs_t;
835 typedef struct {
836 union {
837 struct {
838 Bit16u flags;
839 } r16;
840 struct {
841 Bit8u flagsl;
842 Bit8u flagsh;
843 } r8;
844 } u;
845 } flags_t;
847 #define SetCF(x) x.u.r8.flagsl |= 0x01
848 #define SetZF(x) x.u.r8.flagsl |= 0x40
849 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
850 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
851 #define GetCF(x) (x.u.r8.flagsl & 0x01)
853 typedef struct {
854 Bit16u ip;
855 Bit16u cs;
856 flags_t flags;
857 } iret_addr_t;
861 static Bit8u inb();
862 static Bit8u inb_cmos();
863 static void outb();
864 static void outb_cmos();
865 static Bit16u inw();
866 static void outw();
867 static void init_rtc();
868 static bx_bool rtc_updating();
870 static Bit8u read_byte();
871 static Bit16u read_word();
872 static void write_byte();
873 static void write_word();
874 static void bios_printf();
875 static void copy_e820_table();
877 static Bit8u inhibit_mouse_int_and_events();
878 static void enable_mouse_int_and_events();
879 static Bit8u send_to_mouse_ctrl();
880 static Bit8u get_mouse_data();
881 static void set_kbd_command_byte();
883 static void int09_function();
884 static void int13_harddisk();
885 static void int13_cdrom();
886 static void int13_cdemu();
887 static void int13_eltorito();
888 static void int13_diskette_function();
889 static void int14_function();
890 static void int15_function();
891 static void int16_function();
892 static void int17_function();
893 static void int19_function();
894 static void int1a_function();
895 static void int70_function();
896 static void int74_function();
897 static Bit16u get_CS();
898 //static Bit16u get_DS();
899 //static void set_DS();
900 static Bit16u get_SS();
901 static unsigned int enqueue_key();
902 static unsigned int dequeue_key();
903 static void get_hd_geometry();
904 static void set_diskette_ret_status();
905 static void set_diskette_current_cyl();
906 static void determine_floppy_media();
907 static bx_bool floppy_drive_exists();
908 static bx_bool floppy_drive_recal();
909 static bx_bool floppy_media_known();
910 static bx_bool floppy_media_sense();
911 static bx_bool set_enable_a20();
912 static void debugger_on();
913 static void debugger_off();
914 static void keyboard_init();
915 static void keyboard_panic();
916 static void shutdown_status_panic();
917 static void nmi_handler_msg();
919 static void print_bios_banner();
920 static void print_boot_device();
921 static void print_boot_failure();
922 static void print_cdromboot_failure();
924 # if BX_USE_ATADRV
926 // ATA / ATAPI driver
927 void ata_init();
928 void ata_detect();
929 void ata_reset();
931 Bit16u ata_cmd_non_data();
932 Bit16u ata_cmd_data_in();
933 Bit16u ata_cmd_data_out();
934 Bit16u ata_cmd_packet();
936 Bit16u atapi_get_sense();
937 Bit16u atapi_is_ready();
938 Bit16u atapi_is_cdrom();
940 #endif // BX_USE_ATADRV
942 #if BX_ELTORITO_BOOT
944 void cdemu_init();
945 Bit8u cdemu_isactive();
946 Bit8u cdemu_emulated_drive();
948 Bit16u cdrom_boot();
950 #endif // BX_ELTORITO_BOOT
952 static char bios_cvs_version_string[] = "$Revision: 1.138 $";
953 static char bios_date_string[] = "$Date: 2005/05/07 15:55:26 $";
955 static char CVSID[] = "$Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $";
957 /* Offset to skip the CVS $Id: prefix */
958 #define bios_version_string (CVSID + 4)
960 #define BIOS_PRINTF_HALT 1
961 #define BIOS_PRINTF_SCREEN 2
962 #define BIOS_PRINTF_INFO 4
963 #define BIOS_PRINTF_DEBUG 8
964 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
965 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
967 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
969 // Defines the output macros.
970 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
971 // per-device basis. Debug info are sent only in debug mode
972 #if DEBUG_ROMBIOS
973 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
974 #else
975 # define BX_DEBUG(format, p...)
976 #endif
977 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
978 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
980 #if DEBUG_ATA
981 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
982 #else
983 # define BX_DEBUG_ATA(a...)
984 #endif
985 #if DEBUG_INT13_HD
986 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
987 #else
988 # define BX_DEBUG_INT13_HD(a...)
989 #endif
990 #if DEBUG_INT13_CD
991 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
992 #else
993 # define BX_DEBUG_INT13_CD(a...)
994 #endif
995 #if DEBUG_INT13_ET
996 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
997 #else
998 # define BX_DEBUG_INT13_ET(a...)
999 #endif
1000 #if DEBUG_INT13_FL
1001 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1002 #else
1003 # define BX_DEBUG_INT13_FL(a...)
1004 #endif
1005 #if DEBUG_INT15
1006 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1007 #else
1008 # define BX_DEBUG_INT15(a...)
1009 #endif
1010 #if DEBUG_INT16
1011 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1012 #else
1013 # define BX_DEBUG_INT16(a...)
1014 #endif
1015 #if DEBUG_INT1A
1016 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1017 #else
1018 # define BX_DEBUG_INT1A(a...)
1019 #endif
1020 #if DEBUG_INT74
1021 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1022 #else
1023 # define BX_DEBUG_INT74(a...)
1024 #endif
1026 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1027 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1028 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1029 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1030 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1031 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1032 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1033 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1035 #define GET_AL() ( AX & 0x00ff )
1036 #define GET_BL() ( BX & 0x00ff )
1037 #define GET_CL() ( CX & 0x00ff )
1038 #define GET_DL() ( DX & 0x00ff )
1039 #define GET_AH() ( AX >> 8 )
1040 #define GET_BH() ( BX >> 8 )
1041 #define GET_CH() ( CX >> 8 )
1042 #define GET_DH() ( DX >> 8 )
1044 #define GET_ELDL() ( ELDX & 0x00ff )
1045 #define GET_ELDH() ( ELDX >> 8 )
1047 #define SET_CF() FLAGS |= 0x0001
1048 #define CLEAR_CF() FLAGS &= 0xfffe
1049 #define GET_CF() (FLAGS & 0x0001)
1051 #define SET_ZF() FLAGS |= 0x0040
1052 #define CLEAR_ZF() FLAGS &= 0xffbf
1053 #define GET_ZF() (FLAGS & 0x0040)
1055 #define UNSUPPORTED_FUNCTION 0x86
1057 #define none 0
1058 #define MAX_SCAN_CODE 0x53
1060 static struct {
1061 Bit16u normal;
1062 Bit16u shift;
1063 Bit16u control;
1064 Bit16u alt;
1065 Bit8u lock_flags;
1066 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1067 { none, none, none, none, none },
1068 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1069 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1070 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1071 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1072 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1073 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1074 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1075 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1076 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1077 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1078 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1079 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1080 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1081 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1082 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1083 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1084 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1085 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1086 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1087 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1088 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1089 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1090 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1091 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1092 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1093 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1094 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1095 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1096 { none, none, none, none, none }, /* L Ctrl */
1097 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1098 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1099 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1100 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1101 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1102 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1103 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1104 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1105 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1106 { 0x273b, 0x273a, none, none, none }, /* ;: */
1107 { 0x2827, 0x2822, none, none, none }, /* '" */
1108 { 0x2960, 0x297e, none, none, none }, /* `~ */
1109 { none, none, none, none, none }, /* L shift */
1110 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1111 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1112 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1113 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1114 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1115 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1116 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1117 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1118 { 0x332c, 0x333c, none, none, none }, /* ,< */
1119 { 0x342e, 0x343e, none, none, none }, /* .> */
1120 { 0x352f, 0x353f, none, none, none }, /* /? */
1121 { none, none, none, none, none }, /* R Shift */
1122 { 0x372a, 0x372a, none, none, none }, /* * */
1123 { none, none, none, none, none }, /* L Alt */
1124 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1125 { none, none, none, none, none }, /* caps lock */
1126 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1127 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1128 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1129 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1130 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1131 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1132 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1133 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1134 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1135 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1136 { none, none, none, none, none }, /* Num Lock */
1137 { none, none, none, none, none }, /* Scroll Lock */
1138 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1139 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1140 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1141 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1142 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1143 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1144 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1145 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1146 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1147 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1148 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1149 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1150 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1151 };
1153 Bit8u
1154 inb(port)
1155 Bit16u port;
1157 ASM_START
1158 push bp
1159 mov bp, sp
1161 push dx
1162 mov dx, 4[bp]
1163 in al, dx
1164 pop dx
1166 pop bp
1167 ASM_END
1170 #if BX_USE_ATADRV
1171 Bit16u
1172 inw(port)
1173 Bit16u port;
1175 ASM_START
1176 push bp
1177 mov bp, sp
1179 push dx
1180 mov dx, 4[bp]
1181 in ax, dx
1182 pop dx
1184 pop bp
1185 ASM_END
1187 #endif
1189 void
1190 outb(port, val)
1191 Bit16u port;
1192 Bit8u val;
1194 ASM_START
1195 push bp
1196 mov bp, sp
1198 push ax
1199 push dx
1200 mov dx, 4[bp]
1201 mov al, 6[bp]
1202 out dx, al
1203 pop dx
1204 pop ax
1206 pop bp
1207 ASM_END
1210 #if BX_USE_ATADRV
1211 void
1212 outw(port, val)
1213 Bit16u port;
1214 Bit16u val;
1216 ASM_START
1217 push bp
1218 mov bp, sp
1220 push ax
1221 push dx
1222 mov dx, 4[bp]
1223 mov ax, 6[bp]
1224 out dx, ax
1225 pop dx
1226 pop ax
1228 pop bp
1229 ASM_END
1231 #endif
1233 void
1234 outb_cmos(cmos_reg, val)
1235 Bit8u cmos_reg;
1236 Bit8u val;
1238 ASM_START
1239 push bp
1240 mov bp, sp
1242 mov al, 4[bp] ;; cmos_reg
1243 out 0x70, al
1244 mov al, 6[bp] ;; val
1245 out 0x71, al
1247 pop bp
1248 ASM_END
1251 Bit8u
1252 inb_cmos(cmos_reg)
1253 Bit8u cmos_reg;
1255 ASM_START
1256 push bp
1257 mov bp, sp
1259 mov al, 4[bp] ;; cmos_reg
1260 out 0x70, al
1261 in al, 0x71
1263 pop bp
1264 ASM_END
1267 void
1268 init_rtc()
1270 outb_cmos(0x0a, 0x26);
1271 outb_cmos(0x0b, 0x02);
1272 inb_cmos(0x0c);
1273 inb_cmos(0x0d);
1276 bx_bool
1277 rtc_updating()
1279 // This function checks to see if the update-in-progress bit
1280 // is set in CMOS Status Register A. If not, it returns 0.
1281 // If it is set, it tries to wait until there is a transition
1282 // to 0, and will return 0 if such a transition occurs. A 1
1283 // is returned only after timing out. The maximum period
1284 // that this bit should be set is constrained to 244useconds.
1285 // The count I use below guarantees coverage or more than
1286 // this time, with any reasonable IPS setting.
1288 Bit16u count;
1290 count = 25000;
1291 while (--count != 0) {
1292 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1293 return(0);
1295 return(1); // update-in-progress never transitioned to 0
1299 Bit8u
1300 read_byte(seg, offset)
1301 Bit16u seg;
1302 Bit16u offset;
1304 ASM_START
1305 push bp
1306 mov bp, sp
1308 push bx
1309 push ds
1310 mov ax, 4[bp] ; segment
1311 mov ds, ax
1312 mov bx, 6[bp] ; offset
1313 mov al, [bx]
1314 ;; al = return value (byte)
1315 pop ds
1316 pop bx
1318 pop bp
1319 ASM_END
1322 Bit16u
1323 read_word(seg, offset)
1324 Bit16u seg;
1325 Bit16u offset;
1327 ASM_START
1328 push bp
1329 mov bp, sp
1331 push bx
1332 push ds
1333 mov ax, 4[bp] ; segment
1334 mov ds, ax
1335 mov bx, 6[bp] ; offset
1336 mov ax, [bx]
1337 ;; ax = return value (word)
1338 pop ds
1339 pop bx
1341 pop bp
1342 ASM_END
1345 void
1346 write_byte(seg, offset, data)
1347 Bit16u seg;
1348 Bit16u offset;
1349 Bit8u data;
1351 ASM_START
1352 push bp
1353 mov bp, sp
1355 push ax
1356 push bx
1357 push ds
1358 mov ax, 4[bp] ; segment
1359 mov ds, ax
1360 mov bx, 6[bp] ; offset
1361 mov al, 8[bp] ; data byte
1362 mov [bx], al ; write data byte
1363 pop ds
1364 pop bx
1365 pop ax
1367 pop bp
1368 ASM_END
1371 void
1372 write_word(seg, offset, data)
1373 Bit16u seg;
1374 Bit16u offset;
1375 Bit16u data;
1377 ASM_START
1378 push bp
1379 mov bp, sp
1381 push ax
1382 push bx
1383 push ds
1384 mov ax, 4[bp] ; segment
1385 mov ds, ax
1386 mov bx, 6[bp] ; offset
1387 mov ax, 8[bp] ; data word
1388 mov [bx], ax ; write data word
1389 pop ds
1390 pop bx
1391 pop ax
1393 pop bp
1394 ASM_END
1397 Bit16u
1398 get_CS()
1400 ASM_START
1401 mov ax, cs
1402 ASM_END
1405 // Bit16u
1406 //get_DS()
1407 //{
1408 //ASM_START
1409 // mov ax, ds
1410 //ASM_END
1411 //}
1412 //
1413 // void
1414 //set_DS(ds_selector)
1415 // Bit16u ds_selector;
1416 //{
1417 //ASM_START
1418 // push bp
1419 // mov bp, sp
1420 //
1421 // push ax
1422 // mov ax, 4[bp] ; ds_selector
1423 // mov ds, ax
1424 // pop ax
1425 //
1426 // pop bp
1427 //ASM_END
1428 //}
1430 Bit16u
1431 get_SS()
1433 ASM_START
1434 mov ax, ss
1435 ASM_END
1438 #ifdef HVMASSIST
1439 void
1440 copy_e820_table()
1442 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1443 Bit32u base_mem;
1444 if (nr_entries > 32)
1445 nr_entries = 32;
1446 write_word(0xe000, 0x8, nr_entries);
1447 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1448 /* Report the proper base memory size at address 0x0413: otherwise
1449 * non-e820 code will clobber things if BASE_MEM_IN_K is bigger than
1450 * the first e820 entry. Get the size by reading the second 64bit
1451 * field of the first e820 slot. */
1452 base_mem = read_dword(0x9000, 0x2d0 + 8);
1453 write_word(0x40, 0x13, base_mem >> 10);
1455 #endif /* HVMASSIST */
1457 #if BX_DEBUG_SERIAL
1458 /* serial debug port*/
1459 #define BX_DEBUG_PORT 0x03f8
1461 /* data */
1462 #define UART_RBR 0x00
1463 #define UART_THR 0x00
1465 /* control */
1466 #define UART_IER 0x01
1467 #define UART_IIR 0x02
1468 #define UART_FCR 0x02
1469 #define UART_LCR 0x03
1470 #define UART_MCR 0x04
1471 #define UART_DLL 0x00
1472 #define UART_DLM 0x01
1474 /* status */
1475 #define UART_LSR 0x05
1476 #define UART_MSR 0x06
1477 #define UART_SCR 0x07
1479 int uart_can_tx_byte(base_port)
1480 Bit16u base_port;
1482 return inb(base_port + UART_LSR) & 0x20;
1485 void uart_wait_to_tx_byte(base_port)
1486 Bit16u base_port;
1488 while (!uart_can_tx_byte(base_port));
1491 void uart_wait_until_sent(base_port)
1492 Bit16u base_port;
1494 while (!(inb(base_port + UART_LSR) & 0x40));
1497 void uart_tx_byte(base_port, data)
1498 Bit16u base_port;
1499 Bit8u data;
1501 uart_wait_to_tx_byte(base_port);
1502 outb(base_port + UART_THR, data);
1503 uart_wait_until_sent(base_port);
1505 #endif
1507 void
1508 wrch(c)
1509 Bit8u c;
1511 ASM_START
1512 push bp
1513 mov bp, sp
1515 push bx
1516 mov ah, #0x0e
1517 mov al, 4[bp]
1518 xor bx,bx
1519 int #0x10
1520 pop bx
1522 pop bp
1523 ASM_END
1526 void
1527 send(action, c)
1528 Bit16u action;
1529 Bit8u c;
1531 #if BX_DEBUG_SERIAL
1532 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1533 uart_tx_byte(BX_DEBUG_PORT, c);
1534 #endif
1535 #ifdef HVMASSIST
1536 outb(0xE9, c);
1537 #endif
1538 #if BX_VIRTUAL_PORTS
1539 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1540 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1541 #endif
1542 if (action & BIOS_PRINTF_SCREEN) {
1543 if (c == '\n') wrch('\r');
1544 wrch(c);
1548 void
1549 put_int(action, val, width, neg)
1550 Bit16u action;
1551 short val, width;
1552 bx_bool neg;
1554 short nval = val / 10;
1555 if (nval)
1556 put_int(action, nval, width - 1, neg);
1557 else {
1558 while (--width > 0) send(action, ' ');
1559 if (neg) send(action, '-');
1561 send(action, val - (nval * 10) + '0');
1564 void
1565 put_uint(action, val, width, neg)
1566 Bit16u action;
1567 unsigned short val;
1568 short width;
1569 bx_bool neg;
1571 unsigned short nval = val / 10;
1572 if (nval)
1573 put_uint(action, nval, width - 1, neg);
1574 else {
1575 while (--width > 0) send(action, ' ');
1576 if (neg) send(action, '-');
1578 send(action, val - (nval * 10) + '0');
1581 //--------------------------------------------------------------------------
1582 // bios_printf()
1583 // A compact variable argument printf function which prints its output via
1584 // an I/O port so that it can be logged by Bochs/Plex.
1585 // Currently, only %x is supported (or %02x, %04x, etc).
1586 //
1587 // Supports %[format_width][format]
1588 // where format can be d,x,c,s
1589 //--------------------------------------------------------------------------
1590 void
1591 bios_printf(action, s)
1592 Bit16u action;
1593 Bit8u *s;
1595 Bit8u c, format_char;
1596 bx_bool in_format;
1597 short i;
1598 Bit16u *arg_ptr;
1599 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1601 arg_ptr = &s;
1602 arg_seg = get_SS();
1604 in_format = 0;
1605 format_width = 0;
1607 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1608 #if BX_VIRTUAL_PORTS
1609 outb(PANIC_PORT2, 0x00);
1610 #endif
1611 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1614 while (c = read_byte(get_CS(), s)) {
1615 if ( c == '%' ) {
1616 in_format = 1;
1617 format_width = 0;
1619 else if (in_format) {
1620 if ( (c>='0') && (c<='9') ) {
1621 format_width = (format_width * 10) + (c - '0');
1623 else {
1624 arg_ptr++; // increment to next arg
1625 arg = read_word(arg_seg, arg_ptr);
1626 if (c == 'x') {
1627 if (format_width == 0)
1628 format_width = 4;
1629 for (i=format_width-1; i>=0; i--) {
1630 nibble = (arg >> (4 * i)) & 0x000f;
1631 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1634 else if (c == 'u') {
1635 put_uint(action, arg, format_width, 0);
1637 else if (c == 'd') {
1638 if (arg & 0x8000)
1639 put_int(action, -arg, format_width - 1, 1);
1640 else
1641 put_int(action, arg, format_width, 0);
1643 else if (c == 's') {
1644 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1646 else if (c == 'c') {
1647 send(action, arg);
1649 else
1650 BX_PANIC("bios_printf: unknown format\n");
1651 in_format = 0;
1654 else {
1655 send(action, c);
1657 s ++;
1660 if (action & BIOS_PRINTF_HALT) {
1661 // freeze in a busy loop.
1662 ASM_START
1663 cli
1664 halt2_loop:
1665 hlt
1666 jmp halt2_loop
1667 ASM_END
1671 //--------------------------------------------------------------------------
1672 // keyboard_init
1673 //--------------------------------------------------------------------------
1674 // this file is based on LinuxBIOS implementation of keyboard.c
1675 // could convert to #asm to gain space
1676 void
1677 keyboard_init()
1679 Bit16u max;
1681 /* ------------------- Flush buffers ------------------------*/
1682 /* Wait until buffer is empty */
1683 max=0xffff;
1684 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1686 /* flush incoming keys */
1687 max=0x2000;
1688 while (--max > 0) {
1689 outb(0x80, 0x00);
1690 if (inb(0x64) & 0x01) {
1691 inb(0x60);
1692 max = 0x2000;
1696 // Due to timer issues, and if the IPS setting is > 15000000,
1697 // the incoming keys might not be flushed here. That will
1698 // cause a panic a few lines below. See sourceforge bug report :
1699 // [ 642031 ] FATAL: Keyboard RESET error:993
1701 /* ------------------- controller side ----------------------*/
1702 /* send cmd = 0xAA, self test 8042 */
1703 outb(0x64, 0xaa);
1705 /* Wait until buffer is empty */
1706 max=0xffff;
1707 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1708 if (max==0x0) keyboard_panic(00);
1710 /* Wait for data */
1711 max=0xffff;
1712 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1713 if (max==0x0) keyboard_panic(01);
1715 /* read self-test result, 0x55 should be returned from 0x60 */
1716 if ((inb(0x60) != 0x55)){
1717 keyboard_panic(991);
1720 /* send cmd = 0xAB, keyboard interface test */
1721 outb(0x64,0xab);
1723 /* Wait until buffer is empty */
1724 max=0xffff;
1725 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1726 if (max==0x0) keyboard_panic(10);
1728 /* Wait for data */
1729 max=0xffff;
1730 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1731 if (max==0x0) keyboard_panic(11);
1733 /* read keyboard interface test result, */
1734 /* 0x00 should be returned form 0x60 */
1735 if ((inb(0x60) != 0x00)) {
1736 keyboard_panic(992);
1739 /* Enable Keyboard clock */
1740 outb(0x64,0xae);
1741 outb(0x64,0xa8);
1743 /* ------------------- keyboard side ------------------------*/
1744 /* reset kerboard and self test (keyboard side) */
1745 outb(0x60, 0xff);
1747 /* Wait until buffer is empty */
1748 max=0xffff;
1749 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1750 if (max==0x0) keyboard_panic(20);
1752 /* Wait for data */
1753 max=0xffff;
1754 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1755 if (max==0x0) keyboard_panic(21);
1757 /* keyboard should return ACK */
1758 if ((inb(0x60) != 0xfa)) {
1759 keyboard_panic(993);
1762 /* Wait for data */
1763 max=0xffff;
1764 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1765 if (max==0x0) keyboard_panic(31);
1767 if ((inb(0x60) != 0xaa)) {
1768 keyboard_panic(994);
1771 /* Disable keyboard */
1772 outb(0x60, 0xf5);
1774 /* Wait until buffer is empty */
1775 max=0xffff;
1776 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1777 if (max==0x0) keyboard_panic(40);
1779 /* Wait for data */
1780 max=0xffff;
1781 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1782 if (max==0x0) keyboard_panic(41);
1784 /* keyboard should return ACK */
1785 if ((inb(0x60) != 0xfa)) {
1786 keyboard_panic(995);
1789 /* Write Keyboard Mode */
1790 outb(0x64, 0x60);
1792 /* Wait until buffer is empty */
1793 max=0xffff;
1794 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1795 if (max==0x0) keyboard_panic(50);
1797 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1798 outb(0x60, 0x61);
1800 /* Wait until buffer is empty */
1801 max=0xffff;
1802 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1803 if (max==0x0) keyboard_panic(60);
1805 /* Enable keyboard */
1806 outb(0x60, 0xf4);
1808 /* Wait until buffer is empty */
1809 max=0xffff;
1810 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1811 if (max==0x0) keyboard_panic(70);
1813 /* Wait for data */
1814 max=0xffff;
1815 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1816 if (max==0x0) keyboard_panic(70);
1818 /* keyboard should return ACK */
1819 if ((inb(0x60) != 0xfa)) {
1820 keyboard_panic(996);
1823 outb(0x80, 0x77);
1826 //--------------------------------------------------------------------------
1827 // keyboard_panic
1828 //--------------------------------------------------------------------------
1829 void
1830 keyboard_panic(status)
1831 Bit16u status;
1833 // If you're getting a 993 keyboard panic here,
1834 // please see the comment in keyboard_init
1836 BX_PANIC("Keyboard error:%u\n",status);
1839 //--------------------------------------------------------------------------
1840 // shutdown_status_panic
1841 // called when the shutdown statsu is not implemented, displays the status
1842 //--------------------------------------------------------------------------
1843 void
1844 shutdown_status_panic(status)
1845 Bit16u status;
1847 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1850 //--------------------------------------------------------------------------
1851 // print_bios_banner
1852 // displays a the bios version
1853 //--------------------------------------------------------------------------
1854 void
1855 print_bios_banner()
1857 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1858 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1859 #if BX_TCGBIOS
1860 printf("TCG-enabled BIOS.\n");
1861 #endif
1862 printf("\n");
1863 test_gateway();
1867 //--------------------------------------------------------------------------
1868 // BIOS Boot Specification 1.0.1 compatibility
1869 //
1870 // Very basic support for the BIOS Boot Specification, which allows expansion
1871 // ROMs to register themselves as boot devices, instead of just stealing the
1872 // INT 19h boot vector.
1873 //
1874 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1875 // one; we just lie to the option ROMs to make them behave correctly.
1876 // We also don't support letting option ROMs register as bootable disk
1877 // drives (BCVs), only as bootable devices (BEVs).
1878 //
1879 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1880 //--------------------------------------------------------------------------
1882 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
1883 #define IPL_SEG 0x9ff0
1884 #define IPL_TABLE_OFFSET 0x0000
1885 #define IPL_TABLE_ENTRIES 8
1886 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
1887 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
1889 struct ipl_entry {
1890 Bit16u type;
1891 Bit16u flags;
1892 Bit32u vector;
1893 Bit32u description;
1894 Bit32u reserved;
1895 };
1897 static void
1898 init_boot_vectors()
1900 struct ipl_entry e;
1901 Bit16u count = 0;
1902 Bit16u ss = get_SS();
1904 /* Clear out the IPL table. */
1905 memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, 0xff);
1907 /* Floppy drive */
1908 e.type = 1; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1909 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1910 count++;
1912 /* First HDD */
1913 e.type = 2; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1914 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1915 count++;
1917 #if BX_ELTORITO_BOOT
1918 /* CDROM */
1919 e.type = 3; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1920 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1921 count++;
1922 #endif
1924 /* Remember how many devices we have */
1925 write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
1926 /* Not tried booting anything yet */
1927 write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
1930 static Bit8u
1931 get_boot_vector(i, e)
1932 Bit16u i; struct ipl_entry *e;
1934 Bit16u count;
1935 Bit16u ss = get_SS();
1936 /* Get the count of boot devices, and refuse to overrun the array */
1937 count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
1938 if (i >= count) return 0;
1939 /* OK to read this device */
1940 memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
1941 return 1;
1945 //--------------------------------------------------------------------------
1946 // print_boot_device
1947 // displays the boot device
1948 //--------------------------------------------------------------------------
1950 static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1952 void
1953 print_boot_device(type)
1954 Bit16u type;
1956 /* NIC appears as type 0x80 */
1957 if (type == 0x80 ) type = 0x4;
1958 if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
1959 printf("Booting from %s...\n", drivetypes[type]);
1962 //--------------------------------------------------------------------------
1963 // print_boot_failure
1964 // displays the reason why boot failed
1965 //--------------------------------------------------------------------------
1966 void
1967 print_boot_failure(type, reason)
1968 Bit16u type; Bit8u reason;
1970 if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
1972 printf("Boot from %s failed", drivetypes[type]);
1973 if (type < 4) {
1974 /* Report the reason too */
1975 if (reason==0)
1976 printf(": not a bootable disk");
1977 else
1978 printf(": could not read the boot disk");
1980 printf("\n");
1983 //--------------------------------------------------------------------------
1984 // print_cdromboot_failure
1985 // displays the reason why boot failed
1986 //--------------------------------------------------------------------------
1987 void
1988 print_cdromboot_failure( code )
1989 Bit16u code;
1991 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1993 return;
1996 void
1997 nmi_handler_msg()
1999 BX_PANIC("NMI Handler called\n");
2002 void
2003 int18_panic_msg()
2005 BX_PANIC("INT18: BOOT FAILURE\n");
2008 void
2009 log_bios_start()
2011 #if BX_DEBUG_SERIAL
2012 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2013 #endif
2014 BX_INFO("%s\n", bios_version_string);
2017 bx_bool
2018 set_enable_a20(val)
2019 bx_bool val;
2021 Bit8u oldval;
2023 // Use PS2 System Control port A to set A20 enable
2025 // get current setting first
2026 oldval = inb(0x92);
2028 // change A20 status
2029 if (val)
2030 outb(0x92, oldval | 0x02);
2031 else
2032 outb(0x92, oldval & 0xfd);
2034 return((oldval & 0x02) != 0);
2037 void
2038 debugger_on()
2040 outb(0xfedc, 0x01);
2043 void
2044 debugger_off()
2046 outb(0xfedc, 0x00);
2049 #if BX_USE_ATADRV
2051 // ---------------------------------------------------------------------------
2052 // Start of ATA/ATAPI Driver
2053 // ---------------------------------------------------------------------------
2055 // Global defines -- ATA register and register bits.
2056 // command block & control block regs
2057 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2058 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2059 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2060 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2061 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2062 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2063 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2064 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2065 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2066 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2067 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2068 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2069 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2071 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2072 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2073 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2074 #define ATA_CB_ER_MC 0x20 // ATA media change
2075 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2076 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2077 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2078 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2079 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2081 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2082 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2083 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2084 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2085 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2087 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2088 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2089 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2090 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2091 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2093 // bits 7-4 of the device/head (CB_DH) reg
2094 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2095 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2097 // status reg (CB_STAT and CB_ASTAT) bits
2098 #define ATA_CB_STAT_BSY 0x80 // busy
2099 #define ATA_CB_STAT_RDY 0x40 // ready
2100 #define ATA_CB_STAT_DF 0x20 // device fault
2101 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2102 #define ATA_CB_STAT_SKC 0x10 // seek complete
2103 #define ATA_CB_STAT_SERV 0x10 // service
2104 #define ATA_CB_STAT_DRQ 0x08 // data request
2105 #define ATA_CB_STAT_CORR 0x04 // corrected
2106 #define ATA_CB_STAT_IDX 0x02 // index
2107 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2108 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2110 // device control reg (CB_DC) bits
2111 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2112 #define ATA_CB_DC_SRST 0x04 // soft reset
2113 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2115 // Most mandtory and optional ATA commands (from ATA-3),
2116 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2117 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2118 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2119 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2120 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2121 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2122 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2123 #define ATA_CMD_DEVICE_RESET 0x08
2124 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2125 #define ATA_CMD_FLUSH_CACHE 0xE7
2126 #define ATA_CMD_FORMAT_TRACK 0x50
2127 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2128 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2129 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2130 #define ATA_CMD_IDLE1 0xE3
2131 #define ATA_CMD_IDLE2 0x97
2132 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2133 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2134 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2135 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2136 #define ATA_CMD_NOP 0x00
2137 #define ATA_CMD_PACKET 0xA0
2138 #define ATA_CMD_READ_BUFFER 0xE4
2139 #define ATA_CMD_READ_DMA 0xC8
2140 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2141 #define ATA_CMD_READ_MULTIPLE 0xC4
2142 #define ATA_CMD_READ_SECTORS 0x20
2143 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2144 #define ATA_CMD_RECALIBRATE 0x10
2145 #define ATA_CMD_SEEK 0x70
2146 #define ATA_CMD_SET_FEATURES 0xEF
2147 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2148 #define ATA_CMD_SLEEP1 0xE6
2149 #define ATA_CMD_SLEEP2 0x99
2150 #define ATA_CMD_STANDBY1 0xE2
2151 #define ATA_CMD_STANDBY2 0x96
2152 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2153 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2154 #define ATA_CMD_WRITE_BUFFER 0xE8
2155 #define ATA_CMD_WRITE_DMA 0xCA
2156 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2157 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2158 #define ATA_CMD_WRITE_SECTORS 0x30
2159 #define ATA_CMD_WRITE_VERIFY 0x3C
2161 #define ATA_IFACE_NONE 0x00
2162 #define ATA_IFACE_ISA 0x00
2163 #define ATA_IFACE_PCI 0x01
2165 #define ATA_TYPE_NONE 0x00
2166 #define ATA_TYPE_UNKNOWN 0x01
2167 #define ATA_TYPE_ATA 0x02
2168 #define ATA_TYPE_ATAPI 0x03
2170 #define ATA_DEVICE_NONE 0x00
2171 #define ATA_DEVICE_HD 0xFF
2172 #define ATA_DEVICE_CDROM 0x05
2174 #define ATA_MODE_NONE 0x00
2175 #define ATA_MODE_PIO16 0x00
2176 #define ATA_MODE_PIO32 0x01
2177 #define ATA_MODE_ISADMA 0x02
2178 #define ATA_MODE_PCIDMA 0x03
2179 #define ATA_MODE_USEIRQ 0x10
2181 #define ATA_TRANSLATION_NONE 0
2182 #define ATA_TRANSLATION_LBA 1
2183 #define ATA_TRANSLATION_LARGE 2
2184 #define ATA_TRANSLATION_RECHS 3
2186 #define ATA_DATA_NO 0x00
2187 #define ATA_DATA_IN 0x01
2188 #define ATA_DATA_OUT 0x02
2190 // ---------------------------------------------------------------------------
2191 // ATA/ATAPI driver : initialization
2192 // ---------------------------------------------------------------------------
2193 void ata_init( )
2195 Bit16u ebda_seg=read_word(0x0040,0x000E);
2196 Bit8u channel, device;
2198 // Channels info init.
2199 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2200 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2201 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2202 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2203 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2206 // Devices info init.
2207 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2208 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2209 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2210 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2211 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2212 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2213 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2214 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2215 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2216 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2217 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2218 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2219 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2220 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2222 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2225 // hdidmap and cdidmap init.
2226 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2227 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2228 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2231 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2232 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2235 // ---------------------------------------------------------------------------
2236 // ATA/ATAPI driver : device detection
2237 // ---------------------------------------------------------------------------
2239 void ata_detect( )
2241 Bit16u ebda_seg=read_word(0x0040,0x000E);
2242 Bit8u hdcount, cdcount, device, type;
2243 Bit8u buffer[0x0200];
2245 #if BX_MAX_ATA_INTERFACES > 0
2246 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2247 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2248 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2249 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2250 #endif
2251 #if BX_MAX_ATA_INTERFACES > 1
2252 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2253 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2254 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2255 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2256 #endif
2257 #if BX_MAX_ATA_INTERFACES > 2
2258 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2259 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2260 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2261 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2262 #endif
2263 #if BX_MAX_ATA_INTERFACES > 3
2264 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2265 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2266 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2267 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2268 #endif
2269 #if BX_MAX_ATA_INTERFACES > 4
2270 #error Please fill the ATA interface informations
2271 #endif
2273 // Device detection
2274 hdcount=cdcount=0;
2276 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2277 Bit16u iobase1, iobase2;
2278 Bit8u channel, slave, shift;
2279 Bit8u sc, sn, cl, ch, st;
2281 channel = device / 2;
2282 slave = device % 2;
2284 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2285 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2287 // Disable interrupts
2288 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2290 // Look for device
2291 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2292 outb(iobase1+ATA_CB_SC, 0x55);
2293 outb(iobase1+ATA_CB_SN, 0xaa);
2294 outb(iobase1+ATA_CB_SC, 0xaa);
2295 outb(iobase1+ATA_CB_SN, 0x55);
2296 outb(iobase1+ATA_CB_SC, 0x55);
2297 outb(iobase1+ATA_CB_SN, 0xaa);
2299 // If we found something
2300 sc = inb(iobase1+ATA_CB_SC);
2301 sn = inb(iobase1+ATA_CB_SN);
2303 if ( (sc == 0x55) && (sn == 0xaa) ) {
2304 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2306 // reset the channel
2307 ata_reset (device);
2309 // check for ATA or ATAPI
2310 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2311 sc = inb(iobase1+ATA_CB_SC);
2312 sn = inb(iobase1+ATA_CB_SN);
2313 if ( (sc==0x01) && (sn==0x01) ) {
2314 cl = inb(iobase1+ATA_CB_CL);
2315 ch = inb(iobase1+ATA_CB_CH);
2316 st = inb(iobase1+ATA_CB_STAT);
2318 if ( (cl==0x14) && (ch==0xeb) ) {
2319 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2321 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2322 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2327 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2329 // Now we send a IDENTIFY command to ATA device
2330 if(type == ATA_TYPE_ATA) {
2331 Bit32u sectors;
2332 Bit16u cylinders, heads, spt, blksize;
2333 Bit8u translation, removable, mode;
2335 // default mode to PIO16
2336 mode = ATA_MODE_PIO16;
2338 //Temporary values to do the transfer
2339 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2340 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2342 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2343 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2345 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2346 #ifndef NO_PIO32
2347 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2348 #endif
2350 blksize = read_word(get_SS(),buffer+10);
2352 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2353 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2354 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2356 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2358 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2359 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2360 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2361 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2362 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2363 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2364 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2365 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2366 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2368 translation = inb_cmos(0x39 + channel/2);
2369 for (shift=device%4; shift>0; shift--) translation >>= 2;
2370 translation &= 0x03;
2372 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2374 switch (translation) {
2375 case ATA_TRANSLATION_NONE:
2376 BX_INFO("none");
2377 break;
2378 case ATA_TRANSLATION_LBA:
2379 BX_INFO("lba");
2380 break;
2381 case ATA_TRANSLATION_LARGE:
2382 BX_INFO("large");
2383 break;
2384 case ATA_TRANSLATION_RECHS:
2385 BX_INFO("r-echs");
2386 break;
2388 switch (translation) {
2389 case ATA_TRANSLATION_NONE:
2390 break;
2391 case ATA_TRANSLATION_LBA:
2392 spt = 63;
2393 sectors /= 63;
2394 heads = sectors / 1024;
2395 if (heads>128) heads = 255;
2396 else if (heads>64) heads = 128;
2397 else if (heads>32) heads = 64;
2398 else if (heads>16) heads = 32;
2399 else heads=16;
2400 cylinders = sectors / heads;
2401 break;
2402 case ATA_TRANSLATION_RECHS:
2403 // Take care not to overflow
2404 if (heads==16) {
2405 if(cylinders>61439) cylinders=61439;
2406 heads=15;
2407 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2409 // then go through the large bitshift process
2410 case ATA_TRANSLATION_LARGE:
2411 while(cylinders > 1024) {
2412 cylinders >>= 1;
2413 heads <<= 1;
2415 // If we max out the head count
2416 if (heads > 127) break;
2418 break;
2420 // clip to 1024 cylinders in lchs
2421 if (cylinders > 1024) cylinders=1024;
2422 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2424 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2425 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2426 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2428 // fill hdidmap
2429 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2430 hdcount++;
2433 // Now we send a IDENTIFY command to ATAPI device
2434 if(type == ATA_TYPE_ATAPI) {
2436 Bit8u type, removable, mode;
2437 Bit16u blksize;
2439 // default mode to PIO16
2440 mode = ATA_MODE_PIO16;
2442 //Temporary values to do the transfer
2443 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2444 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2446 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2447 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2449 type = read_byte(get_SS(),buffer+1) & 0x1f;
2450 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2451 #ifndef NO_PIO32
2452 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2453 #endif
2454 blksize = 2048;
2456 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2457 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2458 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2459 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2461 // fill cdidmap
2462 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2463 cdcount++;
2467 Bit32u sizeinmb;
2468 Bit16u ataversion;
2469 Bit8u c, i, version, model[41];
2471 switch (type) {
2472 case ATA_TYPE_ATA:
2473 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2474 sizeinmb >>= 11;
2475 case ATA_TYPE_ATAPI:
2476 // Read ATA/ATAPI version
2477 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2478 for(version=15;version>0;version--) {
2479 if((ataversion&(1<<version))!=0)
2480 break;
2483 // Read model name
2484 for(i=0;i<20;i++){
2485 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2486 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2489 // Reformat
2490 write_byte(get_SS(),model+40,0x00);
2491 for(i=39;i>0;i--){
2492 if(read_byte(get_SS(),model+i)==0x20)
2493 write_byte(get_SS(),model+i,0x00);
2494 else break;
2496 break;
2499 switch (type) {
2500 case ATA_TYPE_ATA:
2501 printf("ata%d %s: ",channel,slave?" slave":"master");
2502 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2503 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2504 break;
2505 case ATA_TYPE_ATAPI:
2506 printf("ata%d %s: ",channel,slave?" slave":"master");
2507 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2508 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2509 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2510 else
2511 printf(" ATAPI-%d Device\n",version);
2512 break;
2513 case ATA_TYPE_UNKNOWN:
2514 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2515 break;
2520 // Store the devices counts
2521 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2522 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2523 write_byte(0x40,0x75, hdcount);
2525 printf("\n");
2527 // FIXME : should use bios=cmos|auto|disable bits
2528 // FIXME : should know about translation bits
2529 // FIXME : move hard_drive_post here
2533 // ---------------------------------------------------------------------------
2534 // ATA/ATAPI driver : software reset
2535 // ---------------------------------------------------------------------------
2536 // ATA-3
2537 // 8.2.1 Software reset - Device 0
2539 void ata_reset(device)
2540 Bit16u device;
2542 Bit16u ebda_seg=read_word(0x0040,0x000E);
2543 Bit16u iobase1, iobase2;
2544 Bit8u channel, slave, sn, sc;
2545 Bit16u max;
2547 channel = device / 2;
2548 slave = device % 2;
2550 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2551 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2553 // Reset
2555 // 8.2.1 (a) -- set SRST in DC
2556 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2558 // 8.2.1 (b) -- wait for BSY
2559 max=0xff;
2560 while(--max>0) {
2561 Bit8u status = inb(iobase1+ATA_CB_STAT);
2562 if ((status & ATA_CB_STAT_BSY) != 0) break;
2565 // 8.2.1 (f) -- clear SRST
2566 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2568 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2570 // 8.2.1 (g) -- check for sc==sn==0x01
2571 // select device
2572 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2573 sc = inb(iobase1+ATA_CB_SC);
2574 sn = inb(iobase1+ATA_CB_SN);
2576 if ( (sc==0x01) && (sn==0x01) ) {
2578 // 8.2.1 (h) -- wait for not BSY
2579 max=0xff;
2580 while(--max>0) {
2581 Bit8u status = inb(iobase1+ATA_CB_STAT);
2582 if ((status & ATA_CB_STAT_BSY) == 0) break;
2587 // 8.2.1 (i) -- wait for DRDY
2588 max=0xfff;
2589 while(--max>0) {
2590 Bit8u status = inb(iobase1+ATA_CB_STAT);
2591 if ((status & ATA_CB_STAT_RDY) != 0) break;
2594 // Enable interrupts
2595 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2598 // ---------------------------------------------------------------------------
2599 // ATA/ATAPI driver : execute a non data command
2600 // ---------------------------------------------------------------------------
2602 Bit16u ata_cmd_non_data()
2603 {return 0;}
2605 // ---------------------------------------------------------------------------
2606 // ATA/ATAPI driver : execute a data-in command
2607 // ---------------------------------------------------------------------------
2608 // returns
2609 // 0 : no error
2610 // 1 : BUSY bit set
2611 // 2 : read error
2612 // 3 : expected DRQ=1
2613 // 4 : no sectors left to read/verify
2614 // 5 : more sectors to read/verify
2615 // 6 : no sectors left to write
2616 // 7 : more sectors to write
2617 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2618 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2619 Bit32u lba;
2621 Bit16u ebda_seg=read_word(0x0040,0x000E);
2622 Bit16u iobase1, iobase2, blksize;
2623 Bit8u channel, slave;
2624 Bit8u status, current, mode;
2626 channel = device / 2;
2627 slave = device % 2;
2629 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2630 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2631 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2632 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2633 if (mode == ATA_MODE_PIO32) blksize>>=2;
2634 else blksize>>=1;
2636 // sector will be 0 only on lba access. Convert to lba-chs
2637 if (sector == 0) {
2638 sector = (Bit16u) (lba & 0x000000ffL);
2639 lba >>= 8;
2640 cylinder = (Bit16u) (lba & 0x0000ffffL);
2641 lba >>= 16;
2642 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2645 // Reset count of transferred data
2646 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2647 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2648 current = 0;
2650 status = inb(iobase1 + ATA_CB_STAT);
2651 if (status & ATA_CB_STAT_BSY) return 1;
2653 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2654 outb(iobase1 + ATA_CB_FR, 0x00);
2655 outb(iobase1 + ATA_CB_SC, count);
2656 outb(iobase1 + ATA_CB_SN, sector);
2657 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2658 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2659 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2660 outb(iobase1 + ATA_CB_CMD, command);
2662 while (1) {
2663 status = inb(iobase1 + ATA_CB_STAT);
2664 if ( !(status & ATA_CB_STAT_BSY) ) break;
2667 if (status & ATA_CB_STAT_ERR) {
2668 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2669 return 2;
2670 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2671 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2672 return 3;
2675 // FIXME : move seg/off translation here
2677 ASM_START
2678 sti ;; enable higher priority interrupts
2679 ASM_END
2681 while (1) {
2683 ASM_START
2684 push bp
2685 mov bp, sp
2686 mov di, _ata_cmd_data_in.offset + 2[bp]
2687 mov ax, _ata_cmd_data_in.segment + 2[bp]
2688 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2690 ;; adjust if there will be an overrun. 2K max sector size
2691 cmp di, #0xf800 ;;
2692 jbe ata_in_no_adjust
2694 ata_in_adjust:
2695 sub di, #0x0800 ;; sub 2 kbytes from offset
2696 add ax, #0x0080 ;; add 2 Kbytes to segment
2698 ata_in_no_adjust:
2699 mov es, ax ;; segment in es
2701 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2703 mov ah, _ata_cmd_data_in.mode + 2[bp]
2704 cmp ah, #ATA_MODE_PIO32
2705 je ata_in_32
2707 ata_in_16:
2708 rep
2709 insw ;; CX words transfered from port(DX) to ES:[DI]
2710 jmp ata_in_done
2712 ata_in_32:
2713 rep
2714 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2716 ata_in_done:
2717 mov _ata_cmd_data_in.offset + 2[bp], di
2718 mov _ata_cmd_data_in.segment + 2[bp], es
2719 pop bp
2720 ASM_END
2722 current++;
2723 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2724 count--;
2725 status = inb(iobase1 + ATA_CB_STAT);
2726 if (count == 0) {
2727 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2728 != ATA_CB_STAT_RDY ) {
2729 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2730 return 4;
2732 break;
2734 else {
2735 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2736 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2737 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2738 return 5;
2740 continue;
2743 // Enable interrupts
2744 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2745 return 0;
2748 // ---------------------------------------------------------------------------
2749 // ATA/ATAPI driver : execute a data-out command
2750 // ---------------------------------------------------------------------------
2751 // returns
2752 // 0 : no error
2753 // 1 : BUSY bit set
2754 // 2 : read error
2755 // 3 : expected DRQ=1
2756 // 4 : no sectors left to read/verify
2757 // 5 : more sectors to read/verify
2758 // 6 : no sectors left to write
2759 // 7 : more sectors to write
2760 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2761 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2762 Bit32u lba;
2764 Bit16u ebda_seg=read_word(0x0040,0x000E);
2765 Bit16u iobase1, iobase2, blksize;
2766 Bit8u channel, slave;
2767 Bit8u status, current, mode;
2769 channel = device / 2;
2770 slave = device % 2;
2772 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2773 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2774 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2775 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2776 if (mode == ATA_MODE_PIO32) blksize>>=2;
2777 else blksize>>=1;
2779 // sector will be 0 only on lba access. Convert to lba-chs
2780 if (sector == 0) {
2781 sector = (Bit16u) (lba & 0x000000ffL);
2782 lba >>= 8;
2783 cylinder = (Bit16u) (lba & 0x0000ffffL);
2784 lba >>= 16;
2785 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2788 // Reset count of transferred data
2789 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2790 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2791 current = 0;
2793 status = inb(iobase1 + ATA_CB_STAT);
2794 if (status & ATA_CB_STAT_BSY) return 1;
2796 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2797 outb(iobase1 + ATA_CB_FR, 0x00);
2798 outb(iobase1 + ATA_CB_SC, count);
2799 outb(iobase1 + ATA_CB_SN, sector);
2800 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2801 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2802 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2803 outb(iobase1 + ATA_CB_CMD, command);
2805 while (1) {
2806 status = inb(iobase1 + ATA_CB_STAT);
2807 if ( !(status & ATA_CB_STAT_BSY) ) break;
2810 if (status & ATA_CB_STAT_ERR) {
2811 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2812 return 2;
2813 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2814 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2815 return 3;
2818 // FIXME : move seg/off translation here
2820 ASM_START
2821 sti ;; enable higher priority interrupts
2822 ASM_END
2824 while (1) {
2826 ASM_START
2827 push bp
2828 mov bp, sp
2829 mov si, _ata_cmd_data_out.offset + 2[bp]
2830 mov ax, _ata_cmd_data_out.segment + 2[bp]
2831 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2833 ;; adjust if there will be an overrun. 2K max sector size
2834 cmp si, #0xf800 ;;
2835 jbe ata_out_no_adjust
2837 ata_out_adjust:
2838 sub si, #0x0800 ;; sub 2 kbytes from offset
2839 add ax, #0x0080 ;; add 2 Kbytes to segment
2841 ata_out_no_adjust:
2842 mov es, ax ;; segment in es
2844 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2846 mov ah, _ata_cmd_data_out.mode + 2[bp]
2847 cmp ah, #ATA_MODE_PIO32
2848 je ata_out_32
2850 ata_out_16:
2851 seg ES
2852 rep
2853 outsw ;; CX words transfered from port(DX) to ES:[SI]
2854 jmp ata_out_done
2856 ata_out_32:
2857 seg ES
2858 rep
2859 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2861 ata_out_done:
2862 mov _ata_cmd_data_out.offset + 2[bp], si
2863 mov _ata_cmd_data_out.segment + 2[bp], es
2864 pop bp
2865 ASM_END
2867 current++;
2868 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2869 count--;
2870 status = inb(iobase1 + ATA_CB_STAT);
2871 if (count == 0) {
2872 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2873 != ATA_CB_STAT_RDY ) {
2874 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2875 return 6;
2877 break;
2879 else {
2880 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2881 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2882 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2883 return 7;
2885 continue;
2888 // Enable interrupts
2889 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2890 return 0;
2893 // ---------------------------------------------------------------------------
2894 // ATA/ATAPI driver : execute a packet command
2895 // ---------------------------------------------------------------------------
2896 // returns
2897 // 0 : no error
2898 // 1 : error in parameters
2899 // 2 : BUSY bit set
2900 // 3 : error
2901 // 4 : not ready
2902 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2903 Bit8u cmdlen,inout;
2904 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2905 Bit16u header;
2906 Bit32u length;
2908 Bit16u ebda_seg=read_word(0x0040,0x000E);
2909 Bit16u iobase1, iobase2;
2910 Bit16u lcount, lbefore, lafter, count;
2911 Bit8u channel, slave;
2912 Bit8u status, mode, lmode;
2913 Bit32u total, transfer;
2915 channel = device / 2;
2916 slave = device % 2;
2918 // Data out is not supported yet
2919 if (inout == ATA_DATA_OUT) {
2920 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2921 return 1;
2924 // The header length must be even
2925 if (header & 1) {
2926 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2927 return 1;
2930 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2931 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2932 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2933 transfer= 0L;
2935 if (cmdlen < 12) cmdlen=12;
2936 if (cmdlen > 12) cmdlen=16;
2937 cmdlen>>=1;
2939 // Reset count of transferred data
2940 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2941 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2943 status = inb(iobase1 + ATA_CB_STAT);
2944 if (status & ATA_CB_STAT_BSY) return 2;
2946 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2947 // outb(iobase1 + ATA_CB_FR, 0x00);
2948 // outb(iobase1 + ATA_CB_SC, 0x00);
2949 // outb(iobase1 + ATA_CB_SN, 0x00);
2950 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2951 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2952 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2953 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2955 // Device should ok to receive command
2956 while (1) {
2957 status = inb(iobase1 + ATA_CB_STAT);
2958 if ( !(status & ATA_CB_STAT_BSY) ) break;
2961 if (status & ATA_CB_STAT_ERR) {
2962 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2963 return 3;
2964 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2965 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2966 return 4;
2969 // Normalize address
2970 cmdseg += (cmdoff / 16);
2971 cmdoff %= 16;
2973 // Send command to device
2974 ASM_START
2975 sti ;; enable higher priority interrupts
2977 push bp
2978 mov bp, sp
2980 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2981 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2982 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2983 mov es, ax ;; segment in es
2985 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2987 seg ES
2988 rep
2989 outsw ;; CX words transfered from port(DX) to ES:[SI]
2991 pop bp
2992 ASM_END
2994 if (inout == ATA_DATA_NO) {
2995 status = inb(iobase1 + ATA_CB_STAT);
2997 else {
2998 while (1) {
3000 status = inb(iobase1 + ATA_CB_STAT);
3002 // Check if command completed
3003 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3005 if (status & ATA_CB_STAT_ERR) {
3006 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3007 return 3;
3010 // Device must be ready to send data
3011 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3012 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3013 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3014 return 4;
3017 // Normalize address
3018 bufseg += (bufoff / 16);
3019 bufoff %= 16;
3021 // Get the byte count
3022 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3024 // adjust to read what we want
3025 if(header>lcount) {
3026 lbefore=lcount;
3027 header-=lcount;
3028 lcount=0;
3030 else {
3031 lbefore=header;
3032 header=0;
3033 lcount-=lbefore;
3036 if(lcount>length) {
3037 lafter=lcount-length;
3038 lcount=length;
3039 length=0;
3041 else {
3042 lafter=0;
3043 length-=lcount;
3046 // Save byte count
3047 count = lcount;
3049 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3050 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3052 // If counts not dividable by 4, use 16bits mode
3053 lmode = mode;
3054 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3055 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3056 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3058 // adds an extra byte if count are odd. before is always even
3059 if (lcount & 0x01) {
3060 lcount+=1;
3061 if ((lafter > 0) && (lafter & 0x01)) {
3062 lafter-=1;
3066 if (lmode == ATA_MODE_PIO32) {
3067 lcount>>=2; lbefore>>=2; lafter>>=2;
3069 else {
3070 lcount>>=1; lbefore>>=1; lafter>>=1;
3073 ; // FIXME bcc bug
3075 ASM_START
3076 push bp
3077 mov bp, sp
3079 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3081 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3082 jcxz ata_packet_no_before
3084 mov ah, _ata_cmd_packet.lmode + 2[bp]
3085 cmp ah, #ATA_MODE_PIO32
3086 je ata_packet_in_before_32
3088 ata_packet_in_before_16:
3089 in ax, dx
3090 loop ata_packet_in_before_16
3091 jmp ata_packet_no_before
3093 ata_packet_in_before_32:
3094 push eax
3095 ata_packet_in_before_32_loop:
3096 in eax, dx
3097 loop ata_packet_in_before_32_loop
3098 pop eax
3100 ata_packet_no_before:
3101 mov cx, _ata_cmd_packet.lcount + 2[bp]
3102 jcxz ata_packet_after
3104 mov di, _ata_cmd_packet.bufoff + 2[bp]
3105 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3106 mov es, ax
3108 mov ah, _ata_cmd_packet.lmode + 2[bp]
3109 cmp ah, #ATA_MODE_PIO32
3110 je ata_packet_in_32
3112 ata_packet_in_16:
3113 rep
3114 insw ;; CX words transfered tp port(DX) to ES:[DI]
3115 jmp ata_packet_after
3117 ata_packet_in_32:
3118 rep
3119 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3121 ata_packet_after:
3122 mov cx, _ata_cmd_packet.lafter + 2[bp]
3123 jcxz ata_packet_done
3125 mov ah, _ata_cmd_packet.lmode + 2[bp]
3126 cmp ah, #ATA_MODE_PIO32
3127 je ata_packet_in_after_32
3129 ata_packet_in_after_16:
3130 in ax, dx
3131 loop ata_packet_in_after_16
3132 jmp ata_packet_done
3134 ata_packet_in_after_32:
3135 push eax
3136 ata_packet_in_after_32_loop:
3137 in eax, dx
3138 loop ata_packet_in_after_32_loop
3139 pop eax
3141 ata_packet_done:
3142 pop bp
3143 ASM_END
3145 // Compute new buffer address
3146 bufoff += count;
3148 // Save transferred bytes count
3149 transfer += count;
3150 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3154 // Final check, device must be ready
3155 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3156 != ATA_CB_STAT_RDY ) {
3157 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3158 return 4;
3161 // Enable interrupts
3162 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3163 return 0;
3166 // ---------------------------------------------------------------------------
3167 // End of ATA/ATAPI Driver
3168 // ---------------------------------------------------------------------------
3170 // ---------------------------------------------------------------------------
3171 // Start of ATA/ATAPI generic functions
3172 // ---------------------------------------------------------------------------
3174 Bit16u
3175 atapi_get_sense(device)
3176 Bit16u device;
3178 Bit8u atacmd[12];
3179 Bit8u buffer[16];
3180 Bit8u i;
3182 memsetb(get_SS(),atacmd,0,12);
3184 // Request SENSE
3185 atacmd[0]=0x03;
3186 atacmd[4]=0x20;
3187 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3188 return 0x0002;
3190 if ((buffer[0] & 0x7e) == 0x70) {
3191 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3194 return 0;
3197 Bit16u
3198 atapi_is_ready(device)
3199 Bit16u device;
3201 Bit8u atacmd[12];
3202 Bit8u buffer[];
3204 memsetb(get_SS(),atacmd,0,12);
3206 // Test Unit Ready
3207 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3208 return 0x000f;
3210 if (atapi_get_sense(device) !=0 ) {
3211 memsetb(get_SS(),atacmd,0,12);
3213 // try to send Test Unit Ready again
3214 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3215 return 0x000f;
3217 return atapi_get_sense(device);
3219 return 0;
3222 Bit16u
3223 atapi_is_cdrom(device)
3224 Bit8u device;
3226 Bit16u ebda_seg=read_word(0x0040,0x000E);
3228 if (device >= BX_MAX_ATA_DEVICES)
3229 return 0;
3231 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3232 return 0;
3234 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3235 return 0;
3237 return 1;
3240 // ---------------------------------------------------------------------------
3241 // End of ATA/ATAPI generic functions
3242 // ---------------------------------------------------------------------------
3244 #endif // BX_USE_ATADRV
3246 #if BX_ELTORITO_BOOT
3248 // ---------------------------------------------------------------------------
3249 // Start of El-Torito boot functions
3250 // ---------------------------------------------------------------------------
3252 void
3253 cdemu_init()
3255 Bit16u ebda_seg=read_word(0x0040,0x000E);
3257 // the only important data is this one for now
3258 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3261 Bit8u
3262 cdemu_isactive()
3264 Bit16u ebda_seg=read_word(0x0040,0x000E);
3266 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3269 Bit8u
3270 cdemu_emulated_drive()
3272 Bit16u ebda_seg=read_word(0x0040,0x000E);
3274 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3277 static char isotag[6]="CD001";
3278 static char eltorito[24]="EL TORITO SPECIFICATION";
3279 //
3280 // Returns ah: emulated drive, al: error code
3281 //
3282 Bit16u
3283 cdrom_boot()
3285 Bit16u ebda_seg=read_word(0x0040,0x000E);
3286 Bit8u atacmd[12], buffer[2048];
3287 Bit32u lba;
3288 Bit16u boot_segment, nbsectors, i, error;
3289 Bit8u device;
3291 // Find out the first cdrom
3292 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3293 if (atapi_is_cdrom(device)) break;
3296 // if not found
3297 if(device >= BX_MAX_ATA_DEVICES) return 2;
3299 // Read the Boot Record Volume Descriptor
3300 memsetb(get_SS(),atacmd,0,12);
3301 atacmd[0]=0x28; // READ command
3302 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3303 atacmd[8]=(0x01 & 0x00ff); // Sectors
3304 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3305 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3306 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3307 atacmd[5]=(0x11 & 0x000000ff);
3308 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3309 return 3;
3311 // Validity checks
3312 if(buffer[0]!=0)return 4;
3313 for(i=0;i<5;i++){
3314 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3316 for(i=0;i<23;i++)
3317 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3319 // ok, now we calculate the Boot catalog address
3320 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3322 // And we read the Boot Catalog
3323 memsetb(get_SS(),atacmd,0,12);
3324 atacmd[0]=0x28; // READ command
3325 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3326 atacmd[8]=(0x01 & 0x00ff); // Sectors
3327 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3328 atacmd[3]=(lba & 0x00ff0000) >> 16;
3329 atacmd[4]=(lba & 0x0000ff00) >> 8;
3330 atacmd[5]=(lba & 0x000000ff);
3331 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3332 return 7;
3334 // Validation entry
3335 if(buffer[0x00]!=0x01)return 8; // Header
3336 if(buffer[0x01]!=0x00)return 9; // Platform
3337 if(buffer[0x1E]!=0x55)return 10; // key 1
3338 if(buffer[0x1F]!=0xAA)return 10; // key 2
3340 // Initial/Default Entry
3341 if(buffer[0x20]!=0x88)return 11; // Bootable
3343 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3344 if(buffer[0x21]==0){
3345 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3346 // Win2000 cd boot needs to know it booted from cd
3347 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3349 else if(buffer[0x21]<4)
3350 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3351 else
3352 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3354 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3355 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3357 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3358 if(boot_segment==0x0000)boot_segment=0x07C0;
3360 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3361 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3363 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3364 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3366 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3367 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3369 // And we read the image in memory
3370 memsetb(get_SS(),atacmd,0,12);
3371 atacmd[0]=0x28; // READ command
3372 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3373 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3374 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3375 atacmd[3]=(lba & 0x00ff0000) >> 16;
3376 atacmd[4]=(lba & 0x0000ff00) >> 8;
3377 atacmd[5]=(lba & 0x000000ff);
3378 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3379 return 12;
3381 // Remember the media type
3382 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3383 case 0x01: // 1.2M floppy
3384 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3385 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3386 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3387 break;
3388 case 0x02: // 1.44M floppy
3389 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3390 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3391 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3392 break;
3393 case 0x03: // 2.88M floppy
3394 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3395 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3396 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3397 break;
3398 case 0x04: // Harddrive
3399 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3400 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3401 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3402 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3403 break;
3406 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3407 // Increase bios installed hardware number of devices
3408 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3409 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3410 else
3411 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3415 // everything is ok, so from now on, the emulation is active
3416 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3417 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3419 // return the boot drive + no error
3420 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3423 // ---------------------------------------------------------------------------
3424 // End of El-Torito boot functions
3425 // ---------------------------------------------------------------------------
3426 #endif // BX_ELTORITO_BOOT
3428 void
3429 int14_function(regs, ds, iret_addr)
3430 pusha_regs_t regs; // regs pushed from PUSHA instruction
3431 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3432 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3434 Bit16u addr,timer,val16;
3435 Bit8u timeout;
3437 ASM_START
3438 sti
3439 ASM_END
3441 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3442 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3443 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3444 switch (regs.u.r8.ah) {
3445 case 0:
3446 outb(addr+3, inb(addr+3) | 0x80);
3447 if (regs.u.r8.al & 0xE0 == 0) {
3448 outb(addr, 0x17);
3449 outb(addr+1, 0x04);
3450 } else {
3451 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3452 outb(addr, val16 & 0xFF);
3453 outb(addr+1, val16 >> 8);
3455 outb(addr+3, regs.u.r8.al & 0x1F);
3456 regs.u.r8.ah = inb(addr+5);
3457 regs.u.r8.al = inb(addr+6);
3458 ClearCF(iret_addr.flags);
3459 break;
3460 case 1:
3461 timer = read_word(0x0040, 0x006C);
3462 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3463 val16 = read_word(0x0040, 0x006C);
3464 if (val16 != timer) {
3465 timer = val16;
3466 timeout--;
3469 if (timeout) outb(addr, regs.u.r8.al);
3470 regs.u.r8.ah = inb(addr+5);
3471 if (!timeout) regs.u.r8.ah |= 0x80;
3472 ClearCF(iret_addr.flags);
3473 break;
3474 case 2:
3475 timer = read_word(0x0040, 0x006C);
3476 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3477 val16 = read_word(0x0040, 0x006C);
3478 if (val16 != timer) {
3479 timer = val16;
3480 timeout--;
3483 if (timeout) {
3484 regs.u.r8.ah = 0;
3485 regs.u.r8.al = inb(addr);
3486 } else {
3487 regs.u.r8.ah = inb(addr+5);
3489 ClearCF(iret_addr.flags);
3490 break;
3491 case 3:
3492 regs.u.r8.ah = inb(addr+5);
3493 regs.u.r8.al = inb(addr+6);
3494 ClearCF(iret_addr.flags);
3495 break;
3496 default:
3497 SetCF(iret_addr.flags); // Unsupported
3499 } else {
3500 SetCF(iret_addr.flags); // Unsupported
3504 void
3505 int15_function(regs, ES, DS, FLAGS)
3506 pusha_regs_t regs; // REGS pushed via pusha
3507 Bit16u ES, DS, FLAGS;
3509 Bit16u ebda_seg=read_word(0x0040,0x000E);
3510 bx_bool prev_a20_enable;
3511 Bit16u base15_00;
3512 Bit8u base23_16;
3513 Bit16u ss;
3514 Bit16u CX,DX;
3516 Bit16u bRegister;
3517 Bit8u irqDisable;
3519 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3521 switch (regs.u.r8.ah) {
3522 case 0x24: /* A20 Control */
3523 switch (regs.u.r8.al) {
3524 case 0x00:
3525 set_enable_a20(0);
3526 CLEAR_CF();
3527 regs.u.r8.ah = 0;
3528 break;
3529 case 0x01:
3530 set_enable_a20(1);
3531 CLEAR_CF();
3532 regs.u.r8.ah = 0;
3533 break;
3534 case 0x02:
3535 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3536 CLEAR_CF();
3537 regs.u.r8.ah = 0;
3538 break;
3539 case 0x03:
3540 CLEAR_CF();
3541 regs.u.r8.ah = 0;
3542 regs.u.r16.bx = 3;
3543 break;
3544 default:
3545 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3546 SET_CF();
3547 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3549 break;
3551 case 0x41:
3552 SET_CF();
3553 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3554 break;
3556 case 0x4f:
3557 /* keyboard intercept */
3558 #if BX_CPU < 2
3559 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3560 #else
3561 // nop
3562 #endif
3563 SET_CF();
3564 break;
3566 case 0x52: // removable media eject
3567 CLEAR_CF();
3568 regs.u.r8.ah = 0; // "ok ejection may proceed"
3569 break;
3571 case 0x83: {
3572 if( regs.u.r8.al == 0 ) {
3573 // Set Interval requested.
3574 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3575 // Interval not already set.
3576 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3577 write_word( 0x40, 0x98, ES ); // Byte location, segment
3578 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3579 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3580 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3581 CLEAR_CF( );
3582 irqDisable = inb( 0xA1 );
3583 outb( 0xA1, irqDisable & 0xFE );
3584 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3585 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3586 } else {
3587 // Interval already set.
3588 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3589 SET_CF();
3590 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3592 } else if( regs.u.r8.al == 1 ) {
3593 // Clear Interval requested
3594 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3595 CLEAR_CF( );
3596 bRegister = inb_cmos( 0xB );
3597 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3598 } else {
3599 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3600 SET_CF();
3601 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3602 regs.u.r8.al--;
3605 break;
3608 case 0x87:
3609 #if BX_CPU < 3
3610 # error "Int15 function 87h not supported on < 80386"
3611 #endif
3612 // +++ should probably have descriptor checks
3613 // +++ should have exception handlers
3615 // turn off interrupts
3616 ASM_START
3617 cli
3618 ASM_END
3620 prev_a20_enable = set_enable_a20(1); // enable A20 line
3622 // 128K max of transfer on 386+ ???
3623 // source == destination ???
3625 // ES:SI points to descriptor table
3626 // offset use initially comments
3627 // ==============================================
3628 // 00..07 Unused zeros Null descriptor
3629 // 08..0f GDT zeros filled in by BIOS
3630 // 10..17 source ssssssss source of data
3631 // 18..1f dest dddddddd destination of data
3632 // 20..27 CS zeros filled in by BIOS
3633 // 28..2f SS zeros filled in by BIOS
3635 //es:si
3636 //eeee0
3637 //0ssss
3638 //-----
3640 // check for access rights of source & dest here
3642 // Initialize GDT descriptor
3643 base15_00 = (ES << 4) + regs.u.r16.si;
3644 base23_16 = ES >> 12;
3645 if (base15_00 < (ES<<4))
3646 base23_16++;
3647 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3648 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3649 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3650 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3651 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3653 // Initialize CS descriptor
3654 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3655 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3656 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3657 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3658 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3660 // Initialize SS descriptor
3661 ss = get_SS();
3662 base15_00 = ss << 4;
3663 base23_16 = ss >> 12;
3664 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3665 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3666 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3667 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3668 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3670 CX = regs.u.r16.cx;
3671 ASM_START
3672 // Compile generates locals offset info relative to SP.
3673 // Get CX (word count) from stack.
3674 mov bx, sp
3675 SEG SS
3676 mov cx, _int15_function.CX [bx]
3678 // since we need to set SS:SP, save them to the BDA
3679 // for future restore
3680 push eax
3681 xor eax, eax
3682 mov ds, ax
3683 mov 0x0469, ss
3684 mov 0x0467, sp
3686 SEG ES
3687 lgdt [si + 0x08]
3688 SEG CS
3689 lidt [pmode_IDT_info]
3690 ;; perhaps do something with IDT here
3692 ;; set PE bit in CR0
3693 mov eax, cr0
3694 or al, #0x01
3695 mov cr0, eax
3696 ;; far jump to flush CPU queue after transition to protected mode
3697 JMP_AP(0x0020, protected_mode)
3699 protected_mode:
3700 ;; GDT points to valid descriptor table, now load SS, DS, ES
3701 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3702 mov ss, ax
3703 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3704 mov ds, ax
3705 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3706 mov es, ax
3707 xor si, si
3708 xor di, di
3709 cld
3710 rep
3711 movsw ;; move CX words from DS:SI to ES:DI
3713 ;; make sure DS and ES limits are 64KB
3714 mov ax, #0x28
3715 mov ds, ax
3716 mov es, ax
3718 ;; reset PG bit in CR0 ???
3719 mov eax, cr0
3720 and al, #0xFE
3721 mov cr0, eax
3723 ;; far jump to flush CPU queue after transition to real mode
3724 JMP_AP(0xf000, real_mode)
3726 real_mode:
3727 ;; restore IDT to normal real-mode defaults
3728 SEG CS
3729 lidt [rmode_IDT_info]
3731 // restore SS:SP from the BDA
3732 xor ax, ax
3733 mov ds, ax
3734 mov ss, 0x0469
3735 mov sp, 0x0467
3736 pop eax
3737 ASM_END
3739 set_enable_a20(prev_a20_enable);
3741 // turn back on interrupts
3742 ASM_START
3743 sti
3744 ASM_END
3746 regs.u.r8.ah = 0;
3747 CLEAR_CF();
3748 break;
3751 case 0x88:
3752 // Get the amount of extended memory (above 1M)
3753 #if BX_CPU < 2
3754 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3755 SET_CF();
3756 #else
3757 regs.u.r8.al = inb_cmos(0x30);
3758 regs.u.r8.ah = inb_cmos(0x31);
3760 // limit to 15M
3761 if(regs.u.r16.ax > 0x3c00)
3762 regs.u.r16.ax = 0x3c00;
3764 CLEAR_CF();
3765 #endif
3766 break;
3768 case 0x90:
3769 /* Device busy interrupt. Called by Int 16h when no key available */
3770 break;
3772 case 0x91:
3773 /* Interrupt complete. Called by Int 16h when key becomes available */
3774 break;
3776 case 0xbf:
3777 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3778 SET_CF();
3779 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3780 break;
3782 case 0xC0:
3783 #if 0
3784 SET_CF();
3785 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3786 break;
3787 #endif
3788 CLEAR_CF();
3789 regs.u.r8.ah = 0;
3790 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3791 ES = 0xF000;
3792 break;
3794 case 0xc1:
3795 ES = ebda_seg;
3796 CLEAR_CF();
3797 break;
3799 case 0xd8:
3800 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3801 SET_CF();
3802 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3803 break;
3805 default:
3806 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3807 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3808 SET_CF();
3809 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3810 break;
3814 #if BX_USE_PS2_MOUSE
3815 void
3816 int15_function_mouse(regs, ES, DS, FLAGS)
3817 pusha_regs_t regs; // REGS pushed via pusha
3818 Bit16u ES, DS, FLAGS;
3820 Bit16u ebda_seg=read_word(0x0040,0x000E);
3821 Bit8u mouse_flags_1, mouse_flags_2;
3822 Bit16u mouse_driver_seg;
3823 Bit16u mouse_driver_offset;
3824 Bit8u comm_byte, prev_command_byte;
3825 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3827 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3829 switch (regs.u.r8.ah) {
3830 case 0xC2:
3831 // Return Codes status in AH
3832 // =========================
3833 // 00: success
3834 // 01: invalid subfunction (AL > 7)
3835 // 02: invalid input value (out of allowable range)
3836 // 03: interface error
3837 // 04: resend command received from mouse controller,
3838 // device driver should attempt command again
3839 // 05: cannot enable mouse, since no far call has been installed
3840 // 80/86: mouse service not implemented
3842 switch (regs.u.r8.al) {
3843 case 0: // Disable/Enable Mouse
3844 BX_DEBUG_INT15("case 0:\n");
3845 switch (regs.u.r8.bh) {
3846 case 0: // Disable Mouse
3847 BX_DEBUG_INT15("case 0: disable mouse\n");
3848 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3849 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3850 if (ret == 0) {
3851 ret = get_mouse_data(&mouse_data1);
3852 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3853 CLEAR_CF();
3854 regs.u.r8.ah = 0;
3855 return;
3859 // error
3860 SET_CF();
3861 regs.u.r8.ah = ret;
3862 return;
3863 break;
3865 case 1: // Enable Mouse
3866 BX_DEBUG_INT15("case 1: enable mouse\n");
3867 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3868 if ( (mouse_flags_2 & 0x80) == 0 ) {
3869 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3870 SET_CF(); // error
3871 regs.u.r8.ah = 5; // no far call installed
3872 return;
3874 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3875 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3876 if (ret == 0) {
3877 ret = get_mouse_data(&mouse_data1);
3878 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3879 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3880 CLEAR_CF();
3881 regs.u.r8.ah = 0;
3882 return;
3885 SET_CF();
3886 regs.u.r8.ah = ret;
3887 return;
3889 default: // invalid subfunction
3890 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3891 SET_CF(); // error
3892 regs.u.r8.ah = 1; // invalid subfunction
3893 return;
3895 break;
3897 case 1: // Reset Mouse
3898 case 5: // Initialize Mouse
3899 BX_DEBUG_INT15("case 1 or 5:\n");
3900 if (regs.u.r8.al == 5) {
3901 if (regs.u.r8.bh != 3) {
3902 SET_CF();
3903 regs.u.r8.ah = 0x02; // invalid input
3904 return;
3906 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3907 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3908 mouse_flags_1 = 0x00;
3909 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3910 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3913 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3914 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3915 if (ret == 0) {
3916 ret = get_mouse_data(&mouse_data3);
3917 // if no mouse attached, it will return RESEND
3918 if (mouse_data3 == 0xfe) {
3919 SET_CF();
3920 return;
3922 if (mouse_data3 != 0xfa)
3923 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3924 if ( ret == 0 ) {
3925 ret = get_mouse_data(&mouse_data1);
3926 if ( ret == 0 ) {
3927 ret = get_mouse_data(&mouse_data2);
3928 if ( ret == 0 ) {
3929 // turn IRQ12 and packet generation on
3930 enable_mouse_int_and_events();
3931 CLEAR_CF();
3932 regs.u.r8.ah = 0;
3933 regs.u.r8.bl = mouse_data1;
3934 regs.u.r8.bh = mouse_data2;
3935 return;
3941 // error
3942 SET_CF();
3943 regs.u.r8.ah = ret;
3944 return;
3946 case 2: // Set Sample Rate
3947 BX_DEBUG_INT15("case 2:\n");
3948 switch (regs.u.r8.bh) {
3949 case 0: mouse_data1 = 10; break; // 10 reports/sec
3950 case 1: mouse_data1 = 20; break; // 20 reports/sec
3951 case 2: mouse_data1 = 40; break; // 40 reports/sec
3952 case 3: mouse_data1 = 60; break; // 60 reports/sec
3953 case 4: mouse_data1 = 80; break; // 80 reports/sec
3954 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3955 case 6: mouse_data1 = 200; break; // 200 reports/sec
3956 default: mouse_data1 = 0;
3958 if (mouse_data1 > 0) {
3959 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3960 if (ret == 0) {
3961 ret = get_mouse_data(&mouse_data2);
3962 ret = send_to_mouse_ctrl(mouse_data1);
3963 ret = get_mouse_data(&mouse_data2);
3964 CLEAR_CF();
3965 regs.u.r8.ah = 0;
3966 } else {
3967 // error
3968 SET_CF();
3969 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3971 } else {
3972 // error
3973 SET_CF();
3974 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3976 break;
3978 case 3: // Set Resolution
3979 BX_DEBUG_INT15("case 3:\n");
3980 // BX:
3981 // 0 = 25 dpi, 1 count per millimeter
3982 // 1 = 50 dpi, 2 counts per millimeter
3983 // 2 = 100 dpi, 4 counts per millimeter
3984 // 3 = 200 dpi, 8 counts per millimeter
3985 CLEAR_CF();
3986 regs.u.r8.ah = 0;
3987 break;
3989 case 4: // Get Device ID
3990 BX_DEBUG_INT15("case 4:\n");
3991 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3992 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3993 if (ret == 0) {
3994 ret = get_mouse_data(&mouse_data1);
3995 ret = get_mouse_data(&mouse_data2);
3996 CLEAR_CF();
3997 regs.u.r8.ah = 0;
3998 regs.u.r8.bh = mouse_data2;
3999 } else {
4000 // error
4001 SET_CF();
4002 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4004 break;
4006 case 6: // Return Status & Set Scaling Factor...
4007 BX_DEBUG_INT15("case 6:\n");
4008 switch (regs.u.r8.bh) {
4009 case 0: // Return Status
4010 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4011 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4012 if (ret == 0) {
4013 ret = get_mouse_data(&mouse_data1);
4014 if (mouse_data1 != 0xfa)
4015 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4016 if (ret == 0) {
4017 ret = get_mouse_data(&mouse_data1);
4018 if ( ret == 0 ) {
4019 ret = get_mouse_data(&mouse_data2);
4020 if ( ret == 0 ) {
4021 ret = get_mouse_data(&mouse_data3);
4022 if ( ret == 0 ) {
4023 CLEAR_CF();
4024 regs.u.r8.ah = 0;
4025 regs.u.r8.bl = mouse_data1;
4026 regs.u.r8.cl = mouse_data2;
4027 regs.u.r8.dl = mouse_data3;
4028 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4029 return;
4036 // error
4037 SET_CF();
4038 regs.u.r8.ah = ret;
4039 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4040 return;
4042 case 1: // Set Scaling Factor to 1:1
4043 case 2: // Set Scaling Factor to 2:1
4044 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4045 if (regs.u.r8.bh == 1) {
4046 ret = send_to_mouse_ctrl(0xE6);
4047 } else {
4048 ret = send_to_mouse_ctrl(0xE7);
4050 if (ret == 0) {
4051 get_mouse_data(&mouse_data1);
4052 ret = (mouse_data1 != 0xFA);
4054 if (ret == 0) {
4055 CLEAR_CF();
4056 regs.u.r8.ah = 0;
4057 } else {
4058 // error
4059 SET_CF();
4060 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4062 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4063 break;
4065 default:
4066 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4068 break;
4070 case 7: // Set Mouse Handler Address
4071 BX_DEBUG_INT15("case 7:\n");
4072 mouse_driver_seg = ES;
4073 mouse_driver_offset = regs.u.r16.bx;
4074 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4075 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4076 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4077 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4078 /* remove handler */
4079 if ( (mouse_flags_2 & 0x80) != 0 ) {
4080 mouse_flags_2 &= ~0x80;
4081 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4084 else {
4085 /* install handler */
4086 mouse_flags_2 |= 0x80;
4088 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4089 CLEAR_CF();
4090 regs.u.r8.ah = 0;
4091 break;
4093 default:
4094 BX_DEBUG_INT15("case default:\n");
4095 regs.u.r8.ah = 1; // invalid function
4096 SET_CF();
4098 break;
4100 default:
4101 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4102 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4103 SET_CF();
4104 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4105 break;
4108 #endif
4110 void
4111 int15_function32(regs, ES, DS, FLAGS)
4112 pushad_regs_t regs; // REGS pushed via pushad
4113 Bit16u ES, DS, FLAGS;
4115 Bit32u extended_memory_size=0; // 64bits long
4116 Bit16u CX,DX;
4118 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4120 switch (regs.u.r8.ah) {
4121 case 0x86:
4122 // Wait for CX:DX microseconds. currently using the
4123 // refresh request port 0x61 bit4, toggling every 15usec
4125 CX = regs.u.r16.cx;
4126 DX = regs.u.r16.dx;
4128 ASM_START
4129 sti
4131 ;; Get the count in eax
4132 mov bx, sp
4133 SEG SS
4134 mov ax, _int15_function.CX [bx]
4135 shl eax, #16
4136 SEG SS
4137 mov ax, _int15_function.DX [bx]
4139 ;; convert to numbers of 15usec ticks
4140 mov ebx, #15
4141 xor edx, edx
4142 div eax, ebx
4143 mov ecx, eax
4145 ;; wait for ecx number of refresh requests
4146 in al, #0x61
4147 and al,#0x10
4148 mov ah, al
4150 or ecx, ecx
4151 je int1586_tick_end
4152 int1586_tick:
4153 in al, #0x61
4154 and al,#0x10
4155 cmp al, ah
4156 je int1586_tick
4157 mov ah, al
4158 dec ecx
4159 jnz int1586_tick
4160 int1586_tick_end:
4161 ASM_END
4163 break;
4165 case 0xe8:
4166 switch(regs.u.r8.al)
4168 case 0x20: // coded by osmaker aka K.J.
4169 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4171 #ifdef HVMASSIST
4172 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4173 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4175 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4176 memcpyb(ES, regs.u.r16.di,
4177 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4179 regs.u.r32.ebx += 0x14;
4180 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4181 regs.u.r32.ebx = 0;
4182 regs.u.r32.eax = 0x534D4150;
4183 regs.u.r32.ecx = 0x14;
4184 CLEAR_CF();
4185 return;
4186 } else if (regs.u.r16.bx == 1) {
4187 extended_memory_size = inb_cmos(0x35);
4188 extended_memory_size <<= 8;
4189 extended_memory_size |= inb_cmos(0x34);
4190 extended_memory_size *= 64;
4191 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4193 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4195 extended_memory_size *= 1024;
4196 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4198 if (extended_memory_size <= 15728640)
4200 extended_memory_size = inb_cmos(0x31);
4201 extended_memory_size <<= 8;
4202 extended_memory_size |= inb_cmos(0x30);
4203 extended_memory_size *= 1024;
4206 write_word(ES, regs.u.r16.di, 0x0000);
4207 write_word(ES, regs.u.r16.di+2, 0x0010);
4208 write_word(ES, regs.u.r16.di+4, 0x0000);
4209 write_word(ES, regs.u.r16.di+6, 0x0000);
4211 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4212 extended_memory_size >>= 16;
4213 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4214 extended_memory_size >>= 16;
4215 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4216 extended_memory_size >>= 16;
4217 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4219 write_word(ES, regs.u.r16.di+16, 0x1);
4220 write_word(ES, regs.u.r16.di+18, 0x0);
4222 regs.u.r32.ebx = 0;
4223 regs.u.r32.eax = 0x534D4150;
4224 regs.u.r32.ecx = 0x14;
4225 CLEAR_CF();
4226 return;
4227 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4228 goto int15_unimplemented;
4230 #else
4231 switch(regs.u.r16.bx)
4233 case 0:
4234 write_word(ES, regs.u.r16.di, 0x00);
4235 write_word(ES, regs.u.r16.di+2, 0x00);
4236 write_word(ES, regs.u.r16.di+4, 0x00);
4237 write_word(ES, regs.u.r16.di+6, 0x00);
4239 write_word(ES, regs.u.r16.di+8, 0xFC00);
4240 write_word(ES, regs.u.r16.di+10, 0x0009);
4241 write_word(ES, regs.u.r16.di+12, 0x0000);
4242 write_word(ES, regs.u.r16.di+14, 0x0000);
4244 write_word(ES, regs.u.r16.di+16, 0x1);
4245 write_word(ES, regs.u.r16.di+18, 0x0);
4247 regs.u.r32.ebx = 1;
4249 regs.u.r32.eax = 0x534D4150;
4250 regs.u.r32.ecx = 0x14;
4251 CLEAR_CF();
4252 return;
4253 break;
4254 case 1:
4255 extended_memory_size = inb_cmos(0x35);
4256 extended_memory_size <<= 8;
4257 extended_memory_size |= inb_cmos(0x34);
4258 extended_memory_size *= 64;
4259 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4261 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4263 extended_memory_size *= 1024;
4264 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4266 if(extended_memory_size <= 15728640)
4268 extended_memory_size = inb_cmos(0x31);
4269 extended_memory_size <<= 8;
4270 extended_memory_size |= inb_cmos(0x30);
4271 extended_memory_size *= 1024;
4274 write_word(ES, regs.u.r16.di, 0x0000);
4275 write_word(ES, regs.u.r16.di+2, 0x0010);
4276 write_word(ES, regs.u.r16.di+4, 0x0000);
4277 write_word(ES, regs.u.r16.di+6, 0x0000);
4279 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4280 extended_memory_size >>= 16;
4281 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4282 extended_memory_size >>= 16;
4283 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4284 extended_memory_size >>= 16;
4285 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4287 write_word(ES, regs.u.r16.di+16, 0x1);
4288 write_word(ES, regs.u.r16.di+18, 0x0);
4290 regs.u.r32.ebx = 0;
4291 regs.u.r32.eax = 0x534D4150;
4292 regs.u.r32.ecx = 0x14;
4293 CLEAR_CF();
4294 return;
4295 break;
4296 default: /* AX=E820, DX=534D4150, BX unrecognized */
4297 goto int15_unimplemented;
4298 break;
4300 #endif
4301 } else {
4302 // if DX != 0x534D4150)
4303 goto int15_unimplemented;
4305 break;
4307 case 0x01:
4308 // do we have any reason to fail here ?
4309 CLEAR_CF();
4311 // my real system sets ax and bx to 0
4312 // this is confirmed by Ralph Brown list
4313 // but syslinux v1.48 is known to behave
4314 // strangely if ax is set to 0
4315 // regs.u.r16.ax = 0;
4316 // regs.u.r16.bx = 0;
4318 // Get the amount of extended memory (above 1M)
4319 regs.u.r8.cl = inb_cmos(0x30);
4320 regs.u.r8.ch = inb_cmos(0x31);
4322 // limit to 15M
4323 if(regs.u.r16.cx > 0x3c00)
4325 regs.u.r16.cx = 0x3c00;
4328 // Get the amount of extended memory above 16M in 64k blocs
4329 regs.u.r8.dl = inb_cmos(0x34);
4330 regs.u.r8.dh = inb_cmos(0x35);
4332 // Set configured memory equal to extended memory
4333 regs.u.r16.ax = regs.u.r16.cx;
4334 regs.u.r16.bx = regs.u.r16.dx;
4335 break;
4336 default: /* AH=0xE8?? but not implemented */
4337 goto int15_unimplemented;
4339 break;
4340 int15_unimplemented:
4341 // fall into the default
4342 default:
4343 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4344 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4345 SET_CF();
4346 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4347 break;
4351 void
4352 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4353 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4355 Bit8u scan_code, ascii_code, shift_flags, count;
4356 Bit16u kbd_code, max;
4358 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4360 switch (GET_AH()) {
4361 case 0x00: /* read keyboard input */
4363 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4364 BX_PANIC("KBD: int16h: out of keyboard input\n");
4366 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4367 else if (ascii_code == 0xE0) ascii_code = 0;
4368 AX = (scan_code << 8) | ascii_code;
4369 break;
4371 case 0x01: /* check keyboard status */
4372 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4373 SET_ZF();
4374 return;
4376 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4377 else if (ascii_code == 0xE0) ascii_code = 0;
4378 AX = (scan_code << 8) | ascii_code;
4379 CLEAR_ZF();
4380 break;
4382 case 0x02: /* get shift flag status */
4383 shift_flags = read_byte(0x0040, 0x17);
4384 SET_AL(shift_flags);
4385 break;
4387 case 0x05: /* store key-stroke into buffer */
4388 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4389 SET_AL(1);
4391 else {
4392 SET_AL(0);
4394 break;
4396 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4397 // bit Bochs Description
4398 // 7 0 reserved
4399 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4400 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4401 // 4 1 INT 16/AH=0Ah supported
4402 // 3 0 INT 16/AX=0306h supported
4403 // 2 0 INT 16/AX=0305h supported
4404 // 1 0 INT 16/AX=0304h supported
4405 // 0 0 INT 16/AX=0300h supported
4406 //
4407 SET_AL(0x30);
4408 break;
4410 case 0x0A: /* GET KEYBOARD ID */
4411 count = 2;
4412 kbd_code = 0x0;
4413 outb(0x60, 0xf2);
4414 /* Wait for data */
4415 max=0xffff;
4416 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4417 if (max>0x0) {
4418 if ((inb(0x60) == 0xfa)) {
4419 do {
4420 max=0xffff;
4421 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4422 if (max>0x0) {
4423 kbd_code >>= 8;
4424 kbd_code |= (inb(0x60) << 8);
4426 } while (--count>0);
4429 BX=kbd_code;
4430 break;
4432 case 0x10: /* read MF-II keyboard input */
4434 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4435 BX_PANIC("KBD: int16h: out of keyboard input\n");
4437 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4438 AX = (scan_code << 8) | ascii_code;
4439 break;
4441 case 0x11: /* check MF-II keyboard status */
4442 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4443 SET_ZF();
4444 return;
4446 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4447 AX = (scan_code << 8) | ascii_code;
4448 CLEAR_ZF();
4449 break;
4451 case 0x12: /* get extended keyboard status */
4452 shift_flags = read_byte(0x0040, 0x17);
4453 SET_AL(shift_flags);
4454 shift_flags = read_byte(0x0040, 0x18);
4455 SET_AH(shift_flags);
4456 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4457 break;
4459 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4460 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4461 break;
4463 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4464 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4465 break;
4467 case 0x6F:
4468 if (GET_AL() == 0x08)
4469 SET_AH(0x02); // unsupported, aka normal keyboard
4471 default:
4472 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4476 unsigned int
4477 dequeue_key(scan_code, ascii_code, incr)
4478 Bit8u *scan_code;
4479 Bit8u *ascii_code;
4480 unsigned int incr;
4482 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4483 Bit16u ss;
4484 Bit8u acode, scode;
4486 #if BX_CPU < 2
4487 buffer_start = 0x001E;
4488 buffer_end = 0x003E;
4489 #else
4490 buffer_start = read_word(0x0040, 0x0080);
4491 buffer_end = read_word(0x0040, 0x0082);
4492 #endif
4494 buffer_head = read_word(0x0040, 0x001a);
4495 buffer_tail = read_word(0x0040, 0x001c);
4497 if (buffer_head != buffer_tail) {
4498 ss = get_SS();
4499 acode = read_byte(0x0040, buffer_head);
4500 scode = read_byte(0x0040, buffer_head+1);
4501 write_byte(ss, ascii_code, acode);
4502 write_byte(ss, scan_code, scode);
4504 if (incr) {
4505 buffer_head += 2;
4506 if (buffer_head >= buffer_end)
4507 buffer_head = buffer_start;
4508 write_word(0x0040, 0x001a, buffer_head);
4510 return(1);
4512 else {
4513 return(0);
4517 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4519 Bit8u
4520 inhibit_mouse_int_and_events()
4522 Bit8u command_byte, prev_command_byte;
4524 // Turn off IRQ generation and aux data line
4525 if ( inb(0x64) & 0x02 )
4526 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4527 outb(0x64, 0x20); // get command byte
4528 while ( (inb(0x64) & 0x01) != 0x01 );
4529 prev_command_byte = inb(0x60);
4530 command_byte = prev_command_byte;
4531 //while ( (inb(0x64) & 0x02) );
4532 if ( inb(0x64) & 0x02 )
4533 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4534 command_byte &= 0xfd; // turn off IRQ 12 generation
4535 command_byte |= 0x20; // disable mouse serial clock line
4536 outb(0x64, 0x60); // write command byte
4537 outb(0x60, command_byte);
4538 return(prev_command_byte);
4541 void
4542 enable_mouse_int_and_events()
4544 Bit8u command_byte;
4546 // Turn on IRQ generation and aux data line
4547 if ( inb(0x64) & 0x02 )
4548 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4549 outb(0x64, 0x20); // get command byte
4550 while ( (inb(0x64) & 0x01) != 0x01 );
4551 command_byte = inb(0x60);
4552 //while ( (inb(0x64) & 0x02) );
4553 if ( inb(0x64) & 0x02 )
4554 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4555 command_byte |= 0x02; // turn on IRQ 12 generation
4556 command_byte &= 0xdf; // enable mouse serial clock line
4557 outb(0x64, 0x60); // write command byte
4558 outb(0x60, command_byte);
4561 Bit8u
4562 send_to_mouse_ctrl(sendbyte)
4563 Bit8u sendbyte;
4565 Bit8u response;
4567 // wait for chance to write to ctrl
4568 if ( inb(0x64) & 0x02 )
4569 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4570 outb(0x64, 0xD4);
4571 outb(0x60, sendbyte);
4572 return(0);
4576 Bit8u
4577 get_mouse_data(data)
4578 Bit8u *data;
4580 Bit8u response;
4581 Bit16u ss;
4583 while ( (inb(0x64) & 0x21) != 0x21 ) {
4586 response = inb(0x60);
4588 ss = get_SS();
4589 write_byte(ss, data, response);
4590 return(0);
4593 void
4594 set_kbd_command_byte(command_byte)
4595 Bit8u command_byte;
4597 if ( inb(0x64) & 0x02 )
4598 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4599 outb(0x64, 0xD4);
4601 outb(0x64, 0x60); // write command byte
4602 outb(0x60, command_byte);
4605 void
4606 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4607 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4609 Bit8u scancode, asciicode, shift_flags;
4610 Bit8u mf2_flags, mf2_state, led_flags;
4612 //
4613 // DS has been set to F000 before call
4614 //
4617 scancode = GET_AL();
4619 if (scancode == 0) {
4620 BX_INFO("KBD: int09 handler: AL=0\n");
4621 return;
4625 shift_flags = read_byte(0x0040, 0x17);
4626 mf2_flags = read_byte(0x0040, 0x18);
4627 mf2_state = read_byte(0x0040, 0x96);
4628 led_flags = read_byte(0x0040, 0x97);
4629 asciicode = 0;
4631 switch (scancode) {
4632 case 0x3a: /* Caps Lock press */
4633 shift_flags ^= 0x40;
4634 write_byte(0x0040, 0x17, shift_flags);
4635 mf2_flags |= 0x40;
4636 write_byte(0x0040, 0x18, mf2_flags);
4637 led_flags ^= 0x04;
4638 write_byte(0x0040, 0x97, led_flags);
4639 break;
4640 case 0xba: /* Caps Lock release */
4641 mf2_flags &= ~0x40;
4642 write_byte(0x0040, 0x18, mf2_flags);
4643 break;
4645 case 0x2a: /* L Shift press */
4646 /*shift_flags &= ~0x40;*/
4647 shift_flags |= 0x02;
4648 write_byte(0x0040, 0x17, shift_flags);
4649 led_flags &= ~0x04;
4650 write_byte(0x0040, 0x97, led_flags);
4651 break;
4652 case 0xaa: /* L Shift release */
4653 shift_flags &= ~0x02;
4654 write_byte(0x0040, 0x17, shift_flags);
4655 break;
4657 case 0x36: /* R Shift press */
4658 /*shift_flags &= ~0x40;*/
4659 shift_flags |= 0x01;
4660 write_byte(0x0040, 0x17, shift_flags);
4661 led_flags &= ~0x04;
4662 write_byte(0x0040, 0x97, led_flags);
4663 break;
4664 case 0xb6: /* R Shift release */
4665 shift_flags &= ~0x01;
4666 write_byte(0x0040, 0x17, shift_flags);
4667 break;
4669 case 0x1d: /* Ctrl press */
4670 shift_flags |= 0x04;
4671 write_byte(0x0040, 0x17, shift_flags);
4672 if (mf2_state & 0x01) {
4673 mf2_flags |= 0x04;
4674 } else {
4675 mf2_flags |= 0x01;
4677 write_byte(0x0040, 0x18, mf2_flags);
4678 break;
4679 case 0x9d: /* Ctrl release */
4680 shift_flags &= ~0x04;
4681 write_byte(0x0040, 0x17, shift_flags);
4682 if (mf2_state & 0x01) {
4683 mf2_flags &= ~0x04;
4684 } else {
4685 mf2_flags &= ~0x01;
4687 write_byte(0x0040, 0x18, mf2_flags);
4688 break;
4690 case 0x38: /* Alt press */
4691 shift_flags |= 0x08;
4692 write_byte(0x0040, 0x17, shift_flags);
4693 if (mf2_state & 0x01) {
4694 mf2_flags |= 0x08;
4695 } else {
4696 mf2_flags |= 0x02;
4698 write_byte(0x0040, 0x18, mf2_flags);
4699 break;
4700 case 0xb8: /* Alt release */
4701 shift_flags &= ~0x08;
4702 write_byte(0x0040, 0x17, shift_flags);
4703 if (mf2_state & 0x01) {
4704 mf2_flags &= ~0x08;
4705 } else {
4706 mf2_flags &= ~0x02;
4708 write_byte(0x0040, 0x18, mf2_flags);
4709 break;
4711 case 0x45: /* Num Lock press */
4712 if ((mf2_state & 0x01) == 0) {
4713 mf2_flags |= 0x20;
4714 write_byte(0x0040, 0x18, mf2_flags);
4715 shift_flags ^= 0x20;
4716 led_flags ^= 0x02;
4717 write_byte(0x0040, 0x17, shift_flags);
4718 write_byte(0x0040, 0x97, led_flags);
4720 break;
4721 case 0xc5: /* Num Lock release */
4722 if ((mf2_state & 0x01) == 0) {
4723 mf2_flags &= ~0x20;
4724 write_byte(0x0040, 0x18, mf2_flags);
4726 break;
4728 case 0x46: /* Scroll Lock press */
4729 mf2_flags |= 0x10;
4730 write_byte(0x0040, 0x18, mf2_flags);
4731 shift_flags ^= 0x10;
4732 led_flags ^= 0x01;
4733 write_byte(0x0040, 0x17, shift_flags);
4734 write_byte(0x0040, 0x97, led_flags);
4735 break;
4737 case 0xc6: /* Scroll Lock release */
4738 mf2_flags &= ~0x10;
4739 write_byte(0x0040, 0x18, mf2_flags);
4740 break;
4742 default:
4743 if (scancode & 0x80) return; /* toss key releases ... */
4744 if (scancode > MAX_SCAN_CODE) {
4745 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4746 return;
4748 if (shift_flags & 0x08) { /* ALT */
4749 asciicode = scan_to_scanascii[scancode].alt;
4750 scancode = scan_to_scanascii[scancode].alt >> 8;
4752 else if (shift_flags & 0x04) { /* CONTROL */
4753 asciicode = scan_to_scanascii[scancode].control;
4754 scancode = scan_to_scanascii[scancode].control >> 8;
4756 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4757 /* check if lock state should be ignored
4758 * because a SHIFT key are pressed */
4760 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4761 asciicode = scan_to_scanascii[scancode].normal;
4762 scancode = scan_to_scanascii[scancode].normal >> 8;
4764 else {
4765 asciicode = scan_to_scanascii[scancode].shift;
4766 scancode = scan_to_scanascii[scancode].shift >> 8;
4769 else {
4770 /* check if lock is on */
4771 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4772 asciicode = scan_to_scanascii[scancode].shift;
4773 scancode = scan_to_scanascii[scancode].shift >> 8;
4775 else {
4776 asciicode = scan_to_scanascii[scancode].normal;
4777 scancode = scan_to_scanascii[scancode].normal >> 8;
4780 if (scancode==0 && asciicode==0) {
4781 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4783 enqueue_key(scancode, asciicode);
4784 break;
4786 mf2_state &= ~0x01;
4789 unsigned int
4790 enqueue_key(scan_code, ascii_code)
4791 Bit8u scan_code, ascii_code;
4793 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4795 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4796 // scan_code, ascii_code);
4798 #if BX_CPU < 2
4799 buffer_start = 0x001E;
4800 buffer_end = 0x003E;
4801 #else
4802 buffer_start = read_word(0x0040, 0x0080);
4803 buffer_end = read_word(0x0040, 0x0082);
4804 #endif
4806 buffer_head = read_word(0x0040, 0x001A);
4807 buffer_tail = read_word(0x0040, 0x001C);
4809 temp_tail = buffer_tail;
4810 buffer_tail += 2;
4811 if (buffer_tail >= buffer_end)
4812 buffer_tail = buffer_start;
4814 if (buffer_tail == buffer_head) {
4815 return(0);
4818 write_byte(0x0040, temp_tail, ascii_code);
4819 write_byte(0x0040, temp_tail+1, scan_code);
4820 write_word(0x0040, 0x001C, buffer_tail);
4821 return(1);
4825 void
4826 int74_function(make_farcall, Z, Y, X, status)
4827 Bit16u make_farcall, Z, Y, X, status;
4829 Bit16u ebda_seg=read_word(0x0040,0x000E);
4830 Bit8u in_byte, index, package_count;
4831 Bit8u mouse_flags_1, mouse_flags_2;
4833 BX_DEBUG_INT74("entering int74_function\n");
4834 make_farcall = 0;
4836 in_byte = inb(0x64);
4837 if ( (in_byte & 0x21) != 0x21 ) {
4838 return;
4840 in_byte = inb(0x60);
4841 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4843 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4844 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4846 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4847 // BX_PANIC("int74_function:\n");
4848 return;
4851 package_count = mouse_flags_2 & 0x07;
4852 index = mouse_flags_1 & 0x07;
4853 write_byte(ebda_seg, 0x28 + index, in_byte);
4855 if ( (index+1) >= package_count ) {
4856 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4857 status = read_byte(ebda_seg, 0x0028 + 0);
4858 X = read_byte(ebda_seg, 0x0028 + 1);
4859 Y = read_byte(ebda_seg, 0x0028 + 2);
4860 Z = 0;
4861 mouse_flags_1 = 0;
4862 // check if far call handler installed
4863 if (mouse_flags_2 & 0x80)
4864 make_farcall = 1;
4866 else {
4867 mouse_flags_1++;
4869 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4872 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4874 #if BX_USE_ATADRV
4876 void
4877 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4878 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4880 Bit32u lba;
4881 Bit16u ebda_seg=read_word(0x0040,0x000E);
4882 Bit16u cylinder, head, sector;
4883 Bit16u segment, offset;
4884 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4885 Bit16u size, count;
4886 Bit8u device, status;
4888 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4890 write_byte(0x0040, 0x008e, 0); // clear completion flag
4892 // basic check : device has to be defined
4893 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4894 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4895 goto int13_fail;
4898 // Get the ata channel
4899 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4901 // basic check : device has to be valid
4902 if (device >= BX_MAX_ATA_DEVICES) {
4903 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4904 goto int13_fail;
4907 switch (GET_AH()) {
4909 case 0x00: /* disk controller reset */
4910 ata_reset (device);
4911 goto int13_success;
4912 break;
4914 case 0x01: /* read disk status */
4915 status = read_byte(0x0040, 0x0074);
4916 SET_AH(status);
4917 SET_DISK_RET_STATUS(0);
4918 /* set CF if error status read */
4919 if (status) goto int13_fail_nostatus;
4920 else goto int13_success_noah;
4921 break;
4923 case 0x02: // read disk sectors
4924 case 0x03: // write disk sectors
4925 case 0x04: // verify disk sectors
4927 count = GET_AL();
4928 cylinder = GET_CH();
4929 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4930 sector = (GET_CL() & 0x3f);
4931 head = GET_DH();
4933 segment = ES;
4934 offset = BX;
4936 if ( (count > 128) || (count == 0) ) {
4937 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4938 goto int13_fail;
4941 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4942 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4943 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4945 // sanity check on cyl heads, sec
4946 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4947 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4948 goto int13_fail;
4951 // FIXME verify
4952 if ( GET_AH() == 0x04 ) goto int13_success;
4954 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4955 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4957 // if needed, translate lchs to lba, and execute command
4958 if ( (nph != nlh) || (npspt != nlspt)) {
4959 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4960 sector = 0; // this forces the command to be lba
4963 if ( GET_AH() == 0x02 )
4964 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4965 else
4966 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4968 // Set nb of sector transferred
4969 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4971 if (status != 0) {
4972 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4973 SET_AH(0x0c);
4974 goto int13_fail_noah;
4977 goto int13_success;
4978 break;
4980 case 0x05: /* format disk track */
4981 BX_INFO("format disk track called\n");
4982 goto int13_success;
4983 return;
4984 break;
4986 case 0x08: /* read disk drive parameters */
4988 // Get logical geometry from table
4989 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4990 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4991 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4992 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4994 nlc = nlc - 2; /* 0 based , last sector not used */
4995 SET_AL(0);
4996 SET_CH(nlc & 0xff);
4997 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4998 SET_DH(nlh - 1);
4999 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5001 // FIXME should set ES & DI
5003 goto int13_success;
5004 break;
5006 case 0x10: /* check drive ready */
5007 // should look at 40:8E also???
5009 // Read the status from controller
5010 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5011 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5012 goto int13_success;
5014 else {
5015 SET_AH(0xAA);
5016 goto int13_fail_noah;
5018 break;
5020 case 0x15: /* read disk drive size */
5022 // Get physical geometry from table
5023 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5024 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5025 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5027 // Compute sector count seen by int13
5028 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5029 CX = lba >> 16;
5030 DX = lba & 0xffff;
5032 SET_AH(3); // hard disk accessible
5033 goto int13_success_noah;
5034 break;
5036 case 0x41: // IBM/MS installation check
5037 BX=0xaa55; // install check
5038 SET_AH(0x30); // EDD 3.0
5039 CX=0x0007; // ext disk access and edd, removable supported
5040 goto int13_success_noah;
5041 break;
5043 case 0x42: // IBM/MS extended read
5044 case 0x43: // IBM/MS extended write
5045 case 0x44: // IBM/MS verify
5046 case 0x47: // IBM/MS extended seek
5048 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5049 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5050 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5052 // Can't use 64 bits lba
5053 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5054 if (lba != 0L) {
5055 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5056 goto int13_fail;
5059 // Get 32 bits lba and check
5060 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5061 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5062 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5063 goto int13_fail;
5066 // If verify or seek
5067 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5068 goto int13_success;
5070 // Execute the command
5071 if ( GET_AH() == 0x42 )
5072 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5073 else
5074 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5076 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5077 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5079 if (status != 0) {
5080 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5081 SET_AH(0x0c);
5082 goto int13_fail_noah;
5085 goto int13_success;
5086 break;
5088 case 0x45: // IBM/MS lock/unlock drive
5089 case 0x49: // IBM/MS extended media change
5090 goto int13_success; // Always success for HD
5091 break;
5093 case 0x46: // IBM/MS eject media
5094 SET_AH(0xb2); // Volume Not Removable
5095 goto int13_fail_noah; // Always fail for HD
5096 break;
5098 case 0x48: // IBM/MS get drive parameters
5099 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5101 // Buffer is too small
5102 if(size < 0x1a)
5103 goto int13_fail;
5105 // EDD 1.x
5106 if(size >= 0x1a) {
5107 Bit16u blksize;
5109 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5110 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5111 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5112 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5113 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5115 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5116 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5117 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5118 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5119 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5120 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5121 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5122 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5125 // EDD 2.x
5126 if(size >= 0x1e) {
5127 Bit8u channel, dev, irq, mode, checksum, i, translation;
5128 Bit16u iobase1, iobase2, options;
5130 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5132 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5133 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5135 // Fill in dpte
5136 channel = device / 2;
5137 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5138 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5139 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5140 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5141 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5143 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5144 options |= (1<<4); // lba translation
5145 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5146 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5147 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5149 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5150 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5151 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5152 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5153 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5154 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5155 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5156 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5157 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5158 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5159 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5161 checksum=0;
5162 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5163 checksum = ~checksum;
5164 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5167 // EDD 3.x
5168 if(size >= 0x42) {
5169 Bit8u channel, iface, checksum, i;
5170 Bit16u iobase1;
5172 channel = device / 2;
5173 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5174 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5176 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5177 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5178 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5179 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5180 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5182 if (iface==ATA_IFACE_ISA) {
5183 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5184 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5185 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5186 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5188 else {
5189 // FIXME PCI
5191 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5192 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5193 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5194 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5196 if (iface==ATA_IFACE_ISA) {
5197 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5198 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5199 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5201 else {
5202 // FIXME PCI
5204 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5205 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5206 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5207 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5209 checksum=0;
5210 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5211 checksum = ~checksum;
5212 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5215 goto int13_success;
5216 break;
5218 case 0x4e: // // IBM/MS set hardware configuration
5219 // DMA, prefetch, PIO maximum not supported
5220 switch (GET_AL()) {
5221 case 0x01:
5222 case 0x03:
5223 case 0x04:
5224 case 0x06:
5225 goto int13_success;
5226 break;
5227 default :
5228 goto int13_fail;
5230 break;
5232 case 0x09: /* initialize drive parameters */
5233 case 0x0c: /* seek to specified cylinder */
5234 case 0x0d: /* alternate disk reset */
5235 case 0x11: /* recalibrate */
5236 case 0x14: /* controller internal diagnostic */
5237 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5238 goto int13_success;
5239 break;
5241 case 0x0a: /* read disk sectors with ECC */
5242 case 0x0b: /* write disk sectors with ECC */
5243 case 0x18: // set media type for format
5244 case 0x50: // IBM/MS send packet command
5245 default:
5246 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5247 goto int13_fail;
5248 break;
5251 int13_fail:
5252 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5253 int13_fail_noah:
5254 SET_DISK_RET_STATUS(GET_AH());
5255 int13_fail_nostatus:
5256 SET_CF(); // error occurred
5257 return;
5259 int13_success:
5260 SET_AH(0x00); // no error
5261 int13_success_noah:
5262 SET_DISK_RET_STATUS(0x00);
5263 CLEAR_CF(); // no error
5264 return;
5267 // ---------------------------------------------------------------------------
5268 // Start of int13 for cdrom
5269 // ---------------------------------------------------------------------------
5271 void
5272 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5273 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5275 Bit16u ebda_seg=read_word(0x0040,0x000E);
5276 Bit8u device, status, locks;
5277 Bit8u atacmd[12];
5278 Bit32u lba;
5279 Bit16u count, segment, offset, i, size;
5281 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5282 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5284 SET_DISK_RET_STATUS(0x00);
5286 /* basic check : device should be 0xE0+ */
5287 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5288 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5289 goto int13_fail;
5292 // Get the ata channel
5293 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5295 /* basic check : device has to be valid */
5296 if (device >= BX_MAX_ATA_DEVICES) {
5297 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5298 goto int13_fail;
5301 switch (GET_AH()) {
5303 // all those functions return SUCCESS
5304 case 0x00: /* disk controller reset */
5305 case 0x09: /* initialize drive parameters */
5306 case 0x0c: /* seek to specified cylinder */
5307 case 0x0d: /* alternate disk reset */
5308 case 0x10: /* check drive ready */
5309 case 0x11: /* recalibrate */
5310 case 0x14: /* controller internal diagnostic */
5311 case 0x16: /* detect disk change */
5312 goto int13_success;
5313 break;
5315 // all those functions return disk write-protected
5316 case 0x03: /* write disk sectors */
5317 case 0x05: /* format disk track */
5318 case 0x43: // IBM/MS extended write
5319 SET_AH(0x03);
5320 goto int13_fail_noah;
5321 break;
5323 case 0x01: /* read disk status */
5324 status = read_byte(0x0040, 0x0074);
5325 SET_AH(status);
5326 SET_DISK_RET_STATUS(0);
5328 /* set CF if error status read */
5329 if (status) goto int13_fail_nostatus;
5330 else goto int13_success_noah;
5331 break;
5333 case 0x15: /* read disk drive size */
5334 SET_AH(0x02);
5335 goto int13_fail_noah;
5336 break;
5338 case 0x41: // IBM/MS installation check
5339 BX=0xaa55; // install check
5340 SET_AH(0x30); // EDD 2.1
5341 CX=0x0007; // ext disk access, removable and edd
5342 goto int13_success_noah;
5343 break;
5345 case 0x42: // IBM/MS extended read
5346 case 0x44: // IBM/MS verify sectors
5347 case 0x47: // IBM/MS extended seek
5349 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5350 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5351 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5353 // Can't use 64 bits lba
5354 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5355 if (lba != 0L) {
5356 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5357 goto int13_fail;
5360 // Get 32 bits lba
5361 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5363 // If verify or seek
5364 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5365 goto int13_success;
5367 memsetb(get_SS(),atacmd,0,12);
5368 atacmd[0]=0x28; // READ command
5369 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5370 atacmd[8]=(count & 0x00ff); // Sectors
5371 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5372 atacmd[3]=(lba & 0x00ff0000) >> 16;
5373 atacmd[4]=(lba & 0x0000ff00) >> 8;
5374 atacmd[5]=(lba & 0x000000ff);
5375 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5377 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5378 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5380 if (status != 0) {
5381 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5382 SET_AH(0x0c);
5383 goto int13_fail_noah;
5386 goto int13_success;
5387 break;
5389 case 0x45: // IBM/MS lock/unlock drive
5390 if (GET_AL() > 2) goto int13_fail;
5392 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5394 switch (GET_AL()) {
5395 case 0 : // lock
5396 if (locks == 0xff) {
5397 SET_AH(0xb4);
5398 SET_AL(1);
5399 goto int13_fail_noah;
5401 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5402 SET_AL(1);
5403 break;
5404 case 1 : // unlock
5405 if (locks == 0x00) {
5406 SET_AH(0xb0);
5407 SET_AL(0);
5408 goto int13_fail_noah;
5410 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5411 SET_AL(locks==0?0:1);
5412 break;
5413 case 2 : // status
5414 SET_AL(locks==0?0:1);
5415 break;
5417 goto int13_success;
5418 break;
5420 case 0x46: // IBM/MS eject media
5421 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5423 if (locks != 0) {
5424 SET_AH(0xb1); // media locked
5425 goto int13_fail_noah;
5427 // FIXME should handle 0x31 no media in device
5428 // FIXME should handle 0xb5 valid request failed
5430 // Call removable media eject
5431 ASM_START
5432 push bp
5433 mov bp, sp
5435 mov ah, #0x52
5436 int 15
5437 mov _int13_cdrom.status + 2[bp], ah
5438 jnc int13_cdrom_rme_end
5439 mov _int13_cdrom.status, #1
5440 int13_cdrom_rme_end:
5441 pop bp
5442 ASM_END
5444 if (status != 0) {
5445 SET_AH(0xb1); // media locked
5446 goto int13_fail_noah;
5449 goto int13_success;
5450 break;
5452 case 0x48: // IBM/MS get drive parameters
5453 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5455 // Buffer is too small
5456 if(size < 0x1a)
5457 goto int13_fail;
5459 // EDD 1.x
5460 if(size >= 0x1a) {
5461 Bit16u cylinders, heads, spt, blksize;
5463 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5465 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5466 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5467 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5468 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5469 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5470 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5471 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5472 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5475 // EDD 2.x
5476 if(size >= 0x1e) {
5477 Bit8u channel, dev, irq, mode, checksum, i;
5478 Bit16u iobase1, iobase2, options;
5480 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5482 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5483 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5485 // Fill in dpte
5486 channel = device / 2;
5487 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5488 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5489 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5490 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5492 // FIXME atapi device
5493 options = (1<<4); // lba translation
5494 options |= (1<<5); // removable device
5495 options |= (1<<6); // atapi device
5496 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5498 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5499 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5500 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5501 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5502 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5503 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5504 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5505 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5506 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5507 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5508 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5510 checksum=0;
5511 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5512 checksum = ~checksum;
5513 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5516 // EDD 3.x
5517 if(size >= 0x42) {
5518 Bit8u channel, iface, checksum, i;
5519 Bit16u iobase1;
5521 channel = device / 2;
5522 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5523 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5525 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5526 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5527 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5528 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5529 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5531 if (iface==ATA_IFACE_ISA) {
5532 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5533 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5534 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5535 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5537 else {
5538 // FIXME PCI
5540 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5541 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5542 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5543 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5545 if (iface==ATA_IFACE_ISA) {
5546 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5547 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5548 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5550 else {
5551 // FIXME PCI
5553 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5554 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5555 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5556 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5558 checksum=0;
5559 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5560 checksum = ~checksum;
5561 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5564 goto int13_success;
5565 break;
5567 case 0x49: // IBM/MS extended media change
5568 // always send changed ??
5569 SET_AH(06);
5570 goto int13_fail_nostatus;
5571 break;
5573 case 0x4e: // // IBM/MS set hardware configuration
5574 // DMA, prefetch, PIO maximum not supported
5575 switch (GET_AL()) {
5576 case 0x01:
5577 case 0x03:
5578 case 0x04:
5579 case 0x06:
5580 goto int13_success;
5581 break;
5582 default :
5583 goto int13_fail;
5585 break;
5587 // all those functions return unimplemented
5588 case 0x02: /* read sectors */
5589 case 0x04: /* verify sectors */
5590 case 0x08: /* read disk drive parameters */
5591 case 0x0a: /* read disk sectors with ECC */
5592 case 0x0b: /* write disk sectors with ECC */
5593 case 0x18: /* set media type for format */
5594 case 0x50: // ? - send packet command
5595 default:
5596 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5597 goto int13_fail;
5598 break;
5601 int13_fail:
5602 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5603 int13_fail_noah:
5604 SET_DISK_RET_STATUS(GET_AH());
5605 int13_fail_nostatus:
5606 SET_CF(); // error occurred
5607 return;
5609 int13_success:
5610 SET_AH(0x00); // no error
5611 int13_success_noah:
5612 SET_DISK_RET_STATUS(0x00);
5613 CLEAR_CF(); // no error
5614 return;
5617 // ---------------------------------------------------------------------------
5618 // End of int13 for cdrom
5619 // ---------------------------------------------------------------------------
5621 #if BX_ELTORITO_BOOT
5622 // ---------------------------------------------------------------------------
5623 // Start of int13 for eltorito functions
5624 // ---------------------------------------------------------------------------
5626 void
5627 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5628 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5630 Bit16u ebda_seg=read_word(0x0040,0x000E);
5632 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5633 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5635 switch (GET_AH()) {
5637 // FIXME ElTorito Various. Should be implemented
5638 case 0x4a: // ElTorito - Initiate disk emu
5639 case 0x4c: // ElTorito - Initiate disk emu and boot
5640 case 0x4d: // ElTorito - Return Boot catalog
5641 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5642 goto int13_fail;
5643 break;
5645 case 0x4b: // ElTorito - Terminate disk emu
5646 // FIXME ElTorito Hardcoded
5647 write_byte(DS,SI+0x00,0x13);
5648 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5649 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5650 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5651 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5652 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5653 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5654 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5655 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5656 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5657 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5658 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5660 // If we have to terminate emulation
5661 if(GET_AL() == 0x00) {
5662 // FIXME ElTorito Various. Should be handled accordingly to spec
5663 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5666 goto int13_success;
5667 break;
5669 default:
5670 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5671 goto int13_fail;
5672 break;
5675 int13_fail:
5676 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5677 SET_DISK_RET_STATUS(GET_AH());
5678 SET_CF(); // error occurred
5679 return;
5681 int13_success:
5682 SET_AH(0x00); // no error
5683 SET_DISK_RET_STATUS(0x00);
5684 CLEAR_CF(); // no error
5685 return;
5688 // ---------------------------------------------------------------------------
5689 // End of int13 for eltorito functions
5690 // ---------------------------------------------------------------------------
5692 // ---------------------------------------------------------------------------
5693 // Start of int13 when emulating a device from the cd
5694 // ---------------------------------------------------------------------------
5696 void
5697 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5698 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5700 Bit16u ebda_seg=read_word(0x0040,0x000E);
5701 Bit8u device, status;
5702 Bit16u vheads, vspt, vcylinders;
5703 Bit16u head, sector, cylinder, nbsectors;
5704 Bit32u vlba, ilba, slba, elba;
5705 Bit16u before, segment, offset;
5706 Bit8u atacmd[12];
5708 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5709 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5711 /* at this point, we are emulating a floppy/harddisk */
5713 // Recompute the device number
5714 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5715 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5717 SET_DISK_RET_STATUS(0x00);
5719 /* basic checks : emulation should be active, dl should equal the emulated drive */
5720 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5721 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5722 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5723 goto int13_fail;
5726 #if BX_TCGBIOS
5727 tcpa_ipl((Bit32u)bootseg); /* specs: 8.2.3 steps 4 and 5 */
5728 #endif
5730 switch (GET_AH()) {
5732 // all those functions return SUCCESS
5733 case 0x00: /* disk controller reset */
5734 case 0x09: /* initialize drive parameters */
5735 case 0x0c: /* seek to specified cylinder */
5736 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5737 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5738 case 0x11: /* recalibrate */
5739 case 0x14: /* controller internal diagnostic */
5740 case 0x16: /* detect disk change */
5741 goto int13_success;
5742 break;
5744 // all those functions return disk write-protected
5745 case 0x03: /* write disk sectors */
5746 case 0x05: /* format disk track */
5747 SET_AH(0x03);
5748 goto int13_fail_noah;
5749 break;
5751 case 0x01: /* read disk status */
5752 status=read_byte(0x0040, 0x0074);
5753 SET_AH(status);
5754 SET_DISK_RET_STATUS(0);
5756 /* set CF if error status read */
5757 if (status) goto int13_fail_nostatus;
5758 else goto int13_success_noah;
5759 break;
5761 case 0x02: // read disk sectors
5762 case 0x04: // verify disk sectors
5763 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5764 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5765 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5767 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5769 sector = GET_CL() & 0x003f;
5770 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5771 head = GET_DH();
5772 nbsectors = GET_AL();
5773 segment = ES;
5774 offset = BX;
5776 // no sector to read ?
5777 if(nbsectors==0) goto int13_success;
5779 // sanity checks sco openserver needs this!
5780 if ((sector > vspt)
5781 || (cylinder >= vcylinders)
5782 || (head >= vheads)) {
5783 goto int13_fail;
5786 // After controls, verify do nothing
5787 if (GET_AH() == 0x04) goto int13_success;
5789 segment = ES+(BX / 16);
5790 offset = BX % 16;
5792 // calculate the virtual lba inside the image
5793 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5795 // In advance so we don't loose the count
5796 SET_AL(nbsectors);
5798 // start lba on cd
5799 slba = (Bit32u)vlba/4;
5800 before= (Bit16u)vlba%4;
5802 // end lba on cd
5803 elba = (Bit32u)(vlba+nbsectors-1)/4;
5805 memsetb(get_SS(),atacmd,0,12);
5806 atacmd[0]=0x28; // READ command
5807 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5808 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5809 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5810 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5811 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5812 atacmd[5]=(ilba+slba & 0x000000ff);
5813 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5814 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5815 SET_AH(0x02);
5816 SET_AL(0);
5817 goto int13_fail_noah;
5820 goto int13_success;
5821 break;
5823 case 0x08: /* read disk drive parameters */
5824 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5825 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5826 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5828 SET_AL( 0x00 );
5829 SET_BL( 0x00 );
5830 SET_CH( vcylinders & 0xff );
5831 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5832 SET_DH( vheads );
5833 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5834 // FIXME ElTorito Harddisk. should send the HD count
5836 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5837 case 0x01: SET_BL( 0x02 ); break;
5838 case 0x02: SET_BL( 0x04 ); break;
5839 case 0x03: SET_BL( 0x06 ); break;
5842 ASM_START
5843 push bp
5844 mov bp, sp
5845 mov ax, #diskette_param_table2
5846 mov _int13_cdemu.DI+2[bp], ax
5847 mov _int13_cdemu.ES+2[bp], cs
5848 pop bp
5849 ASM_END
5850 goto int13_success;
5851 break;
5853 case 0x15: /* read disk drive size */
5854 // FIXME ElTorito Harddisk. What geometry to send ?
5855 SET_AH(0x03);
5856 goto int13_success_noah;
5857 break;
5859 // all those functions return unimplemented
5860 case 0x0a: /* read disk sectors with ECC */
5861 case 0x0b: /* write disk sectors with ECC */
5862 case 0x18: /* set media type for format */
5863 case 0x41: // IBM/MS installation check
5864 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5865 case 0x42: // IBM/MS extended read
5866 case 0x43: // IBM/MS extended write
5867 case 0x44: // IBM/MS verify sectors
5868 case 0x45: // IBM/MS lock/unlock drive
5869 case 0x46: // IBM/MS eject media
5870 case 0x47: // IBM/MS extended seek
5871 case 0x48: // IBM/MS get drive parameters
5872 case 0x49: // IBM/MS extended media change
5873 case 0x4e: // ? - set hardware configuration
5874 case 0x50: // ? - send packet command
5875 default:
5876 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5877 goto int13_fail;
5878 break;
5881 int13_fail:
5882 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5883 int13_fail_noah:
5884 SET_DISK_RET_STATUS(GET_AH());
5885 int13_fail_nostatus:
5886 SET_CF(); // error occurred
5887 return;
5889 int13_success:
5890 SET_AH(0x00); // no error
5891 int13_success_noah:
5892 SET_DISK_RET_STATUS(0x00);
5893 CLEAR_CF(); // no error
5894 return;
5897 // ---------------------------------------------------------------------------
5898 // End of int13 when emulating a device from the cd
5899 // ---------------------------------------------------------------------------
5901 #endif // BX_ELTORITO_BOOT
5903 #else //BX_USE_ATADRV
5905 void
5906 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5907 Bit16u cylinder;
5908 Bit16u hd_heads;
5909 Bit16u head;
5910 Bit16u hd_sectors;
5911 Bit16u sector;
5912 Bit16u dl;
5914 ASM_START
5915 push bp
5916 mov bp, sp
5917 push eax
5918 push ebx
5919 push edx
5920 xor eax,eax
5921 mov ax,4[bp] // cylinder
5922 xor ebx,ebx
5923 mov bl,6[bp] // hd_heads
5924 imul ebx
5926 mov bl,8[bp] // head
5927 add eax,ebx
5928 mov bl,10[bp] // hd_sectors
5929 imul ebx
5930 mov bl,12[bp] // sector
5931 add eax,ebx
5933 dec eax
5934 mov dx,#0x1f3
5935 out dx,al
5936 mov dx,#0x1f4
5937 mov al,ah
5938 out dx,al
5939 shr eax,#16
5940 mov dx,#0x1f5
5941 out dx,al
5942 and ah,#0xf
5943 mov bl,14[bp] // dl
5944 and bl,#1
5945 shl bl,#4
5946 or ah,bl
5947 or ah,#0xe0
5948 mov al,ah
5949 mov dx,#0x01f6
5950 out dx,al
5951 pop edx
5952 pop ebx
5953 pop eax
5954 pop bp
5955 ASM_END
5958 void
5959 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5960 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5962 Bit8u drive, num_sectors, sector, head, status, mod;
5963 Bit8u drive_map;
5964 Bit8u n_drives;
5965 Bit16u cyl_mod, ax;
5966 Bit16u max_cylinder, cylinder, total_sectors;
5967 Bit16u hd_cylinders;
5968 Bit8u hd_heads, hd_sectors;
5969 Bit16u val16;
5970 Bit8u sector_count;
5971 unsigned int i;
5972 Bit16u tempbx;
5973 Bit16u dpsize;
5975 Bit16u count, segment, offset;
5976 Bit32u lba;
5977 Bit16u error;
5979 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5981 write_byte(0x0040, 0x008e, 0); // clear completion flag
5983 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5984 handler code */
5985 /* check how many disks first (cmos reg 0x12), return an error if
5986 drive not present */
5987 drive_map = inb_cmos(0x12);
5988 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5989 (((drive_map & 0x0f)==0) ? 0 : 2);
5990 n_drives = (drive_map==0) ? 0 :
5991 ((drive_map==3) ? 2 : 1);
5993 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5994 SET_AH(0x01);
5995 SET_DISK_RET_STATUS(0x01);
5996 SET_CF(); /* error occurred */
5997 return;
6000 switch (GET_AH()) {
6002 case 0x00: /* disk controller reset */
6003 BX_DEBUG_INT13_HD("int13_f00\n");
6005 SET_AH(0);
6006 SET_DISK_RET_STATUS(0);
6007 set_diskette_ret_status(0);
6008 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6009 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6010 CLEAR_CF(); /* successful */
6011 return;
6012 break;
6014 case 0x01: /* read disk status */
6015 BX_DEBUG_INT13_HD("int13_f01\n");
6016 status = read_byte(0x0040, 0x0074);
6017 SET_AH(status);
6018 SET_DISK_RET_STATUS(0);
6019 /* set CF if error status read */
6020 if (status) SET_CF();
6021 else CLEAR_CF();
6022 return;
6023 break;
6025 case 0x04: // verify disk sectors
6026 case 0x02: // read disk sectors
6027 drive = GET_ELDL();
6028 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6030 num_sectors = GET_AL();
6031 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6032 sector = (GET_CL() & 0x3f);
6033 head = GET_DH();
6036 if (hd_cylinders > 1024) {
6037 if (hd_cylinders <= 2048) {
6038 cylinder <<= 1;
6040 else if (hd_cylinders <= 4096) {
6041 cylinder <<= 2;
6043 else if (hd_cylinders <= 8192) {
6044 cylinder <<= 3;
6046 else { // hd_cylinders <= 16384
6047 cylinder <<= 4;
6050 ax = head / hd_heads;
6051 cyl_mod = ax & 0xff;
6052 head = ax >> 8;
6053 cylinder |= cyl_mod;
6056 if ( (cylinder >= hd_cylinders) ||
6057 (sector > hd_sectors) ||
6058 (head >= hd_heads) ) {
6059 SET_AH(1);
6060 SET_DISK_RET_STATUS(1);
6061 SET_CF(); /* error occurred */
6062 return;
6065 if ( (num_sectors > 128) || (num_sectors == 0) )
6066 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6068 if (head > 15)
6069 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6071 if ( GET_AH() == 0x04 ) {
6072 SET_AH(0);
6073 SET_DISK_RET_STATUS(0);
6074 CLEAR_CF();
6075 return;
6078 status = inb(0x1f7);
6079 if (status & 0x80) {
6080 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6082 outb(0x01f2, num_sectors);
6083 /* activate LBA? (tomv) */
6084 if (hd_heads > 16) {
6085 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6086 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6088 else {
6089 outb(0x01f3, sector);
6090 outb(0x01f4, cylinder & 0x00ff);
6091 outb(0x01f5, cylinder >> 8);
6092 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6094 outb(0x01f7, 0x20);
6096 while (1) {
6097 status = inb(0x1f7);
6098 if ( !(status & 0x80) ) break;
6101 if (status & 0x01) {
6102 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6103 } else if ( !(status & 0x08) ) {
6104 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6105 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6108 sector_count = 0;
6109 tempbx = BX;
6111 ASM_START
6112 sti ;; enable higher priority interrupts
6113 ASM_END
6115 while (1) {
6116 ASM_START
6117 ;; store temp bx in real DI register
6118 push bp
6119 mov bp, sp
6120 mov di, _int13_harddisk.tempbx + 2 [bp]
6121 pop bp
6123 ;; adjust if there will be an overrun
6124 cmp di, #0xfe00
6125 jbe i13_f02_no_adjust
6126 i13_f02_adjust:
6127 sub di, #0x0200 ; sub 512 bytes from offset
6128 mov ax, es
6129 add ax, #0x0020 ; add 512 to segment
6130 mov es, ax
6132 i13_f02_no_adjust:
6133 mov cx, #0x0100 ;; counter (256 words = 512b)
6134 mov dx, #0x01f0 ;; AT data read port
6136 rep
6137 insw ;; CX words transfered from port(DX) to ES:[DI]
6139 i13_f02_done:
6140 ;; store real DI register back to temp bx
6141 push bp
6142 mov bp, sp
6143 mov _int13_harddisk.tempbx + 2 [bp], di
6144 pop bp
6145 ASM_END
6147 sector_count++;
6148 num_sectors--;
6149 if (num_sectors == 0) {
6150 status = inb(0x1f7);
6151 if ( (status & 0xc9) != 0x40 )
6152 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6153 break;
6155 else {
6156 status = inb(0x1f7);
6157 if ( (status & 0xc9) != 0x48 )
6158 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6159 continue;
6163 SET_AH(0);
6164 SET_DISK_RET_STATUS(0);
6165 SET_AL(sector_count);
6166 CLEAR_CF(); /* successful */
6167 return;
6168 break;
6171 case 0x03: /* write disk sectors */
6172 BX_DEBUG_INT13_HD("int13_f03\n");
6173 drive = GET_ELDL ();
6174 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6176 num_sectors = GET_AL();
6177 cylinder = GET_CH();
6178 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6179 sector = (GET_CL() & 0x3f);
6180 head = GET_DH();
6182 if (hd_cylinders > 1024) {
6183 if (hd_cylinders <= 2048) {
6184 cylinder <<= 1;
6186 else if (hd_cylinders <= 4096) {
6187 cylinder <<= 2;
6189 else if (hd_cylinders <= 8192) {
6190 cylinder <<= 3;
6192 else { // hd_cylinders <= 16384
6193 cylinder <<= 4;
6196 ax = head / hd_heads;
6197 cyl_mod = ax & 0xff;
6198 head = ax >> 8;
6199 cylinder |= cyl_mod;
6202 if ( (cylinder >= hd_cylinders) ||
6203 (sector > hd_sectors) ||
6204 (head >= hd_heads) ) {
6205 SET_AH( 1);
6206 SET_DISK_RET_STATUS(1);
6207 SET_CF(); /* error occurred */
6208 return;
6211 if ( (num_sectors > 128) || (num_sectors == 0) )
6212 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6214 if (head > 15)
6215 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6217 status = inb(0x1f7);
6218 if (status & 0x80) {
6219 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6221 // should check for Drive Ready Bit also in status reg
6222 outb(0x01f2, num_sectors);
6224 /* activate LBA? (tomv) */
6225 if (hd_heads > 16) {
6226 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6227 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6229 else {
6230 outb(0x01f3, sector);
6231 outb(0x01f4, cylinder & 0x00ff);
6232 outb(0x01f5, cylinder >> 8);
6233 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6235 outb(0x01f7, 0x30);
6237 // wait for busy bit to turn off after seeking
6238 while (1) {
6239 status = inb(0x1f7);
6240 if ( !(status & 0x80) ) break;
6243 if ( !(status & 0x08) ) {
6244 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6245 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6248 sector_count = 0;
6249 tempbx = BX;
6251 ASM_START
6252 sti ;; enable higher priority interrupts
6253 ASM_END
6255 while (1) {
6256 ASM_START
6257 ;; store temp bx in real SI register
6258 push bp
6259 mov bp, sp
6260 mov si, _int13_harddisk.tempbx + 2 [bp]
6261 pop bp
6263 ;; adjust if there will be an overrun
6264 cmp si, #0xfe00
6265 jbe i13_f03_no_adjust
6266 i13_f03_adjust:
6267 sub si, #0x0200 ; sub 512 bytes from offset
6268 mov ax, es
6269 add ax, #0x0020 ; add 512 to segment
6270 mov es, ax
6272 i13_f03_no_adjust:
6273 mov cx, #0x0100 ;; counter (256 words = 512b)
6274 mov dx, #0x01f0 ;; AT data read port
6276 seg ES
6277 rep
6278 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6280 ;; store real SI register back to temp bx
6281 push bp
6282 mov bp, sp
6283 mov _int13_harddisk.tempbx + 2 [bp], si
6284 pop bp
6285 ASM_END
6287 sector_count++;
6288 num_sectors--;
6289 if (num_sectors == 0) {
6290 status = inb(0x1f7);
6291 if ( (status & 0xe9) != 0x40 )
6292 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6293 break;
6295 else {
6296 status = inb(0x1f7);
6297 if ( (status & 0xc9) != 0x48 )
6298 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6299 continue;
6303 SET_AH(0);
6304 SET_DISK_RET_STATUS(0);
6305 SET_AL(sector_count);
6306 CLEAR_CF(); /* successful */
6307 return;
6308 break;
6310 case 0x05: /* format disk track */
6311 BX_DEBUG_INT13_HD("int13_f05\n");
6312 BX_PANIC("format disk track called\n");
6313 /* nop */
6314 SET_AH(0);
6315 SET_DISK_RET_STATUS(0);
6316 CLEAR_CF(); /* successful */
6317 return;
6318 break;
6320 case 0x08: /* read disk drive parameters */
6321 BX_DEBUG_INT13_HD("int13_f08\n");
6323 drive = GET_ELDL ();
6324 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6326 // translate CHS
6327 //
6328 if (hd_cylinders <= 1024) {
6329 // hd_cylinders >>= 0;
6330 // hd_heads <<= 0;
6332 else if (hd_cylinders <= 2048) {
6333 hd_cylinders >>= 1;
6334 hd_heads <<= 1;
6336 else if (hd_cylinders <= 4096) {
6337 hd_cylinders >>= 2;
6338 hd_heads <<= 2;
6340 else if (hd_cylinders <= 8192) {
6341 hd_cylinders >>= 3;
6342 hd_heads <<= 3;
6344 else { // hd_cylinders <= 16384
6345 hd_cylinders >>= 4;
6346 hd_heads <<= 4;
6349 max_cylinder = hd_cylinders - 2; /* 0 based */
6350 SET_AL(0);
6351 SET_CH(max_cylinder & 0xff);
6352 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6353 SET_DH(hd_heads - 1);
6354 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6355 SET_AH(0);
6356 SET_DISK_RET_STATUS(0);
6357 CLEAR_CF(); /* successful */
6359 return;
6360 break;
6362 case 0x09: /* initialize drive parameters */
6363 BX_DEBUG_INT13_HD("int13_f09\n");
6364 SET_AH(0);
6365 SET_DISK_RET_STATUS(0);
6366 CLEAR_CF(); /* successful */
6367 return;
6368 break;
6370 case 0x0a: /* read disk sectors with ECC */
6371 BX_DEBUG_INT13_HD("int13_f0a\n");
6372 case 0x0b: /* write disk sectors with ECC */
6373 BX_DEBUG_INT13_HD("int13_f0b\n");
6374 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6375 return;
6376 break;
6378 case 0x0c: /* seek to specified cylinder */
6379 BX_DEBUG_INT13_HD("int13_f0c\n");
6380 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6381 SET_AH(0);
6382 SET_DISK_RET_STATUS(0);
6383 CLEAR_CF(); /* successful */
6384 return;
6385 break;
6387 case 0x0d: /* alternate disk reset */
6388 BX_DEBUG_INT13_HD("int13_f0d\n");
6389 SET_AH(0);
6390 SET_DISK_RET_STATUS(0);
6391 CLEAR_CF(); /* successful */
6392 return;
6393 break;
6395 case 0x10: /* check drive ready */
6396 BX_DEBUG_INT13_HD("int13_f10\n");
6397 //SET_AH(0);
6398 //SET_DISK_RET_STATUS(0);
6399 //CLEAR_CF(); /* successful */
6400 //return;
6401 //break;
6403 // should look at 40:8E also???
6404 status = inb(0x01f7);
6405 if ( (status & 0xc0) == 0x40 ) {
6406 SET_AH(0);
6407 SET_DISK_RET_STATUS(0);
6408 CLEAR_CF(); // drive ready
6409 return;
6411 else {
6412 SET_AH(0xAA);
6413 SET_DISK_RET_STATUS(0xAA);
6414 SET_CF(); // not ready
6415 return;
6417 break;
6419 case 0x11: /* recalibrate */
6420 BX_DEBUG_INT13_HD("int13_f11\n");
6421 SET_AH(0);
6422 SET_DISK_RET_STATUS(0);
6423 CLEAR_CF(); /* successful */
6424 return;
6425 break;
6427 case 0x14: /* controller internal diagnostic */
6428 BX_DEBUG_INT13_HD("int13_f14\n");
6429 SET_AH(0);
6430 SET_DISK_RET_STATUS(0);
6431 CLEAR_CF(); /* successful */
6432 SET_AL(0);
6433 return;
6434 break;
6436 case 0x15: /* read disk drive size */
6437 drive = GET_ELDL();
6438 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6439 ASM_START
6440 push bp
6441 mov bp, sp
6442 mov al, _int13_harddisk.hd_heads + 2 [bp]
6443 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6444 mul al, ah ;; ax = heads * sectors
6445 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6446 dec bx ;; use (cylinders - 1) ???
6447 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6448 ;; now we need to move the 32bit result dx:ax to what the
6449 ;; BIOS wants which is cx:dx.
6450 ;; and then into CX:DX on the stack
6451 mov _int13_harddisk.CX + 2 [bp], dx
6452 mov _int13_harddisk.DX + 2 [bp], ax
6453 pop bp
6454 ASM_END
6455 SET_AH(3); // hard disk accessible
6456 SET_DISK_RET_STATUS(0); // ??? should this be 0
6457 CLEAR_CF(); // successful
6458 return;
6459 break;
6461 case 0x18: // set media type for format
6462 case 0x41: // IBM/MS
6463 case 0x42: // IBM/MS
6464 case 0x43: // IBM/MS
6465 case 0x44: // IBM/MS
6466 case 0x45: // IBM/MS lock/unlock drive
6467 case 0x46: // IBM/MS eject media
6468 case 0x47: // IBM/MS extended seek
6469 case 0x49: // IBM/MS extended media change
6470 case 0x50: // IBM/MS send packet command
6471 default:
6472 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6474 SET_AH(1); // code=invalid function in AH or invalid parameter
6475 SET_DISK_RET_STATUS(1);
6476 SET_CF(); /* unsuccessful */
6477 return;
6478 break;
6482 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6483 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6485 void
6486 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6487 Bit8u drive;
6488 Bit16u *hd_cylinders;
6489 Bit8u *hd_heads;
6490 Bit8u *hd_sectors;
6492 Bit8u hd_type;
6493 Bit16u ss;
6494 Bit16u cylinders;
6495 Bit8u iobase;
6497 ss = get_SS();
6498 if (drive == 0x80) {
6499 hd_type = inb_cmos(0x12) & 0xf0;
6500 if (hd_type != 0xf0)
6501 BX_INFO(panic_msg_reg12h,0);
6502 hd_type = inb_cmos(0x19); // HD0: extended type
6503 if (hd_type != 47)
6504 BX_INFO(panic_msg_reg19h,0,0x19);
6505 iobase = 0x1b;
6506 } else {
6507 hd_type = inb_cmos(0x12) & 0x0f;
6508 if (hd_type != 0x0f)
6509 BX_INFO(panic_msg_reg12h,1);
6510 hd_type = inb_cmos(0x1a); // HD0: extended type
6511 if (hd_type != 47)
6512 BX_INFO(panic_msg_reg19h,0,0x1a);
6513 iobase = 0x24;
6516 // cylinders
6517 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6518 write_word(ss, hd_cylinders, cylinders);
6520 // heads
6521 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6523 // sectors per track
6524 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6527 #endif //else BX_USE_ATADRV
6530 //////////////////////
6531 // FLOPPY functions //
6532 //////////////////////
6534 bx_bool
6535 floppy_media_known(drive)
6536 Bit16u drive;
6538 Bit8u val8;
6539 Bit16u media_state_offset;
6541 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6542 if (drive)
6543 val8 >>= 1;
6544 val8 &= 0x01;
6545 if (val8 == 0)
6546 return(0);
6548 media_state_offset = 0x0090;
6549 if (drive)
6550 media_state_offset += 1;
6552 val8 = read_byte(0x0040, media_state_offset);
6553 val8 = (val8 >> 4) & 0x01;
6554 if (val8 == 0)
6555 return(0);
6557 // check pass, return KNOWN
6558 return(1);
6561 bx_bool
6562 floppy_media_sense(drive)
6563 Bit16u drive;
6565 bx_bool retval;
6566 Bit16u media_state_offset;
6567 Bit8u drive_type, config_data, media_state;
6569 if (floppy_drive_recal(drive) == 0) {
6570 return(0);
6573 // for now cheat and get drive type from CMOS,
6574 // assume media is same as drive type
6576 // ** config_data **
6577 // Bitfields for diskette media control:
6578 // Bit(s) Description (Table M0028)
6579 // 7-6 last data rate set by controller
6580 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6581 // 5-4 last diskette drive step rate selected
6582 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6583 // 3-2 {data rate at start of operation}
6584 // 1-0 reserved
6586 // ** media_state **
6587 // Bitfields for diskette drive media state:
6588 // Bit(s) Description (Table M0030)
6589 // 7-6 data rate
6590 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6591 // 5 double stepping required (e.g. 360kB in 1.2MB)
6592 // 4 media type established
6593 // 3 drive capable of supporting 4MB media
6594 // 2-0 on exit from BIOS, contains
6595 // 000 trying 360kB in 360kB
6596 // 001 trying 360kB in 1.2MB
6597 // 010 trying 1.2MB in 1.2MB
6598 // 011 360kB in 360kB established
6599 // 100 360kB in 1.2MB established
6600 // 101 1.2MB in 1.2MB established
6601 // 110 reserved
6602 // 111 all other formats/drives
6604 drive_type = inb_cmos(0x10);
6605 if (drive == 0)
6606 drive_type >>= 4;
6607 else
6608 drive_type &= 0x0f;
6609 if ( drive_type == 1 ) {
6610 // 360K 5.25" drive
6611 config_data = 0x00; // 0000 0000
6612 media_state = 0x25; // 0010 0101
6613 retval = 1;
6615 else if ( drive_type == 2 ) {
6616 // 1.2 MB 5.25" drive
6617 config_data = 0x00; // 0000 0000
6618 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6619 retval = 1;
6621 else if ( drive_type == 3 ) {
6622 // 720K 3.5" drive
6623 config_data = 0x00; // 0000 0000 ???
6624 media_state = 0x17; // 0001 0111
6625 retval = 1;
6627 else if ( drive_type == 4 ) {
6628 // 1.44 MB 3.5" drive
6629 config_data = 0x00; // 0000 0000
6630 media_state = 0x17; // 0001 0111
6631 retval = 1;
6633 else if ( drive_type == 5 ) {
6634 // 2.88 MB 3.5" drive
6635 config_data = 0xCC; // 1100 1100
6636 media_state = 0xD7; // 1101 0111
6637 retval = 1;
6639 //
6640 // Extended floppy size uses special cmos setting
6641 else if ( drive_type == 6 ) {
6642 // 160k 5.25" drive
6643 config_data = 0x00; // 0000 0000
6644 media_state = 0x27; // 0010 0111
6645 retval = 1;
6647 else if ( drive_type == 7 ) {
6648 // 180k 5.25" drive
6649 config_data = 0x00; // 0000 0000
6650 media_state = 0x27; // 0010 0111
6651 retval = 1;
6653 else if ( drive_type == 8 ) {
6654 // 320k 5.25" drive
6655 config_data = 0x00; // 0000 0000
6656 media_state = 0x27; // 0010 0111
6657 retval = 1;
6660 else {
6661 // not recognized
6662 config_data = 0x00; // 0000 0000
6663 media_state = 0x00; // 0000 0000
6664 retval = 0;
6667 if (drive == 0)
6668 media_state_offset = 0x90;
6669 else
6670 media_state_offset = 0x91;
6671 write_byte(0x0040, 0x008B, config_data);
6672 write_byte(0x0040, media_state_offset, media_state);
6674 return(retval);
6677 bx_bool
6678 floppy_drive_recal(drive)
6679 Bit16u drive;
6681 Bit8u val8, dor;
6682 Bit16u curr_cyl_offset;
6684 // set 40:3e bit 7 to 0
6685 val8 = read_byte(0x0000, 0x043e);
6686 val8 &= 0x7f;
6687 write_byte(0x0000, 0x043e, val8);
6689 // turn on motor of selected drive, DMA & int enabled, normal operation
6690 if (drive)
6691 dor = 0x20;
6692 else
6693 dor = 0x10;
6694 dor |= 0x0c;
6695 dor |= drive;
6696 outb(0x03f2, dor);
6698 // reset the disk motor timeout value of INT 08
6699 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6701 // check port 3f4 for drive readiness
6702 val8 = inb(0x3f4);
6703 if ( (val8 & 0xf0) != 0x80 )
6704 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6706 // send Recalibrate command (2 bytes) to controller
6707 outb(0x03f5, 0x07); // 07: Recalibrate
6708 outb(0x03f5, drive); // 0=drive0, 1=drive1
6710 // turn on interrupts
6711 ASM_START
6712 sti
6713 ASM_END
6715 // wait on 40:3e bit 7 to become 1
6716 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6717 while ( val8 == 0 ) {
6718 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6721 val8 = 0; // separate asm from while() loop
6722 // turn off interrupts
6723 ASM_START
6724 cli
6725 ASM_END
6727 // set 40:3e bit 7 to 0, and calibrated bit
6728 val8 = read_byte(0x0000, 0x043e);
6729 val8 &= 0x7f;
6730 if (drive) {
6731 val8 |= 0x02; // Drive 1 calibrated
6732 curr_cyl_offset = 0x0095;
6734 else {
6735 val8 |= 0x01; // Drive 0 calibrated
6736 curr_cyl_offset = 0x0094;
6738 write_byte(0x0040, 0x003e, val8);
6739 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6741 return(1);
6746 bx_bool
6747 floppy_drive_exists(drive)
6748 Bit16u drive;
6750 Bit8u drive_type;
6752 // check CMOS to see if drive exists
6753 drive_type = inb_cmos(0x10);
6754 if (drive == 0)
6755 drive_type >>= 4;
6756 else
6757 drive_type &= 0x0f;
6758 if ( drive_type == 0 )
6759 return(0);
6760 else
6761 return(1);
6764 #if BX_SUPPORT_FLOPPY
6765 void
6766 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6767 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6769 Bit8u drive, num_sectors, track, sector, head, status;
6770 Bit16u base_address, base_count, base_es;
6771 Bit8u page, mode_register, val8, dor;
6772 Bit8u return_status[7];
6773 Bit8u drive_type, num_floppies, ah;
6774 Bit16u es, last_addr;
6776 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6777 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6779 ah = GET_AH();
6781 switch ( ah ) {
6782 case 0x00: // diskette controller reset
6783 BX_DEBUG_INT13_FL("floppy f00\n");
6784 drive = GET_ELDL();
6785 if (drive > 1) {
6786 SET_AH(1); // invalid param
6787 set_diskette_ret_status(1);
6788 SET_CF();
6789 return;
6791 drive_type = inb_cmos(0x10);
6793 if (drive == 0)
6794 drive_type >>= 4;
6795 else
6796 drive_type &= 0x0f;
6797 if (drive_type == 0) {
6798 SET_AH(0x80); // drive not responding
6799 set_diskette_ret_status(0x80);
6800 SET_CF();
6801 return;
6803 SET_AH(0);
6804 set_diskette_ret_status(0);
6805 CLEAR_CF(); // successful
6806 set_diskette_current_cyl(drive, 0); // current cylinder
6807 return;
6809 case 0x01: // Read Diskette Status
6810 CLEAR_CF();
6811 val8 = read_byte(0x0000, 0x0441);
6812 SET_AH(val8);
6813 if (val8) {
6814 SET_CF();
6816 return;
6818 case 0x02: // Read Diskette Sectors
6819 case 0x03: // Write Diskette Sectors
6820 case 0x04: // Verify Diskette Sectors
6821 num_sectors = GET_AL();
6822 track = GET_CH();
6823 sector = GET_CL();
6824 head = GET_DH();
6825 drive = GET_ELDL();
6827 if ( (drive > 1) || (head > 1) ||
6828 (num_sectors == 0) || (num_sectors > 72) ) {
6829 BX_INFO("floppy: drive>1 || head>1 ...\n");
6830 SET_AH(1);
6831 set_diskette_ret_status(1);
6832 SET_AL(0); // no sectors read
6833 SET_CF(); // error occurred
6834 return;
6837 // see if drive exists
6838 if (floppy_drive_exists(drive) == 0) {
6839 SET_AH(0x80); // not responding
6840 set_diskette_ret_status(0x80);
6841 SET_AL(0); // no sectors read
6842 SET_CF(); // error occurred
6843 return;
6846 // see if media in drive, and type is known
6847 if (floppy_media_known(drive) == 0) {
6848 if (floppy_media_sense(drive) == 0) {
6849 SET_AH(0x0C); // Media type not found
6850 set_diskette_ret_status(0x0C);
6851 SET_AL(0); // no sectors read
6852 SET_CF(); // error occurred
6853 return;
6857 if (ah == 0x02) {
6858 // Read Diskette Sectors
6860 //-----------------------------------
6861 // set up DMA controller for transfer
6862 //-----------------------------------
6864 // es:bx = pointer to where to place information from diskette
6865 // port 04: DMA-1 base and current address, channel 2
6866 // port 05: DMA-1 base and current count, channel 2
6867 page = (ES >> 12); // upper 4 bits
6868 base_es = (ES << 4); // lower 16bits contributed by ES
6869 base_address = base_es + BX; // lower 16 bits of address
6870 // contributed by ES:BX
6871 if ( base_address < base_es ) {
6872 // in case of carry, adjust page by 1
6873 page++;
6875 base_count = (num_sectors * 512) - 1;
6877 // check for 64K boundary overrun
6878 last_addr = base_address + base_count;
6879 if (last_addr < base_address) {
6880 SET_AH(0x09);
6881 set_diskette_ret_status(0x09);
6882 SET_AL(0); // no sectors read
6883 SET_CF(); // error occurred
6884 return;
6887 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6888 outb(0x000a, 0x06);
6890 BX_DEBUG_INT13_FL("clear flip-flop\n");
6891 outb(0x000c, 0x00); // clear flip-flop
6892 outb(0x0004, base_address);
6893 outb(0x0004, base_address>>8);
6894 BX_DEBUG_INT13_FL("clear flip-flop\n");
6895 outb(0x000c, 0x00); // clear flip-flop
6896 outb(0x0005, base_count);
6897 outb(0x0005, base_count>>8);
6899 // port 0b: DMA-1 Mode Register
6900 mode_register = 0x46; // single mode, increment, autoinit disable,
6901 // transfer type=write, channel 2
6902 BX_DEBUG_INT13_FL("setting mode register\n");
6903 outb(0x000b, mode_register);
6905 BX_DEBUG_INT13_FL("setting page register\n");
6906 // port 81: DMA-1 Page Register, channel 2
6907 outb(0x0081, page);
6909 BX_DEBUG_INT13_FL("unmask chan 2\n");
6910 outb(0x000a, 0x02); // unmask channel 2
6912 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6913 outb(0x000a, 0x02);
6915 //--------------------------------------
6916 // set up floppy controller for transfer
6917 //--------------------------------------
6919 // set 40:3e bit 7 to 0
6920 val8 = read_byte(0x0000, 0x043e);
6921 val8 &= 0x7f;
6922 write_byte(0x0000, 0x043e, val8);
6924 // turn on motor of selected drive, DMA & int enabled, normal operation
6925 if (drive)
6926 dor = 0x20;
6927 else
6928 dor = 0x10;
6929 dor |= 0x0c;
6930 dor |= drive;
6931 outb(0x03f2, dor);
6933 // reset the disk motor timeout value of INT 08
6934 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6936 // check port 3f4 for drive readiness
6937 val8 = inb(0x3f4);
6938 if ( (val8 & 0xf0) != 0x80 )
6939 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6941 // send read-normal-data command (9 bytes) to controller
6942 outb(0x03f5, 0xe6); // e6: read normal data
6943 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6944 outb(0x03f5, track);
6945 outb(0x03f5, head);
6946 outb(0x03f5, sector);
6947 outb(0x03f5, 2); // 512 byte sector size
6948 outb(0x03f5, 0); // last sector number possible on track
6949 outb(0x03f5, 0); // Gap length
6950 outb(0x03f5, 0xff); // Gap length
6952 // turn on interrupts
6953 ASM_START
6954 sti
6955 ASM_END
6957 // wait on 40:3e bit 7 to become 1
6958 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6959 while ( val8 == 0 ) {
6960 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6963 val8 = 0; // separate asm from while() loop
6964 // turn off interrupts
6965 ASM_START
6966 cli
6967 ASM_END
6969 // set 40:3e bit 7 to 0
6970 val8 = read_byte(0x0000, 0x043e);
6971 val8 &= 0x7f;
6972 write_byte(0x0000, 0x043e, val8);
6974 // check port 3f4 for accessibility to status bytes
6975 val8 = inb(0x3f4);
6976 if ( (val8 & 0xc0) != 0xc0 )
6977 BX_PANIC("int13_diskette: ctrl not ready\n");
6979 // read 7 return status bytes from controller
6980 // using loop index broken, have to unroll...
6981 return_status[0] = inb(0x3f5);
6982 return_status[1] = inb(0x3f5);
6983 return_status[2] = inb(0x3f5);
6984 return_status[3] = inb(0x3f5);
6985 return_status[4] = inb(0x3f5);
6986 return_status[5] = inb(0x3f5);
6987 return_status[6] = inb(0x3f5);
6988 // record in BIOS Data Area
6989 write_byte(0x0040, 0x0042, return_status[0]);
6990 write_byte(0x0040, 0x0043, return_status[1]);
6991 write_byte(0x0040, 0x0044, return_status[2]);
6992 write_byte(0x0040, 0x0045, return_status[3]);
6993 write_byte(0x0040, 0x0046, return_status[4]);
6994 write_byte(0x0040, 0x0047, return_status[5]);
6995 write_byte(0x0040, 0x0048, return_status[6]);
6997 if ( (return_status[0] & 0xc0) != 0 ) {
6998 SET_AH(0x20);
6999 set_diskette_ret_status(0x20);
7000 SET_AL(0); // no sectors read
7001 SET_CF(); // error occurred
7002 return;
7005 // ??? should track be new val from return_status[3] ?
7006 set_diskette_current_cyl(drive, track);
7007 // AL = number of sectors read (same value as passed)
7008 SET_AH(0x00); // success
7009 CLEAR_CF(); // success
7010 return;
7012 else if (ah == 0x03) {
7013 // Write Diskette Sectors
7015 //-----------------------------------
7016 // set up DMA controller for transfer
7017 //-----------------------------------
7019 // es:bx = pointer to where to place information from diskette
7020 // port 04: DMA-1 base and current address, channel 2
7021 // port 05: DMA-1 base and current count, channel 2
7022 page = (ES >> 12); // upper 4 bits
7023 base_es = (ES << 4); // lower 16bits contributed by ES
7024 base_address = base_es + BX; // lower 16 bits of address
7025 // contributed by ES:BX
7026 if ( base_address < base_es ) {
7027 // in case of carry, adjust page by 1
7028 page++;
7030 base_count = (num_sectors * 512) - 1;
7032 // check for 64K boundary overrun
7033 last_addr = base_address + base_count;
7034 if (last_addr < base_address) {
7035 SET_AH(0x09);
7036 set_diskette_ret_status(0x09);
7037 SET_AL(0); // no sectors read
7038 SET_CF(); // error occurred
7039 return;
7042 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7043 outb(0x000a, 0x06);
7045 outb(0x000c, 0x00); // clear flip-flop
7046 outb(0x0004, base_address);
7047 outb(0x0004, base_address>>8);
7048 outb(0x000c, 0x00); // clear flip-flop
7049 outb(0x0005, base_count);
7050 outb(0x0005, base_count>>8);
7052 // port 0b: DMA-1 Mode Register
7053 mode_register = 0x4a; // single mode, increment, autoinit disable,
7054 // transfer type=read, channel 2
7055 outb(0x000b, mode_register);
7057 // port 81: DMA-1 Page Register, channel 2
7058 outb(0x0081, page);
7060 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7061 outb(0x000a, 0x02);
7063 //--------------------------------------
7064 // set up floppy controller for transfer
7065 //--------------------------------------
7067 // set 40:3e bit 7 to 0
7068 val8 = read_byte(0x0000, 0x043e);
7069 val8 &= 0x7f;
7070 write_byte(0x0000, 0x043e, val8);
7072 // turn on motor of selected drive, DMA & int enabled, normal operation
7073 if (drive)
7074 dor = 0x20;
7075 else
7076 dor = 0x10;
7077 dor |= 0x0c;
7078 dor |= drive;
7079 outb(0x03f2, dor);
7081 // reset the disk motor timeout value of INT 08
7082 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7084 // check port 3f4 for drive readiness
7085 val8 = inb(0x3f4);
7086 if ( (val8 & 0xf0) != 0x80 )
7087 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7089 // send read-normal-data command (9 bytes) to controller
7090 outb(0x03f5, 0xc5); // c5: write normal data
7091 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7092 outb(0x03f5, track);
7093 outb(0x03f5, head);
7094 outb(0x03f5, sector);
7095 outb(0x03f5, 2); // 512 byte sector size
7096 outb(0x03f5, 0); // last sector number possible on track
7097 outb(0x03f5, 0); // Gap length
7098 outb(0x03f5, 0xff); // Gap length
7100 // turn on interrupts
7101 ASM_START
7102 sti
7103 ASM_END
7105 // wait on 40:3e bit 7 to become 1
7106 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7107 while ( val8 == 0 ) {
7108 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7111 val8 = 0; // separate asm from while() loop
7112 // turn off interrupts
7113 ASM_START
7114 cli
7115 ASM_END
7117 // set 40:3e bit 7 to 0
7118 val8 = read_byte(0x0000, 0x043e);
7119 val8 &= 0x7f;
7120 write_byte(0x0000, 0x043e, val8);
7122 // check port 3f4 for accessibility to status bytes
7123 val8 = inb(0x3f4);
7124 if ( (val8 & 0xc0) != 0xc0 )
7125 BX_PANIC("int13_diskette: ctrl not ready\n");
7127 // read 7 return status bytes from controller
7128 // using loop index broken, have to unroll...
7129 return_status[0] = inb(0x3f5);
7130 return_status[1] = inb(0x3f5);
7131 return_status[2] = inb(0x3f5);
7132 return_status[3] = inb(0x3f5);
7133 return_status[4] = inb(0x3f5);
7134 return_status[5] = inb(0x3f5);
7135 return_status[6] = inb(0x3f5);
7136 // record in BIOS Data Area
7137 write_byte(0x0040, 0x0042, return_status[0]);
7138 write_byte(0x0040, 0x0043, return_status[1]);
7139 write_byte(0x0040, 0x0044, return_status[2]);
7140 write_byte(0x0040, 0x0045, return_status[3]);
7141 write_byte(0x0040, 0x0046, return_status[4]);
7142 write_byte(0x0040, 0x0047, return_status[5]);
7143 write_byte(0x0040, 0x0048, return_status[6]);
7145 if ( (return_status[0] & 0xc0) != 0 ) {
7146 if ( (return_status[1] & 0x02) != 0 ) {
7147 // diskette not writable.
7148 // AH=status code=0x03 (tried to write on write-protected disk)
7149 // AL=number of sectors written=0
7150 AX = 0x0300;
7151 SET_CF();
7152 return;
7153 } else {
7154 BX_PANIC("int13_diskette_function: read error\n");
7158 // ??? should track be new val from return_status[3] ?
7159 set_diskette_current_cyl(drive, track);
7160 // AL = number of sectors read (same value as passed)
7161 SET_AH(0x00); // success
7162 CLEAR_CF(); // success
7163 return;
7165 else { // if (ah == 0x04)
7166 // Verify Diskette Sectors
7168 // ??? should track be new val from return_status[3] ?
7169 set_diskette_current_cyl(drive, track);
7170 // AL = number of sectors verified (same value as passed)
7171 CLEAR_CF(); // success
7172 SET_AH(0x00); // success
7173 return;
7177 case 0x05: // format diskette track
7178 BX_DEBUG_INT13_FL("floppy f05\n");
7180 num_sectors = GET_AL();
7181 track = GET_CH();
7182 head = GET_DH();
7183 drive = GET_ELDL();
7185 if ((drive > 1) || (head > 1) || (track > 79) ||
7186 (num_sectors == 0) || (num_sectors > 18)) {
7187 SET_AH(1);
7188 set_diskette_ret_status(1);
7189 SET_CF(); // error occurred
7192 // see if drive exists
7193 if (floppy_drive_exists(drive) == 0) {
7194 SET_AH(0x80); // drive not responding
7195 set_diskette_ret_status(0x80);
7196 SET_CF(); // error occurred
7197 return;
7200 // see if media in drive, and type is known
7201 if (floppy_media_known(drive) == 0) {
7202 if (floppy_media_sense(drive) == 0) {
7203 SET_AH(0x0C); // Media type not found
7204 set_diskette_ret_status(0x0C);
7205 SET_AL(0); // no sectors read
7206 SET_CF(); // error occurred
7207 return;
7211 // set up DMA controller for transfer
7212 page = (ES >> 12); // upper 4 bits
7213 base_es = (ES << 4); // lower 16bits contributed by ES
7214 base_address = base_es + BX; // lower 16 bits of address
7215 // contributed by ES:BX
7216 if ( base_address < base_es ) {
7217 // in case of carry, adjust page by 1
7218 page++;
7220 base_count = (num_sectors * 4) - 1;
7222 // check for 64K boundary overrun
7223 last_addr = base_address + base_count;
7224 if (last_addr < base_address) {
7225 SET_AH(0x09);
7226 set_diskette_ret_status(0x09);
7227 SET_AL(0); // no sectors read
7228 SET_CF(); // error occurred
7229 return;
7232 outb(0x000a, 0x06);
7233 outb(0x000c, 0x00); // clear flip-flop
7234 outb(0x0004, base_address);
7235 outb(0x0004, base_address>>8);
7236 outb(0x000c, 0x00); // clear flip-flop
7237 outb(0x0005, base_count);
7238 outb(0x0005, base_count>>8);
7239 mode_register = 0x4a; // single mode, increment, autoinit disable,
7240 // transfer type=read, channel 2
7241 outb(0x000b, mode_register);
7242 // port 81: DMA-1 Page Register, channel 2
7243 outb(0x0081, page);
7244 outb(0x000a, 0x02);
7246 // set up floppy controller for transfer
7247 val8 = read_byte(0x0000, 0x043e);
7248 val8 &= 0x7f;
7249 write_byte(0x0000, 0x043e, val8);
7250 // turn on motor of selected drive, DMA & int enabled, normal operation
7251 if (drive)
7252 dor = 0x20;
7253 else
7254 dor = 0x10;
7255 dor |= 0x0c;
7256 dor |= drive;
7257 outb(0x03f2, dor);
7259 // reset the disk motor timeout value of INT 08
7260 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7262 // check port 3f4 for drive readiness
7263 val8 = inb(0x3f4);
7264 if ( (val8 & 0xf0) != 0x80 )
7265 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7267 // send read-normal-data command (6 bytes) to controller
7268 outb(0x03f5, 0x4d); // 4d: format track
7269 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7270 outb(0x03f5, 2); // 512 byte sector size
7271 outb(0x03f5, num_sectors); // number of sectors per track
7272 outb(0x03f5, 0); // Gap length
7273 outb(0x03f5, 0xf6); // Fill byte
7274 // turn on interrupts
7275 ASM_START
7276 sti
7277 ASM_END
7278 // wait on 40:3e bit 7 to become 1
7279 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7280 while ( val8 == 0 ) {
7281 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7283 val8 = 0; // separate asm from while() loop
7284 // turn off interrupts
7285 ASM_START
7286 cli
7287 ASM_END
7288 // set 40:3e bit 7 to 0
7289 val8 = read_byte(0x0000, 0x043e);
7290 val8 &= 0x7f;
7291 write_byte(0x0000, 0x043e, val8);
7292 // check port 3f4 for accessibility to status bytes
7293 val8 = inb(0x3f4);
7294 if ( (val8 & 0xc0) != 0xc0 )
7295 BX_PANIC("int13_diskette: ctrl not ready\n");
7297 // read 7 return status bytes from controller
7298 // using loop index broken, have to unroll...
7299 return_status[0] = inb(0x3f5);
7300 return_status[1] = inb(0x3f5);
7301 return_status[2] = inb(0x3f5);
7302 return_status[3] = inb(0x3f5);
7303 return_status[4] = inb(0x3f5);
7304 return_status[5] = inb(0x3f5);
7305 return_status[6] = inb(0x3f5);
7306 // record in BIOS Data Area
7307 write_byte(0x0040, 0x0042, return_status[0]);
7308 write_byte(0x0040, 0x0043, return_status[1]);
7309 write_byte(0x0040, 0x0044, return_status[2]);
7310 write_byte(0x0040, 0x0045, return_status[3]);
7311 write_byte(0x0040, 0x0046, return_status[4]);
7312 write_byte(0x0040, 0x0047, return_status[5]);
7313 write_byte(0x0040, 0x0048, return_status[6]);
7315 if ( (return_status[0] & 0xc0) != 0 ) {
7316 if ( (return_status[1] & 0x02) != 0 ) {
7317 // diskette not writable.
7318 // AH=status code=0x03 (tried to write on write-protected disk)
7319 // AL=number of sectors written=0
7320 AX = 0x0300;
7321 SET_CF();
7322 return;
7323 } else {
7324 BX_PANIC("int13_diskette_function: write error\n");
7328 SET_AH(0);
7329 set_diskette_ret_status(0);
7330 set_diskette_current_cyl(drive, 0);
7331 CLEAR_CF(); // successful
7332 return;
7335 case 0x08: // read diskette drive parameters
7336 BX_DEBUG_INT13_FL("floppy f08\n");
7337 drive = GET_ELDL();
7339 if (drive > 1) {
7340 AX = 0;
7341 BX = 0;
7342 CX = 0;
7343 DX = 0;
7344 ES = 0;
7345 DI = 0;
7346 SET_DL(num_floppies);
7347 SET_CF();
7348 return;
7351 drive_type = inb_cmos(0x10);
7352 num_floppies = 0;
7353 if (drive_type & 0xf0)
7354 num_floppies++;
7355 if (drive_type & 0x0f)
7356 num_floppies++;
7358 if (drive == 0)
7359 drive_type >>= 4;
7360 else
7361 drive_type &= 0x0f;
7363 SET_BH(0);
7364 SET_BL(drive_type);
7365 SET_AH(0);
7366 SET_AL(0);
7367 SET_DL(num_floppies);
7369 switch (drive_type) {
7370 case 0: // none
7371 CX = 0;
7372 SET_DH(0); // max head #
7373 break;
7375 case 1: // 360KB, 5.25"
7376 CX = 0x2709; // 40 tracks, 9 sectors
7377 SET_DH(1); // max head #
7378 break;
7380 case 2: // 1.2MB, 5.25"
7381 CX = 0x4f0f; // 80 tracks, 15 sectors
7382 SET_DH(1); // max head #
7383 break;
7385 case 3: // 720KB, 3.5"
7386 CX = 0x4f09; // 80 tracks, 9 sectors
7387 SET_DH(1); // max head #
7388 break;
7390 case 4: // 1.44MB, 3.5"
7391 CX = 0x4f12; // 80 tracks, 18 sectors
7392 SET_DH(1); // max head #
7393 break;
7395 case 5: // 2.88MB, 3.5"
7396 CX = 0x4f24; // 80 tracks, 36 sectors
7397 SET_DH(1); // max head #
7398 break;
7400 case 6: // 160k, 5.25"
7401 CX = 0x2708; // 40 tracks, 8 sectors
7402 SET_DH(0); // max head #
7403 break;
7405 case 7: // 180k, 5.25"
7406 CX = 0x2709; // 40 tracks, 9 sectors
7407 SET_DH(0); // max head #
7408 break;
7410 case 8: // 320k, 5.25"
7411 CX = 0x2708; // 40 tracks, 8 sectors
7412 SET_DH(1); // max head #
7413 break;
7415 default: // ?
7416 BX_PANIC("floppy: int13: bad floppy type\n");
7419 /* set es & di to point to 11 byte diskette param table in ROM */
7420 ASM_START
7421 push bp
7422 mov bp, sp
7423 mov ax, #diskette_param_table2
7424 mov _int13_diskette_function.DI+2[bp], ax
7425 mov _int13_diskette_function.ES+2[bp], cs
7426 pop bp
7427 ASM_END
7428 CLEAR_CF(); // success
7429 /* disk status not changed upon success */
7430 return;
7433 case 0x15: // read diskette drive type
7434 BX_DEBUG_INT13_FL("floppy f15\n");
7435 drive = GET_ELDL();
7436 if (drive > 1) {
7437 SET_AH(0); // only 2 drives supported
7438 // set_diskette_ret_status here ???
7439 SET_CF();
7440 return;
7442 drive_type = inb_cmos(0x10);
7444 if (drive == 0)
7445 drive_type >>= 4;
7446 else
7447 drive_type &= 0x0f;
7448 CLEAR_CF(); // successful, not present
7449 if (drive_type==0) {
7450 SET_AH(0); // drive not present
7452 else {
7453 SET_AH(1); // drive present, does not support change line
7456 return;
7458 case 0x16: // get diskette change line status
7459 BX_DEBUG_INT13_FL("floppy f16\n");
7460 drive = GET_ELDL();
7461 if (drive > 1) {
7462 SET_AH(0x01); // invalid drive
7463 set_diskette_ret_status(0x01);
7464 SET_CF();
7465 return;
7468 SET_AH(0x06); // change line not supported
7469 set_diskette_ret_status(0x06);
7470 SET_CF();
7471 return;
7473 case 0x17: // set diskette type for format(old)
7474 BX_DEBUG_INT13_FL("floppy f17\n");
7475 /* not used for 1.44M floppies */
7476 SET_AH(0x01); // not supported
7477 set_diskette_ret_status(1); /* not supported */
7478 SET_CF();
7479 return;
7481 case 0x18: // set diskette type for format(new)
7482 BX_DEBUG_INT13_FL("floppy f18\n");
7483 SET_AH(0x01); // do later
7484 set_diskette_ret_status(1);
7485 SET_CF();
7486 return;
7488 default:
7489 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7491 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7492 SET_AH(0x01); // ???
7493 set_diskette_ret_status(1);
7494 SET_CF();
7495 return;
7496 // }
7499 #else // #if BX_SUPPORT_FLOPPY
7500 void
7501 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7502 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7504 Bit8u val8;
7506 switch ( GET_AH() ) {
7508 case 0x01: // Read Diskette Status
7509 CLEAR_CF();
7510 val8 = read_byte(0x0000, 0x0441);
7511 SET_AH(val8);
7512 if (val8) {
7513 SET_CF();
7515 return;
7517 default:
7518 SET_CF();
7519 write_byte(0x0000, 0x0441, 0x01);
7520 SET_AH(0x01);
7523 #endif // #if BX_SUPPORT_FLOPPY
7525 void
7526 set_diskette_ret_status(value)
7527 Bit8u value;
7529 write_byte(0x0040, 0x0041, value);
7532 void
7533 set_diskette_current_cyl(drive, cyl)
7534 Bit8u drive;
7535 Bit8u cyl;
7537 if (drive > 1)
7538 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7539 write_byte(0x0040, 0x0094+drive, cyl);
7542 void
7543 determine_floppy_media(drive)
7544 Bit16u drive;
7546 #if 0
7547 Bit8u val8, DOR, ctrl_info;
7549 ctrl_info = read_byte(0x0040, 0x008F);
7550 if (drive==1)
7551 ctrl_info >>= 4;
7552 else
7553 ctrl_info &= 0x0f;
7555 #if 0
7556 if (drive == 0) {
7557 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7559 else {
7560 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7562 #endif
7564 if ( (ctrl_info & 0x04) != 0x04 ) {
7565 // Drive not determined means no drive exists, done.
7566 return;
7569 #if 0
7570 // check Main Status Register for readiness
7571 val8 = inb(0x03f4) & 0x80; // Main Status Register
7572 if (val8 != 0x80)
7573 BX_PANIC("d_f_m: MRQ bit not set\n");
7575 // change line
7577 // existing BDA values
7579 // turn on drive motor
7580 outb(0x03f2, DOR); // Digital Output Register
7581 //
7582 #endif
7583 BX_PANIC("d_f_m: OK so far\n");
7584 #endif
7587 void
7588 int17_function(regs, ds, iret_addr)
7589 pusha_regs_t regs; // regs pushed from PUSHA instruction
7590 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7591 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7593 Bit16u addr,timeout;
7594 Bit8u val8;
7596 ASM_START
7597 sti
7598 ASM_END
7600 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7601 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7602 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7603 if (regs.u.r8.ah == 0) {
7604 outb(addr, regs.u.r8.al);
7605 val8 = inb(addr+2);
7606 outb(addr+2, val8 | 0x01); // send strobe
7607 ASM_START
7608 nop
7609 ASM_END
7610 outb(addr+2, val8 & ~0x01);
7611 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7612 timeout--;
7615 if (regs.u.r8.ah == 1) {
7616 val8 = inb(addr+2);
7617 outb(addr+2, val8 & ~0x04); // send init
7618 ASM_START
7619 nop
7620 ASM_END
7621 outb(addr+2, val8 | 0x04);
7623 val8 = inb(addr+1);
7624 regs.u.r8.ah = (val8 ^ 0x48);
7625 if (!timeout) regs.u.r8.ah |= 0x01;
7626 ClearCF(iret_addr.flags);
7627 } else {
7628 SetCF(iret_addr.flags); // Unsupported
7632 void
7633 int19_function(seq_nr)
7634 Bit16u seq_nr;
7636 Bit16u ebda_seg=read_word(0x0040,0x000E);
7637 Bit16u bootdev;
7638 Bit8u bootdrv;
7639 Bit8u bootchk;
7640 Bit16u bootseg;
7641 Bit16u bootip;
7642 Bit16u status;
7644 struct ipl_entry e;
7646 // if BX_ELTORITO_BOOT is not defined, old behavior
7647 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7648 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7649 // 0: system boot sequence, first drive C: then A:
7650 // 1: system boot sequence, first drive A: then C:
7651 // else BX_ELTORITO_BOOT is defined
7652 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7653 // CMOS reg 0x3D & 0x0f : 1st boot device
7654 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7655 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7656 // boot device codes:
7657 // 0x00 : not defined
7658 // 0x01 : first floppy
7659 // 0x02 : first harddrive
7660 // 0x03 : first cdrom
7661 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7662 // else : boot failure
7664 // Get the boot sequence
7665 #if BX_ELTORITO_BOOT
7666 bootdev = inb_cmos(0x3d);
7667 bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
7668 bootdev >>= 4 * seq_nr;
7669 bootdev &= 0xf;
7670 if (bootdev == 0) BX_PANIC("No bootable device.\n");
7672 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7673 bootdev -= 1;
7674 #else
7675 if (seq_nr ==2) BX_PANIC("No more boot devices.");
7676 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
7677 /* Boot from floppy if the bit is set or it's the second boot */
7678 bootdev = 0x00;
7679 else
7680 bootdev = 0x01;
7681 #endif
7683 /* Read the boot device from the IPL table */
7684 if (get_boot_vector(bootdev, &e) == 0) {
7685 BX_INFO("Invalid boot device (0x%x)\n", bootdev);
7686 return;
7689 /* Do the loading, and set up vector as a far pointer to the boot
7690 * address, and bootdrv as the boot drive */
7691 print_boot_device(e.type);
7693 switch(e.type) {
7694 case 0x01: /* FDD */
7695 case 0x02: /* HDD */
7697 bootdrv = (e.type == 0x02) ? 0x80 : 0x00;
7698 bootseg = 0x07c0;
7699 status = 0;
7701 ASM_START
7702 push bp
7703 mov bp, sp
7704 push ax
7705 push bx
7706 push cx
7707 push dx
7709 mov dl, _int19_function.bootdrv + 2[bp]
7710 mov ax, _int19_function.bootseg + 2[bp]
7711 mov es, ax ;; segment
7712 mov bx, #0x0000 ;; offset
7713 mov ah, #0x02 ;; function 2, read diskette sector
7714 mov al, #0x01 ;; read 1 sector
7715 mov ch, #0x00 ;; track 0
7716 mov cl, #0x01 ;; sector 1
7717 mov dh, #0x00 ;; head 0
7718 int #0x13 ;; read sector
7719 jnc int19_load_done
7720 mov ax, #0x0001
7721 mov _int19_function.status + 2[bp], ax
7723 int19_load_done:
7724 pop dx
7725 pop cx
7726 pop bx
7727 pop ax
7728 pop bp
7729 ASM_END
7731 if (status != 0) {
7732 print_boot_failure(e.type, 1);
7733 return;
7736 /* Always check the signature on a HDD boot sector; on FDD, only do
7737 * the check if the CMOS doesn't tell us to skip it */
7738 if (e.type != 0x00 || !((inb_cmos(0x38) & 0x01))) {
7739 if (read_word(bootseg,0x1fe) != 0xaa55) {
7740 print_boot_failure(e.type, 0);
7741 return;
7745 /* Canonicalize bootseg:bootip */
7746 bootip = (bootseg & 0x0fff) << 4;
7747 bootseg &= 0xf000;
7748 break;
7750 #if BX_ELTORITO_BOOT
7751 case 0x03: /* CD-ROM */
7752 status = cdrom_boot();
7754 // If failure
7755 if ( (status & 0x00ff) !=0 ) {
7756 print_cdromboot_failure(status);
7757 print_boot_failure(e.type, 1);
7758 return;
7761 bootdrv = (Bit8u)(status>>8);
7762 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7763 /* Canonicalize bootseg:bootip */
7764 bootip = (bootseg & 0x0fff) << 4;
7765 bootseg &= 0xf000;
7766 break;
7767 #endif
7769 case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7770 bootseg = e.vector >> 16;
7771 bootip = e.vector & 0xffff;
7772 break;
7774 default: return;
7777 /* Debugging info */
7778 printf("Booting from %x:%x\n", bootseg, bootip);
7780 /* Jump to the boot vector */
7781 ASM_START
7782 mov bp, sp
7783 ;; Build an iret stack frame that will take us to the boot vector.
7784 ;; iret pops ip, then cs, then flags, so push them in the opposite order.
7785 pushf
7786 mov ax, _int19_function.bootseg + 0[bp]
7787 push ax
7788 mov ax, _int19_function.bootip + 0[bp]
7789 push ax
7790 ;; Set the magic number in ax and the boot drive in dl.
7791 mov ax, #0xaa55
7792 mov dl, _int19_function.bootdrv + 0[bp]
7793 ;; Zero some of the other registers.
7794 xor bx, bx
7795 mov ds, bx
7796 mov es, bx
7797 mov bp, bx
7798 ;; Go!
7799 iret
7800 ASM_END
7803 void
7804 int1a_function(regs, ds, iret_addr)
7805 pusha_regs_t regs; // regs pushed from PUSHA instruction
7806 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7807 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7809 Bit8u val8;
7811 BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
7813 ASM_START
7814 sti
7815 ASM_END
7817 switch (regs.u.r8.ah) {
7818 case 0: // get current clock count
7819 ASM_START
7820 cli
7821 ASM_END
7822 regs.u.r16.cx = BiosData->ticks_high;
7823 regs.u.r16.dx = BiosData->ticks_low;
7824 regs.u.r8.al = BiosData->midnight_flag;
7825 BiosData->midnight_flag = 0; // reset flag
7826 ASM_START
7827 sti
7828 ASM_END
7829 // AH already 0
7830 ClearCF(iret_addr.flags); // OK
7831 break;
7833 case 1: // Set Current Clock Count
7834 ASM_START
7835 cli
7836 ASM_END
7837 BiosData->ticks_high = regs.u.r16.cx;
7838 BiosData->ticks_low = regs.u.r16.dx;
7839 BiosData->midnight_flag = 0; // reset flag
7840 ASM_START
7841 sti
7842 ASM_END
7843 regs.u.r8.ah = 0;
7844 ClearCF(iret_addr.flags); // OK
7845 break;
7848 case 2: // Read CMOS Time
7849 if (rtc_updating()) {
7850 SetCF(iret_addr.flags);
7851 break;
7854 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7855 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7856 regs.u.r8.ch = inb_cmos(0x04); // Hours
7857 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7858 regs.u.r8.ah = 0;
7859 regs.u.r8.al = regs.u.r8.ch;
7860 ClearCF(iret_addr.flags); // OK
7861 break;
7863 case 3: // Set CMOS Time
7864 // Using a debugger, I notice the following masking/setting
7865 // of bits in Status Register B, by setting Reg B to
7866 // a few values and getting its value after INT 1A was called.
7867 //
7868 // try#1 try#2 try#3
7869 // before 1111 1101 0111 1101 0000 0000
7870 // after 0110 0010 0110 0010 0000 0010
7871 //
7872 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7873 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7874 if (rtc_updating()) {
7875 init_rtc();
7876 // fall through as if an update were not in progress
7878 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7879 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7880 outb_cmos(0x04, regs.u.r8.ch); // Hours
7881 // Set Daylight Savings time enabled bit to requested value
7882 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7883 // (reg B already selected)
7884 outb_cmos(0x0b, val8);
7885 regs.u.r8.ah = 0;
7886 regs.u.r8.al = val8; // val last written to Reg B
7887 ClearCF(iret_addr.flags); // OK
7888 break;
7890 case 4: // Read CMOS Date
7891 regs.u.r8.ah = 0;
7892 if (rtc_updating()) {
7893 SetCF(iret_addr.flags);
7894 break;
7896 regs.u.r8.cl = inb_cmos(0x09); // Year
7897 regs.u.r8.dh = inb_cmos(0x08); // Month
7898 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7899 regs.u.r8.ch = inb_cmos(0x32); // Century
7900 regs.u.r8.al = regs.u.r8.ch;
7901 ClearCF(iret_addr.flags); // OK
7902 break;
7904 case 5: // Set CMOS Date
7905 // Using a debugger, I notice the following masking/setting
7906 // of bits in Status Register B, by setting Reg B to
7907 // a few values and getting its value after INT 1A was called.
7908 //
7909 // try#1 try#2 try#3 try#4
7910 // before 1111 1101 0111 1101 0000 0010 0000 0000
7911 // after 0110 1101 0111 1101 0000 0010 0000 0000
7912 //
7913 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7914 // My assumption: RegB = (RegB & 01111111b)
7915 if (rtc_updating()) {
7916 init_rtc();
7917 SetCF(iret_addr.flags);
7918 break;
7920 outb_cmos(0x09, regs.u.r8.cl); // Year
7921 outb_cmos(0x08, regs.u.r8.dh); // Month
7922 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7923 outb_cmos(0x32, regs.u.r8.ch); // Century
7924 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7925 outb_cmos(0x0b, val8);
7926 regs.u.r8.ah = 0;
7927 regs.u.r8.al = val8; // AL = val last written to Reg B
7928 ClearCF(iret_addr.flags); // OK
7929 break;
7931 case 6: // Set Alarm Time in CMOS
7932 // Using a debugger, I notice the following masking/setting
7933 // of bits in Status Register B, by setting Reg B to
7934 // a few values and getting its value after INT 1A was called.
7935 //
7936 // try#1 try#2 try#3
7937 // before 1101 1111 0101 1111 0000 0000
7938 // after 0110 1111 0111 1111 0010 0000
7939 //
7940 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7941 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7942 val8 = inb_cmos(0x0b); // Get Status Reg B
7943 regs.u.r16.ax = 0;
7944 if (val8 & 0x20) {
7945 // Alarm interrupt enabled already
7946 SetCF(iret_addr.flags); // Error: alarm in use
7947 break;
7949 if (rtc_updating()) {
7950 init_rtc();
7951 // fall through as if an update were not in progress
7953 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7954 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7955 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7956 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7957 // enable Status Reg B alarm bit, clear halt clock bit
7958 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7959 ClearCF(iret_addr.flags); // OK
7960 break;
7962 case 7: // Turn off Alarm
7963 // Using a debugger, I notice the following masking/setting
7964 // of bits in Status Register B, by setting Reg B to
7965 // a few values and getting its value after INT 1A was called.
7966 //
7967 // try#1 try#2 try#3 try#4
7968 // before 1111 1101 0111 1101 0010 0000 0010 0010
7969 // after 0100 0101 0101 0101 0000 0000 0000 0010
7970 //
7971 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7972 // My assumption: RegB = (RegB & 01010111b)
7973 val8 = inb_cmos(0x0b); // Get Status Reg B
7974 // clear clock-halt bit, disable alarm bit
7975 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7976 regs.u.r8.ah = 0;
7977 regs.u.r8.al = val8; // val last written to Reg B
7978 ClearCF(iret_addr.flags); // OK
7979 break;
7980 #if BX_PCIBIOS
7981 case 0xb1:
7982 // real mode PCI BIOS functions now handled in assembler code
7983 // this C code handles the error code for information only
7984 if (regs.u.r8.bl == 0xff) {
7985 BX_INFO("PCI BIOS: PCI not present\n");
7986 } else if (regs.u.r8.bl == 0x81) {
7987 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7988 } else if (regs.u.r8.bl == 0x83) {
7989 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7990 } else if (regs.u.r8.bl == 0x86) {
7991 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7993 regs.u.r8.ah = regs.u.r8.bl;
7994 SetCF(iret_addr.flags);
7995 break;
7996 #endif
7998 default:
7999 SetCF(iret_addr.flags); // Unsupported
8003 void
8004 int70_function(regs, ds, iret_addr)
8005 pusha_regs_t regs; // regs pushed from PUSHA instruction
8006 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8007 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8009 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8010 Bit8u registerB = 0, registerC = 0;
8012 // Check which modes are enabled and have occurred.
8013 registerB = inb_cmos( 0xB );
8014 registerC = inb_cmos( 0xC );
8016 if( ( registerB & 0x60 ) != 0 ) {
8017 if( ( registerC & 0x20 ) != 0 ) {
8018 // Handle Alarm Interrupt.
8019 ASM_START
8020 sti
8021 int #0x4a
8022 cli
8023 ASM_END
8025 if( ( registerC & 0x40 ) != 0 ) {
8026 // Handle Periodic Interrupt.
8028 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8029 // Wait Interval (Int 15, AH=83) active.
8030 Bit32u time, toggle;
8032 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8033 if( time < 0x3D1 ) {
8034 // Done waiting.
8035 Bit16u segment, offset;
8037 offset = read_word( 0x40, 0x98 );
8038 segment = read_word( 0x40, 0x9A );
8039 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8040 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8041 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8042 } else {
8043 // Continue waiting.
8044 time -= 0x3D1;
8045 write_dword( 0x40, 0x9C, time );
8051 ASM_START
8052 call eoi_both_pics
8053 ASM_END
8057 ASM_START
8058 ;------------------------------------------
8059 ;- INT74h : PS/2 mouse hardware interrupt -
8060 ;------------------------------------------
8061 int74_handler:
8062 sti
8063 pusha
8064 push ds ;; save DS
8065 push #0x00 ;; placeholder for status
8066 push #0x00 ;; placeholder for X
8067 push #0x00 ;; placeholder for Y
8068 push #0x00 ;; placeholder for Z
8069 push #0x00 ;; placeholder for make_far_call boolean
8070 call _int74_function
8071 pop cx ;; remove make_far_call from stack
8072 jcxz int74_done
8074 ;; make far call to EBDA:0022
8075 push #0x00
8076 pop ds
8077 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8078 pop ds
8079 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8080 call far ptr[0x22]
8081 int74_done:
8082 cli
8083 call eoi_both_pics
8084 add sp, #8 ;; pop status, x, y, z
8086 pop ds ;; restore DS
8087 popa
8088 iret
8091 ;; This will perform an IRET, but will retain value of current CF
8092 ;; by altering flags on stack. Better than RETF #02.
8093 iret_modify_cf:
8094 jc carry_set
8095 push bp
8096 mov bp, sp
8097 and BYTE [bp + 0x06], #0xfe
8098 pop bp
8099 iret
8100 carry_set:
8101 push bp
8102 mov bp, sp
8103 or BYTE [bp + 0x06], #0x01
8104 pop bp
8105 iret
8108 ;----------------------
8109 ;- INT13h (relocated) -
8110 ;----------------------
8112 ; int13_relocated is a little bit messed up since I played with it
8113 ; I have to rewrite it:
8114 ; - call a function that detect which function to call
8115 ; - make all called C function get the same parameters list
8117 int13_relocated:
8119 #if BX_ELTORITO_BOOT
8120 ;; check for an eltorito function
8121 cmp ah,#0x4a
8122 jb int13_not_eltorito
8123 cmp ah,#0x4d
8124 ja int13_not_eltorito
8126 pusha
8127 push es
8128 push ds
8129 push ss
8130 pop ds
8132 push #int13_out
8133 jmp _int13_eltorito ;; ELDX not used
8135 int13_not_eltorito:
8136 push ax
8137 push bx
8138 push cx
8139 push dx
8141 ;; check if emulation active
8142 call _cdemu_isactive
8143 cmp al,#0x00
8144 je int13_cdemu_inactive
8146 ;; check if access to the emulated drive
8147 call _cdemu_emulated_drive
8148 pop dx
8149 push dx
8150 cmp al,dl ;; int13 on emulated drive
8151 jne int13_nocdemu
8153 pop dx
8154 pop cx
8155 pop bx
8156 pop ax
8158 pusha
8159 push es
8160 push ds
8161 push ss
8162 pop ds
8164 push #int13_out
8165 jmp _int13_cdemu ;; ELDX not used
8167 int13_nocdemu:
8168 and dl,#0xE0 ;; mask to get device class, including cdroms
8169 cmp al,dl ;; al is 0x00 or 0x80
8170 jne int13_cdemu_inactive ;; inactive for device class
8172 pop dx
8173 pop cx
8174 pop bx
8175 pop ax
8177 push ax
8178 push cx
8179 push dx
8180 push bx
8182 dec dl ;; real drive is dl - 1
8183 jmp int13_legacy
8185 int13_cdemu_inactive:
8186 pop dx
8187 pop cx
8188 pop bx
8189 pop ax
8191 #endif // BX_ELTORITO_BOOT
8193 int13_noeltorito:
8195 push ax
8196 push cx
8197 push dx
8198 push bx
8200 int13_legacy:
8202 push dx ;; push eltorito value of dx instead of sp
8204 push bp
8205 push si
8206 push di
8208 push es
8209 push ds
8210 push ss
8211 pop ds
8213 ;; now the 16-bit registers can be restored with:
8214 ;; pop ds; pop es; popa; iret
8215 ;; arguments passed to functions should be
8216 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8218 test dl, #0x80
8219 jnz int13_notfloppy
8221 push #int13_out
8222 jmp _int13_diskette_function
8224 int13_notfloppy:
8226 #if BX_USE_ATADRV
8228 cmp dl, #0xE0
8229 jb int13_notcdrom
8231 // ebx is modified: BSD 5.2.1 boot loader problem
8232 // someone should figure out which 32 bit register that actually are used
8234 shr ebx, #16
8235 push bx
8237 call _int13_cdrom
8239 pop bx
8240 shl ebx, #16
8242 jmp int13_out
8244 int13_notcdrom:
8246 #endif
8248 int13_disk:
8249 call _int13_harddisk
8251 int13_out:
8252 pop ds
8253 pop es
8254 popa
8255 iret
8257 ;----------
8258 ;- INT18h -
8259 ;----------
8260 int18_handler: ;; Boot Failure recovery: try the next device.
8262 ;; Reset SP and SS
8263 mov ax, #0xfffe
8264 mov sp, ax
8265 xor ax, ax
8266 mov ss, ax
8268 ;; Get the boot sequence number out of the IPL memory
8269 mov bx, #IPL_SEG
8270 mov ds, bx ;; Set segment
8271 mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number
8272 inc bx ;; ++
8273 mov IPL_SEQUENCE_OFFSET, bx ;; Write it back
8274 mov ds, ax ;; and reset the segment to zero.
8276 ;; Carry on in the INT 19h handler, using the new sequence number
8277 push bx
8279 jmp int19_next_boot
8281 ;----------
8282 ;- INT19h -
8283 ;----------
8284 int19_relocated: ;; Boot function, relocated
8286 ;; int19 was beginning to be really complex, so now it
8287 ;; just calls a C function that does the work
8289 push bp
8290 mov bp, sp
8292 ;; Reset SS and SP
8293 mov ax, #0xfffe
8294 mov sp, ax
8295 xor ax, ax
8296 mov ss, ax
8298 ;; Start from the first boot device (0, in AX)
8299 mov bx, #IPL_SEG
8300 mov ds, bx ;; Set segment to write to the IPL memory
8301 mov IPL_SEQUENCE_OFFSET, ax ;; Save the sequence number
8302 mov ds, ax ;; and reset the segment.
8304 push ax
8306 int19_next_boot:
8308 ;; Call the C code for the next boot device
8309 call _int19_function
8311 ;; Boot failed: invoke the boot recovery function
8312 int #0x18
8314 ;----------
8315 ;- INT1Ch -
8316 ;----------
8317 int1c_handler: ;; User Timer Tick
8318 iret
8321 ;----------------------
8322 ;- POST: Floppy Drive -
8323 ;----------------------
8324 floppy_drive_post:
8325 mov ax, #0x0000
8326 mov ds, ax
8328 mov al, #0x00
8329 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8331 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8333 mov 0x0440, al ;; diskette motor timeout counter: not active
8334 mov 0x0441, al ;; diskette controller status return code
8336 mov 0x0442, al ;; disk & diskette controller status register 0
8337 mov 0x0443, al ;; diskette controller status register 1
8338 mov 0x0444, al ;; diskette controller status register 2
8339 mov 0x0445, al ;; diskette controller cylinder number
8340 mov 0x0446, al ;; diskette controller head number
8341 mov 0x0447, al ;; diskette controller sector number
8342 mov 0x0448, al ;; diskette controller bytes written
8344 mov 0x048b, al ;; diskette configuration data
8346 ;; -----------------------------------------------------------------
8347 ;; (048F) diskette controller information
8348 ;;
8349 mov al, #0x10 ;; get CMOS diskette drive type
8350 out 0x70, AL
8351 in AL, 0x71
8352 mov ah, al ;; save byte to AH
8354 look_drive0:
8355 shr al, #4 ;; look at top 4 bits for drive 0
8356 jz f0_missing ;; jump if no drive0
8357 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8358 jmp look_drive1
8359 f0_missing:
8360 mov bl, #0x00 ;; no drive0
8362 look_drive1:
8363 mov al, ah ;; restore from AH
8364 and al, #0x0f ;; look at bottom 4 bits for drive 1
8365 jz f1_missing ;; jump if no drive1
8366 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8367 f1_missing:
8368 ;; leave high bits in BL zerod
8369 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8370 ;; -----------------------------------------------------------------
8372 mov al, #0x00
8373 mov 0x0490, al ;; diskette 0 media state
8374 mov 0x0491, al ;; diskette 1 media state
8376 ;; diskette 0,1 operational starting state
8377 ;; drive type has not been determined,
8378 ;; has no changed detection line
8379 mov 0x0492, al
8380 mov 0x0493, al
8382 mov 0x0494, al ;; diskette 0 current cylinder
8383 mov 0x0495, al ;; diskette 1 current cylinder
8385 mov al, #0x02
8386 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8388 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8389 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8390 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8392 ret
8395 ;--------------------
8396 ;- POST: HARD DRIVE -
8397 ;--------------------
8398 ; relocated here because the primary POST area isnt big enough.
8399 hard_drive_post:
8400 // IRQ 14 = INT 76h
8401 // INT 76h calls INT 15h function ax=9100
8403 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8404 mov dx, #0x03f6
8405 out dx, al
8407 mov ax, #0x0000
8408 mov ds, ax
8409 mov 0x0474, al /* hard disk status of last operation */
8410 mov 0x0477, al /* hard disk port offset (XT only ???) */
8411 mov 0x048c, al /* hard disk status register */
8412 mov 0x048d, al /* hard disk error register */
8413 mov 0x048e, al /* hard disk task complete flag */
8414 mov al, #0x01
8415 mov 0x0475, al /* hard disk number attached */
8416 mov al, #0xc0
8417 mov 0x0476, al /* hard disk control byte */
8418 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8419 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8420 ;; INT 41h: hard disk 0 configuration pointer
8421 ;; INT 46h: hard disk 1 configuration pointer
8422 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8423 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8425 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8426 mov al, #0x12
8427 out #0x70, al
8428 in al, #0x71
8429 and al, #0xf0
8430 cmp al, #0xf0
8431 je post_d0_extended
8432 jmp check_for_hd1
8433 post_d0_extended:
8434 mov al, #0x19
8435 out #0x70, al
8436 in al, #0x71
8437 cmp al, #47 ;; decimal 47 - user definable
8438 je post_d0_type47
8439 HALT(__LINE__)
8440 post_d0_type47:
8441 ;; CMOS purpose param table offset
8442 ;; 1b cylinders low 0
8443 ;; 1c cylinders high 1
8444 ;; 1d heads 2
8445 ;; 1e write pre-comp low 5
8446 ;; 1f write pre-comp high 6
8447 ;; 20 retries/bad map/heads>8 8
8448 ;; 21 landing zone low C
8449 ;; 22 landing zone high D
8450 ;; 23 sectors/track E
8452 mov ax, #EBDA_SEG
8453 mov ds, ax
8455 ;;; Filling EBDA table for hard disk 0.
8456 mov al, #0x1f
8457 out #0x70, al
8458 in al, #0x71
8459 mov ah, al
8460 mov al, #0x1e
8461 out #0x70, al
8462 in al, #0x71
8463 mov (0x003d + 0x05), ax ;; write precomp word
8465 mov al, #0x20
8466 out #0x70, al
8467 in al, #0x71
8468 mov (0x003d + 0x08), al ;; drive control byte
8470 mov al, #0x22
8471 out #0x70, al
8472 in al, #0x71
8473 mov ah, al
8474 mov al, #0x21
8475 out #0x70, al
8476 in al, #0x71
8477 mov (0x003d + 0x0C), ax ;; landing zone word
8479 mov al, #0x1c ;; get cylinders word in AX
8480 out #0x70, al
8481 in al, #0x71 ;; high byte
8482 mov ah, al
8483 mov al, #0x1b
8484 out #0x70, al
8485 in al, #0x71 ;; low byte
8486 mov bx, ax ;; BX = cylinders
8488 mov al, #0x1d
8489 out #0x70, al
8490 in al, #0x71
8491 mov cl, al ;; CL = heads
8493 mov al, #0x23
8494 out #0x70, al
8495 in al, #0x71
8496 mov dl, al ;; DL = sectors
8498 cmp bx, #1024
8499 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8501 hd0_post_physical_chs:
8502 ;; no logical CHS mapping used, just physical CHS
8503 ;; use Standard Fixed Disk Parameter Table (FDPT)
8504 mov (0x003d + 0x00), bx ;; number of physical cylinders
8505 mov (0x003d + 0x02), cl ;; number of physical heads
8506 mov (0x003d + 0x0E), dl ;; number of physical sectors
8507 jmp check_for_hd1
8509 hd0_post_logical_chs:
8510 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8511 mov (0x003d + 0x09), bx ;; number of physical cylinders
8512 mov (0x003d + 0x0b), cl ;; number of physical heads
8513 mov (0x003d + 0x04), dl ;; number of physical sectors
8514 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8515 mov al, #0xa0
8516 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8518 cmp bx, #2048
8519 jnbe hd0_post_above_2048
8520 ;; 1024 < c <= 2048 cylinders
8521 shr bx, #0x01
8522 shl cl, #0x01
8523 jmp hd0_post_store_logical
8525 hd0_post_above_2048:
8526 cmp bx, #4096
8527 jnbe hd0_post_above_4096
8528 ;; 2048 < c <= 4096 cylinders
8529 shr bx, #0x02
8530 shl cl, #0x02
8531 jmp hd0_post_store_logical
8533 hd0_post_above_4096:
8534 cmp bx, #8192
8535 jnbe hd0_post_above_8192
8536 ;; 4096 < c <= 8192 cylinders
8537 shr bx, #0x03
8538 shl cl, #0x03
8539 jmp hd0_post_store_logical
8541 hd0_post_above_8192:
8542 ;; 8192 < c <= 16384 cylinders
8543 shr bx, #0x04
8544 shl cl, #0x04
8546 hd0_post_store_logical:
8547 mov (0x003d + 0x00), bx ;; number of physical cylinders
8548 mov (0x003d + 0x02), cl ;; number of physical heads
8549 ;; checksum
8550 mov cl, #0x0f ;; repeat count
8551 mov si, #0x003d ;; offset to disk0 FDPT
8552 mov al, #0x00 ;; sum
8553 hd0_post_checksum_loop:
8554 add al, [si]
8555 inc si
8556 dec cl
8557 jnz hd0_post_checksum_loop
8558 not al ;; now take 2s complement
8559 inc al
8560 mov [si], al
8561 ;;; Done filling EBDA table for hard disk 0.
8564 check_for_hd1:
8565 ;; is there really a second hard disk? if not, return now
8566 mov al, #0x12
8567 out #0x70, al
8568 in al, #0x71
8569 and al, #0x0f
8570 jnz post_d1_exists
8571 ret
8572 post_d1_exists:
8573 ;; check that the hd type is really 0x0f.
8574 cmp al, #0x0f
8575 jz post_d1_extended
8576 HALT(__LINE__)
8577 post_d1_extended:
8578 ;; check that the extended type is 47 - user definable
8579 mov al, #0x1a
8580 out #0x70, al
8581 in al, #0x71
8582 cmp al, #47 ;; decimal 47 - user definable
8583 je post_d1_type47
8584 HALT(__LINE__)
8585 post_d1_type47:
8586 ;; Table for disk1.
8587 ;; CMOS purpose param table offset
8588 ;; 0x24 cylinders low 0
8589 ;; 0x25 cylinders high 1
8590 ;; 0x26 heads 2
8591 ;; 0x27 write pre-comp low 5
8592 ;; 0x28 write pre-comp high 6
8593 ;; 0x29 heads>8 8
8594 ;; 0x2a landing zone low C
8595 ;; 0x2b landing zone high D
8596 ;; 0x2c sectors/track E
8597 ;;; Fill EBDA table for hard disk 1.
8598 mov ax, #EBDA_SEG
8599 mov ds, ax
8600 mov al, #0x28
8601 out #0x70, al
8602 in al, #0x71
8603 mov ah, al
8604 mov al, #0x27
8605 out #0x70, al
8606 in al, #0x71
8607 mov (0x004d + 0x05), ax ;; write precomp word
8609 mov al, #0x29
8610 out #0x70, al
8611 in al, #0x71
8612 mov (0x004d + 0x08), al ;; drive control byte
8614 mov al, #0x2b
8615 out #0x70, al
8616 in al, #0x71
8617 mov ah, al
8618 mov al, #0x2a
8619 out #0x70, al
8620 in al, #0x71
8621 mov (0x004d + 0x0C), ax ;; landing zone word
8623 mov al, #0x25 ;; get cylinders word in AX
8624 out #0x70, al
8625 in al, #0x71 ;; high byte
8626 mov ah, al
8627 mov al, #0x24
8628 out #0x70, al
8629 in al, #0x71 ;; low byte
8630 mov bx, ax ;; BX = cylinders
8632 mov al, #0x26
8633 out #0x70, al
8634 in al, #0x71
8635 mov cl, al ;; CL = heads
8637 mov al, #0x2c
8638 out #0x70, al
8639 in al, #0x71
8640 mov dl, al ;; DL = sectors
8642 cmp bx, #1024
8643 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8645 hd1_post_physical_chs:
8646 ;; no logical CHS mapping used, just physical CHS
8647 ;; use Standard Fixed Disk Parameter Table (FDPT)
8648 mov (0x004d + 0x00), bx ;; number of physical cylinders
8649 mov (0x004d + 0x02), cl ;; number of physical heads
8650 mov (0x004d + 0x0E), dl ;; number of physical sectors
8651 ret
8653 hd1_post_logical_chs:
8654 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8655 mov (0x004d + 0x09), bx ;; number of physical cylinders
8656 mov (0x004d + 0x0b), cl ;; number of physical heads
8657 mov (0x004d + 0x04), dl ;; number of physical sectors
8658 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8659 mov al, #0xa0
8660 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8662 cmp bx, #2048
8663 jnbe hd1_post_above_2048
8664 ;; 1024 < c <= 2048 cylinders
8665 shr bx, #0x01
8666 shl cl, #0x01
8667 jmp hd1_post_store_logical
8669 hd1_post_above_2048:
8670 cmp bx, #4096
8671 jnbe hd1_post_above_4096
8672 ;; 2048 < c <= 4096 cylinders
8673 shr bx, #0x02
8674 shl cl, #0x02
8675 jmp hd1_post_store_logical
8677 hd1_post_above_4096:
8678 cmp bx, #8192
8679 jnbe hd1_post_above_8192
8680 ;; 4096 < c <= 8192 cylinders
8681 shr bx, #0x03
8682 shl cl, #0x03
8683 jmp hd1_post_store_logical
8685 hd1_post_above_8192:
8686 ;; 8192 < c <= 16384 cylinders
8687 shr bx, #0x04
8688 shl cl, #0x04
8690 hd1_post_store_logical:
8691 mov (0x004d + 0x00), bx ;; number of physical cylinders
8692 mov (0x004d + 0x02), cl ;; number of physical heads
8693 ;; checksum
8694 mov cl, #0x0f ;; repeat count
8695 mov si, #0x004d ;; offset to disk0 FDPT
8696 mov al, #0x00 ;; sum
8697 hd1_post_checksum_loop:
8698 add al, [si]
8699 inc si
8700 dec cl
8701 jnz hd1_post_checksum_loop
8702 not al ;; now take 2s complement
8703 inc al
8704 mov [si], al
8705 ;;; Done filling EBDA table for hard disk 1.
8707 ret
8709 ;--------------------
8710 ;- POST: EBDA segment
8711 ;--------------------
8712 ; relocated here because the primary POST area isnt big enough.
8713 ebda_post:
8714 #if BX_USE_EBDA
8715 mov ax, #EBDA_SEG
8716 mov ds, ax
8717 mov byte ptr [0x0], #EBDA_SIZE
8718 #endif
8719 xor ax, ax ; mov EBDA seg into 40E
8720 mov ds, ax
8721 mov word ptr [0x40E], #EBDA_SEG
8722 ret;;
8724 ;--------------------
8725 ;- POST: EOI + jmp via [0x40:67)
8726 ;--------------------
8727 ; relocated here because the primary POST area isnt big enough.
8728 eoi_jmp_post:
8729 call eoi_both_pics
8731 xor ax, ax
8732 mov ds, ax
8734 jmp far ptr [0x467]
8737 ;--------------------
8738 eoi_both_pics:
8739 mov al, #0x20
8740 out #0xA0, al ;; slave PIC EOI
8741 eoi_master_pic:
8742 mov al, #0x20
8743 out #0x20, al ;; master PIC EOI
8744 ret
8746 ;--------------------
8747 BcdToBin:
8748 ;; in: AL in BCD format
8749 ;; out: AL in binary format, AH will always be 0
8750 ;; trashes BX
8751 mov bl, al
8752 and bl, #0x0f ;; bl has low digit
8753 shr al, #4 ;; al has high digit
8754 mov bh, #10
8755 mul al, bh ;; multiply high digit by 10 (result in AX)
8756 add al, bl ;; then add low digit
8757 ret
8759 ;--------------------
8760 timer_tick_post:
8761 ;; Setup the Timer Ticks Count (0x46C:dword) and
8762 ;; Timer Ticks Roller Flag (0x470:byte)
8763 ;; The Timer Ticks Count needs to be set according to
8764 ;; the current CMOS time, as if ticks have been occurring
8765 ;; at 18.2hz since midnight up to this point. Calculating
8766 ;; this is a little complicated. Here are the factors I gather
8767 ;; regarding this. 14,318,180 hz was the original clock speed,
8768 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8769 ;; at the time, or 4 to drive the CGA video adapter. The div3
8770 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8771 ;; the timer. With a maximum 16bit timer count, this is again
8772 ;; divided down by 65536 to 18.2hz.
8773 ;;
8774 ;; 14,318,180 Hz clock
8775 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8776 ;; /4 = 1,193,181 Hz fed to timer
8777 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8778 ;; 1 second = 18.20650736 ticks
8779 ;; 1 minute = 1092.390442 ticks
8780 ;; 1 hour = 65543.42651 ticks
8781 ;;
8782 ;; Given the values in the CMOS clock, one could calculate
8783 ;; the number of ticks by the following:
8784 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8785 ;; (BcdToBin(minutes) * 1092.3904)
8786 ;; (BcdToBin(hours) * 65543.427)
8787 ;; To get a little more accuracy, since Im using integer
8788 ;; arithmatic, I use:
8789 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8790 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8791 ;; (BcdToBin(hours) * 65543427) / 1000
8793 ;; assuming DS=0000
8795 ;; get CMOS seconds
8796 xor eax, eax ;; clear EAX
8797 mov al, #0x00
8798 out #0x70, al
8799 in al, #0x71 ;; AL has CMOS seconds in BCD
8800 call BcdToBin ;; EAX now has seconds in binary
8801 mov edx, #18206507
8802 mul eax, edx
8803 mov ebx, #1000000
8804 xor edx, edx
8805 div eax, ebx
8806 mov ecx, eax ;; ECX will accumulate total ticks
8808 ;; get CMOS minutes
8809 xor eax, eax ;; clear EAX
8810 mov al, #0x02
8811 out #0x70, al
8812 in al, #0x71 ;; AL has CMOS minutes in BCD
8813 call BcdToBin ;; EAX now has minutes in binary
8814 mov edx, #10923904
8815 mul eax, edx
8816 mov ebx, #10000
8817 xor edx, edx
8818 div eax, ebx
8819 add ecx, eax ;; add to total ticks
8821 ;; get CMOS hours
8822 xor eax, eax ;; clear EAX
8823 mov al, #0x04
8824 out #0x70, al
8825 in al, #0x71 ;; AL has CMOS hours in BCD
8826 call BcdToBin ;; EAX now has hours in binary
8827 mov edx, #65543427
8828 mul eax, edx
8829 mov ebx, #1000
8830 xor edx, edx
8831 div eax, ebx
8832 add ecx, eax ;; add to total ticks
8834 mov 0x46C, ecx ;; Timer Ticks Count
8835 xor al, al
8836 mov 0x470, al ;; Timer Ticks Rollover Flag
8837 ret
8839 ;--------------------
8840 int76_handler:
8841 ;; record completion in BIOS task complete flag
8842 push ax
8843 push ds
8844 mov ax, #0x0040
8845 mov ds, ax
8846 mov 0x008E, #0xff
8847 call eoi_both_pics
8848 pop ds
8849 pop ax
8850 iret
8853 ;--------------------
8854 #if BX_APM
8856 use32 386
8857 #define APM_PROT32
8858 #include "apmbios.S"
8860 use16 386
8861 #define APM_PROT16
8862 #include "apmbios.S"
8864 #define APM_REAL
8865 #include "apmbios.S"
8867 #endif
8869 ASM_END
8870 #include "32bitgateway.c"
8871 ASM_START
8873 ;--------------------
8874 #if BX_PCIBIOS
8875 use32 386
8876 .align 16
8877 bios32_structure:
8878 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8879 dw bios32_entry_point, 0xf ;; 32 bit physical address
8880 db 0 ;; revision level
8881 ;; length in paragraphs and checksum stored in a word to prevent errors
8882 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8883 & 0xff) << 8) + 0x01
8884 db 0,0,0,0,0 ;; reserved
8886 .align 16
8887 bios32_entry_point:
8888 pushf
8889 cmp eax, #0x49435024
8890 jne unknown_service
8891 mov eax, #0x80000000
8892 mov dx, #0x0cf8
8893 out dx, eax
8894 mov dx, #0x0cfc
8895 in eax, dx
8896 cmp eax, #0x12378086
8897 jne unknown_service
8898 mov ebx, #0x000f0000
8899 mov ecx, #0
8900 mov edx, #pcibios_protected
8901 xor al, al
8902 jmp bios32_end
8903 unknown_service:
8904 mov al, #0x80
8905 bios32_end:
8906 popf
8907 retf
8909 .align 16
8910 pcibios_protected:
8911 pushf
8912 cli
8913 push esi
8914 push edi
8915 cmp al, #0x01 ;; installation check
8916 jne pci_pro_f02
8917 mov bx, #0x0210
8918 mov cx, #0
8919 mov edx, #0x20494350
8920 mov al, #0x01
8921 jmp pci_pro_ok
8922 pci_pro_f02: ;; find pci device
8923 cmp al, #0x02
8924 jne pci_pro_f08
8925 shl ecx, #16
8926 mov cx, dx
8927 mov bx, #0x0000
8928 mov di, #0x00
8929 pci_pro_devloop:
8930 call pci_pro_select_reg
8931 mov dx, #0x0cfc
8932 in eax, dx
8933 cmp eax, ecx
8934 jne pci_pro_nextdev
8935 cmp si, #0
8936 je pci_pro_ok
8937 dec si
8938 pci_pro_nextdev:
8939 inc bx
8940 cmp bx, #0x0100
8941 jne pci_pro_devloop
8942 mov ah, #0x86
8943 jmp pci_pro_fail
8944 pci_pro_f08: ;; read configuration byte
8945 cmp al, #0x08
8946 jne pci_pro_f09
8947 call pci_pro_select_reg
8948 push edx
8949 mov dx, di
8950 and dx, #0x03
8951 add dx, #0x0cfc
8952 in al, dx
8953 pop edx
8954 mov cl, al
8955 jmp pci_pro_ok
8956 pci_pro_f09: ;; read configuration word
8957 cmp al, #0x09
8958 jne pci_pro_f0a
8959 call pci_pro_select_reg
8960 push edx
8961 mov dx, di
8962 and dx, #0x02
8963 add dx, #0x0cfc
8964 in ax, dx
8965 pop edx
8966 mov cx, ax
8967 jmp pci_pro_ok
8968 pci_pro_f0a: ;; read configuration dword
8969 cmp al, #0x0a
8970 jne pci_pro_f0b
8971 call pci_pro_select_reg
8972 push edx
8973 mov dx, #0x0cfc
8974 in eax, dx
8975 pop edx
8976 mov ecx, eax
8977 jmp pci_pro_ok
8978 pci_pro_f0b: ;; write configuration byte
8979 cmp al, #0x0b
8980 jne pci_pro_f0c
8981 call pci_pro_select_reg
8982 push edx
8983 mov dx, di
8984 and dx, #0x03
8985 add dx, #0x0cfc
8986 mov al, cl
8987 out dx, al
8988 pop edx
8989 jmp pci_pro_ok
8990 pci_pro_f0c: ;; write configuration word
8991 cmp al, #0x0c
8992 jne pci_pro_f0d
8993 call pci_pro_select_reg
8994 push edx
8995 mov dx, di
8996 and dx, #0x02
8997 add dx, #0x0cfc
8998 mov ax, cx
8999 out dx, ax
9000 pop edx
9001 jmp pci_pro_ok
9002 pci_pro_f0d: ;; write configuration dword
9003 cmp al, #0x0d
9004 jne pci_pro_unknown
9005 call pci_pro_select_reg
9006 push edx
9007 mov dx, #0x0cfc
9008 mov eax, ecx
9009 out dx, eax
9010 pop edx
9011 jmp pci_pro_ok
9012 pci_pro_unknown:
9013 mov ah, #0x81
9014 pci_pro_fail:
9015 pop edi
9016 pop esi
9017 sti
9018 popf
9019 stc
9020 retf
9021 pci_pro_ok:
9022 xor ah, ah
9023 pop edi
9024 pop esi
9025 sti
9026 popf
9027 clc
9028 retf
9030 pci_pro_select_reg:
9031 push edx
9032 mov eax, #0x800000
9033 mov ax, bx
9034 shl eax, #8
9035 and di, #0xff
9036 or ax, di
9037 and al, #0xfc
9038 mov dx, #0x0cf8
9039 out dx, eax
9040 pop edx
9041 ret
9043 use16 386
9045 pcibios_real:
9046 push eax
9047 push dx
9048 mov eax, #0x80000000
9049 mov dx, #0x0cf8
9050 out dx, eax
9051 mov dx, #0x0cfc
9052 in eax, dx
9053 cmp eax, #0x12378086
9054 je pci_present
9055 pop dx
9056 pop eax
9057 mov ah, #0xff
9058 stc
9059 ret
9060 pci_present:
9061 pop dx
9062 pop eax
9063 cmp al, #0x01 ;; installation check
9064 jne pci_real_f02
9065 mov ax, #0x0001
9066 mov bx, #0x0210
9067 mov cx, #0
9068 mov edx, #0x20494350
9069 mov edi, #0xf0000
9070 mov di, #pcibios_protected
9071 clc
9072 ret
9073 pci_real_f02: ;; find pci device
9074 push esi
9075 push edi
9076 cmp al, #0x02
9077 jne pci_real_f08
9078 shl ecx, #16
9079 mov cx, dx
9080 mov bx, #0x0000
9081 mov di, #0x00
9082 pci_real_devloop:
9083 call pci_real_select_reg
9084 mov dx, #0x0cfc
9085 in eax, dx
9086 cmp eax, ecx
9087 jne pci_real_nextdev
9088 cmp si, #0
9089 je pci_real_ok
9090 dec si
9091 pci_real_nextdev:
9092 inc bx
9093 cmp bx, #0x0100
9094 jne pci_real_devloop
9095 mov dx, cx
9096 shr ecx, #16
9097 mov ah, #0x86
9098 jmp pci_real_fail
9099 pci_real_f08: ;; read configuration byte
9100 cmp al, #0x08
9101 jne pci_real_f09
9102 call pci_real_select_reg
9103 push dx
9104 mov dx, di
9105 and dx, #0x03
9106 add dx, #0x0cfc
9107 in al, dx
9108 pop dx
9109 mov cl, al
9110 jmp pci_real_ok
9111 pci_real_f09: ;; read configuration word
9112 cmp al, #0x09
9113 jne pci_real_f0a
9114 call pci_real_select_reg
9115 push dx
9116 mov dx, di
9117 and dx, #0x02
9118 add dx, #0x0cfc
9119 in ax, dx
9120 pop dx
9121 mov cx, ax
9122 jmp pci_real_ok
9123 pci_real_f0a: ;; read configuration dword
9124 cmp al, #0x0a
9125 jne pci_real_f0b
9126 call pci_real_select_reg
9127 push dx
9128 mov dx, #0x0cfc
9129 in eax, dx
9130 pop dx
9131 mov ecx, eax
9132 jmp pci_real_ok
9133 pci_real_f0b: ;; write configuration byte
9134 cmp al, #0x0b
9135 jne pci_real_f0c
9136 call pci_real_select_reg
9137 push dx
9138 mov dx, di
9139 and dx, #0x03
9140 add dx, #0x0cfc
9141 mov al, cl
9142 out dx, al
9143 pop dx
9144 jmp pci_real_ok
9145 pci_real_f0c: ;; write configuration word
9146 cmp al, #0x0c
9147 jne pci_real_f0d
9148 call pci_real_select_reg
9149 push dx
9150 mov dx, di
9151 and dx, #0x02
9152 add dx, #0x0cfc
9153 mov ax, cx
9154 out dx, ax
9155 pop dx
9156 jmp pci_real_ok
9157 pci_real_f0d: ;; write configuration dword
9158 cmp al, #0x0d
9159 jne pci_real_unknown
9160 call pci_real_select_reg
9161 push dx
9162 mov dx, #0x0cfc
9163 mov eax, ecx
9164 out dx, eax
9165 pop dx
9166 jmp pci_real_ok
9167 pci_real_unknown:
9168 mov ah, #0x81
9169 pci_real_fail:
9170 pop edi
9171 pop esi
9172 stc
9173 ret
9174 pci_real_ok:
9175 xor ah, ah
9176 pop edi
9177 pop esi
9178 clc
9179 ret
9181 pci_real_select_reg:
9182 push dx
9183 mov eax, #0x800000
9184 mov ax, bx
9185 shl eax, #8
9186 and di, #0xff
9187 or ax, di
9188 and al, #0xfc
9189 mov dx, #0x0cf8
9190 out dx, eax
9191 pop dx
9192 ret
9194 .align 16
9195 pci_routing_table_structure:
9196 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9197 db 0, 1 ;; version
9198 dw 32 + (6 * 16) ;; table size
9199 db 0 ;; PCI interrupt router bus
9200 db 0x08 ;; PCI interrupt router DevFunc
9201 dw 0x0000 ;; PCI exclusive IRQs
9202 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9203 dw 0x7000 ;; compatible PCI interrupt router device ID
9204 dw 0,0 ;; Miniport data
9205 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9206 db 0x07 ;; checksum
9207 ;; first slot entry PCI-to-ISA (embedded)
9208 db 0 ;; pci bus number
9209 db 0x08 ;; pci device number (bit 7-3)
9210 db 0x61 ;; link value INTA#: pointer into PCI2ISA config space
9211 dw 0x0c60 ;; IRQ bitmap INTA#
9212 db 0x62 ;; link value INTB#
9213 dw 0x0c60 ;; IRQ bitmap INTB#
9214 db 0x63 ;; link value INTC#
9215 dw 0x0c60 ;; IRQ bitmap INTC#
9216 db 0x60 ;; link value INTD#
9217 dw 0x0c60 ;; IRQ bitmap INTD#
9218 db 0 ;; physical slot (0 = embedded)
9219 db 0 ;; reserved
9220 ;; second slot entry: 1st PCI slot
9221 db 0 ;; pci bus number
9222 db 0x10 ;; pci device number (bit 7-3)
9223 db 0x62 ;; link value INTA#
9224 dw 0x0c60 ;; IRQ bitmap INTA#
9225 db 0x63 ;; link value INTB#
9226 dw 0x0c60 ;; IRQ bitmap INTB#
9227 db 0x60 ;; link value INTC#
9228 dw 0x0c60 ;; IRQ bitmap INTC#
9229 db 0x61 ;; link value INTD#
9230 dw 0x0c60 ;; IRQ bitmap INTD#
9231 db 1 ;; physical slot (0 = embedded)
9232 db 0 ;; reserved
9233 ;; third slot entry: 2nd PCI slot
9234 db 0 ;; pci bus number
9235 db 0x18 ;; pci device number (bit 7-3)
9236 db 0x63 ;; link value INTA#
9237 dw 0x0c60 ;; IRQ bitmap INTA#
9238 db 0x60 ;; link value INTB#
9239 dw 0x0c60 ;; IRQ bitmap INTB#
9240 db 0x61 ;; link value INTC#
9241 dw 0x0c60 ;; IRQ bitmap INTC#
9242 db 0x62 ;; link value INTD#
9243 dw 0x0c60 ;; IRQ bitmap INTD#
9244 db 2 ;; physical slot (0 = embedded)
9245 db 0 ;; reserved
9246 ;; 4th slot entry: 3rd PCI slot
9247 db 0 ;; pci bus number
9248 db 0x20 ;; pci device number (bit 7-3)
9249 db 0x60 ;; link value INTA#
9250 dw 0x0c60 ;; IRQ bitmap INTA#
9251 db 0x61 ;; link value INTB#
9252 dw 0x0c60 ;; IRQ bitmap INTB#
9253 db 0x62 ;; link value INTC#
9254 dw 0x0c60 ;; IRQ bitmap INTC#
9255 db 0x63 ;; link value INTD#
9256 dw 0x0c60 ;; IRQ bitmap INTD#
9257 db 3 ;; physical slot (0 = embedded)
9258 db 0 ;; reserved
9259 ;; 5th slot entry: 4rd PCI slot
9260 db 0 ;; pci bus number
9261 db 0x28 ;; pci device number (bit 7-3)
9262 db 0x61 ;; link value INTA#
9263 dw 0x0c60 ;; IRQ bitmap INTA#
9264 db 0x62 ;; link value INTB#
9265 dw 0x0c60 ;; IRQ bitmap INTB#
9266 db 0x63 ;; link value INTC#
9267 dw 0x0c60 ;; IRQ bitmap INTC#
9268 db 0x60 ;; link value INTD#
9269 dw 0x0c60 ;; IRQ bitmap INTD#
9270 db 4 ;; physical slot (0 = embedded)
9271 db 0 ;; reserved
9272 ;; 6th slot entry: 5rd PCI slot
9273 db 0 ;; pci bus number
9274 db 0x30 ;; pci device number (bit 7-3)
9275 db 0x62 ;; link value INTA#
9276 dw 0x0c60 ;; IRQ bitmap INTA#
9277 db 0x63 ;; link value INTB#
9278 dw 0x0c60 ;; IRQ bitmap INTB#
9279 db 0x60 ;; link value INTC#
9280 dw 0x0c60 ;; IRQ bitmap INTC#
9281 db 0x61 ;; link value INTD#
9282 dw 0x0c60 ;; IRQ bitmap INTD#
9283 db 5 ;; physical slot (0 = embedded)
9284 db 0 ;; reserved
9286 pci_irq_list:
9287 db 11, 10, 9, 5;
9289 pcibios_init_sel_reg:
9290 push eax
9291 mov eax, #0x800000
9292 mov ax, bx
9293 shl eax, #8
9294 and dl, #0xfc
9295 or al, dl
9296 mov dx, #0x0cf8
9297 out dx, eax
9298 pop eax
9299 ret
9301 pcibios_init_set_elcr:
9302 push ax
9303 push cx
9304 mov dx, #0x04d0
9305 test al, #0x08
9306 jz is_master_pic
9307 inc dx
9308 and al, #0x07
9309 is_master_pic:
9310 mov cl, al
9311 mov bl, #0x01
9312 shl bl, cl
9313 in al, dx
9314 or al, bl
9315 out dx, al
9316 pop cx
9317 pop ax
9318 ret
9320 pcibios_init:
9321 push ds
9322 push bp
9323 mov ax, #0xf000
9324 mov ds, ax
9325 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9326 mov al, #0x00
9327 out dx, al
9328 inc dx
9329 out dx, al
9330 mov si, #pci_routing_table_structure
9331 mov bh, [si+8]
9332 mov bl, [si+9]
9333 mov dl, #0x00
9334 call pcibios_init_sel_reg
9335 mov dx, #0x0cfc
9336 in eax, dx
9337 cmp eax, [si+12] ;; check irq router
9338 jne pci_init_end
9339 mov dl, [si+34]
9340 call pcibios_init_sel_reg
9341 push bx ;; save irq router bus + devfunc
9342 mov dx, #0x0cfc
9343 mov ax, #0x8080
9344 out dx, ax ;; reset PIRQ route control
9345 inc dx
9346 inc dx
9347 out dx, ax
9348 mov ax, [si+6]
9349 sub ax, #0x20
9350 shr ax, #4
9351 mov cx, ax
9352 add si, #0x20 ;; set pointer to 1st entry
9353 mov bp, sp
9354 mov ax, #pci_irq_list
9355 push ax
9356 xor ax, ax
9357 push ax
9358 pci_init_loop1:
9359 mov bh, [si]
9360 mov bl, [si+1]
9361 pci_init_loop2:
9362 mov dl, #0x00
9363 call pcibios_init_sel_reg
9364 mov dx, #0x0cfc
9365 in ax, dx
9366 cmp ax, #0xffff
9367 jnz pci_test_int_pin
9368 test bl, #0x07
9369 jz next_pir_entry
9370 jmp next_pci_func
9371 pci_test_int_pin:
9372 mov dl, #0x3c
9373 call pcibios_init_sel_reg
9374 mov dx, #0x0cfd
9375 in al, dx
9376 and al, #0x07
9377 jz next_pci_func
9378 dec al ;; determine pirq reg
9379 mov dl, #0x03
9380 mul al, dl
9381 add al, #0x02
9382 xor ah, ah
9383 mov bx, ax
9384 mov al, [si+bx]
9385 mov dl, al
9386 mov bx, [bp]
9387 call pcibios_init_sel_reg
9388 mov dx, #0x0cfc
9389 and al, #0x03
9390 add dl, al
9391 in al, dx
9392 cmp al, #0x80
9393 jb pirq_found
9394 mov bx, [bp-2] ;; pci irq list pointer
9395 mov al, [bx]
9396 out dx, al
9397 inc bx
9398 mov [bp-2], bx
9399 call pcibios_init_set_elcr
9400 pirq_found:
9401 mov bh, [si]
9402 mov bl, [si+1]
9403 add bl, [bp-3] ;; pci function number
9404 mov dl, #0x3c
9405 call pcibios_init_sel_reg
9406 mov dx, #0x0cfc
9407 out dx, al
9408 next_pci_func:
9409 inc byte ptr[bp-3]
9410 inc bl
9411 test bl, #0x07
9412 jnz pci_init_loop2
9413 next_pir_entry:
9414 add si, #0x10
9415 mov byte ptr[bp-3], #0x00
9416 loop pci_init_loop1
9417 mov sp, bp
9418 pop bx
9419 pci_init_end:
9420 pop bp
9421 pop ds
9422 ret
9423 #endif // BX_PCIBIOS
9425 ; parallel port detection: base address in DX, index in BX, timeout in CL
9426 detect_parport:
9427 push dx
9428 add dx, #2
9429 in al, dx
9430 and al, #0xdf ; clear input mode
9431 out dx, al
9432 pop dx
9433 mov al, #0xaa
9434 out dx, al
9435 in al, dx
9436 cmp al, #0xaa
9437 jne no_parport
9438 push bx
9439 shl bx, #1
9440 mov [bx+0x408], dx ; Parallel I/O address
9441 pop bx
9442 mov [bx+0x478], cl ; Parallel printer timeout
9443 inc bx
9444 no_parport:
9445 ret
9447 ; serial port detection: base address in DX, index in BX, timeout in CL
9448 detect_serial:
9449 push dx
9450 inc dx
9451 mov al, #0x02
9452 out dx, al
9453 in al, dx
9454 cmp al, #0x02
9455 jne no_serial
9456 inc dx
9457 in al, dx
9458 cmp al, #0x02
9459 jne no_serial
9460 dec dx
9461 xor al, al
9462 out dx, al
9463 pop dx
9464 push bx
9465 shl bx, #1
9466 mov [bx+0x400], dx ; Serial I/O address
9467 pop bx
9468 mov [bx+0x47c], cl ; Serial timeout
9469 inc bx
9470 ret
9471 no_serial:
9472 pop dx
9473 ret
9475 rom_checksum:
9476 push ax
9477 push bx
9478 push cx
9479 xor ax, ax
9480 xor bx, bx
9481 xor cx, cx
9482 mov ch, [2]
9483 shl cx, #1
9484 checksum_loop:
9485 add al, [bx]
9486 inc bx
9487 loop checksum_loop
9488 and al, #0xff
9489 pop cx
9490 pop bx
9491 pop ax
9492 ret
9495 ;; We need a copy of this string, but we are not actually a PnP BIOS,
9496 ;; so make sure it is *not* aligned, so OSes will not see it if they scan.
9497 .align 16
9498 db 0
9499 pnp_string:
9500 .ascii "$PnP"
9503 rom_scan:
9504 ;; Scan for existence of valid expansion ROMS.
9505 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9506 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9507 ;; System ROM: only 0xE0000
9508 ;;
9509 ;; Header:
9510 ;; Offset Value
9511 ;; 0 0x55
9512 ;; 1 0xAA
9513 ;; 2 ROM length in 512-byte blocks
9514 ;; 3 ROM initialization entry point (FAR CALL)
9516 #if BX_TCGBIOS
9517 call _tcpa_start_option_rom_scan /* specs: 3.2.3.3 + 10.4.3 */
9518 #endif
9519 mov cx, #0xc000
9520 rom_scan_loop:
9521 mov ds, cx
9522 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9523 cmp [0], #0xAA55 ;; look for signature
9524 jne rom_scan_increment
9525 call rom_checksum
9526 jnz rom_scan_increment
9527 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9529 ;; We want our increment in 512-byte quantities, rounded to
9530 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9531 test al, #0x03
9532 jz block_count_rounded
9533 and al, #0xfc ;; needs rounding up
9534 add al, #0x04
9535 block_count_rounded:
9537 #if BX_TCGBIOS
9538 push ax
9539 push ds
9540 push ecx
9541 xor ax, ax
9542 mov ds, ax
9543 and ecx, #0xffff
9544 push ecx ;; segment where option rom is located at
9545 call _tcpa_option_rom /* specs: 3.2.3.3 */
9546 add sp, #4 ;; pop segment
9547 pop ecx ;; original ecx
9548 pop ds
9549 pop ax
9550 #endif
9551 xor bx, bx ;; Restore DS back to 0000:
9552 mov ds, bx
9553 push ax ;; Save AX
9554 push di ;; Save DI
9555 ;; Push addr of ROM entry point
9556 push cx ;; Push seg
9557 push #0x0003 ;; Push offset
9559 ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
9560 ;; That should stop it grabbing INT 19h; we will use its BEV instead.
9561 mov ax, #0xf000
9562 mov es, ax
9563 lea di, pnp_string
9565 mov bp, sp ;; Call ROM init routine using seg:off on stack
9566 db 0xff ;; call_far ss:[bp+0]
9567 db 0x5e
9568 db 0
9569 cli ;; In case expansion ROM BIOS turns IF on
9570 add sp, #2 ;; Pop offset value
9571 pop cx ;; Pop seg value (restore CX)
9573 ;; Look at the ROM's PnP Expansion header. Properly, we're supposed
9574 ;; to init all the ROMs and then go back and build an IPL table of
9575 ;; all the bootable devices, but we can get away with one pass.
9576 mov ds, cx ;; ROM base
9577 mov bx, 0x001a ;; 0x1A is the offset into ROM header that contains...
9578 mov ax, [bx] ;; the offset of PnP expansion header, where...
9579 cmp ax, #0x5024 ;; we look for signature "$PnP"
9580 jne no_bev
9581 mov ax, 2[bx]
9582 cmp ax, #0x506e
9583 jne no_bev
9584 mov ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
9585 cmp ax, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
9586 je no_bev
9588 ;; Found a device that thinks it can boot the system. Record its BEV.
9589 mov bx, #IPL_SEG ;; Go to the segment where the IPL table lives
9590 mov ds, bx
9591 mov bx, IPL_COUNT_OFFSET ;; Read the number of entries so far
9592 cmp bx, #IPL_TABLE_ENTRIES
9593 je no_bev ;; Get out if the table is full
9594 shl bx, #0x4 ;; Turn count into offset (entries are 16 bytes)
9595 mov 0[bx], #0x80 ;; This entry is a BEV device
9596 mov 6[bx], cx ;; Build a far pointer from the segment...
9597 mov 4[bx], ax ;; and the offset
9598 shr bx, #0x4 ;; Turn the offset back into a count
9599 inc bx ;; We have one more entry now
9600 mov IPL_COUNT_OFFSET, bx ;; Remember that.
9602 no_bev:
9603 pop di ;; Restore DI
9604 pop ax ;; Restore AX
9605 rom_scan_increment:
9606 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9607 ;; because the segment selector is shifted left 4 bits.
9608 add cx, ax
9609 cmp cx, #0xe000
9610 jbe rom_scan_loop
9612 xor ax, ax ;; Restore DS back to 0000:
9613 mov ds, ax
9614 ret
9616 #ifdef HVMASSIST
9618 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9619 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9620 ; but the tables themeselves can be elsewhere.
9621 smbios_init:
9622 push ax
9623 push cx
9624 push es
9625 push ds
9626 push di
9627 push si
9629 mov cx, #0x001f ; 0x1f bytes to copy
9630 mov ax, #0xf000
9631 mov es, ax ; destination segment is 0xf0000
9632 mov di, #smbios_entry_point ; destination offset
9633 mov ax, #0x9f00
9634 mov ds, ax ; source segment is 0x9f000
9635 mov si, #0x0000 ; source offset is 0
9636 cld
9637 rep
9638 movsb
9640 pop si
9641 pop di
9642 pop ds
9643 pop es
9644 pop cx
9645 pop ax
9647 ret
9649 #endif
9653 ;; for 'C' strings and other data, insert them here with
9654 ;; a the following hack:
9655 ;; DATA_SEG_DEFS_HERE
9658 ;--------
9659 ;- POST -
9660 ;--------
9661 .org 0xe05b ; POST Entry Point
9662 post:
9664 xor ax, ax
9666 ;; first reset the DMA controllers
9667 out 0x0d,al
9668 out 0xda,al
9670 ;; then initialize the DMA controllers
9671 mov al, #0xC0
9672 out 0xD6, al ; cascade mode of channel 4 enabled
9673 mov al, #0x00
9674 out 0xD4, al ; unmask channel 4
9676 ;; Examine CMOS shutdown status.
9677 mov AL, #0x0f
9678 out 0x70, AL
9679 in AL, 0x71
9681 ;; backup status
9682 mov bl, al
9684 ;; Reset CMOS shutdown status.
9685 mov AL, #0x0f
9686 out 0x70, AL ; select CMOS register Fh
9687 mov AL, #0x00
9688 out 0x71, AL ; set shutdown action to normal
9690 ;; Examine CMOS shutdown status.
9691 mov al, bl
9693 ;; 0x00, 0x09, 0x0D+ = normal startup
9694 cmp AL, #0x00
9695 jz normal_post
9696 cmp AL, #0x0d
9697 jae normal_post
9698 cmp AL, #0x09
9699 je normal_post
9701 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9702 cmp al, #0x05
9703 je eoi_jmp_post
9705 ;; Examine CMOS shutdown status.
9706 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9707 push bx
9708 call _shutdown_status_panic
9710 #if 0
9711 HALT(__LINE__)
9713 ;#if 0
9714 ; 0xb0, 0x20, /* mov al, #0x20 */
9715 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9716 ;#endif
9718 pop es
9719 pop ds
9720 popa
9721 iret
9722 #endif
9724 normal_post:
9725 ; case 0: normal startup
9727 cli
9728 mov ax, #0xfffe
9729 mov sp, ax
9730 mov ax, #0x0000
9731 mov ds, ax
9732 mov ss, ax
9734 ;; zero out BIOS data area (40:00..40:ff)
9735 mov es, ax
9736 mov cx, #0x0080 ;; 128 words
9737 mov di, #0x0400
9738 cld
9739 rep
9740 stosw
9742 call _log_bios_start
9744 ;; set all interrupts to default handler
9745 mov bx, #0x0000 ;; offset index
9746 mov cx, #0x0100 ;; counter (256 interrupts)
9747 mov ax, #dummy_iret_handler
9748 mov dx, #0xF000
9750 post_default_ints:
9751 mov [bx], ax
9752 inc bx
9753 inc bx
9754 mov [bx], dx
9755 inc bx
9756 inc bx
9757 loop post_default_ints
9759 ;; set vector 0x79 to zero
9760 ;; this is used by 'gardian angel' protection system
9761 SET_INT_VECTOR(0x79, #0, #0)
9763 ;; base memory in K 40:13 (word)
9764 mov ax, #BASE_MEM_IN_K
9765 mov 0x0413, ax
9768 ;; Manufacturing Test 40:12
9769 ;; zerod out above
9771 ;; Warm Boot Flag 0040:0072
9772 ;; value of 1234h = skip memory checks
9773 ;; zerod out above
9776 ;; Printer Services vector
9777 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9779 ;; Bootstrap failure vector
9780 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9782 ;; Bootstrap Loader vector
9783 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9785 ;; User Timer Tick vector
9786 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9788 ;; Memory Size Check vector
9789 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9791 ;; Equipment Configuration Check vector
9792 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9794 ;; System Services
9795 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9797 ;; EBDA setup
9798 call ebda_post
9800 ;; PIT setup
9801 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9802 ;; int 1C already points at dummy_iret_handler (above)
9803 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9804 out 0x43, al
9805 #ifdef HVMASSIST
9806 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9807 out 0x40, al ; lsb
9808 mov al, #0xe9
9809 out 0x40, al ; msb
9810 #else
9811 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9812 out 0x40, al
9813 out 0x40, al
9814 #endif
9816 ;; Keyboard
9817 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9818 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9820 xor ax, ax
9821 mov ds, ax
9822 mov 0x0417, al /* keyboard shift flags, set 1 */
9823 mov 0x0418, al /* keyboard shift flags, set 2 */
9824 mov 0x0419, al /* keyboard alt-numpad work area */
9825 mov 0x0471, al /* keyboard ctrl-break flag */
9826 mov 0x0497, al /* keyboard status flags 4 */
9827 mov al, #0x10
9828 mov 0x0496, al /* keyboard status flags 3 */
9831 /* keyboard head of buffer pointer */
9832 mov bx, #0x001E
9833 mov 0x041A, bx
9835 /* keyboard end of buffer pointer */
9836 mov 0x041C, bx
9838 /* keyboard pointer to start of buffer */
9839 mov bx, #0x001E
9840 mov 0x0480, bx
9842 /* keyboard pointer to end of buffer */
9843 mov bx, #0x003E
9844 mov 0x0482, bx
9846 /* init the keyboard */
9847 call _keyboard_init
9849 ;; mov CMOS Equipment Byte to BDA Equipment Word
9850 mov ax, 0x0410
9851 mov al, #0x14
9852 out 0x70, al
9853 in al, 0x71
9854 mov 0x0410, ax
9856 #if BX_TCGBIOS
9857 call _tcpa_acpi_init
9859 push dword #0
9860 call _tcpa_initialize_tpm
9861 add sp, #4
9863 call _tcpa_do_measure_POSTs
9864 call _tcpa_wake_event /* specs: 3.2.3.7 */
9865 #endif
9867 ;; Parallel setup
9868 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9869 xor ax, ax
9870 mov ds, ax
9871 xor bx, bx
9872 mov cl, #0x14 ; timeout value
9873 mov dx, #0x378 ; Parallel I/O address, port 1
9874 call detect_parport
9875 mov dx, #0x278 ; Parallel I/O address, port 2
9876 call detect_parport
9877 shl bx, #0x0e
9878 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9879 and ax, #0x3fff
9880 or ax, bx ; set number of parallel ports
9881 mov 0x410, ax
9883 ;; Serial setup
9884 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9885 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9886 xor bx, bx
9887 mov cl, #0x0a ; timeout value
9888 mov dx, #0x03f8 ; Serial I/O address, port 1
9889 call detect_serial
9890 mov dx, #0x02f8 ; Serial I/O address, port 2
9891 call detect_serial
9892 mov dx, #0x03e8 ; Serial I/O address, port 3
9893 call detect_serial
9894 mov dx, #0x02e8 ; Serial I/O address, port 4
9895 call detect_serial
9896 shl bx, #0x09
9897 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9898 and ax, #0xf1ff
9899 or ax, bx ; set number of serial port
9900 mov 0x410, ax
9902 ;; CMOS RTC
9903 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9904 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9905 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9906 ;; BIOS DATA AREA 0x4CE ???
9907 call timer_tick_post
9909 ;; PS/2 mouse setup
9910 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9912 ;; IRQ13 (FPU exception) setup
9913 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9915 ;; Video setup
9916 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9918 ;; PIC
9919 mov al, #0x11 ; send initialisation commands
9920 out 0x20, al
9921 out 0xa0, al
9922 mov al, #0x08
9923 out 0x21, al
9924 mov al, #0x70
9925 out 0xa1, al
9926 mov al, #0x04
9927 out 0x21, al
9928 mov al, #0x02
9929 out 0xa1, al
9930 mov al, #0x01
9931 out 0x21, al
9932 out 0xa1, al
9933 mov al, #0xb8
9934 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9935 #if BX_USE_PS2_MOUSE
9936 mov al, #0x8f
9937 #else
9938 mov al, #0x9f
9939 #endif
9940 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9942 #ifdef HVMASSIST
9943 call _copy_e820_table
9944 call smbios_init
9945 #endif
9947 call _init_boot_vectors
9949 call rom_scan
9951 call _print_bios_banner
9953 ;;
9954 ;; Floppy setup
9955 ;;
9956 call floppy_drive_post
9958 #if BX_USE_ATADRV
9960 ;;
9961 ;; Hard Drive setup
9962 ;;
9963 call hard_drive_post
9965 ;;
9966 ;; ATA/ATAPI driver setup
9967 ;;
9968 call _ata_init
9969 call _ata_detect
9970 ;;
9971 #else // BX_USE_ATADRV
9973 ;;
9974 ;; Hard Drive setup
9975 ;;
9976 call hard_drive_post
9978 #endif // BX_USE_ATADRV
9980 #if BX_ELTORITO_BOOT
9981 ;;
9982 ;; eltorito floppy/harddisk emulation from cd
9983 ;;
9984 call _cdemu_init
9985 ;;
9986 #endif // BX_ELTORITO_BOOT
9988 #if BX_TCGBIOS
9989 call _tcpa_calling_int19h /* specs: 8.2.3 step 1 */
9990 call _tcpa_add_event_separators /* specs: 8.2.3 step 2 */
9991 #endif
9992 int #0x19
9993 //JMP_EP(0x0064) ; INT 19h location
9995 #if BX_TCGBIOS
9996 call _tcpa_returned_int19h /* specs: 8.2.3 step 3/7 */
9997 #endif
9999 .org 0xe2c3 ; NMI Handler Entry Point
10000 nmi:
10001 ;; FIXME the NMI handler should not panic
10002 ;; but iret when called from int75 (fpu exception)
10003 call _nmi_handler_msg
10004 iret
10006 int75_handler:
10007 out 0xf0, al // clear irq13
10008 call eoi_both_pics // clear interrupt
10009 int 2 // legacy nmi call
10010 iret
10012 ;-------------------------------------------
10013 ;- INT 13h Fixed Disk Services Entry Point -
10014 ;-------------------------------------------
10015 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
10016 int13_handler:
10017 //JMPL(int13_relocated)
10018 jmp int13_relocated
10020 .org 0xe401 ; Fixed Disk Parameter Table
10022 ;----------
10023 ;- INT19h -
10024 ;----------
10025 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
10026 int19_handler:
10028 jmp int19_relocated
10029 ;-------------------------------------------
10030 ;- System BIOS Configuration Data Table
10031 ;-------------------------------------------
10032 .org BIOS_CONFIG_TABLE
10033 db 0x08 ; Table size (bytes) -Lo
10034 db 0x00 ; Table size (bytes) -Hi
10035 db SYS_MODEL_ID
10036 db SYS_SUBMODEL_ID
10037 db BIOS_REVISION
10038 ; Feature byte 1
10039 ; b7: 1=DMA channel 3 used by hard disk
10040 ; b6: 1=2 interrupt controllers present
10041 ; b5: 1=RTC present
10042 ; b4: 1=BIOS calls int 15h/4Fh every key
10043 ; b3: 1=wait for extern event supported (Int 15h/41h)
10044 ; b2: 1=extended BIOS data area used
10045 ; b1: 0=AT or ESDI bus, 1=MicroChannel
10046 ; b0: 1=Dual bus (MicroChannel + ISA)
10047 db (0 << 7) | \
10048 (1 << 6) | \
10049 (1 << 5) | \
10050 (BX_CALL_INT15_4F << 4) | \
10051 (0 << 3) | \
10052 (BX_USE_EBDA << 2) | \
10053 (0 << 1) | \
10054 (0 << 0)
10055 ; Feature byte 2
10056 ; b7: 1=32-bit DMA supported
10057 ; b6: 1=int16h, function 9 supported
10058 ; b5: 1=int15h/C6h (get POS data) supported
10059 ; b4: 1=int15h/C7h (get mem map info) supported
10060 ; b3: 1=int15h/C8h (en/dis CPU) supported
10061 ; b2: 1=non-8042 kb controller
10062 ; b1: 1=data streaming supported
10063 ; b0: reserved
10064 db (0 << 7) | \
10065 (1 << 6) | \
10066 (0 << 5) | \
10067 (0 << 4) | \
10068 (0 << 3) | \
10069 (0 << 2) | \
10070 (0 << 1) | \
10071 (0 << 0)
10072 ; Feature byte 3
10073 ; b7: not used
10074 ; b6: reserved
10075 ; b5: reserved
10076 ; b4: POST supports ROM-to-RAM enable/disable
10077 ; b3: SCSI on system board
10078 ; b2: info panel installed
10079 ; b1: Initial Machine Load (IML) system - BIOS on disk
10080 ; b0: SCSI supported in IML
10081 db 0x00
10082 ; Feature byte 4
10083 ; b7: IBM private
10084 ; b6: EEPROM present
10085 ; b5-3: ABIOS presence (011 = not supported)
10086 ; b2: private
10087 ; b1: memory split above 16Mb supported
10088 ; b0: POSTEXT directly supported by POST
10089 db 0x00
10090 ; Feature byte 5 (IBM)
10091 ; b1: enhanced mouse
10092 ; b0: flash EPROM
10093 db 0x00
10097 .org 0xe729 ; Baud Rate Generator Table
10099 ;----------
10100 ;- INT14h -
10101 ;----------
10102 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10103 int14_handler:
10104 push ds
10105 pusha
10106 mov ax, #0x0000
10107 mov ds, ax
10108 call _int14_function
10109 popa
10110 pop ds
10111 iret
10114 ;----------------------------------------
10115 ;- INT 16h Keyboard Service Entry Point -
10116 ;----------------------------------------
10117 .org 0xe82e
10118 int16_handler:
10120 sti
10121 push ds
10122 pushf
10123 pusha
10125 cmp ah, #0x00
10126 je int16_F00
10127 cmp ah, #0x10
10128 je int16_F00
10130 mov bx, #0xf000
10131 mov ds, bx
10132 call _int16_function
10133 popa
10134 popf
10135 pop ds
10136 jz int16_zero_set
10138 int16_zero_clear:
10139 push bp
10140 mov bp, sp
10141 //SEG SS
10142 and BYTE [bp + 0x06], #0xbf
10143 pop bp
10144 iret
10146 int16_zero_set:
10147 push bp
10148 mov bp, sp
10149 //SEG SS
10150 or BYTE [bp + 0x06], #0x40
10151 pop bp
10152 iret
10154 int16_F00:
10155 mov bx, #0x0040
10156 mov ds, bx
10158 int16_wait_for_key:
10159 cli
10160 mov bx, 0x001a
10161 cmp bx, 0x001c
10162 jne int16_key_found
10163 sti
10164 nop
10165 #if 0
10166 /* no key yet, call int 15h, function AX=9002 */
10167 0x50, /* push AX */
10168 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10169 0xcd, 0x15, /* int 15h */
10170 0x58, /* pop AX */
10171 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10172 #endif
10173 jmp int16_wait_for_key
10175 int16_key_found:
10176 mov bx, #0xf000
10177 mov ds, bx
10178 call _int16_function
10179 popa
10180 popf
10181 pop ds
10182 #if 0
10183 /* notify int16 complete w/ int 15h, function AX=9102 */
10184 0x50, /* push AX */
10185 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10186 0xcd, 0x15, /* int 15h */
10187 0x58, /* pop AX */
10188 #endif
10189 iret
10193 ;-------------------------------------------------
10194 ;- INT09h : Keyboard Hardware Service Entry Point -
10195 ;-------------------------------------------------
10196 .org 0xe987
10197 int09_handler:
10198 cli
10199 push ax
10201 mov al, #0xAD ;;disable keyboard
10202 out #0x64, al
10204 mov al, #0x0B
10205 out #0x20, al
10206 in al, #0x20
10207 and al, #0x02
10208 jz int09_finish