ia64/xen-unstable

view tools/firmware/rombios/rombios.c @ 19079:f3240cd3cd2b

rombios: Indirect through 32-bit jump table from within the 32-bit bios.

This gets rid of shenanigans with relocating the jump table around the
place.

Also clean up bios_info table while we are updating it.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jan 23 14:32:41 2009 +0000 (2009-01-23)
parents 8de0aae803e0
children c9dc7dcacc1d
line source
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.221 2008/12/07 17:32:29 sshwarts 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
29 #define uint8_t unsigned char
30 #define uint16_t unsigned short
31 #define uint32_t unsigned long
32 #include "../hvmloader/config.h"
34 #define HVMASSIST
35 #undef HVMTEST
37 // Xen full virtualization does not handle unaligned IO with page crossing.
38 // Disable 32-bit PIO as a workaround.
39 #undef NO_PIO32
42 // ROM BIOS compatability entry points:
43 // ===================================
44 // $e05b ; POST Entry Point
45 // $e2c3 ; NMI Handler Entry Point
46 // $e3fe ; INT 13h Fixed Disk Services Entry Point
47 // $e401 ; Fixed Disk Parameter Table
48 // $e6f2 ; INT 19h Boot Load Service Entry Point
49 // $e6f5 ; Configuration Data Table
50 // $e729 ; Baud Rate Generator Table
51 // $e739 ; INT 14h Serial Communications Service Entry Point
52 // $e82e ; INT 16h Keyboard Service Entry Point
53 // $e987 ; INT 09h Keyboard Service Entry Point
54 // $ec59 ; INT 13h Diskette Service Entry Point
55 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
56 // $efc7 ; Diskette Controller Parameter Table
57 // $efd2 ; INT 17h Printer Service Entry Point
58 // $f045 ; INT 10 Functions 0-Fh Entry Point
59 // $f065 ; INT 10h Video Support Service Entry Point
60 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
61 // $f841 ; INT 12h Memory Size Service Entry Point
62 // $f84d ; INT 11h Equipment List Service Entry Point
63 // $f859 ; INT 15h System Services Entry Point
64 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
65 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
66 // $fea5 ; INT 08h System Timer ISR Entry Point
67 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
68 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
69 // $ff54 ; INT 05h Print Screen Service Entry Point
70 // $fff0 ; Power-up Entry Point
71 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
72 // $fffe ; System Model ID
74 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
75 // Features
76 // - supports up to 4 ATA interfaces
77 // - device/geometry detection
78 // - 16bits/32bits device access
79 // - pchs/lba access
80 // - datain/dataout/packet command support
81 //
82 // NOTES for El-Torito Boot (cbbochs@free.fr)
83 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
84 // - Current code is only able to boot mono-session cds
85 // - Current code can not boot and emulate a hard-disk
86 // the bios will panic otherwise
87 // - Current code also use memory in EBDA segement.
88 // - I used cmos byte 0x3D to store extended information on boot-device
89 // - Code has to be modified modified to handle multiple cdrom drives
90 // - Here are the cdrom boot failure codes:
91 // 1 : no atapi device found
92 // 2 : no atapi cdrom found
93 // 3 : can not read cd - BRVD
94 // 4 : cd is not eltorito (BRVD)
95 // 5 : cd is not eltorito (ISO TAG)
96 // 6 : cd is not eltorito (ELTORITO TAG)
97 // 7 : can not read cd - boot catalog
98 // 8 : boot catalog : bad header
99 // 9 : boot catalog : bad platform
100 // 10 : boot catalog : bad signature
101 // 11 : boot catalog : bootable flag not set
102 // 12 : can not read cd - boot image
103 //
104 // ATA driver
105 // - EBDA segment.
106 // I used memory starting at 0x121 in the segment
107 // - the translation policy is defined in cmos regs 0x39 & 0x3a
108 //
109 // TODO :
110 //
111 // int74
112 // - needs to be reworked. Uses direct [bp] offsets. (?)
113 //
114 // int13:
115 // - f04 (verify sectors) isn't complete (?)
116 // - f02/03/04 should set current cyl,etc in BDA (?)
117 // - rewrite int13_relocated & clean up int13 entry code
118 //
119 // NOTES:
120 // - NMI access (bit7 of addr written to 70h)
121 //
122 // ATA driver
123 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
124 // - could send the multiple-sector read/write commands
125 //
126 // El-Torito
127 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
128 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
129 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
130 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
131 // This is ok. But DL should be reincremented afterwards.
132 // - Fix all "FIXME ElTorito Various"
133 // - should be able to boot any cdrom instead of the first one
134 //
135 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
137 #include "rombios.h"
139 #define DEBUG_ATA 0
140 #define DEBUG_INT13_HD 0
141 #define DEBUG_INT13_CD 0
142 #define DEBUG_INT13_ET 0
143 #define DEBUG_INT13_FL 0
144 #define DEBUG_INT15 0
145 #define DEBUG_INT16 0
146 #define DEBUG_INT1A 0
147 #define DEBUG_INT74 0
148 #define DEBUG_APM 0
150 #define BX_CPU 3
151 #define BX_USE_PS2_MOUSE 1
152 #define BX_CALL_INT15_4F 1
153 #define BX_USE_EBDA 1
154 #define BX_SUPPORT_FLOPPY 1
155 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
156 #define BX_PCIBIOS 1
157 #define BX_APM 1
159 #define BX_USE_ATADRV 1
160 #define BX_ELTORITO_BOOT 1
162 #define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */
164 #define BX_PMM 1 /* POST Memory Manager */
166 #define BX_MAX_ATA_INTERFACES 4
167 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
169 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
170 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
172 /* model byte 0xFC = AT */
173 #define SYS_MODEL_ID 0xFC
174 #define SYS_SUBMODEL_ID 0x00
175 #define BIOS_REVISION 1
176 #define BIOS_CONFIG_TABLE 0xe6f5
178 #ifndef BIOS_BUILD_DATE
179 # define BIOS_BUILD_DATE "06/23/99"
180 #endif
182 #define E820_SEG (Bit16u)(E820_PHYSICAL_ADDRESS >> 4)
184 // 1K of base memory used for Extended Bios Data Area (EBDA)
185 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
186 #define EBDA_SEG 0x9FC0
187 #define EBDA_SIZE 1 // In KiB
188 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
190 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
191 #define IPL_TABLE_OFFSET 0x0300 /* offset from EBDA */
192 #define IPL_TABLE_ENTRIES 8
193 #define IPL_COUNT_OFFSET 0x0380 /* u16: number of valid table entries */
194 #define IPL_SEQUENCE_OFFSET 0x0382 /* u16: next boot device */
195 #define IPL_BOOTFIRST_OFFSET 0x0384 /* u16: user selected device */
196 #define IPL_SIZE 0xff
197 #define IPL_TYPE_FLOPPY 0x01
198 #define IPL_TYPE_HARDDISK 0x02
199 #define IPL_TYPE_CDROM 0x03
200 #define IPL_TYPE_BEV 0x80
203 // Sanity Checks
204 #if BX_USE_ATADRV && BX_CPU<3
205 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
206 #endif
207 #if BX_USE_ATADRV && !BX_USE_EBDA
208 # error ATA/ATAPI Driver can only be used if EBDA is available
209 #endif
210 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
211 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
212 #endif
213 #if BX_PCIBIOS && BX_CPU<3
214 # error PCI BIOS can only be used with 386+ cpu
215 #endif
216 #if BX_APM && BX_CPU<3
217 # error APM BIOS can only be used with 386+ cpu
218 #endif
220 // define this if you want to make PCIBIOS working on a specific bridge only
221 // undef enables PCIBIOS when at least one PCI device is found
222 // i440FX is emulated by Bochs and QEMU
223 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
225 // #20 is dec 20
226 // #$20 is hex 20 = 32
227 // #0x20 is hex 20 = 32
228 // LDA #$20
229 // JSR $E820
230 // LDD .i,S
231 // JSR $C682
232 // mov al, #$20
234 // all hex literals should be prefixed with '0x'
235 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
236 // no mov SEG-REG, #value, must mov register into seg-reg
237 // grep -i "mov[ ]*.s" rombios.c
239 // This is for compiling with gcc2 and gcc3
240 #define ASM_START #asm
241 #define ASM_END #endasm
243 ASM_START
244 .rom
246 .org 0x0000
248 #if BX_CPU >= 3
249 use16 386
250 #else
251 use16 286
252 #endif
254 MACRO HALT
255 ;; the HALT macro is called with the line number of the HALT call.
256 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
257 ;; to print a BX_PANIC message. This will normally halt the simulation
258 ;; with a message such as "BIOS panic at rombios.c, line 4091".
259 ;; However, users can choose to make panics non-fatal and continue.
260 #if BX_VIRTUAL_PORTS
261 mov dx,#PANIC_PORT
262 mov ax,#?1
263 out dx,ax
264 #else
265 mov dx,#0x80
266 mov ax,#?1
267 out dx,al
268 #endif
269 MEND
271 MACRO JMP_AP
272 db 0xea
273 dw ?2
274 dw ?1
275 MEND
277 MACRO SET_INT_VECTOR
278 mov ax, ?3
279 mov ?1*4, ax
280 mov ax, ?2
281 mov ?1*4+2, ax
282 MEND
284 ASM_END
286 typedef unsigned char Bit8u;
287 typedef unsigned short Bit16u;
288 typedef unsigned short bx_bool;
289 typedef unsigned long Bit32u;
292 void memsetb(seg,offset,value,count);
293 void memcpyb(dseg,doffset,sseg,soffset,count);
294 void memcpyd(dseg,doffset,sseg,soffset,count);
296 // memset of count bytes
297 void
298 memsetb(seg,offset,value,count)
299 Bit16u seg;
300 Bit16u offset;
301 Bit16u value;
302 Bit16u count;
303 {
304 ASM_START
305 push bp
306 mov bp, sp
308 push ax
309 push cx
310 push es
311 push di
313 mov cx, 10[bp] ; count
314 test cx, cx
315 je memsetb_end
316 mov ax, 4[bp] ; segment
317 mov es, ax
318 mov ax, 6[bp] ; offset
319 mov di, ax
320 mov al, 8[bp] ; value
321 cld
322 rep
323 stosb
325 memsetb_end:
326 pop di
327 pop es
328 pop cx
329 pop ax
331 pop bp
332 ASM_END
333 }
335 // memcpy of count bytes
336 void
337 memcpyb(dseg,doffset,sseg,soffset,count)
338 Bit16u dseg;
339 Bit16u doffset;
340 Bit16u sseg;
341 Bit16u soffset;
342 Bit16u count;
343 {
344 ASM_START
345 push bp
346 mov bp, sp
348 push ax
349 push cx
350 push es
351 push di
352 push ds
353 push si
355 mov cx, 12[bp] ; count
356 test cx, cx
357 je memcpyb_end
358 mov ax, 4[bp] ; dsegment
359 mov es, ax
360 mov ax, 6[bp] ; doffset
361 mov di, ax
362 mov ax, 8[bp] ; ssegment
363 mov ds, ax
364 mov ax, 10[bp] ; soffset
365 mov si, ax
366 cld
367 rep
368 movsb
370 memcpyb_end:
371 pop si
372 pop ds
373 pop di
374 pop es
375 pop cx
376 pop ax
378 pop bp
379 ASM_END
380 }
382 // memcpy of count dword
383 void
384 memcpyd(dseg,doffset,sseg,soffset,count)
385 Bit16u dseg;
386 Bit16u doffset;
387 Bit16u sseg;
388 Bit16u soffset;
389 Bit16u count;
390 {
391 ASM_START
392 push bp
393 mov bp, sp
395 push ax
396 push cx
397 push es
398 push di
399 push ds
400 push si
402 mov cx, 12[bp] ; count
403 test cx, cx
404 je memcpyd_end
405 mov ax, 4[bp] ; dsegment
406 mov es, ax
407 mov ax, 6[bp] ; doffset
408 mov di, ax
409 mov ax, 8[bp] ; ssegment
410 mov ds, ax
411 mov ax, 10[bp] ; soffset
412 mov si, ax
413 cld
414 rep
415 movsd
417 memcpyd_end:
418 pop si
419 pop ds
420 pop di
421 pop es
422 pop cx
423 pop ax
425 pop bp
426 ASM_END
427 }
429 // read_dword and write_dword functions
430 static Bit32u read_dword();
431 static void write_dword();
433 Bit32u
434 read_dword(seg, offset)
435 Bit16u seg;
436 Bit16u offset;
437 {
438 ASM_START
439 push bp
440 mov bp, sp
442 push bx
443 push ds
444 mov ax, 4[bp] ; segment
445 mov ds, ax
446 mov bx, 6[bp] ; offset
447 mov ax, [bx]
448 add bx, #2
449 mov dx, [bx]
450 ;; ax = return value (word)
451 ;; dx = return value (word)
452 pop ds
453 pop bx
455 pop bp
456 ASM_END
457 }
459 void
460 write_dword(seg, offset, data)
461 Bit16u seg;
462 Bit16u offset;
463 Bit32u data;
464 {
465 ASM_START
466 push bp
467 mov bp, sp
469 push ax
470 push bx
471 push ds
472 mov ax, 4[bp] ; segment
473 mov ds, ax
474 mov bx, 6[bp] ; offset
475 mov ax, 8[bp] ; data word
476 mov [bx], ax ; write data word
477 add bx, #2
478 mov ax, 10[bp] ; data word
479 mov [bx], ax ; write data word
480 pop ds
481 pop bx
482 pop ax
484 pop bp
485 ASM_END
486 }
488 // Bit32u (unsigned long) and long helper functions
489 ASM_START
491 ;; and function
492 landl:
493 landul:
494 SEG SS
495 and ax,[di]
496 SEG SS
497 and bx,2[di]
498 ret
500 ;; add function
501 laddl:
502 laddul:
503 SEG SS
504 add ax,[di]
505 SEG SS
506 adc bx,2[di]
507 ret
509 ;; cmp function
510 lcmpl:
511 lcmpul:
512 and eax, #0x0000FFFF
513 shl ebx, #16
514 or eax, ebx
515 shr ebx, #16
516 SEG SS
517 cmp eax, dword ptr [di]
518 ret
520 ;; sub function
521 lsubl:
522 lsubul:
523 SEG SS
524 sub ax,[di]
525 SEG SS
526 sbb bx,2[di]
527 ret
529 ;; mul function
530 lmull:
531 lmulul:
532 and eax, #0x0000FFFF
533 shl ebx, #16
534 or eax, ebx
535 SEG SS
536 mul eax, dword ptr [di]
537 mov ebx, eax
538 shr ebx, #16
539 ret
541 ;; dec function
542 ldecl:
543 ldecul:
544 SEG SS
545 dec dword ptr [bx]
546 ret
548 ;; or function
549 lorl:
550 lorul:
551 SEG SS
552 or ax,[di]
553 SEG SS
554 or bx,2[di]
555 ret
557 ;; inc function
558 lincl:
559 lincul:
560 SEG SS
561 inc dword ptr [bx]
562 ret
564 ;; tst function
565 ltstl:
566 ltstul:
567 and eax, #0x0000FFFF
568 shl ebx, #16
569 or eax, ebx
570 shr ebx, #16
571 test eax, eax
572 ret
574 ;; sr function
575 lsrul:
576 mov cx,di
577 jcxz lsr_exit
578 and eax, #0x0000FFFF
579 shl ebx, #16
580 or eax, ebx
581 lsr_loop:
582 shr eax, #1
583 loop lsr_loop
584 mov ebx, eax
585 shr ebx, #16
586 lsr_exit:
587 ret
589 ;; sl function
590 lsll:
591 lslul:
592 mov cx,di
593 jcxz lsl_exit
594 and eax, #0x0000FFFF
595 shl ebx, #16
596 or eax, ebx
597 lsl_loop:
598 shl eax, #1
599 loop lsl_loop
600 mov ebx, eax
601 shr ebx, #16
602 lsl_exit:
603 ret
605 idiv_:
606 cwd
607 idiv bx
608 ret
610 idiv_u:
611 xor dx,dx
612 div bx
613 ret
615 ldivul:
616 and eax, #0x0000FFFF
617 shl ebx, #16
618 or eax, ebx
619 xor edx, edx
620 SEG SS
621 mov bx, 2[di]
622 shl ebx, #16
623 SEG SS
624 mov bx, [di]
625 div ebx
626 mov ebx, eax
627 shr ebx, #16
628 ret
630 ASM_END
632 // for access to RAM area which is used by interrupt vectors
633 // and BIOS Data Area
635 typedef struct {
636 unsigned char filler1[0x400];
637 unsigned char filler2[0x6c];
638 Bit16u ticks_low;
639 Bit16u ticks_high;
640 Bit8u midnight_flag;
641 } bios_data_t;
643 #define BiosData ((bios_data_t *) 0)
645 #if BX_USE_ATADRV
646 typedef struct {
647 Bit16u heads; // # heads
648 Bit16u cylinders; // # cylinders
649 Bit16u spt; // # sectors / track
650 } chs_t;
652 // DPTE definition
653 typedef struct {
654 Bit16u iobase1;
655 Bit16u iobase2;
656 Bit8u prefix;
657 Bit8u unused;
658 Bit8u irq;
659 Bit8u blkcount;
660 Bit8u dma;
661 Bit8u pio;
662 Bit16u options;
663 Bit16u reserved;
664 Bit8u revision;
665 Bit8u checksum;
666 } dpte_t;
668 typedef struct {
669 Bit8u iface; // ISA or PCI
670 Bit16u iobase1; // IO Base 1
671 Bit16u iobase2; // IO Base 2
672 Bit8u irq; // IRQ
673 } ata_channel_t;
675 typedef struct {
676 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
677 Bit8u device; // Detected type of attached devices (hd/cd/none)
678 Bit8u removable; // Removable device flag
679 Bit8u lock; // Locks for removable devices
680 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
681 Bit16u blksize; // block size
683 Bit8u translation; // type of translation
684 chs_t lchs; // Logical CHS
685 chs_t pchs; // Physical CHS
687 Bit32u sectors_low; // Total sectors count
688 Bit32u sectors_high;
689 } ata_device_t;
691 typedef struct {
692 // ATA channels info
693 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
695 // ATA devices info
696 ata_device_t devices[BX_MAX_ATA_DEVICES];
697 //
698 // map between (bios hd id - 0x80) and ata channels
699 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
701 // map between (bios cd id - 0xE0) and ata channels
702 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
704 // Buffer for DPTE table
705 dpte_t dpte;
707 // Count of transferred sectors and bytes
708 Bit16u trsfsectors;
709 Bit32u trsfbytes;
711 } ata_t;
713 #if BX_ELTORITO_BOOT
714 // ElTorito Device Emulation data
715 typedef struct {
716 Bit8u active;
717 Bit8u media;
718 Bit8u emulated_drive;
719 Bit8u controller_index;
720 Bit16u device_spec;
721 Bit32u ilba;
722 Bit16u buffer_segment;
723 Bit16u load_segment;
724 Bit16u sector_count;
726 // Virtual device
727 chs_t vdevice;
728 } cdemu_t;
729 #endif // BX_ELTORITO_BOOT
731 #define X(idx, ret, fn, arg...) ret fn ();
732 #include "32bitprotos.h"
733 #undef X
735 // for access to EBDA area
736 // The EBDA structure should conform to
737 // http://www.frontiernet.net/~fys/rombios.htm document
738 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
739 // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot
740 // device tables are at EBDA_SEG:IPL_TABLE_OFFSET
741 typedef struct {
742 unsigned char ebda_size;
743 unsigned char cmos_shutdown_status;
744 unsigned char filler1[0x3B];
746 // FDPT - Can be splitted in data members if needed
747 unsigned char fdpt0[0x10];
748 unsigned char fdpt1[0x10];
750 unsigned char filler2[0xC4];
752 // ATA Driver data
753 ata_t ata;
755 #if BX_ELTORITO_BOOT
756 // El Torito Emulation data
757 cdemu_t cdemu;
758 #endif // BX_ELTORITO_BOOT
759 } ebda_data_t;
761 #define EBDA_CMOS_SHUTDOWN_STATUS_OFFSET 1
762 #define EbdaData ((ebda_data_t *) 0)
764 // for access to the int13ext structure
765 typedef struct {
766 Bit8u size;
767 Bit8u reserved;
768 Bit16u count;
769 Bit16u offset;
770 Bit16u segment;
771 Bit32u lba1;
772 Bit32u lba2;
773 } int13ext_t;
775 #define Int13Ext ((int13ext_t *) 0)
777 // Disk Physical Table definition
778 typedef struct {
779 Bit16u size;
780 Bit16u infos;
781 Bit32u cylinders;
782 Bit32u heads;
783 Bit32u spt;
784 Bit32u sector_count1;
785 Bit32u sector_count2;
786 Bit16u blksize;
787 Bit16u dpte_offset;
788 Bit16u dpte_segment;
789 Bit16u key;
790 Bit8u dpi_length;
791 Bit8u reserved1;
792 Bit16u reserved2;
793 Bit8u host_bus[4];
794 Bit8u iface_type[8];
795 Bit8u iface_path[8];
796 Bit8u device_path[8];
797 Bit8u reserved3;
798 Bit8u checksum;
799 } dpt_t;
801 #define Int13DPT ((dpt_t *) 0)
803 #endif // BX_USE_ATADRV
805 typedef struct {
806 union {
807 struct {
808 Bit16u di, si, bp, sp;
809 Bit16u bx, dx, cx, ax;
810 } r16;
811 struct {
812 Bit16u filler[4];
813 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
814 } r8;
815 } u;
816 } pusha_regs_t;
818 typedef struct {
819 union {
820 struct {
821 Bit32u edi, esi, ebp, esp;
822 Bit32u ebx, edx, ecx, eax;
823 } r32;
824 struct {
825 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
826 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
827 } r16;
828 struct {
829 Bit32u filler[4];
830 Bit8u bl, bh;
831 Bit16u filler1;
832 Bit8u dl, dh;
833 Bit16u filler2;
834 Bit8u cl, ch;
835 Bit16u filler3;
836 Bit8u al, ah;
837 Bit16u filler4;
838 } r8;
839 } u;
840 } pushad_regs_t;
842 typedef struct {
843 union {
844 struct {
845 Bit16u flags;
846 } r16;
847 struct {
848 Bit8u flagsl;
849 Bit8u flagsh;
850 } r8;
851 } u;
852 } flags_t;
854 #define SetCF(x) x.u.r8.flagsl |= 0x01
855 #define SetZF(x) x.u.r8.flagsl |= 0x40
856 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
857 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
858 #define GetCF(x) (x.u.r8.flagsl & 0x01)
860 typedef struct {
861 Bit16u ip;
862 Bit16u cs;
863 flags_t flags;
864 } iret_addr_t;
866 typedef struct {
867 Bit16u type;
868 Bit16u flags;
869 Bit32u vector;
870 Bit32u description;
871 Bit32u reserved;
872 } ipl_entry_t;
876 static Bit8u inb();
877 static Bit8u inb_cmos();
878 static void outb();
879 static void outb_cmos();
880 static Bit16u inw();
881 static void outw();
882 static void init_rtc();
883 static bx_bool rtc_updating();
885 static Bit8u read_byte();
886 static Bit16u read_word();
887 static void write_byte();
888 static void write_word();
889 static void bios_printf();
891 static Bit8u inhibit_mouse_int_and_events();
892 static void enable_mouse_int_and_events();
893 static Bit8u send_to_mouse_ctrl();
894 static Bit8u get_mouse_data();
895 static void set_kbd_command_byte();
897 static void int09_function();
898 static void int13_harddisk();
899 static void int13_cdrom();
900 static void int13_cdemu();
901 static void int13_eltorito();
902 static void int13_diskette_function();
903 static void int14_function();
904 static void int15_function();
905 static void int16_function();
906 static void int17_function();
907 static void int18_function();
908 static void int1a_function();
909 static void int70_function();
910 static void int74_function();
911 static Bit16u get_CS();
912 static Bit16u get_SS();
913 static unsigned int enqueue_key();
914 static unsigned int dequeue_key();
915 static void get_hd_geometry();
916 static void set_diskette_ret_status();
917 static void set_diskette_current_cyl();
918 static void determine_floppy_media();
919 static bx_bool floppy_drive_exists();
920 static bx_bool floppy_drive_recal();
921 static bx_bool floppy_media_known();
922 static bx_bool floppy_media_sense();
923 static bx_bool set_enable_a20();
924 static void debugger_on();
925 static void debugger_off();
926 static void keyboard_init();
927 static void keyboard_panic();
928 static void shutdown_status_panic();
929 static void nmi_handler_msg();
930 static void delay_ticks();
931 static void delay_ticks_and_check_for_keystroke();
933 static void interactive_bootkey();
934 static void print_bios_banner();
935 static void print_boot_device();
936 static void print_boot_failure();
937 static void print_cdromboot_failure();
939 # if BX_USE_ATADRV
941 // ATA / ATAPI driver
942 void ata_init();
943 void ata_detect();
944 void ata_reset();
946 Bit16u ata_cmd_non_data();
947 Bit16u ata_cmd_data_in();
948 Bit16u ata_cmd_data_out();
949 Bit16u ata_cmd_packet();
951 Bit16u atapi_get_sense();
952 Bit16u atapi_is_ready();
953 Bit16u atapi_is_cdrom();
955 #endif // BX_USE_ATADRV
957 #if BX_ELTORITO_BOOT
959 void cdemu_init();
960 Bit8u cdemu_isactive();
961 Bit8u cdemu_emulated_drive();
963 Bit16u cdrom_boot();
965 #endif // BX_ELTORITO_BOOT
967 static char bios_cvs_version_string[] = "$Revision: 1.221 $ $Date: 2008/12/07 17:32:29 $";
969 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
971 #if DEBUG_ATA
972 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
973 #else
974 # define BX_DEBUG_ATA(a...)
975 #endif
976 #if DEBUG_INT13_HD
977 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
978 #else
979 # define BX_DEBUG_INT13_HD(a...)
980 #endif
981 #if DEBUG_INT13_CD
982 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
983 #else
984 # define BX_DEBUG_INT13_CD(a...)
985 #endif
986 #if DEBUG_INT13_ET
987 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
988 #else
989 # define BX_DEBUG_INT13_ET(a...)
990 #endif
991 #if DEBUG_INT13_FL
992 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
993 #else
994 # define BX_DEBUG_INT13_FL(a...)
995 #endif
996 #if DEBUG_INT15
997 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
998 #else
999 # define BX_DEBUG_INT15(a...)
1000 #endif
1001 #if DEBUG_INT16
1002 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1003 #else
1004 # define BX_DEBUG_INT16(a...)
1005 #endif
1006 #if DEBUG_INT1A
1007 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1008 #else
1009 # define BX_DEBUG_INT1A(a...)
1010 #endif
1011 #if DEBUG_INT74
1012 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1013 #else
1014 # define BX_DEBUG_INT74(a...)
1015 #endif
1017 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1018 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1019 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1020 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1021 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1022 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1023 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1024 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1026 #define GET_AL() ( AX & 0x00ff )
1027 #define GET_BL() ( BX & 0x00ff )
1028 #define GET_CL() ( CX & 0x00ff )
1029 #define GET_DL() ( DX & 0x00ff )
1030 #define GET_AH() ( AX >> 8 )
1031 #define GET_BH() ( BX >> 8 )
1032 #define GET_CH() ( CX >> 8 )
1033 #define GET_DH() ( DX >> 8 )
1035 #define GET_ELDL() ( ELDX & 0x00ff )
1036 #define GET_ELDH() ( ELDX >> 8 )
1038 #define SET_CF() FLAGS |= 0x0001
1039 #define CLEAR_CF() FLAGS &= 0xfffe
1040 #define GET_CF() (FLAGS & 0x0001)
1042 #define SET_ZF() FLAGS |= 0x0040
1043 #define CLEAR_ZF() FLAGS &= 0xffbf
1044 #define GET_ZF() (FLAGS & 0x0040)
1046 #define UNSUPPORTED_FUNCTION 0x86
1048 #define none 0
1049 #define MAX_SCAN_CODE 0x58
1051 static struct {
1052 Bit16u normal;
1053 Bit16u shift;
1054 Bit16u control;
1055 Bit16u alt;
1056 Bit8u lock_flags;
1057 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1058 { none, none, none, none, none },
1059 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1060 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1061 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1062 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1063 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1064 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1065 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1066 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1067 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1068 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1069 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1070 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1071 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1072 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1073 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1074 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1075 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1076 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1077 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1078 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1079 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1080 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1081 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1082 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1083 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1084 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1085 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1086 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1087 { none, none, none, none, none }, /* L Ctrl */
1088 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1089 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1090 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1091 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1092 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1093 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1094 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1095 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1096 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1097 { 0x273b, 0x273a, none, none, none }, /* ;: */
1098 { 0x2827, 0x2822, none, none, none }, /* '" */
1099 { 0x2960, 0x297e, none, none, none }, /* `~ */
1100 { none, none, none, none, none }, /* L shift */
1101 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1102 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1103 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1104 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1105 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1106 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1107 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1108 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1109 { 0x332c, 0x333c, none, none, none }, /* ,< */
1110 { 0x342e, 0x343e, none, none, none }, /* .> */
1111 { 0x352f, 0x353f, none, none, none }, /* /? */
1112 { none, none, none, none, none }, /* R Shift */
1113 { 0x372a, 0x372a, none, none, none }, /* * */
1114 { none, none, none, none, none }, /* L Alt */
1115 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1116 { none, none, none, none, none }, /* caps lock */
1117 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1118 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1119 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1120 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1121 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1122 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1123 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1124 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1125 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1126 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1127 { none, none, none, none, none }, /* Num Lock */
1128 { none, none, none, none, none }, /* Scroll Lock */
1129 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1130 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1131 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1132 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1133 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1134 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1135 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1136 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1137 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1138 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1139 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1140 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1141 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1142 { none, none, none, none, none },
1143 { none, none, none, none, none },
1144 { 0x565c, 0x567c, none, none, none }, /* \| */
1145 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1146 { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
1147 };
1149 Bit8u
1150 inb(port)
1151 Bit16u port;
1153 ASM_START
1154 push bp
1155 mov bp, sp
1157 push dx
1158 mov dx, 4[bp]
1159 in al, dx
1160 pop dx
1162 pop bp
1163 ASM_END
1166 #if BX_USE_ATADRV
1167 Bit16u
1168 inw(port)
1169 Bit16u port;
1171 ASM_START
1172 push bp
1173 mov bp, sp
1175 push dx
1176 mov dx, 4[bp]
1177 in ax, dx
1178 pop dx
1180 pop bp
1181 ASM_END
1183 #endif
1185 void
1186 outb(port, val)
1187 Bit16u port;
1188 Bit8u val;
1190 ASM_START
1191 push bp
1192 mov bp, sp
1194 push ax
1195 push dx
1196 mov dx, 4[bp]
1197 mov al, 6[bp]
1198 out dx, al
1199 pop dx
1200 pop ax
1202 pop bp
1203 ASM_END
1206 #if BX_USE_ATADRV
1207 void
1208 outw(port, val)
1209 Bit16u port;
1210 Bit16u val;
1212 ASM_START
1213 push bp
1214 mov bp, sp
1216 push ax
1217 push dx
1218 mov dx, 4[bp]
1219 mov ax, 6[bp]
1220 out dx, ax
1221 pop dx
1222 pop ax
1224 pop bp
1225 ASM_END
1227 #endif
1229 void
1230 outb_cmos(cmos_reg, val)
1231 Bit8u cmos_reg;
1232 Bit8u val;
1234 ASM_START
1235 push bp
1236 mov bp, sp
1238 mov al, 4[bp] ;; cmos_reg
1239 out 0x70, al
1240 mov al, 6[bp] ;; val
1241 out 0x71, al
1243 pop bp
1244 ASM_END
1247 Bit8u
1248 inb_cmos(cmos_reg)
1249 Bit8u cmos_reg;
1251 ASM_START
1252 push bp
1253 mov bp, sp
1255 mov al, 4[bp] ;; cmos_reg
1256 out 0x70, al
1257 in al, 0x71
1259 pop bp
1260 ASM_END
1263 void
1264 init_rtc()
1266 outb_cmos(0x0a, 0x26);
1267 outb_cmos(0x0b, 0x02);
1268 inb_cmos(0x0c);
1269 inb_cmos(0x0d);
1272 bx_bool
1273 rtc_updating()
1275 // This function checks to see if the update-in-progress bit
1276 // is set in CMOS Status Register A. If not, it returns 0.
1277 // If it is set, it tries to wait until there is a transition
1278 // to 0, and will return 0 if such a transition occurs. A 1
1279 // is returned only after timing out. The maximum period
1280 // that this bit should be set is constrained to 244useconds.
1281 // The count I use below guarantees coverage or more than
1282 // this time, with any reasonable IPS setting.
1284 Bit16u count;
1286 count = 25000;
1287 while (--count != 0) {
1288 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1289 return(0);
1291 return(1); // update-in-progress never transitioned to 0
1295 Bit8u
1296 read_byte(seg, offset)
1297 Bit16u seg;
1298 Bit16u offset;
1300 ASM_START
1301 push bp
1302 mov bp, sp
1304 push bx
1305 push ds
1306 mov ax, 4[bp] ; segment
1307 mov ds, ax
1308 mov bx, 6[bp] ; offset
1309 mov al, [bx]
1310 ;; al = return value (byte)
1311 pop ds
1312 pop bx
1314 pop bp
1315 ASM_END
1318 Bit16u
1319 read_word(seg, offset)
1320 Bit16u seg;
1321 Bit16u offset;
1323 ASM_START
1324 push bp
1325 mov bp, sp
1327 push bx
1328 push ds
1329 mov ax, 4[bp] ; segment
1330 mov ds, ax
1331 mov bx, 6[bp] ; offset
1332 mov ax, [bx]
1333 ;; ax = return value (word)
1334 pop ds
1335 pop bx
1337 pop bp
1338 ASM_END
1341 void
1342 write_byte(seg, offset, data)
1343 Bit16u seg;
1344 Bit16u offset;
1345 Bit8u data;
1347 ASM_START
1348 push bp
1349 mov bp, sp
1351 push ax
1352 push bx
1353 push ds
1354 mov ax, 4[bp] ; segment
1355 mov ds, ax
1356 mov bx, 6[bp] ; offset
1357 mov al, 8[bp] ; data byte
1358 mov [bx], al ; write data byte
1359 pop ds
1360 pop bx
1361 pop ax
1363 pop bp
1364 ASM_END
1367 void
1368 write_word(seg, offset, data)
1369 Bit16u seg;
1370 Bit16u offset;
1371 Bit16u data;
1373 ASM_START
1374 push bp
1375 mov bp, sp
1377 push ax
1378 push bx
1379 push ds
1380 mov ax, 4[bp] ; segment
1381 mov ds, ax
1382 mov bx, 6[bp] ; offset
1383 mov ax, 8[bp] ; data word
1384 mov [bx], ax ; write data word
1385 pop ds
1386 pop bx
1387 pop ax
1389 pop bp
1390 ASM_END
1393 Bit16u
1394 get_CS()
1396 ASM_START
1397 mov ax, cs
1398 ASM_END
1401 Bit16u
1402 get_SS()
1404 ASM_START
1405 mov ax, ss
1406 ASM_END
1409 #ifdef HVMASSIST
1410 void
1411 fixup_base_mem_in_k()
1413 /* Report the proper base memory size at address 0x0413: otherwise
1414 * non-e820 code will clobber things if BASE_MEM_IN_K is bigger than
1415 * the first e820 entry. Get the size by reading the second 64bit
1416 * field of the first e820 slot. */
1417 Bit32u base_mem = read_dword(E820_SEG, E820_OFFSET + 8);
1418 write_word(0x40, 0x13, base_mem >> 10);
1421 ASM_START
1422 _rom_write_access_control:
1423 push ds
1424 mov ax,#(BIOS_INFO_PHYSICAL_ADDRESS >> 4)
1425 mov ds,ax
1426 mov ax,[BIOSINFO_OFF_xen_pfiob]
1427 pop ds
1428 ret
1429 ASM_END
1431 void enable_rom_write_access()
1433 outb(rom_write_access_control(), 0);
1436 void disable_rom_write_access()
1438 outb(rom_write_access_control(), PFFLAG_ROM_LOCK);
1441 #endif /* HVMASSIST */
1443 #if BX_DEBUG_SERIAL
1444 /* serial debug port*/
1445 #define BX_DEBUG_PORT 0x03f8
1447 /* data */
1448 #define UART_RBR 0x00
1449 #define UART_THR 0x00
1451 /* control */
1452 #define UART_IER 0x01
1453 #define UART_IIR 0x02
1454 #define UART_FCR 0x02
1455 #define UART_LCR 0x03
1456 #define UART_MCR 0x04
1457 #define UART_DLL 0x00
1458 #define UART_DLM 0x01
1460 /* status */
1461 #define UART_LSR 0x05
1462 #define UART_MSR 0x06
1463 #define UART_SCR 0x07
1465 int uart_can_tx_byte(base_port)
1466 Bit16u base_port;
1468 return inb(base_port + UART_LSR) & 0x20;
1471 void uart_wait_to_tx_byte(base_port)
1472 Bit16u base_port;
1474 while (!uart_can_tx_byte(base_port));
1477 void uart_wait_until_sent(base_port)
1478 Bit16u base_port;
1480 while (!(inb(base_port + UART_LSR) & 0x40));
1483 void uart_tx_byte(base_port, data)
1484 Bit16u base_port;
1485 Bit8u data;
1487 uart_wait_to_tx_byte(base_port);
1488 outb(base_port + UART_THR, data);
1489 uart_wait_until_sent(base_port);
1491 #endif
1493 void
1494 wrch(c)
1495 Bit8u c;
1497 ASM_START
1498 push bp
1499 mov bp, sp
1501 push bx
1502 mov ah, #0x0e
1503 mov al, 4[bp]
1504 xor bx,bx
1505 int #0x10
1506 pop bx
1508 pop bp
1509 ASM_END
1512 void
1513 send(action, c)
1514 Bit16u action;
1515 Bit8u c;
1517 #if BX_DEBUG_SERIAL
1518 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1519 uart_tx_byte(BX_DEBUG_PORT, c);
1520 #endif
1521 #ifdef HVMASSIST
1522 outb(0xE9, c);
1523 #endif
1524 #if BX_VIRTUAL_PORTS
1525 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1526 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1527 #endif
1528 if (action & BIOS_PRINTF_SCREEN) {
1529 if (c == '\n') wrch('\r');
1530 wrch(c);
1534 void
1535 put_int(action, val, width, neg)
1536 Bit16u action;
1537 short val, width;
1538 bx_bool neg;
1540 short nval = val / 10;
1541 if (nval)
1542 put_int(action, nval, width - 1, neg);
1543 else {
1544 while (--width > 0) send(action, ' ');
1545 if (neg) send(action, '-');
1547 send(action, val - (nval * 10) + '0');
1550 void
1551 put_uint(action, val, width, neg)
1552 Bit16u action;
1553 unsigned short val;
1554 short width;
1555 bx_bool neg;
1557 unsigned short nval = val / 10;
1558 if (nval)
1559 put_uint(action, nval, width - 1, neg);
1560 else {
1561 while (--width > 0) send(action, ' ');
1562 if (neg) send(action, '-');
1564 send(action, val - (nval * 10) + '0');
1567 void
1568 put_luint(action, val, width, neg)
1569 Bit16u action;
1570 unsigned long val;
1571 short width;
1572 bx_bool neg;
1574 unsigned long nval = val / 10;
1575 if (nval)
1576 put_luint(action, nval, width - 1, neg);
1577 else {
1578 while (--width > 0) send(action, ' ');
1579 if (neg) send(action, '-');
1581 send(action, val - (nval * 10) + '0');
1584 void put_str(action, segment, offset)
1585 Bit16u action;
1586 Bit16u segment;
1587 Bit16u offset;
1589 Bit8u c;
1591 while (c = read_byte(segment, offset)) {
1592 send(action, c);
1593 offset++;
1597 void
1598 delay_ticks(ticks)
1599 Bit16u ticks;
1601 long ticks_to_wait, delta;
1602 Bit32u prev_ticks, t;
1604 /*
1605 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
1606 * We also have to be careful about interrupt storms.
1607 */
1608 ASM_START
1609 pushf
1610 sti
1611 ASM_END
1612 ticks_to_wait = ticks;
1613 prev_ticks = read_dword(0x0, 0x46c);
1614 do
1616 ASM_START
1617 hlt
1618 ASM_END
1619 t = read_dword(0x0, 0x46c);
1620 if (t > prev_ticks)
1622 delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
1623 ticks_to_wait -= delta;
1625 else if (t < prev_ticks)
1627 ticks_to_wait -= t; /* wrapped */
1630 prev_ticks = t;
1631 } while (ticks_to_wait > 0);
1632 ASM_START
1633 cli
1634 popf
1635 ASM_END
1638 Bit8u
1639 check_for_keystroke()
1641 ASM_START
1642 mov ax, #0x100
1643 int #0x16
1644 jz no_key
1645 mov al, #1
1646 jmp done
1647 no_key:
1648 xor al, al
1649 done:
1650 ASM_END
1653 Bit8u
1654 get_keystroke()
1656 ASM_START
1657 mov ax, #0x0
1658 int #0x16
1659 xchg ah, al
1660 ASM_END
1663 void
1664 delay_ticks_and_check_for_keystroke(ticks, count)
1665 Bit16u ticks, count;
1667 Bit16u i;
1668 for (i = 1; i <= count; i++) {
1669 delay_ticks(ticks);
1670 if (check_for_keystroke())
1671 break;
1675 //--------------------------------------------------------------------------
1676 // bios_printf()
1677 // A compact variable argument printf function.
1678 //
1679 // Supports %[format_width][length]format
1680 // where format can be x,X,u,d,s,S,c
1681 // and the optional length modifier is l (ell)
1682 //--------------------------------------------------------------------------
1683 void
1684 bios_printf(action, s)
1685 Bit16u action;
1686 Bit8u *s;
1688 Bit8u c, format_char;
1689 bx_bool in_format;
1690 short i;
1691 Bit16u *arg_ptr;
1692 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1694 arg_ptr = &s;
1695 arg_seg = get_SS();
1697 in_format = 0;
1698 format_width = 0;
1700 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1701 #if BX_VIRTUAL_PORTS
1702 outb(PANIC_PORT2, 0x00);
1703 #endif
1704 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1707 while (c = read_byte(get_CS(), s)) {
1708 if ( c == '%' ) {
1709 in_format = 1;
1710 format_width = 0;
1712 else if (in_format) {
1713 if ( (c>='0') && (c<='9') ) {
1714 format_width = (format_width * 10) + (c - '0');
1716 else {
1717 arg_ptr++; // increment to next arg
1718 arg = read_word(arg_seg, arg_ptr);
1719 if (c == 'x' || c == 'X') {
1720 if (format_width == 0)
1721 format_width = 4;
1722 if (c == 'x')
1723 hexadd = 'a';
1724 else
1725 hexadd = 'A';
1726 for (i=format_width-1; i>=0; i--) {
1727 nibble = (arg >> (4 * i)) & 0x000f;
1728 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1731 else if (c == 'u') {
1732 put_uint(action, arg, format_width, 0);
1734 else if (c == 'l') {
1735 s++;
1736 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1737 arg_ptr++; /* increment to next arg */
1738 hibyte = read_word(arg_seg, arg_ptr);
1739 if (c == 'd') {
1740 if (hibyte & 0x8000)
1741 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1742 else
1743 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1745 else if (c == 'u') {
1746 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1748 else if (c == 'x' || c == 'X')
1750 if (format_width == 0)
1751 format_width = 8;
1752 if (c == 'x')
1753 hexadd = 'a';
1754 else
1755 hexadd = 'A';
1756 for (i=format_width-1; i>=0; i--) {
1757 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1758 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1762 else if (c == 'd') {
1763 if (arg & 0x8000)
1764 put_int(action, -arg, format_width - 1, 1);
1765 else
1766 put_int(action, arg, format_width, 0);
1768 else if (c == 's') {
1769 put_str(action, get_CS(), arg);
1771 else if (c == 'S') {
1772 hibyte = arg;
1773 arg_ptr++;
1774 arg = read_word(arg_seg, arg_ptr);
1775 put_str(action, hibyte, arg);
1777 else if (c == 'c') {
1778 send(action, arg);
1780 else
1781 BX_PANIC("bios_printf: unknown format\n");
1782 in_format = 0;
1785 else {
1786 send(action, c);
1788 s ++;
1791 if (action & BIOS_PRINTF_HALT) {
1792 // freeze in a busy loop.
1793 ASM_START
1794 cli
1795 halt2_loop:
1796 hlt
1797 jmp halt2_loop
1798 ASM_END
1802 //--------------------------------------------------------------------------
1803 // keyboard_init
1804 //--------------------------------------------------------------------------
1805 // this file is based on LinuxBIOS implementation of keyboard.c
1806 // could convert to #asm to gain space
1807 void
1808 keyboard_init()
1810 Bit16u max;
1812 /* ------------------- Flush buffers ------------------------*/
1813 /* Wait until buffer is empty */
1814 max=0xffff;
1815 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1817 /* flush incoming keys */
1818 max=0x2000;
1819 while (--max > 0) {
1820 outb(0x80, 0x00);
1821 if (inb(0x64) & 0x01) {
1822 inb(0x60);
1823 max = 0x2000;
1827 // Due to timer issues, and if the IPS setting is > 15000000,
1828 // the incoming keys might not be flushed here. That will
1829 // cause a panic a few lines below. See sourceforge bug report :
1830 // [ 642031 ] FATAL: Keyboard RESET error:993
1832 /* ------------------- controller side ----------------------*/
1833 /* send cmd = 0xAA, self test 8042 */
1834 outb(0x64, 0xaa);
1836 /* Wait until buffer is empty */
1837 max=0xffff;
1838 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1839 if (max==0x0) keyboard_panic(00);
1841 /* Wait for data */
1842 max=0xffff;
1843 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1844 if (max==0x0) keyboard_panic(01);
1846 /* read self-test result, 0x55 should be returned from 0x60 */
1847 if ((inb(0x60) != 0x55)){
1848 keyboard_panic(991);
1851 /* send cmd = 0xAB, keyboard interface test */
1852 outb(0x64,0xab);
1854 /* Wait until buffer is empty */
1855 max=0xffff;
1856 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1857 if (max==0x0) keyboard_panic(10);
1859 /* Wait for data */
1860 max=0xffff;
1861 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1862 if (max==0x0) keyboard_panic(11);
1864 /* read keyboard interface test result, */
1865 /* 0x00 should be returned form 0x60 */
1866 if ((inb(0x60) != 0x00)) {
1867 keyboard_panic(992);
1870 /* Enable Keyboard clock */
1871 outb(0x64,0xae);
1872 outb(0x64,0xa8);
1874 /* ------------------- keyboard side ------------------------*/
1875 /* reset kerboard and self test (keyboard side) */
1876 outb(0x60, 0xff);
1878 /* Wait until buffer is empty */
1879 max=0xffff;
1880 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1881 if (max==0x0) keyboard_panic(20);
1883 /* Wait for data */
1884 max=0xffff;
1885 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1886 if (max==0x0) keyboard_panic(21);
1888 /* keyboard should return ACK */
1889 if ((inb(0x60) != 0xfa)) {
1890 keyboard_panic(993);
1893 /* Wait for data */
1894 max=0xffff;
1895 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1896 if (max==0x0) keyboard_panic(31);
1898 if ((inb(0x60) != 0xaa)) {
1899 keyboard_panic(994);
1902 /* Disable keyboard */
1903 outb(0x60, 0xf5);
1905 /* Wait until buffer is empty */
1906 max=0xffff;
1907 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1908 if (max==0x0) keyboard_panic(40);
1910 /* Wait for data */
1911 max=0xffff;
1912 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1913 if (max==0x0) keyboard_panic(41);
1915 /* keyboard should return ACK */
1916 if ((inb(0x60) != 0xfa)) {
1917 keyboard_panic(995);
1920 /* Write Keyboard Mode */
1921 outb(0x64, 0x60);
1923 /* Wait until buffer is empty */
1924 max=0xffff;
1925 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1926 if (max==0x0) keyboard_panic(50);
1928 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1929 outb(0x60, 0x61);
1931 /* Wait until buffer is empty */
1932 max=0xffff;
1933 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1934 if (max==0x0) keyboard_panic(60);
1936 /* Enable keyboard */
1937 outb(0x60, 0xf4);
1939 /* Wait until buffer is empty */
1940 max=0xffff;
1941 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1942 if (max==0x0) keyboard_panic(70);
1944 /* Wait for data */
1945 max=0xffff;
1946 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1947 if (max==0x0) keyboard_panic(70);
1949 /* keyboard should return ACK */
1950 if ((inb(0x60) != 0xfa)) {
1951 keyboard_panic(996);
1954 outb(0x80, 0x77);
1957 //--------------------------------------------------------------------------
1958 // keyboard_panic
1959 //--------------------------------------------------------------------------
1960 void
1961 keyboard_panic(status)
1962 Bit16u status;
1964 // If you're getting a 993 keyboard panic here,
1965 // please see the comment in keyboard_init
1967 BX_PANIC("Keyboard error:%u\n",status);
1970 #define CMOS_SHUTDOWN_S3 0xFE
1971 //--------------------------------------------------------------------------
1972 // machine_reset
1973 //--------------------------------------------------------------------------
1974 void
1975 machine_reset()
1977 ASM_START
1978 ;we must check whether CMOS_SHUTDOWN_S3 is set or not
1979 ;if it is s3 resume, just jmp back to normal Post Entry
1980 ;below port io will prevent s3 resume
1981 mov al, #0x0f
1982 out 0x70, al
1983 in al, 0x71
1984 cmp al, #0xFE
1985 jz post
1986 ASM_END
1987 /* Frob the keyboard reset line to reset the processor */
1988 outb(0x64, 0x60); /* Map the flags register at data port (0x60) */
1989 outb(0x60, 0x14); /* Set the flags to system|disable */
1990 outb(0x64, 0xfe); /* Pulse output 0 (system reset) low */
1991 BX_PANIC("Couldn't reset the machine\n");
1994 //--------------------------------------------------------------------------
1995 // clobber_entry_point
1996 // Because PV drivers in HVM guests detach some of the emulated devices,
1997 // it is not safe to do a soft reboot by just dropping to real mode and
1998 // jumping at ffff:0000. -- the boot drives might have disappeared!
1999 // This rather foul function overwrites(!) the BIOS entry point
2000 // to point at machine-reset, which will cause the Xen tools to
2001 // rebuild the whole machine from scratch.
2002 //--------------------------------------------------------------------------
2003 void
2004 clobber_entry_point()
2006 /* The instruction at the entry point is one byte (0xea) for the
2007 * jump opcode, then two bytes of address, then two of segment.
2008 * Overwrite the address bytes.*/
2009 write_word(0xffff, 0x0001, machine_reset);
2013 //--------------------------------------------------------------------------
2014 // shutdown_status_panic
2015 // called when the shutdown statsu is not implemented, displays the status
2016 //--------------------------------------------------------------------------
2017 void
2018 shutdown_status_panic(status)
2019 Bit16u status;
2021 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
2024 void s3_resume_panic()
2026 BX_PANIC("Returned from s3_resume.\n");
2029 //--------------------------------------------------------------------------
2030 // print_bios_banner
2031 // displays a the bios version
2032 //--------------------------------------------------------------------------
2033 void
2034 print_bios_banner()
2036 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
2037 BIOS_BUILD_DATE, bios_cvs_version_string);
2038 printf(
2039 #if BX_APM
2040 "apmbios "
2041 #endif
2042 #if BX_PCIBIOS
2043 "pcibios "
2044 #endif
2045 #if BX_ELTORITO_BOOT
2046 "eltorito "
2047 #endif
2048 #if BX_ROMBIOS32
2049 "rombios32 "
2050 #endif
2051 #if BX_TCGBIOS
2052 "TCG-enabled "
2053 #endif
2054 #if BX_PMM
2055 "PMM "
2056 #endif
2057 "\n\n");
2060 //--------------------------------------------------------------------------
2061 // BIOS Boot Specification 1.0.1 compatibility
2062 //
2063 // Very basic support for the BIOS Boot Specification, which allows expansion
2064 // ROMs to register themselves as boot devices, instead of just stealing the
2065 // INT 19h boot vector.
2066 //
2067 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
2068 // one; we just lie to the option ROMs to make them behave correctly.
2069 // We also don't support letting option ROMs register as bootable disk
2070 // drives (BCVs), only as bootable devices (BEVs).
2071 //
2072 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
2073 //--------------------------------------------------------------------------
2075 static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
2077 static void
2078 init_boot_vectors()
2080 ipl_entry_t e;
2081 Bit16u count = 0;
2082 Bit16u ss = get_SS();
2083 Bit16u ebda_seg = read_word(0x0040, 0x000E);
2085 /* Clear out the IPL table. */
2086 memsetb(ebda_seg, IPL_TABLE_OFFSET, 0, IPL_SIZE);
2088 /* User selected device not set */
2089 write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF);
2091 /* Floppy drive */
2092 e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
2093 memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
2094 count++;
2096 /* First HDD */
2097 e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
2098 memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
2099 count++;
2101 #if BX_ELTORITO_BOOT
2102 /* CDROM */
2103 e.type = IPL_TYPE_CDROM; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
2104 memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
2105 count++;
2106 #endif
2108 /* Remember how many devices we have */
2109 write_word(ebda_seg, IPL_COUNT_OFFSET, count);
2110 /* Not tried booting anything yet */
2111 write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xffff);
2114 static Bit8u
2115 get_boot_vector(i, e)
2116 Bit16u i; ipl_entry_t *e;
2118 Bit16u count;
2119 Bit16u ss = get_SS();
2120 Bit16u ebda_seg = read_word(0x0040, 0x000E);
2121 /* Get the count of boot devices, and refuse to overrun the array */
2122 count = read_word(ebda_seg, IPL_COUNT_OFFSET);
2123 if (i >= count) return 0;
2124 /* OK to read this device */
2125 memcpyb(ss, e, ebda_seg, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
2126 return 1;
2129 #if BX_ELTORITO_BOOT
2130 void
2131 interactive_bootkey()
2133 ipl_entry_t e;
2134 Bit16u count;
2135 char description[33];
2136 Bit8u scan_code;
2137 Bit8u i;
2138 Bit16u ss = get_SS();
2139 Bit16u valid_choice = 0;
2140 Bit16u ebda_seg = read_word(0x0040, 0x000E);
2142 printf("\n\nPress F12 for boot menu.\n\n");
2144 while (check_for_keystroke())
2146 scan_code = get_keystroke();
2147 if (scan_code != 0x86) /* F12 */
2148 continue;
2150 while (check_for_keystroke())
2151 get_keystroke();
2153 printf("Select boot device:\n\n");
2155 count = read_word(ebda_seg, IPL_COUNT_OFFSET);
2156 for (i = 0; i < count; i++)
2158 memcpyb(ss, &e, ebda_seg, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e));
2159 printf("%d. ", i+1);
2160 switch(e.type)
2162 case IPL_TYPE_FLOPPY:
2163 case IPL_TYPE_HARDDISK:
2164 case IPL_TYPE_CDROM:
2165 printf("%s\n", drivetypes[e.type]);
2166 break;
2167 case IPL_TYPE_BEV:
2168 printf("%s", drivetypes[4]);
2169 if (e.description != 0)
2171 memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32);
2172 description[32] = 0;
2173 printf(" [%S]", ss, description);
2175 printf("\n");
2176 break;
2180 count++;
2181 while (!valid_choice) {
2182 scan_code = get_keystroke();
2183 if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */
2185 valid_choice = 1;
2187 else if (scan_code <= count)
2189 valid_choice = 1;
2190 scan_code -= 1;
2191 /* Set user selected device */
2192 write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, scan_code);
2196 printf("\n");
2197 break;
2200 #endif // BX_ELTORITO_BOOT
2202 //--------------------------------------------------------------------------
2203 // print_boot_device
2204 // displays the boot device
2205 //--------------------------------------------------------------------------
2207 void
2208 print_boot_device(e)
2209 ipl_entry_t *e;
2211 Bit16u type;
2212 char description[33];
2213 Bit16u ss = get_SS();
2214 type = e->type;
2215 /* NIC appears as type 0x80 */
2216 if (type == IPL_TYPE_BEV) type = 0x4;
2217 if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
2218 printf("Booting from %s", drivetypes[type]);
2219 /* print product string if BEV */
2220 if (type == 4 && e->description != 0) {
2221 /* first 32 bytes are significant */
2222 memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
2223 /* terminate string */
2224 description[32] = 0;
2225 printf(" [%S]", ss, description);
2227 printf("...\n");
2230 //--------------------------------------------------------------------------
2231 // print_boot_failure
2232 // displays the reason why boot failed
2233 //--------------------------------------------------------------------------
2234 void
2235 print_boot_failure(type, reason)
2236 Bit16u type; Bit8u reason;
2238 if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
2240 printf("Boot from %s failed", drivetypes[type]);
2241 if (type < 4) {
2242 /* Report the reason too */
2243 if (reason==0)
2244 printf(": not a bootable disk");
2245 else
2246 printf(": could not read the boot disk");
2248 printf("\n\n");
2251 //--------------------------------------------------------------------------
2252 // print_cdromboot_failure
2253 // displays the reason why boot failed
2254 //--------------------------------------------------------------------------
2255 void
2256 print_cdromboot_failure( code )
2257 Bit16u code;
2259 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2261 return;
2264 void
2265 nmi_handler_msg()
2267 BX_PANIC("NMI Handler called\n");
2270 void
2271 int18_panic_msg()
2273 BX_PANIC("INT18: BOOT FAILURE\n");
2276 void
2277 log_bios_start()
2279 #if BX_DEBUG_SERIAL
2280 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2281 #endif
2282 BX_INFO("%s\n", bios_cvs_version_string);
2285 bx_bool
2286 set_enable_a20(val)
2287 bx_bool val;
2289 Bit8u oldval;
2291 // Use PS2 System Control port A to set A20 enable
2293 // get current setting first
2294 oldval = inb(0x92);
2296 // change A20 status
2297 if (val)
2298 outb(0x92, oldval | 0x02);
2299 else
2300 outb(0x92, oldval & 0xfd);
2302 return((oldval & 0x02) != 0);
2305 void
2306 debugger_on()
2308 outb(0xfedc, 0x01);
2311 void
2312 debugger_off()
2314 outb(0xfedc, 0x00);
2317 int
2318 s3_resume()
2320 Bit32u s3_wakeup_vector;
2321 Bit8u s3_resume_flag;
2323 s3_resume_flag = read_byte(0x40, 0xb0);
2324 #ifdef HVMASSIST
2325 s3_wakeup_vector = get_s3_waking_vector();
2326 #else
2327 s3_wakeup_vector = read_dword(0x40, 0xb2);
2328 #endif
2330 BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag, s3_wakeup_vector);
2331 if (s3_resume_flag != CMOS_SHUTDOWN_S3 || !s3_wakeup_vector)
2332 return 0;
2334 write_byte(0x40, 0xb0, 0);
2336 /* setup wakeup vector */
2337 write_word(0x40, 0xb6, (s3_wakeup_vector & 0xF)); /* IP */
2338 write_word(0x40, 0xb8, (s3_wakeup_vector >> 4)); /* CS */
2340 BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector >> 4),
2341 (s3_wakeup_vector & 0xF));
2342 ASM_START
2343 jmpf [0x04b6]
2344 ASM_END
2345 return 1;
2348 #if BX_USE_ATADRV
2350 // ---------------------------------------------------------------------------
2351 // Start of ATA/ATAPI Driver
2352 // ---------------------------------------------------------------------------
2354 // Global defines -- ATA register and register bits.
2355 // command block & control block regs
2356 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2357 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2358 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2359 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2360 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2361 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2362 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2363 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2364 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2365 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2366 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2367 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2368 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2370 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2371 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2372 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2373 #define ATA_CB_ER_MC 0x20 // ATA media change
2374 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2375 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2376 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2377 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2378 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2380 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2381 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2382 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2383 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2384 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2386 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2387 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2388 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2389 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2390 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2392 // bits 7-4 of the device/head (CB_DH) reg
2393 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2394 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2395 #define ATA_CB_DH_LBA 0x40 // use LBA
2397 // status reg (CB_STAT and CB_ASTAT) bits
2398 #define ATA_CB_STAT_BSY 0x80 // busy
2399 #define ATA_CB_STAT_RDY 0x40 // ready
2400 #define ATA_CB_STAT_DF 0x20 // device fault
2401 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2402 #define ATA_CB_STAT_SKC 0x10 // seek complete
2403 #define ATA_CB_STAT_SERV 0x10 // service
2404 #define ATA_CB_STAT_DRQ 0x08 // data request
2405 #define ATA_CB_STAT_CORR 0x04 // corrected
2406 #define ATA_CB_STAT_IDX 0x02 // index
2407 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2408 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2410 // device control reg (CB_DC) bits
2411 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2412 #define ATA_CB_DC_SRST 0x04 // soft reset
2413 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2415 // Most mandtory and optional ATA commands (from ATA-3),
2416 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2417 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2418 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2419 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2420 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2421 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2422 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2423 #define ATA_CMD_DEVICE_RESET 0x08
2424 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2425 #define ATA_CMD_FLUSH_CACHE 0xE7
2426 #define ATA_CMD_FORMAT_TRACK 0x50
2427 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2428 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2429 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2430 #define ATA_CMD_IDLE1 0xE3
2431 #define ATA_CMD_IDLE2 0x97
2432 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2433 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2434 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2435 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2436 #define ATA_CMD_NOP 0x00
2437 #define ATA_CMD_PACKET 0xA0
2438 #define ATA_CMD_READ_BUFFER 0xE4
2439 #define ATA_CMD_READ_DMA 0xC8
2440 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2441 #define ATA_CMD_READ_MULTIPLE 0xC4
2442 #define ATA_CMD_READ_SECTORS 0x20
2443 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2444 #define ATA_CMD_RECALIBRATE 0x10
2445 #define ATA_CMD_REQUEST_SENSE 0x03
2446 #define ATA_CMD_SEEK 0x70
2447 #define ATA_CMD_SET_FEATURES 0xEF
2448 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2449 #define ATA_CMD_SLEEP1 0xE6
2450 #define ATA_CMD_SLEEP2 0x99
2451 #define ATA_CMD_STANDBY1 0xE2
2452 #define ATA_CMD_STANDBY2 0x96
2453 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2454 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2455 #define ATA_CMD_WRITE_BUFFER 0xE8
2456 #define ATA_CMD_WRITE_DMA 0xCA
2457 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2458 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2459 #define ATA_CMD_WRITE_SECTORS 0x30
2460 #define ATA_CMD_WRITE_VERIFY 0x3C
2462 #define ATA_IFACE_NONE 0x00
2463 #define ATA_IFACE_ISA 0x00
2464 #define ATA_IFACE_PCI 0x01
2466 #define ATA_TYPE_NONE 0x00
2467 #define ATA_TYPE_UNKNOWN 0x01
2468 #define ATA_TYPE_ATA 0x02
2469 #define ATA_TYPE_ATAPI 0x03
2471 #define ATA_DEVICE_NONE 0x00
2472 #define ATA_DEVICE_HD 0xFF
2473 #define ATA_DEVICE_CDROM 0x05
2475 #define ATA_MODE_NONE 0x00
2476 #define ATA_MODE_PIO16 0x00
2477 #define ATA_MODE_PIO32 0x01
2478 #define ATA_MODE_ISADMA 0x02
2479 #define ATA_MODE_PCIDMA 0x03
2480 #define ATA_MODE_USEIRQ 0x10
2482 #define ATA_TRANSLATION_NONE 0
2483 #define ATA_TRANSLATION_LBA 1
2484 #define ATA_TRANSLATION_LARGE 2
2485 #define ATA_TRANSLATION_RECHS 3
2487 #define ATA_DATA_NO 0x00
2488 #define ATA_DATA_IN 0x01
2489 #define ATA_DATA_OUT 0x02
2491 // ---------------------------------------------------------------------------
2492 // ATA/ATAPI driver : initialization
2493 // ---------------------------------------------------------------------------
2494 void ata_init( )
2496 Bit16u ebda_seg=read_word(0x0040,0x000E);
2497 Bit8u channel, device;
2499 // Channels info init.
2500 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2501 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2502 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2503 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2504 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2507 // Devices info init.
2508 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2509 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2510 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2511 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2512 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2513 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2514 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2515 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2516 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2517 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2518 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2519 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2520 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2521 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2523 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low,0L);
2524 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high,0L);
2527 // hdidmap and cdidmap init.
2528 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2529 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2530 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2533 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2534 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2537 #define TIMEOUT 0
2538 #define BSY 1
2539 #define NOT_BSY 2
2540 #define NOT_BSY_DRQ 3
2541 #define NOT_BSY_NOT_DRQ 4
2542 #define NOT_BSY_RDY 5
2544 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
2546 int await_ide();
2547 static int await_ide(when_done,base,timeout)
2548 Bit8u when_done;
2549 Bit16u base;
2550 Bit16u timeout;
2552 Bit32u time=0,last=0;
2553 Bit16u status;
2554 Bit8u result;
2555 status = inb(base + ATA_CB_STAT); // for the times you're supposed to throw one away
2556 for(;;) {
2557 status = inb(base+ATA_CB_STAT);
2558 time++;
2559 if (when_done == BSY)
2560 result = status & ATA_CB_STAT_BSY;
2561 else if (when_done == NOT_BSY)
2562 result = !(status & ATA_CB_STAT_BSY);
2563 else if (when_done == NOT_BSY_DRQ)
2564 result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ);
2565 else if (when_done == NOT_BSY_NOT_DRQ)
2566 result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ);
2567 else if (when_done == NOT_BSY_RDY)
2568 result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY);
2569 else if (when_done == TIMEOUT)
2570 result = 0;
2572 if (result) return 0;
2573 if (time>>16 != last) // mod 2048 each 16 ms
2575 last = time >>16;
2576 BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
2578 if (status & ATA_CB_STAT_ERR)
2580 BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
2581 return -1;
2583 if ((timeout == 0) || ((time>>11) > timeout)) break;
2585 BX_INFO("IDE time out\n");
2586 return -1;
2589 // ---------------------------------------------------------------------------
2590 // ATA/ATAPI driver : device detection
2591 // ---------------------------------------------------------------------------
2593 void ata_detect( )
2595 Bit16u ebda_seg=read_word(0x0040,0x000E);
2596 Bit8u hdcount, cdcount, device, type;
2597 Bit8u buffer[0x0200];
2599 #if BX_MAX_ATA_INTERFACES > 0
2600 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2601 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2602 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2603 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2604 #endif
2605 #if BX_MAX_ATA_INTERFACES > 1
2606 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2607 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2608 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2609 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2610 #endif
2611 #if BX_MAX_ATA_INTERFACES > 2
2612 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2613 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2614 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2615 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2616 #endif
2617 #if BX_MAX_ATA_INTERFACES > 3
2618 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2619 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2620 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2621 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2622 #endif
2623 #if BX_MAX_ATA_INTERFACES > 4
2624 #error Please fill the ATA interface informations
2625 #endif
2627 // Device detection
2628 hdcount=cdcount=0;
2630 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2631 Bit16u iobase1, iobase2;
2632 Bit8u channel, slave, shift;
2633 Bit8u sc, sn, cl, ch, st;
2635 channel = device / 2;
2636 slave = device % 2;
2638 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2639 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2641 // Disable interrupts
2642 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2644 // Look for device
2645 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2646 outb(iobase1+ATA_CB_SC, 0x55);
2647 outb(iobase1+ATA_CB_SN, 0xaa);
2648 outb(iobase1+ATA_CB_SC, 0xaa);
2649 outb(iobase1+ATA_CB_SN, 0x55);
2650 outb(iobase1+ATA_CB_SC, 0x55);
2651 outb(iobase1+ATA_CB_SN, 0xaa);
2653 // If we found something
2654 sc = inb(iobase1+ATA_CB_SC);
2655 sn = inb(iobase1+ATA_CB_SN);
2657 if ( (sc == 0x55) && (sn == 0xaa) ) {
2658 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2660 // reset the channel
2661 ata_reset(device);
2663 // check for ATA or ATAPI
2664 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2665 sc = inb(iobase1+ATA_CB_SC);
2666 sn = inb(iobase1+ATA_CB_SN);
2667 if ((sc==0x01) && (sn==0x01)) {
2668 cl = inb(iobase1+ATA_CB_CL);
2669 ch = inb(iobase1+ATA_CB_CH);
2670 st = inb(iobase1+ATA_CB_STAT);
2672 if ((cl==0x14) && (ch==0xeb)) {
2673 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2674 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2675 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2676 } else if ((cl==0xff) && (ch==0xff)) {
2677 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2682 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2684 // Now we send a IDENTIFY command to ATA device
2685 if(type == ATA_TYPE_ATA) {
2686 Bit32u sectors_low, sectors_high;
2687 Bit16u cylinders, heads, spt, blksize;
2688 Bit8u translation, removable, mode;
2690 // default mode to PIO16
2691 mode = ATA_MODE_PIO16;
2693 //Temporary values to do the transfer
2694 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2695 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2697 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) !=0 )
2698 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2700 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2701 #ifndef NO_PIO32
2702 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2703 #endif
2704 blksize = read_word(get_SS(),buffer+10);
2706 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2707 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2708 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2710 if (read_word(get_SS(),buffer+(83*2)) & (1 << 10)) { // word 83 - lba48 support
2711 sectors_low = read_dword(get_SS(),buffer+(100*2)); // word 100 and word 101
2712 sectors_high = read_dword(get_SS(),buffer+(102*2)); // word 102 and word 103
2713 } else {
2714 sectors_low = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2715 sectors_high = 0;
2718 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2719 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2720 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2721 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2722 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2723 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2724 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2725 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors_low);
2726 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high, sectors_high);
2727 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2729 translation = inb_cmos(0x39 + channel/2);
2730 for (shift=device%4; shift>0; shift--) translation >>= 2;
2731 translation &= 0x03;
2733 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2735 switch (translation) {
2736 case ATA_TRANSLATION_NONE:
2737 BX_INFO("none");
2738 break;
2739 case ATA_TRANSLATION_LBA:
2740 BX_INFO("lba");
2741 break;
2742 case ATA_TRANSLATION_LARGE:
2743 BX_INFO("large");
2744 break;
2745 case ATA_TRANSLATION_RECHS:
2746 BX_INFO("r-echs");
2747 break;
2749 switch (translation) {
2750 case ATA_TRANSLATION_NONE:
2751 break;
2752 case ATA_TRANSLATION_LBA:
2753 spt = 63;
2754 sectors_low /= 63;
2755 heads = sectors_low / 1024;
2756 if (heads>128) heads = 255;
2757 else if (heads>64) heads = 128;
2758 else if (heads>32) heads = 64;
2759 else if (heads>16) heads = 32;
2760 else heads=16;
2761 cylinders = sectors_low / heads;
2762 break;
2763 case ATA_TRANSLATION_RECHS:
2764 // Take care not to overflow
2765 if (heads==16) {
2766 if(cylinders>61439) cylinders=61439;
2767 heads=15;
2768 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2770 // then go through the large bitshift process
2771 case ATA_TRANSLATION_LARGE:
2772 while(cylinders > 1024) {
2773 cylinders >>= 1;
2774 heads <<= 1;
2776 // If we max out the head count
2777 if (heads > 127) break;
2779 break;
2781 // clip to 1024 cylinders in lchs
2782 if (cylinders > 1024) cylinders=1024;
2783 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2785 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2786 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2787 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2789 // fill hdidmap
2790 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2791 hdcount++;
2794 // Now we send a IDENTIFY command to ATAPI device
2795 if(type == ATA_TYPE_ATAPI) {
2797 Bit8u type, removable, mode;
2798 Bit16u blksize;
2800 // default mode to PIO16
2801 mode = ATA_MODE_PIO16;
2803 //Temporary values to do the transfer
2804 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2805 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2807 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) != 0)
2808 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2810 type = read_byte(get_SS(),buffer+1) & 0x1f;
2811 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2812 #ifndef NO_PIO32
2813 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2814 #endif
2815 blksize = 2048;
2817 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2818 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2819 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2820 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2822 // fill cdidmap
2823 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2824 cdcount++;
2828 Bit32u sizeinmb;
2829 Bit16u ataversion;
2830 Bit8u c, i, version, model[41];
2832 switch (type) {
2833 case ATA_TYPE_ATA:
2834 sizeinmb = (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high) << 21)
2835 | (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low) >> 11);
2836 case ATA_TYPE_ATAPI:
2837 // Read ATA/ATAPI version
2838 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2839 for(version=15;version>0;version--) {
2840 if((ataversion&(1<<version))!=0)
2841 break;
2844 // Read model name
2845 for(i=0;i<20;i++){
2846 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2847 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2850 // Reformat
2851 write_byte(get_SS(),model+40,0x00);
2852 for(i=39;i>0;i--){
2853 if(read_byte(get_SS(),model+i)==0x20)
2854 write_byte(get_SS(),model+i,0x00);
2855 else break;
2857 if (i>36) {
2858 write_byte(get_SS(),model+36,0x00);
2859 for(i=35;i>32;i--){
2860 write_byte(get_SS(),model+i,0x2E);
2863 break;
2866 switch (type) {
2867 case ATA_TYPE_ATA:
2868 printf("ata%d %s: ",channel,slave?" slave":"master");
2869 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2870 if (sizeinmb < (1UL<<16))
2871 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (Bit16u)sizeinmb);
2872 else
2873 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (Bit16u)(sizeinmb>>10));
2874 break;
2875 case ATA_TYPE_ATAPI:
2876 printf("ata%d %s: ",channel,slave?" slave":"master");
2877 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2878 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2879 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2880 else
2881 printf(" ATAPI-%d Device\n",version);
2882 break;
2883 case ATA_TYPE_UNKNOWN:
2884 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2885 break;
2890 // Store the devices counts
2891 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2892 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2893 write_byte(0x40,0x75, hdcount);
2895 printf("\n");
2897 // FIXME : should use bios=cmos|auto|disable bits
2898 // FIXME : should know about translation bits
2899 // FIXME : move hard_drive_post here
2903 // ---------------------------------------------------------------------------
2904 // ATA/ATAPI driver : software reset
2905 // ---------------------------------------------------------------------------
2906 // ATA-3
2907 // 8.2.1 Software reset - Device 0
2909 void ata_reset(device)
2910 Bit16u device;
2912 Bit16u ebda_seg=read_word(0x0040,0x000E);
2913 Bit16u iobase1, iobase2;
2914 Bit8u channel, slave, sn, sc;
2915 Bit8u type;
2916 Bit16u max;
2918 channel = device / 2;
2919 slave = device % 2;
2921 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2922 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2924 // Reset
2926 // 8.2.1 (a) -- set SRST in DC
2927 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2929 // 8.2.1 (b) -- wait for BSY
2930 await_ide(BSY, iobase1, 20);
2932 // 8.2.1 (f) -- clear SRST
2933 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2935 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2936 if (type != ATA_TYPE_NONE) {
2938 // 8.2.1 (g) -- check for sc==sn==0x01
2939 // select device
2940 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2941 sc = inb(iobase1+ATA_CB_SC);
2942 sn = inb(iobase1+ATA_CB_SN);
2944 if ( (sc==0x01) && (sn==0x01) ) {
2945 if (type == ATA_TYPE_ATA) //ATA
2946 await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT);
2947 else //ATAPI
2948 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
2951 // 8.2.1 (h) -- wait for not BSY
2952 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
2955 // Enable interrupts
2956 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2959 // ---------------------------------------------------------------------------
2960 // ATA/ATAPI driver : execute a non data command
2961 // ---------------------------------------------------------------------------
2963 Bit16u ata_cmd_non_data()
2964 {return 0;}
2966 // ---------------------------------------------------------------------------
2967 // ATA/ATAPI driver : execute a data-in command
2968 // ---------------------------------------------------------------------------
2969 // returns
2970 // 0 : no error
2971 // 1 : BUSY bit set
2972 // 2 : read error
2973 // 3 : expected DRQ=1
2974 // 4 : no sectors left to read/verify
2975 // 5 : more sectors to read/verify
2976 // 6 : no sectors left to write
2977 // 7 : more sectors to write
2978 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
2979 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2980 Bit32u lba_low, lba_high;
2982 Bit16u ebda_seg=read_word(0x0040,0x000E);
2983 Bit16u iobase1, iobase2, blksize;
2984 Bit8u channel, slave;
2985 Bit8u status, current, mode;
2987 channel = device / 2;
2988 slave = device % 2;
2990 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2991 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2992 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2993 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2994 if (mode == ATA_MODE_PIO32) blksize>>=2;
2995 else blksize>>=1;
2997 // Reset count of transferred data
2998 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2999 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3000 current = 0;
3002 status = inb(iobase1 + ATA_CB_STAT);
3003 if (status & ATA_CB_STAT_BSY) return 1;
3005 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3007 // sector will be 0 only on lba access. Convert to lba-chs
3008 if (sector == 0) {
3009 if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
3010 outb(iobase1 + ATA_CB_FR, 0x00);
3011 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
3012 outb(iobase1 + ATA_CB_SN, lba_low >> 24);
3013 outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
3014 outb(iobase1 + ATA_CB_CH, lba_high >> 8);
3015 command |= 0x04;
3016 count &= (1UL << 8) - 1;
3017 lba_low &= (1UL << 24) - 1;
3019 sector = (Bit16u) (lba_low & 0x000000ffL);
3020 cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
3021 head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
3024 outb(iobase1 + ATA_CB_FR, 0x00);
3025 outb(iobase1 + ATA_CB_SC, count);
3026 outb(iobase1 + ATA_CB_SN, sector);
3027 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3028 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3029 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3030 outb(iobase1 + ATA_CB_CMD, command);
3032 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3033 status = inb(iobase1 + ATA_CB_STAT);
3035 if (status & ATA_CB_STAT_ERR) {
3036 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
3037 return 2;
3038 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3039 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
3040 return 3;
3043 // FIXME : move seg/off translation here
3045 ASM_START
3046 sti ;; enable higher priority interrupts
3047 ASM_END
3049 while (1) {
3051 ASM_START
3052 push bp
3053 mov bp, sp
3054 mov di, _ata_cmd_data_in.offset + 2[bp]
3055 mov ax, _ata_cmd_data_in.segment + 2[bp]
3056 mov cx, _ata_cmd_data_in.blksize + 2[bp]
3058 ;; adjust if there will be an overrun. 2K max sector size
3059 cmp di, #0xf800 ;;
3060 jbe ata_in_no_adjust
3062 ata_in_adjust:
3063 sub di, #0x0800 ;; sub 2 kbytes from offset
3064 add ax, #0x0080 ;; add 2 Kbytes to segment
3066 ata_in_no_adjust:
3067 mov es, ax ;; segment in es
3069 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
3071 mov ah, _ata_cmd_data_in.mode + 2[bp]
3072 cmp ah, #ATA_MODE_PIO32
3073 je ata_in_32
3075 ata_in_16:
3076 rep
3077 insw ;; CX words transfered from port(DX) to ES:[DI]
3078 jmp ata_in_done
3080 ata_in_32:
3081 rep
3082 insd ;; CX dwords transfered from port(DX) to ES:[DI]
3084 ata_in_done:
3085 mov _ata_cmd_data_in.offset + 2[bp], di
3086 mov _ata_cmd_data_in.segment + 2[bp], es
3087 pop bp
3088 ASM_END
3090 current++;
3091 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3092 count--;
3093 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
3094 status = inb(iobase1 + ATA_CB_STAT);
3095 if (count == 0) {
3096 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3097 != ATA_CB_STAT_RDY ) {
3098 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3099 return 4;
3101 break;
3103 else {
3104 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3105 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3106 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3107 return 5;
3109 continue;
3112 // Enable interrupts
3113 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3114 return 0;
3117 // ---------------------------------------------------------------------------
3118 // ATA/ATAPI driver : execute a data-out command
3119 // ---------------------------------------------------------------------------
3120 // returns
3121 // 0 : no error
3122 // 1 : BUSY bit set
3123 // 2 : read error
3124 // 3 : expected DRQ=1
3125 // 4 : no sectors left to read/verify
3126 // 5 : more sectors to read/verify
3127 // 6 : no sectors left to write
3128 // 7 : more sectors to write
3129 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
3130 Bit16u device, command, count, cylinder, head, sector, segment, offset;
3131 Bit32u lba_low, lba_high;
3133 Bit16u ebda_seg=read_word(0x0040,0x000E);
3134 Bit16u iobase1, iobase2, blksize;
3135 Bit8u channel, slave;
3136 Bit8u status, current, mode;
3138 channel = device / 2;
3139 slave = device % 2;
3141 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3142 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3143 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3144 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3145 if (mode == ATA_MODE_PIO32) blksize>>=2;
3146 else blksize>>=1;
3148 // Reset count of transferred data
3149 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3150 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3151 current = 0;
3153 status = inb(iobase1 + ATA_CB_STAT);
3154 if (status & ATA_CB_STAT_BSY) return 1;
3156 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3158 // sector will be 0 only on lba access. Convert to lba-chs
3159 if (sector == 0) {
3160 if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
3161 outb(iobase1 + ATA_CB_FR, 0x00);
3162 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
3163 outb(iobase1 + ATA_CB_SN, lba_low >> 24);
3164 outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
3165 outb(iobase1 + ATA_CB_CH, lba_high >> 8);
3166 command |= 0x04;
3167 count &= (1UL << 8) - 1;
3168 lba_low &= (1UL << 24) - 1;
3170 sector = (Bit16u) (lba_low & 0x000000ffL);
3171 cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
3172 head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
3175 outb(iobase1 + ATA_CB_FR, 0x00);
3176 outb(iobase1 + ATA_CB_SC, count);
3177 outb(iobase1 + ATA_CB_SN, sector);
3178 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3179 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3180 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3181 outb(iobase1 + ATA_CB_CMD, command);
3183 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3184 status = inb(iobase1 + ATA_CB_STAT);
3186 if (status & ATA_CB_STAT_ERR) {
3187 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3188 return 2;
3189 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3190 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3191 return 3;
3194 // FIXME : move seg/off translation here
3196 ASM_START
3197 sti ;; enable higher priority interrupts
3198 ASM_END
3200 while (1) {
3202 ASM_START
3203 push bp
3204 mov bp, sp
3205 mov si, _ata_cmd_data_out.offset + 2[bp]
3206 mov ax, _ata_cmd_data_out.segment + 2[bp]
3207 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3209 ;; adjust if there will be an overrun. 2K max sector size
3210 cmp si, #0xf800 ;;
3211 jbe ata_out_no_adjust
3213 ata_out_adjust:
3214 sub si, #0x0800 ;; sub 2 kbytes from offset
3215 add ax, #0x0080 ;; add 2 Kbytes to segment
3217 ata_out_no_adjust:
3218 mov es, ax ;; segment in es
3220 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3222 mov ah, _ata_cmd_data_out.mode + 2[bp]
3223 cmp ah, #ATA_MODE_PIO32
3224 je ata_out_32
3226 ata_out_16:
3227 seg ES
3228 rep
3229 outsw ;; CX words transfered from port(DX) to ES:[SI]
3230 jmp ata_out_done
3232 ata_out_32:
3233 seg ES
3234 rep
3235 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3237 ata_out_done:
3238 mov _ata_cmd_data_out.offset + 2[bp], si
3239 mov _ata_cmd_data_out.segment + 2[bp], es
3240 pop bp
3241 ASM_END
3243 current++;
3244 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3245 count--;
3246 status = inb(iobase1 + ATA_CB_STAT);
3247 if (count == 0) {
3248 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3249 != ATA_CB_STAT_RDY ) {
3250 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3251 return 6;
3253 break;
3255 else {
3256 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3257 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3258 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3259 return 7;
3261 continue;
3264 // Enable interrupts
3265 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3266 return 0;
3269 // ---------------------------------------------------------------------------
3270 // ATA/ATAPI driver : execute a packet command
3271 // ---------------------------------------------------------------------------
3272 // returns
3273 // 0 : no error
3274 // 1 : error in parameters
3275 // 2 : BUSY bit set
3276 // 3 : error
3277 // 4 : not ready
3278 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3279 Bit8u cmdlen,inout;
3280 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3281 Bit16u header;
3282 Bit32u length;
3284 Bit16u ebda_seg=read_word(0x0040,0x000E);
3285 Bit16u iobase1, iobase2;
3286 Bit16u lcount, lbefore, lafter, count;
3287 Bit8u channel, slave;
3288 Bit8u status, mode, lmode;
3289 Bit32u total, transfer;
3291 channel = device / 2;
3292 slave = device % 2;
3294 // Data out is not supported yet
3295 if (inout == ATA_DATA_OUT) {
3296 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3297 return 1;
3300 // The header length must be even
3301 if (header & 1) {
3302 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3303 return 1;
3306 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3307 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3308 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3309 transfer= 0L;
3311 if (cmdlen < 12) cmdlen=12;
3312 if (cmdlen > 12) cmdlen=16;
3313 cmdlen>>=1;
3315 // Reset count of transferred data
3316 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3317 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3319 status = inb(iobase1 + ATA_CB_STAT);
3320 if (status & ATA_CB_STAT_BSY) return 2;
3322 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3323 outb(iobase1 + ATA_CB_FR, 0x00);
3324 outb(iobase1 + ATA_CB_SC, 0x00);
3325 outb(iobase1 + ATA_CB_SN, 0x00);
3326 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3327 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3328 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3329 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3331 // Device should ok to receive command
3332 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3333 status = inb(iobase1 + ATA_CB_STAT);
3335 if (status & ATA_CB_STAT_ERR) {
3336 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3337 return 3;
3338 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3339 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3340 return 4;
3343 // Normalize address
3344 cmdseg += (cmdoff / 16);
3345 cmdoff %= 16;
3347 // Send command to device
3348 ASM_START
3349 sti ;; enable higher priority interrupts
3351 push bp
3352 mov bp, sp
3354 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3355 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3356 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3357 mov es, ax ;; segment in es
3359 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3361 seg ES
3362 rep
3363 outsw ;; CX words transfered from port(DX) to ES:[SI]
3365 pop bp
3366 ASM_END
3368 if (inout == ATA_DATA_NO) {
3369 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
3370 status = inb(iobase1 + ATA_CB_STAT);
3372 else {
3373 Bit16u loops = 0;
3374 Bit8u sc;
3375 while (1) {
3377 if (loops == 0) {//first time through
3378 status = inb(iobase2 + ATA_CB_ASTAT);
3379 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3381 else
3382 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
3383 loops++;
3385 status = inb(iobase1 + ATA_CB_STAT);
3386 sc = inb(iobase1 + ATA_CB_SC);
3388 // Check if command completed
3389 if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) &&
3390 ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) break;
3392 if (status & ATA_CB_STAT_ERR) {
3393 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3394 return 3;
3397 // Normalize address
3398 bufseg += (bufoff / 16);
3399 bufoff %= 16;
3401 // Get the byte count
3402 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3404 // adjust to read what we want
3405 if(header>lcount) {
3406 lbefore=lcount;
3407 header-=lcount;
3408 lcount=0;
3410 else {
3411 lbefore=header;
3412 header=0;
3413 lcount-=lbefore;
3416 if(lcount>length) {
3417 lafter=lcount-length;
3418 lcount=length;
3419 length=0;
3421 else {
3422 lafter=0;
3423 length-=lcount;
3426 // Save byte count
3427 count = lcount;
3429 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3430 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3432 // If counts not dividable by 4, use 16bits mode
3433 lmode = mode;
3434 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3435 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3436 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3438 // adds an extra byte if count are odd. before is always even
3439 if (lcount & 0x01) {
3440 lcount+=1;
3441 if ((lafter > 0) && (lafter & 0x01)) {
3442 lafter-=1;
3446 if (lmode == ATA_MODE_PIO32) {
3447 lcount>>=2; lbefore>>=2; lafter>>=2;
3449 else {
3450 lcount>>=1; lbefore>>=1; lafter>>=1;
3453 ; // FIXME bcc bug
3455 ASM_START
3456 push bp
3457 mov bp, sp
3459 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3461 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3462 jcxz ata_packet_no_before
3464 mov ah, _ata_cmd_packet.lmode + 2[bp]
3465 cmp ah, #ATA_MODE_PIO32
3466 je ata_packet_in_before_32
3468 ata_packet_in_before_16:
3469 in ax, dx
3470 loop ata_packet_in_before_16
3471 jmp ata_packet_no_before
3473 ata_packet_in_before_32:
3474 push eax
3475 ata_packet_in_before_32_loop:
3476 in eax, dx
3477 loop ata_packet_in_before_32_loop
3478 pop eax
3480 ata_packet_no_before:
3481 mov cx, _ata_cmd_packet.lcount + 2[bp]
3482 jcxz ata_packet_after
3484 mov di, _ata_cmd_packet.bufoff + 2[bp]
3485 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3486 mov es, ax
3488 mov ah, _ata_cmd_packet.lmode + 2[bp]
3489 cmp ah, #ATA_MODE_PIO32
3490 je ata_packet_in_32
3492 ata_packet_in_16:
3493 rep
3494 insw ;; CX words transfered tp port(DX) to ES:[DI]
3495 jmp ata_packet_after
3497 ata_packet_in_32:
3498 rep
3499 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3501 ata_packet_after:
3502 mov cx, _ata_cmd_packet.lafter + 2[bp]
3503 jcxz ata_packet_done
3505 mov ah, _ata_cmd_packet.lmode + 2[bp]
3506 cmp ah, #ATA_MODE_PIO32
3507 je ata_packet_in_after_32
3509 ata_packet_in_after_16:
3510 in ax, dx
3511 loop ata_packet_in_after_16
3512 jmp ata_packet_done
3514 ata_packet_in_after_32:
3515 push eax
3516 ata_packet_in_after_32_loop:
3517 in eax, dx
3518 loop ata_packet_in_after_32_loop
3519 pop eax
3521 ata_packet_done:
3522 pop bp
3523 ASM_END
3525 // Compute new buffer address
3526 bufoff += count;
3528 // Save transferred bytes count
3529 transfer += count;
3530 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3534 // Final check, device must be ready
3535 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3536 != ATA_CB_STAT_RDY ) {
3537 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3538 return 4;
3541 // Enable interrupts
3542 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3543 return 0;
3546 // ---------------------------------------------------------------------------
3547 // End of ATA/ATAPI Driver
3548 // ---------------------------------------------------------------------------
3550 // ---------------------------------------------------------------------------
3551 // Start of ATA/ATAPI generic functions
3552 // ---------------------------------------------------------------------------
3554 Bit16u
3555 atapi_get_sense(device, seg, asc, ascq)
3556 Bit16u device;
3558 Bit8u atacmd[12];
3559 Bit8u buffer[18];
3560 Bit8u i;
3562 memsetb(get_SS(),atacmd,0,12);
3564 // Request SENSE
3565 atacmd[0]=ATA_CMD_REQUEST_SENSE;
3566 atacmd[4]=sizeof(buffer);
3567 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 18L, ATA_DATA_IN, get_SS(), buffer) != 0)
3568 return 0x0002;
3570 write_byte(seg,asc,buffer[12]);
3571 write_byte(seg,ascq,buffer[13]);
3573 return 0;
3576 Bit16u
3577 atapi_is_ready(device)
3578 Bit16u device;
3580 Bit8u packet[12];
3581 Bit8u buf[8];
3582 Bit32u block_len;
3583 Bit32u sectors;
3584 Bit32u timeout; //measured in ms
3585 Bit32u time;
3586 Bit8u asc, ascq;
3587 Bit8u in_progress;
3588 Bit16u ebda_seg = read_word(0x0040,0x000E);
3589 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) {
3590 printf("not implemented for non-ATAPI device\n");
3591 return -1;
3594 BX_DEBUG_ATA("ata_detect_medium: begin\n");
3595 memsetb(get_SS(),packet, 0, sizeof packet);
3596 packet[0] = 0x25; /* READ CAPACITY */
3598 /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
3599 * is reported by the device. If the device reports "IN PROGRESS",
3600 * 30 seconds is added. */
3601 timeout = 5000;
3602 time = 0;
3603 in_progress = 0;
3604 while (time < timeout) {
3605 if (ata_cmd_packet(device, sizeof(packet), get_SS(), packet, 0, 8L, ATA_DATA_IN, get_SS(), buf) == 0)
3606 goto ok;
3608 if (atapi_get_sense(device, get_SS(), &asc, &ascq) == 0) {
3609 if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
3610 BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
3611 return -1;
3614 if (asc == 0x04 && ascq == 0x01 && !in_progress) {
3615 /* IN PROGRESS OF BECOMING READY */
3616 printf("Waiting for device to detect medium... ");
3617 /* Allow 30 seconds more */
3618 timeout = 30000;
3619 in_progress = 1;
3622 time += 100;
3624 BX_DEBUG_ATA("read capacity failed\n");
3625 return -1;
3626 ok:
3628 block_len = (Bit32u) buf[4] << 24
3629 | (Bit32u) buf[5] << 16
3630 | (Bit32u) buf[6] << 8
3631 | (Bit32u) buf[7] << 0;
3632 BX_DEBUG_ATA("block_len=%u\n", block_len);
3634 if (block_len!= 2048 && block_len!= 512)
3636 printf("Unsupported sector size %u\n", block_len);
3637 return -1;
3639 write_dword(ebda_seg,&EbdaData->ata.devices[device].blksize, block_len);
3641 sectors = (Bit32u) buf[0] << 24
3642 | (Bit32u) buf[1] << 16
3643 | (Bit32u) buf[2] << 8
3644 | (Bit32u) buf[3] << 0;
3646 BX_DEBUG_ATA("sectors=%u\n", sectors);
3647 if (block_len == 2048)
3648 sectors <<= 2; /* # of sectors in 512-byte "soft" sector */
3649 if (sectors != read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low))
3650 printf("%dMB medium detected\n", sectors>>(20-9));
3651 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors);
3652 return 0;
3655 Bit16u
3656 atapi_is_cdrom(device)
3657 Bit8u device;
3659 Bit16u ebda_seg=read_word(0x0040,0x000E);
3661 if (device >= BX_MAX_ATA_DEVICES)
3662 return 0;
3664 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3665 return 0;
3667 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3668 return 0;
3670 return 1;
3673 // ---------------------------------------------------------------------------
3674 // End of ATA/ATAPI generic functions
3675 // ---------------------------------------------------------------------------
3677 #endif // BX_USE_ATADRV
3679 #if BX_ELTORITO_BOOT
3681 // ---------------------------------------------------------------------------
3682 // Start of El-Torito boot functions
3683 // ---------------------------------------------------------------------------
3685 void
3686 cdemu_init()
3688 Bit16u ebda_seg=read_word(0x0040,0x000E);
3690 // the only important data is this one for now
3691 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3694 Bit8u
3695 cdemu_isactive()
3697 Bit16u ebda_seg=read_word(0x0040,0x000E);
3699 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3702 Bit8u
3703 cdemu_emulated_drive()
3705 Bit16u ebda_seg=read_word(0x0040,0x000E);
3707 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3710 static char isotag[6]="CD001";
3711 static char eltorito[24]="EL TORITO SPECIFICATION";
3712 //
3713 // Returns ah: emulated drive, al: error code
3714 //
3715 Bit16u
3716 cdrom_boot()
3718 Bit16u ebda_seg=read_word(0x0040,0x000E);
3719 Bit8u atacmd[12], buffer[2048];
3720 Bit32u lba;
3721 Bit16u boot_segment, nbsectors, i, error;
3722 Bit8u device;
3724 // Find out the first cdrom
3725 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3726 if (atapi_is_cdrom(device)) break;
3729 // if not found
3730 if(device >= BX_MAX_ATA_DEVICES) return 2;
3732 if(error = atapi_is_ready(device) != 0)
3733 BX_INFO("ata_is_ready returned %d\n",error);
3735 // Read the Boot Record Volume Descriptor
3736 memsetb(get_SS(),atacmd,0,12);
3737 atacmd[0]=0x28; // READ command
3738 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3739 atacmd[8]=(0x01 & 0x00ff); // Sectors
3740 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3741 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3742 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3743 atacmd[5]=(0x11 & 0x000000ff);
3744 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3745 return 3;
3747 // Validity checks
3748 if(buffer[0]!=0)return 4;
3749 for(i=0;i<5;i++){
3750 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3752 for(i=0;i<23;i++)
3753 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3755 // ok, now we calculate the Boot catalog address
3756 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3758 // And we read the Boot Catalog
3759 memsetb(get_SS(),atacmd,0,12);
3760 atacmd[0]=0x28; // READ command
3761 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3762 atacmd[8]=(0x01 & 0x00ff); // Sectors
3763 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3764 atacmd[3]=(lba & 0x00ff0000) >> 16;
3765 atacmd[4]=(lba & 0x0000ff00) >> 8;
3766 atacmd[5]=(lba & 0x000000ff);
3767 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3768 return 7;
3770 // Validation entry
3771 if(buffer[0x00]!=0x01)return 8; // Header
3772 if(buffer[0x01]!=0x00)return 9; // Platform
3773 if(buffer[0x1E]!=0x55)return 10; // key 1
3774 if(buffer[0x1F]!=0xAA)return 10; // key 2
3776 // Initial/Default Entry
3777 if(buffer[0x20]!=0x88)return 11; // Bootable
3779 #if BX_TCGBIOS
3780 /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
3781 /* measure 2048 bytes (one sector) */
3782 tcpa_add_bootdevice((Bit32u)1L, (Bit32u)0L); /* bootcd = 1 */
3783 tcpa_ipl((Bit32u)2L,(Bit32u)get_SS(),(Bit32u)buffer,(Bit32u)2048L);
3784 #endif
3786 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3787 if(buffer[0x21]==0){
3788 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3789 // Win2000 cd boot needs to know it booted from cd
3790 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3792 else if(buffer[0x21]<4)
3793 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3794 else
3795 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3797 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3798 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3800 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3801 if(boot_segment==0x0000)boot_segment=0x07C0;
3803 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3804 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3806 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3807 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3809 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3810 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3812 // And we read the image in memory
3813 memsetb(get_SS(),atacmd,0,12);
3814 atacmd[0]=0x28; // READ command
3815 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3816 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3817 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3818 atacmd[3]=(lba & 0x00ff0000) >> 16;
3819 atacmd[4]=(lba & 0x0000ff00) >> 8;
3820 atacmd[5]=(lba & 0x000000ff);
3821 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3822 return 12;
3824 #if BX_TCGBIOS
3825 /* specs: 8.2.3 step 4 and 8.2.5.6, measure El Torito boot image */
3826 /* measure 1st 512 bytes */
3827 tcpa_ipl((Bit32u)1L,(Bit32u)boot_segment,(Bit32u)0L,(Bit32u)512L);
3828 #endif
3830 // Remember the media type
3831 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3832 case 0x01: // 1.2M floppy
3833 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3834 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3835 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3836 break;
3837 case 0x02: // 1.44M floppy
3838 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3839 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3840 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3841 break;
3842 case 0x03: // 2.88M floppy
3843 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3844 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3845 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3846 break;
3847 case 0x04: // Harddrive
3848 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3849 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3850 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3851 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3852 break;
3855 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3856 // Increase bios installed hardware number of devices
3857 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3858 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3859 else
3860 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3864 // everything is ok, so from now on, the emulation is active
3865 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3866 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3868 // return the boot drive + no error
3869 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3872 // ---------------------------------------------------------------------------
3873 // End of El-Torito boot functions
3874 // ---------------------------------------------------------------------------
3875 #endif // BX_ELTORITO_BOOT
3877 void
3878 int14_function(regs, ds, iret_addr)
3879 pusha_regs_t regs; // regs pushed from PUSHA instruction
3880 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3881 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3883 Bit16u addr,timer,val16;
3884 Bit8u timeout;
3886 ASM_START
3887 sti
3888 ASM_END
3890 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3891 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3892 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3893 switch (regs.u.r8.ah) {
3894 case 0:
3895 outb(addr+3, inb(addr+3) | 0x80);
3896 if (regs.u.r8.al & 0xE0 == 0) {
3897 outb(addr, 0x17);
3898 outb(addr+1, 0x04);
3899 } else {
3900 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3901 outb(addr, val16 & 0xFF);
3902 outb(addr+1, val16 >> 8);
3904 outb(addr+3, regs.u.r8.al & 0x1F);
3905 regs.u.r8.ah = inb(addr+5);
3906 regs.u.r8.al = inb(addr+6);
3907 ClearCF(iret_addr.flags);
3908 break;
3909 case 1:
3910 timer = read_word(0x0040, 0x006C);
3911 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3912 val16 = read_word(0x0040, 0x006C);
3913 if (val16 != timer) {
3914 timer = val16;
3915 timeout--;
3918 if (timeout) outb(addr, regs.u.r8.al);
3919 regs.u.r8.ah = inb(addr+5);
3920 if (!timeout) regs.u.r8.ah |= 0x80;
3921 ClearCF(iret_addr.flags);
3922 break;
3923 case 2:
3924 timer = read_word(0x0040, 0x006C);
3925 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3926 val16 = read_word(0x0040, 0x006C);
3927 if (val16 != timer) {
3928 timer = val16;
3929 timeout--;
3932 if (timeout) {
3933 regs.u.r8.ah = 0;
3934 regs.u.r8.al = inb(addr);
3935 } else {
3936 regs.u.r8.ah = inb(addr+5);
3938 ClearCF(iret_addr.flags);
3939 break;
3940 case 3:
3941 regs.u.r8.ah = inb(addr+5);
3942 regs.u.r8.al = inb(addr+6);
3943 ClearCF(iret_addr.flags);
3944 break;
3945 default:
3946 SetCF(iret_addr.flags); // Unsupported
3948 } else {
3949 SetCF(iret_addr.flags); // Unsupported
3953 void
3954 int15_function(regs, ES, DS, FLAGS)
3955 pusha_regs_t regs; // REGS pushed via pusha
3956 Bit16u ES, DS, FLAGS;
3958 Bit16u ebda_seg=read_word(0x0040,0x000E);
3959 bx_bool prev_a20_enable;
3960 Bit16u base15_00;
3961 Bit8u base23_16;
3962 Bit16u ss;
3963 Bit16u CX,DX;
3965 Bit16u bRegister;
3966 Bit8u irqDisable;
3968 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3970 switch (regs.u.r8.ah) {
3971 case 0x24: /* A20 Control */
3972 switch (regs.u.r8.al) {
3973 case 0x00:
3974 set_enable_a20(0);
3975 CLEAR_CF();
3976 regs.u.r8.ah = 0;
3977 break;
3978 case 0x01:
3979 set_enable_a20(1);
3980 CLEAR_CF();
3981 regs.u.r8.ah = 0;
3982 break;
3983 case 0x02:
3984 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3985 CLEAR_CF();
3986 regs.u.r8.ah = 0;
3987 break;
3988 case 0x03:
3989 CLEAR_CF();
3990 regs.u.r8.ah = 0;
3991 regs.u.r16.bx = 3;
3992 break;
3993 default:
3994 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3995 SET_CF();
3996 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3998 break;
4000 case 0x41:
4001 SET_CF();
4002 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4003 break;
4005 case 0x4f:
4006 /* keyboard intercept */
4007 #if BX_CPU < 2
4008 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4009 #else
4010 // nop
4011 #endif
4012 SET_CF();
4013 break;
4015 case 0x52: // removable media eject
4016 CLEAR_CF();
4017 regs.u.r8.ah = 0; // "ok ejection may proceed"
4018 break;
4020 case 0x83: {
4021 if( regs.u.r8.al == 0 ) {
4022 // Set Interval requested.
4023 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
4024 // Interval not already set.
4025 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
4026 write_word( 0x40, 0x98, ES ); // Byte location, segment
4027 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
4028 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
4029 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
4030 CLEAR_CF( );
4031 irqDisable = inb( 0xA1 );
4032 outb( 0xA1, irqDisable & 0xFE );
4033 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
4034 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
4035 } else {
4036 // Interval already set.
4037 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
4038 SET_CF();
4039 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4041 } else if( regs.u.r8.al == 1 ) {
4042 // Clear Interval requested
4043 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
4044 CLEAR_CF( );
4045 bRegister = inb_cmos( 0xB );
4046 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
4047 } else {
4048 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
4049 SET_CF();
4050 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4051 regs.u.r8.al--;
4054 break;
4057 case 0x87:
4058 #if BX_CPU < 3
4059 # error "Int15 function 87h not supported on < 80386"
4060 #endif
4061 // +++ should probably have descriptor checks
4062 // +++ should have exception handlers
4064 // turn off interrupts
4065 ASM_START
4066 cli
4067 ASM_END
4069 prev_a20_enable = set_enable_a20(1); // enable A20 line
4071 // 128K max of transfer on 386+ ???
4072 // source == destination ???
4074 // ES:SI points to descriptor table
4075 // offset use initially comments
4076 // ==============================================
4077 // 00..07 Unused zeros Null descriptor
4078 // 08..0f GDT zeros filled in by BIOS
4079 // 10..17 source ssssssss source of data
4080 // 18..1f dest dddddddd destination of data
4081 // 20..27 CS zeros filled in by BIOS
4082 // 28..2f SS zeros filled in by BIOS
4084 //es:si
4085 //eeee0
4086 //0ssss
4087 //-----
4089 // check for access rights of source & dest here
4091 // Initialize GDT descriptor
4092 base15_00 = (ES << 4) + regs.u.r16.si;
4093 base23_16 = ES >> 12;
4094 if (base15_00 < (ES<<4))
4095 base23_16++;
4096 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4097 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4098 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4099 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4100 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4102 // Initialize CS descriptor
4103 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4104 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4105 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4106 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4107 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4109 // Initialize SS descriptor
4110 ss = get_SS();
4111 base15_00 = ss << 4;
4112 base23_16 = ss >> 12;
4113 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4114 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4115 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4116 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4117 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4119 CX = regs.u.r16.cx;
4120 ASM_START
4121 // Compile generates locals offset info relative to SP.
4122 // Get CX (word count) from stack.
4123 mov bx, sp
4124 SEG SS
4125 mov cx, _int15_function.CX [bx]
4127 // since we need to set SS:SP, save them to the BDA
4128 // for future restore
4129 push eax
4130 xor eax, eax
4131 mov ds, ax
4132 mov 0x0469, ss
4133 mov 0x0467, sp
4135 SEG ES
4136 lgdt [si + 0x08]
4137 SEG CS
4138 lidt [pmode_IDT_info]
4139 ;; perhaps do something with IDT here
4141 ;; set PE bit in CR0
4142 mov eax, cr0
4143 or al, #0x01
4144 mov cr0, eax
4145 ;; far jump to flush CPU queue after transition to protected mode
4146 JMP_AP(0x0020, protected_mode)
4148 protected_mode:
4149 ;; GDT points to valid descriptor table, now load SS, DS, ES
4150 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4151 mov ss, ax
4152 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4153 mov ds, ax
4154 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4155 mov es, ax
4156 xor si, si
4157 xor di, di
4158 cld
4159 rep
4160 movsw ;; move CX words from DS:SI to ES:DI
4162 ;; make sure DS and ES limits are 64KB
4163 mov ax, #0x28
4164 mov ds, ax
4165 mov es, ax
4167 ;; reset PG bit in CR0 ???
4168 mov eax, cr0
4169 and al, #0xFE
4170 mov cr0, eax
4172 ;; far jump to flush CPU queue after transition to real mode
4173 JMP_AP(0xf000, real_mode)
4175 real_mode:
4176 ;; restore IDT to normal real-mode defaults
4177 SEG CS
4178 lidt [rmode_IDT_info]
4180 // restore SS:SP from the BDA
4181 xor ax, ax
4182 mov ds, ax
4183 mov ss, 0x0469
4184 mov sp, 0x0467
4185 pop eax
4186 ASM_END
4188 set_enable_a20(prev_a20_enable);
4190 // turn back on interrupts
4191 ASM_START
4192 sti
4193 ASM_END
4195 regs.u.r8.ah = 0;
4196 CLEAR_CF();
4197 break;
4200 case 0x88:
4201 // Get the amount of extended memory (above 1M)
4202 #if BX_CPU < 2
4203 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4204 SET_CF();
4205 #else
4206 regs.u.r8.al = inb_cmos(0x30);
4207 regs.u.r8.ah = inb_cmos(0x31);
4209 // According to Ralf Brown's interrupt the limit should be 15M,
4210 // but real machines mostly return max. 63M.
4211 if(regs.u.r16.ax > 0xffc0)
4212 regs.u.r16.ax = 0xffc0;
4214 CLEAR_CF();
4215 #endif
4216 break;
4218 case 0x90:
4219 /* Device busy interrupt. Called by Int 16h when no key available */
4220 break;
4222 case 0x91:
4223 /* Interrupt complete. Called by Int 16h when key becomes available */
4224 break;
4226 case 0xbf:
4227 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4228 SET_CF();
4229 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4230 break;
4232 case 0xC0:
4233 #if 0
4234 SET_CF();
4235 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4236 break;
4237 #endif
4238 CLEAR_CF();
4239 regs.u.r8.ah = 0;
4240 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4241 ES = 0xF000;
4242 break;
4244 case 0xc1:
4245 ES = ebda_seg;
4246 CLEAR_CF();
4247 break;
4249 case 0xd8:
4250 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4251 SET_CF();
4252 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4253 break;
4255 default:
4256 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4257 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4258 SET_CF();
4259 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4260 break;
4264 #if BX_USE_PS2_MOUSE
4265 void
4266 int15_function_mouse(regs, ES, DS, FLAGS)
4267 pusha_regs_t regs; // REGS pushed via pusha
4268 Bit16u ES, DS, FLAGS;
4270 Bit16u ebda_seg=read_word(0x0040,0x000E);
4271 Bit8u mouse_flags_1, mouse_flags_2;
4272 Bit16u mouse_driver_seg;
4273 Bit16u mouse_driver_offset;
4274 Bit8u comm_byte, prev_command_byte;
4275 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4277 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4279 switch (regs.u.r8.ah) {
4280 case 0xC2:
4281 // Return Codes status in AH
4282 // =========================
4283 // 00: success
4284 // 01: invalid subfunction (AL > 7)
4285 // 02: invalid input value (out of allowable range)
4286 // 03: interface error
4287 // 04: resend command received from mouse controller,
4288 // device driver should attempt command again
4289 // 05: cannot enable mouse, since no far call has been installed
4290 // 80/86: mouse service not implemented
4292 switch (regs.u.r8.al) {
4293 case 0: // Disable/Enable Mouse
4294 BX_DEBUG_INT15("case 0:\n");
4295 switch (regs.u.r8.bh) {
4296 case 0: // Disable Mouse
4297 BX_DEBUG_INT15("case 0: disable mouse\n");
4298 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4299 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
4300 if (ret == 0) {
4301 ret = get_mouse_data(&mouse_data1);
4302 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4303 CLEAR_CF();
4304 regs.u.r8.ah = 0;
4305 return;
4309 // error
4310 SET_CF();
4311 regs.u.r8.ah = ret;
4312 return;
4313 break;
4315 case 1: // Enable Mouse
4316 BX_DEBUG_INT15("case 1: enable mouse\n");
4317 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4318 if ( (mouse_flags_2 & 0x80) == 0 ) {
4319 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4320 SET_CF(); // error
4321 regs.u.r8.ah = 5; // no far call installed
4322 return;
4324 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4325 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
4326 if (ret == 0) {
4327 ret = get_mouse_data(&mouse_data1);
4328 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
4329 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4330 CLEAR_CF();
4331 regs.u.r8.ah = 0;
4332 return;
4335 SET_CF();
4336 regs.u.r8.ah = ret;
4337 return;
4339 default: // invalid subfunction
4340 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4341 SET_CF(); // error
4342 regs.u.r8.ah = 1; // invalid subfunction
4343 return;
4345 break;
4347 case 1: // Reset Mouse
4348 case 5: // Initialize Mouse
4349 BX_DEBUG_INT15("case 1 or 5:\n");
4350 if (regs.u.r8.al == 5) {
4351 if (regs.u.r8.bh != 3) {
4352 SET_CF();
4353 regs.u.r8.ah = 0x02; // invalid input
4354 return;
4356 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4357 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
4358 mouse_flags_1 = 0x00;
4359 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4360 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4363 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4364 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4365 if (ret == 0) {
4366 ret = get_mouse_data(&mouse_data3);
4367 // if no mouse attached, it will return RESEND
4368 if (mouse_data3 == 0xfe) {
4369 SET_CF();
4370 return;
4372 if (mouse_data3 != 0xfa)
4373 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4374 if ( ret == 0 ) {
4375 ret = get_mouse_data(&mouse_data1);
4376 if ( ret == 0 ) {
4377 ret = get_mouse_data(&mouse_data2);
4378 if ( ret == 0 ) {
4379 // turn IRQ12 and packet generation on
4380 enable_mouse_int_and_events();
4381 CLEAR_CF();
4382 regs.u.r8.ah = 0;
4383 regs.u.r8.bl = mouse_data1;
4384 regs.u.r8.bh = mouse_data2;
4385 return;
4391 // error
4392 SET_CF();
4393 regs.u.r8.ah = ret;
4394 return;
4396 case 2: // Set Sample Rate
4397 BX_DEBUG_INT15("case 2:\n");
4398 switch (regs.u.r8.bh) {
4399 case 0: mouse_data1 = 10; break; // 10 reports/sec
4400 case 1: mouse_data1 = 20; break; // 20 reports/sec
4401 case 2: mouse_data1 = 40; break; // 40 reports/sec
4402 case 3: mouse_data1 = 60; break; // 60 reports/sec
4403 case 4: mouse_data1 = 80; break; // 80 reports/sec
4404 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4405 case 6: mouse_data1 = 200; break; // 200 reports/sec
4406 default: mouse_data1 = 0;
4408 if (mouse_data1 > 0) {
4409 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4410 if (ret == 0) {
4411 ret = get_mouse_data(&mouse_data2);
4412 ret = send_to_mouse_ctrl(mouse_data1);
4413 ret = get_mouse_data(&mouse_data2);
4414 CLEAR_CF();
4415 regs.u.r8.ah = 0;
4416 } else {
4417 // error
4418 SET_CF();
4419 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4421 } else {
4422 // error
4423 SET_CF();
4424 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4426 break;
4428 case 3: // Set Resolution
4429 BX_DEBUG_INT15("case 3:\n");
4430 // BH:
4431 // 0 = 25 dpi, 1 count per millimeter
4432 // 1 = 50 dpi, 2 counts per millimeter
4433 // 2 = 100 dpi, 4 counts per millimeter
4434 // 3 = 200 dpi, 8 counts per millimeter
4435 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4436 if (regs.u.r8.bh < 4) {
4437 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4438 if (ret == 0) {
4439 ret = get_mouse_data(&mouse_data1);
4440 if (mouse_data1 != 0xfa)
4441 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4442 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4443 ret = get_mouse_data(&mouse_data1);
4444 if (mouse_data1 != 0xfa)
4445 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4446 CLEAR_CF();
4447 regs.u.r8.ah = 0;
4448 } else {
4449 // error
4450 SET_CF();
4451 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4453 } else {
4454 // error
4455 SET_CF();
4456 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4458 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4459 break;
4461 case 4: // Get Device ID
4462 BX_DEBUG_INT15("case 4:\n");
4463 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4464 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4465 if (ret == 0) {
4466 ret = get_mouse_data(&mouse_data1);
4467 ret = get_mouse_data(&mouse_data2);
4468 CLEAR_CF();
4469 regs.u.r8.ah = 0;
4470 regs.u.r8.bh = mouse_data2;
4471 } else {
4472 // error
4473 SET_CF();
4474 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4476 break;
4478 case 6: // Return Status & Set Scaling Factor...
4479 BX_DEBUG_INT15("case 6:\n");
4480 switch (regs.u.r8.bh) {
4481 case 0: // Return Status
4482 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4483 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4484 if (ret == 0) {
4485 ret = get_mouse_data(&mouse_data1);
4486 if (mouse_data1 != 0xfa)
4487 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4488 if (ret == 0) {
4489 ret = get_mouse_data(&mouse_data1);
4490 if ( ret == 0 ) {
4491 ret = get_mouse_data(&mouse_data2);
4492 if ( ret == 0 ) {
4493 ret = get_mouse_data(&mouse_data3);
4494 if ( ret == 0 ) {
4495 CLEAR_CF();
4496 regs.u.r8.ah = 0;
4497 regs.u.r8.bl = mouse_data1;
4498 regs.u.r8.cl = mouse_data2;
4499 regs.u.r8.dl = mouse_data3;
4500 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4501 return;
4508 // error
4509 SET_CF();
4510 regs.u.r8.ah = ret;
4511 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4512 return;
4514 case 1: // Set Scaling Factor to 1:1
4515 case 2: // Set Scaling Factor to 2:1
4516 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4517 if (regs.u.r8.bh == 1) {
4518 ret = send_to_mouse_ctrl(0xE6);
4519 } else {
4520 ret = send_to_mouse_ctrl(0xE7);
4522 if (ret == 0) {
4523 get_mouse_data(&mouse_data1);
4524 ret = (mouse_data1 != 0xFA);
4526 if (ret == 0) {
4527 CLEAR_CF();
4528 regs.u.r8.ah = 0;
4529 } else {
4530 // error
4531 SET_CF();
4532 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4534 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4535 break;
4537 default:
4538 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4540 break;
4542 case 7: // Set Mouse Handler Address
4543 BX_DEBUG_INT15("case 7:\n");
4544 mouse_driver_seg = ES;
4545 mouse_driver_offset = regs.u.r16.bx;
4546 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4547 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4548 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4549 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4550 /* remove handler */
4551 if ( (mouse_flags_2 & 0x80) != 0 ) {
4552 mouse_flags_2 &= ~0x80;
4553 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4556 else {
4557 /* install handler */
4558 mouse_flags_2 |= 0x80;
4560 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4561 CLEAR_CF();
4562 regs.u.r8.ah = 0;
4563 break;
4565 default:
4566 BX_DEBUG_INT15("case default:\n");
4567 regs.u.r8.ah = 1; // invalid function
4568 SET_CF();
4570 break;
4572 default:
4573 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4574 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4575 SET_CF();
4576 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4577 break;
4580 #endif // BX_USE_PS2_MOUSE
4583 void set_e820_range(ES, DI, start, end, type)
4584 Bit16u ES;
4585 Bit16u DI;
4586 Bit32u start;
4587 Bit32u end;
4588 Bit16u type;
4590 write_word(ES, DI, start);
4591 write_word(ES, DI+2, start >> 16);
4592 write_word(ES, DI+4, 0x00);
4593 write_word(ES, DI+6, 0x00);
4595 end -= start;
4596 write_word(ES, DI+8, end);
4597 write_word(ES, DI+10, end >> 16);
4598 write_word(ES, DI+12, 0x0000);
4599 write_word(ES, DI+14, 0x0000);
4601 write_word(ES, DI+16, type);
4602 write_word(ES, DI+18, 0x0);
4605 void
4606 int15_function32(regs, ES, DS, FLAGS)
4607 pushad_regs_t regs; // REGS pushed via pushad
4608 Bit16u ES, DS, FLAGS;
4610 Bit32u extended_memory_size=0; // 64bits long
4611 Bit16u CX,DX;
4613 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4615 switch (regs.u.r8.ah) {
4616 case 0x86:
4617 // Wait for CX:DX microseconds. currently using the
4618 // refresh request port 0x61 bit4, toggling every 15usec
4620 CX = regs.u.r16.cx;
4621 DX = regs.u.r16.dx;
4623 ASM_START
4624 sti
4626 ;; Get the count in eax
4627 mov bx, sp
4628 mov ax, _int15_function32.CX [bx]
4629 shl eax, #16
4630 mov ax, _int15_function32.DX [bx]
4632 ;; convert to numbers of 15usec ticks
4633 mov ebx, #15
4634 xor edx, edx
4635 div eax, ebx
4636 mov ecx, eax
4638 ;; wait for ecx number of refresh requests
4639 in al, #0x61
4640 and al,#0x10
4641 mov ah, al
4643 or ecx, ecx
4644 je int1586_tick_end
4645 int1586_tick:
4646 in al, #0x61
4647 and al,#0x10
4648 cmp al, ah
4649 je int1586_tick
4650 mov ah, al
4651 dec ecx
4652 jnz int1586_tick
4653 int1586_tick_end:
4654 ASM_END
4656 break;
4658 case 0xe8:
4659 switch(regs.u.r8.al)
4661 #ifdef HVMASSIST
4662 case 0x20: {
4663 Bit16u e820_table_size =
4664 read_word(E820_SEG, E820_NR_OFFSET) * 0x14;
4666 if (regs.u.r32.edx != 0x534D4150) /* SMAP */
4667 goto int15_unimplemented;
4669 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4670 if (regs.u.r16.bx + 0x14 <= e820_table_size)
4671 memcpyb(ES, regs.u.r16.di,
4672 E820_SEG, E820_OFFSET + regs.u.r16.bx, 0x14);
4673 regs.u.r32.ebx += 0x14;
4674 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4675 regs.u.r32.ebx = 0;
4676 } else if (regs.u.r16.bx == 1) {
4677 Bit32u base, type;
4678 Bit16u off;
4679 for (off = 0; off < e820_table_size; off += 0x14) {
4680 base = read_dword(E820_SEG, E820_OFFSET + off);
4681 type = read_dword(E820_SEG, E820_OFFSET + 0x10 + off);
4682 if ((base >= 0x100000) && (type == 1))
4683 break;
4685 if (off == e820_table_size) {
4686 SET_CF();
4687 break;
4689 memcpyb(ES, regs.u.r16.di, E820_SEG, E820_OFFSET + off, 0x14);
4690 regs.u.r32.ebx = 0;
4691 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4692 goto int15_unimplemented;
4695 regs.u.r32.eax = 0x534D4150;
4696 regs.u.r32.ecx = 0x14;
4697 CLEAR_CF();
4698 break;
4701 case 0x01: {
4702 Bit16u off, e820_table_size =
4703 read_word(E820_SEG, E820_NR_OFFSET) * 0x14;
4704 Bit32u base, type, size;
4706 // do we have any reason to fail here ?
4707 CLEAR_CF();
4709 // Get the amount of extended memory (above 1M)
4710 regs.u.r8.cl = inb_cmos(0x30);
4711 regs.u.r8.ch = inb_cmos(0x31);
4713 // limit to 15M
4714 if (regs.u.r16.cx > (15*1024))
4715 regs.u.r16.cx = 15*1024;
4717 // Find first RAM E820 entry >= 1MB.
4718 for (off = 0; off < e820_table_size; off += 0x14) {
4719 base = read_dword(E820_SEG, E820_OFFSET + off);
4720 type = read_dword(E820_SEG, E820_OFFSET + 0x10 + off);
4721 if ((base >= 0x100000) && (type == 1))
4722 break;
4725 // If there is RAM above 16MB, return amount in 64kB chunks.
4726 regs.u.r16.dx = 0;
4727 if (off != e820_table_size) {
4728 size = base + read_dword(E820_SEG, E820_OFFSET + 0x8 + off);
4729 if (size > 0x1000000) {
4730 size -= 0x1000000;
4731 regs.u.r16.dx = (Bit16u)(size >> 16);
4735 // Set configured memory equal to extended memory
4736 regs.u.r16.ax = regs.u.r16.cx;
4737 regs.u.r16.bx = regs.u.r16.dx;
4738 break;
4740 default: /* AH=0xE8?? but not implemented */
4741 goto int15_unimplemented;
4743 break;
4744 int15_unimplemented:
4745 // fall into the default
4746 default:
4747 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4748 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4749 SET_CF();
4750 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4751 break;
4753 #else
4754 case 0x20: // coded by osmaker aka K.J.
4755 if(regs.u.r32.edx == 0x534D4150)
4757 extended_memory_size = inb_cmos(0x35);
4758 extended_memory_size <<= 8;
4759 extended_memory_size |= inb_cmos(0x34);
4760 extended_memory_size *= 64;
4761 // greater than EFF00000???
4762 if(extended_memory_size > 0x3bc000) {
4763 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4765 extended_memory_size *= 1024;
4766 extended_memory_size += (16L * 1024 * 1024);
4768 if(extended_memory_size <= (16L * 1024 * 1024)) {
4769 extended_memory_size = inb_cmos(0x31);
4770 extended_memory_size <<= 8;
4771 extended_memory_size |= inb_cmos(0x30);
4772 extended_memory_size *= 1024;
4773 extended_memory_size += (1L * 1024 * 1024);
4776 switch(regs.u.r16.bx)
4778 case 0:
4779 set_e820_range(ES, regs.u.r16.di,
4780 0x0000000L, 0x0009f000L, 1);
4781 regs.u.r32.ebx = 1;
4782 regs.u.r32.eax = 0x534D4150;
4783 regs.u.r32.ecx = 0x14;
4784 CLEAR_CF();
4785 return;
4786 break;
4787 case 1:
4788 set_e820_range(ES, regs.u.r16.di,
4789 0x0009f000L, 0x000a0000L, 2);
4790 regs.u.r32.ebx = 2;
4791 regs.u.r32.eax = 0x534D4150;
4792 regs.u.r32.ecx = 0x14;
4793 CLEAR_CF();
4794 return;
4795 break;
4796 case 2:
4797 set_e820_range(ES, regs.u.r16.di,
4798 0x000e8000L, 0x00100000L, 2);
4799 regs.u.r32.ebx = 3;
4800 regs.u.r32.eax = 0x534D4150;
4801 regs.u.r32.ecx = 0x14;
4802 CLEAR_CF();
4803 return;
4804 break;
4805 case 3:
4806 #if BX_ROMBIOS32
4807 set_e820_range(ES, regs.u.r16.di,
4808 0x00100000L,
4809 extended_memory_size - ACPI_DATA_SIZE, 1);
4810 regs.u.r32.ebx = 4;
4811 #else
4812 set_e820_range(ES, regs.u.r16.di,
4813 0x00100000L,
4814 extended_memory_size, 1);
4815 regs.u.r32.ebx = 5;
4816 #endif
4817 regs.u.r32.eax = 0x534D4150;
4818 regs.u.r32.ecx = 0x14;
4819 CLEAR_CF();
4820 return;
4821 break;
4822 case 4:
4823 set_e820_range(ES, regs.u.r16.di,
4824 extended_memory_size - ACPI_DATA_SIZE,
4825 extended_memory_size, 3); // ACPI RAM
4826 regs.u.r32.ebx = 5;
4827 regs.u.r32.eax = 0x534D4150;
4828 regs.u.r32.ecx = 0x14;
4829 CLEAR_CF();
4830 return;
4831 break;
4832 case 5:
4833 /* 256KB BIOS area at the end of 4 GB */
4834 set_e820_range(ES, regs.u.r16.di,
4835 0xfffc0000L, 0x00000000L, 2);
4836 regs.u.r32.ebx = 0;
4837 regs.u.r32.eax = 0x534D4150;
4838 regs.u.r32.ecx = 0x14;
4839 CLEAR_CF();
4840 return;
4841 default: /* AX=E820, DX=534D4150, BX unrecognized */
4842 goto int15_unimplemented;
4843 break;
4845 } else {
4846 // if DX != 0x534D4150)
4847 goto int15_unimplemented;
4849 break;
4851 case 0x01:
4852 // do we have any reason to fail here ?
4853 CLEAR_CF();
4855 // my real system sets ax and bx to 0
4856 // this is confirmed by Ralph Brown list
4857 // but syslinux v1.48 is known to behave
4858 // strangely if ax is set to 0
4859 // regs.u.r16.ax = 0;
4860 // regs.u.r16.bx = 0;
4862 // Get the amount of extended memory (above 1M)
4863 regs.u.r8.cl = inb_cmos(0x30);
4864 regs.u.r8.ch = inb_cmos(0x31);
4866 // limit to 15M
4867 if(regs.u.r16.cx > 0x3c00)
4869 regs.u.r16.cx = 0x3c00;
4872 // Get the amount of extended memory above 16M in 64k blocs
4873 regs.u.r8.dl = inb_cmos(0x34);
4874 regs.u.r8.dh = inb_cmos(0x35);
4876 // Set configured memory equal to extended memory
4877 regs.u.r16.ax = regs.u.r16.cx;
4878 regs.u.r16.bx = regs.u.r16.dx;
4879 break;
4880 default: /* AH=0xE8?? but not implemented */
4881 goto int15_unimplemented;
4883 break;
4884 int15_unimplemented:
4885 // fall into the default
4886 default:
4887 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4888 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4889 SET_CF();
4890 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4891 break;
4893 #endif /* HVMASSIST */
4896 void
4897 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4898 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4900 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4901 Bit16u kbd_code, max;
4903 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4905 shift_flags = read_byte(0x0040, 0x17);
4906 led_flags = read_byte(0x0040, 0x97);
4907 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4908 ASM_START
4909 cli
4910 ASM_END
4911 outb(0x60, 0xed);
4912 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4913 if ((inb(0x60) == 0xfa)) {
4914 led_flags &= 0xf8;
4915 led_flags |= ((shift_flags >> 4) & 0x07);
4916 outb(0x60, led_flags & 0x07);
4917 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4918 inb(0x60);
4919 write_byte(0x0040, 0x97, led_flags);
4921 ASM_START
4922 sti
4923 ASM_END
4926 switch (GET_AH()) {
4927 case 0x00: /* read keyboard input */
4929 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4930 BX_PANIC("KBD: int16h: out of keyboard input\n");
4932 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4933 else if (ascii_code == 0xE0) ascii_code = 0;
4934 AX = (scan_code << 8) | ascii_code;
4935 break;
4937 case 0x01: /* check keyboard status */
4938 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4939 SET_ZF();
4940 return;
4942 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4943 else if (ascii_code == 0xE0) ascii_code = 0;
4944 AX = (scan_code << 8) | ascii_code;
4945 CLEAR_ZF();
4946 break;
4948 case 0x02: /* get shift flag status */
4949 shift_flags = read_byte(0x0040, 0x17);
4950 SET_AL(shift_flags);
4951 break;
4953 case 0x05: /* store key-stroke into buffer */
4954 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4955 SET_AL(1);
4957 else {
4958 SET_AL(0);
4960 break;
4962 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4963 // bit Bochs Description
4964 // 7 0 reserved
4965 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4966 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4967 // 4 1 INT 16/AH=0Ah supported
4968 // 3 0 INT 16/AX=0306h supported
4969 // 2 0 INT 16/AX=0305h supported
4970 // 1 0 INT 16/AX=0304h supported
4971 // 0 0 INT 16/AX=0300h supported
4972 //
4973 SET_AL(0x30);
4974 break;
4976 case 0x0A: /* GET KEYBOARD ID */
4977 count = 2;
4978 kbd_code = 0x0;
4979 outb(0x60, 0xf2);
4980 /* Wait for data */
4981 max=0xffff;
4982 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4983 if (max>0x0) {
4984 if ((inb(0x60) == 0xfa)) {
4985 do {
4986 max=0xffff;
4987 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4988 if (max>0x0) {
4989 kbd_code >>= 8;
4990 kbd_code |= (inb(0x60) << 8);
4992 } while (--count>0);
4995 BX=kbd_code;
4996 break;
4998 case 0x10: /* read MF-II keyboard input */
5000 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5001 BX_PANIC("KBD: int16h: out of keyboard input\n");
5003 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5004 AX = (scan_code << 8) | ascii_code;
5005 break;
5007 case 0x11: /* check MF-II keyboard status */
5008 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5009 SET_ZF();
5010 return;
5012 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5013 AX = (scan_code << 8) | ascii_code;
5014 CLEAR_ZF();
5015 break;
5017 case 0x12: /* get extended keyboard status */
5018 shift_flags = read_byte(0x0040, 0x17);
5019 SET_AL(shift_flags);
5020 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5021 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5022 SET_AH(shift_flags);
5023 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5024 break;
5026 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5027 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5028 break;
5030 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5031 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5032 break;
5034 case 0x6F:
5035 if (GET_AL() == 0x08)
5036 SET_AH(0x02); // unsupported, aka normal keyboard
5038 default:
5039 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5043 unsigned int
5044 dequeue_key(scan_code, ascii_code, incr)
5045 Bit8u *scan_code;
5046 Bit8u *ascii_code;
5047 unsigned int incr;
5049 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5050 Bit16u ss;
5051 Bit8u acode, scode;
5053 #if BX_CPU < 2
5054 buffer_start = 0x001E;
5055 buffer_end = 0x003E;
5056 #else
5057 buffer_start = read_word(0x0040, 0x0080);
5058 buffer_end = read_word(0x0040, 0x0082);
5059 #endif
5061 buffer_head = read_word(0x0040, 0x001a);
5062 buffer_tail = read_word(0x0040, 0x001c);
5064 if (buffer_head != buffer_tail) {
5065 ss = get_SS();
5066 acode = read_byte(0x0040, buffer_head);
5067 scode = read_byte(0x0040, buffer_head+1);
5068 write_byte(ss, ascii_code, acode);
5069 write_byte(ss, scan_code, scode);
5071 if (incr) {
5072 buffer_head += 2;
5073 if (buffer_head >= buffer_end)
5074 buffer_head = buffer_start;
5075 write_word(0x0040, 0x001a, buffer_head);
5077 return(1);
5079 else {
5080 return(0);
5084 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5086 Bit8u
5087 inhibit_mouse_int_and_events()
5089 Bit8u command_byte, prev_command_byte;
5091 // Turn off IRQ generation and aux data line
5092 if ( inb(0x64) & 0x02 )
5093 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
5094 outb(0x64, 0x20); // get command byte
5095 while ( (inb(0x64) & 0x01) != 0x01 );
5096 prev_command_byte = inb(0x60);
5097 command_byte = prev_command_byte;
5098 //while ( (inb(0x64) & 0x02) );
5099 if ( inb(0x64) & 0x02 )
5100 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
5101 command_byte &= 0xfd; // turn off IRQ 12 generation
5102 command_byte |= 0x20; // disable mouse serial clock line
5103 outb(0x64, 0x60); // write command byte
5104 outb(0x60, command_byte);
5105 return(prev_command_byte);
5108 void
5109 enable_mouse_int_and_events()
5111 Bit8u command_byte;
5113 // Turn on IRQ generation and aux data line
5114 if ( inb(0x64) & 0x02 )
5115 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
5116 outb(0x64, 0x20); // get command byte
5117 while ( (inb(0x64) & 0x01) != 0x01 );
5118 command_byte = inb(0x60);
5119 //while ( (inb(0x64) & 0x02) );
5120 if ( inb(0x64) & 0x02 )
5121 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
5122 command_byte |= 0x02; // turn on IRQ 12 generation
5123 command_byte &= 0xdf; // enable mouse serial clock line
5124 outb(0x64, 0x60); // write command byte
5125 outb(0x60, command_byte);
5128 Bit8u
5129 send_to_mouse_ctrl(sendbyte)
5130 Bit8u sendbyte;
5132 Bit8u response;
5134 // wait for chance to write to ctrl
5135 if ( inb(0x64) & 0x02 )
5136 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5137 outb(0x64, 0xD4);
5138 outb(0x60, sendbyte);
5139 return(0);
5143 Bit8u
5144 get_mouse_data(data)
5145 Bit8u *data;
5147 Bit8u response;
5148 Bit16u ss;
5150 while ( (inb(0x64) & 0x21) != 0x21 ) {
5153 response = inb(0x60);
5155 ss = get_SS();
5156 write_byte(ss, data, response);
5157 return(0);
5160 void
5161 set_kbd_command_byte(command_byte)
5162 Bit8u command_byte;
5164 if ( inb(0x64) & 0x02 )
5165 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5166 outb(0x64, 0xD4);
5168 outb(0x64, 0x60); // write command byte
5169 outb(0x60, command_byte);
5172 void
5173 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5174 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5176 Bit8u scancode, asciicode, shift_flags;
5177 Bit8u mf2_flags, mf2_state;
5179 //
5180 // DS has been set to F000 before call
5181 //
5184 scancode = GET_AL();
5186 if (scancode == 0) {
5187 BX_INFO("KBD: int09 handler: AL=0\n");
5188 return;
5192 shift_flags = read_byte(0x0040, 0x17);
5193 mf2_flags = read_byte(0x0040, 0x18);
5194 mf2_state = read_byte(0x0040, 0x96);
5195 asciicode = 0;
5197 switch (scancode) {
5198 case 0x3a: /* Caps Lock press */
5199 shift_flags ^= 0x40;
5200 write_byte(0x0040, 0x17, shift_flags);
5201 mf2_flags |= 0x40;
5202 write_byte(0x0040, 0x18, mf2_flags);
5203 break;
5204 case 0xba: /* Caps Lock release */
5205 mf2_flags &= ~0x40;
5206 write_byte(0x0040, 0x18, mf2_flags);
5207 break;
5209 case 0x2a: /* L Shift press */
5210 shift_flags |= 0x02;
5211 write_byte(0x0040, 0x17, shift_flags);
5212 break;
5213 case 0xaa: /* L Shift release */
5214 shift_flags &= ~0x02;
5215 write_byte(0x0040, 0x17, shift_flags);
5216 break;
5218 case 0x36: /* R Shift press */
5219 shift_flags |= 0x01;
5220 write_byte(0x0040, 0x17, shift_flags);
5221 break;
5222 case 0xb6: /* R Shift release */
5223 shift_flags &= ~0x01;
5224 write_byte(0x0040, 0x17, shift_flags);
5225 break;
5227 case 0x1d: /* Ctrl press */
5228 if ((mf2_state & 0x01) == 0) {
5229 shift_flags |= 0x04;
5230 write_byte(0x0040, 0x17, shift_flags);
5231 if (mf2_state & 0x02) {
5232 mf2_state |= 0x04;
5233 write_byte(0x0040, 0x96, mf2_state);
5234 } else {
5235 mf2_flags |= 0x01;
5236 write_byte(0x0040, 0x18, mf2_flags);
5239 break;
5240 case 0x9d: /* Ctrl release */
5241 if ((mf2_state & 0x01) == 0) {
5242 shift_flags &= ~0x04;
5243 write_byte(0x0040, 0x17, shift_flags);
5244 if (mf2_state & 0x02) {
5245 mf2_state &= ~0x04;
5246 write_byte(0x0040, 0x96, mf2_state);
5247 } else {
5248 mf2_flags &= ~0x01;
5249 write_byte(0x0040, 0x18, mf2_flags);
5252 break;
5254 case 0x38: /* Alt press */
5255 shift_flags |= 0x08;
5256 write_byte(0x0040, 0x17, shift_flags);
5257 if (mf2_state & 0x02) {
5258 mf2_state |= 0x08;
5259 write_byte(0x0040, 0x96, mf2_state);
5260 } else {
5261 mf2_flags |= 0x02;
5262 write_byte(0x0040, 0x18, mf2_flags);
5264 break;
5265 case 0xb8: /* Alt release */
5266 shift_flags &= ~0x08;
5267 write_byte(0x0040, 0x17, shift_flags);
5268 if (mf2_state & 0x02) {
5269 mf2_state &= ~0x08;
5270 write_byte(0x0040, 0x96, mf2_state);
5271 } else {
5272 mf2_flags &= ~0x02;
5273 write_byte(0x0040, 0x18, mf2_flags);
5275 break;
5277 case 0x45: /* Num Lock press */
5278 if ((mf2_state & 0x03) == 0) {
5279 mf2_flags |= 0x20;
5280 write_byte(0x0040, 0x18, mf2_flags);
5281 shift_flags ^= 0x20;
5282 write_byte(0x0040, 0x17, shift_flags);
5284 break;
5285 case 0xc5: /* Num Lock release */
5286 if ((mf2_state & 0x03) == 0) {
5287 mf2_flags &= ~0x20;
5288 write_byte(0x0040, 0x18, mf2_flags);
5290 break;
5292 case 0x46: /* Scroll Lock press */
5293 mf2_flags |= 0x10;
5294 write_byte(0x0040, 0x18, mf2_flags);
5295 shift_flags ^= 0x10;
5296 write_byte(0x0040, 0x17, shift_flags);
5297 break;
5299 case 0xc6: /* Scroll Lock release */
5300 mf2_flags &= ~0x10;
5301 write_byte(0x0040, 0x18, mf2_flags);
5302 break;
5304 case 0x53: /* Del */
5305 if ((shift_flags & 0x0c) == 0x0c) /* Ctrl + Alt */
5306 machine_reset();
5307 /* Fall through */
5308 default:
5309 if (scancode & 0x80) {
5310 break; /* toss key releases ... */
5312 if (scancode > MAX_SCAN_CODE) {
5313 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5314 return;
5316 if (shift_flags & 0x08) { /* ALT */
5317 asciicode = scan_to_scanascii[scancode].alt;
5318 scancode = scan_to_scanascii[scancode].alt >> 8;
5319 } else if (shift_flags & 0x04) { /* CONTROL */
5320 asciicode = scan_to_scanascii[scancode].control;
5321 scancode = scan_to_scanascii[scancode].control >> 8;
5322 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5323 /* extended keys handling */
5324 asciicode = 0xe0;
5325 scancode = scan_to_scanascii[scancode].normal >> 8;
5326 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5327 /* check if lock state should be ignored
5328 * because a SHIFT key are pressed */
5330 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5331 asciicode = scan_to_scanascii[scancode].normal;
5332 scancode = scan_to_scanascii[scancode].normal >> 8;
5333 } else {
5334 asciicode = scan_to_scanascii[scancode].shift;
5335 scancode = scan_to_scanascii[scancode].shift >> 8;
5337 } else {
5338 /* check if lock is on */
5339 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5340 asciicode = scan_to_scanascii[scancode].shift;
5341 scancode = scan_to_scanascii[scancode].shift >> 8;
5342 } else {
5343 asciicode = scan_to_scanascii[scancode].normal;
5344 scancode = scan_to_scanascii[scancode].normal >> 8;
5347 if (scancode==0 && asciicode==0) {
5348 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5350 enqueue_key(scancode, asciicode);
5351 break;
5353 if ((scancode & 0x7f) != 0x1d) {
5354 mf2_state &= ~0x01;
5356 mf2_state &= ~0x02;
5357 write_byte(0x0040, 0x96, mf2_state);
5360 unsigned int
5361 enqueue_key(scan_code, ascii_code)
5362 Bit8u scan_code, ascii_code;
5364 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5366 #if BX_CPU < 2
5367 buffer_start = 0x001E;
5368 buffer_end = 0x003E;
5369 #else
5370 buffer_start = read_word(0x0040, 0x0080);
5371 buffer_end = read_word(0x0040, 0x0082);
5372 #endif
5374 buffer_head = read_word(0x0040, 0x001A);
5375 buffer_tail = read_word(0x0040, 0x001C);
5377 temp_tail = buffer_tail;
5378 buffer_tail += 2;
5379 if (buffer_tail >= buffer_end)
5380 buffer_tail = buffer_start;
5382 if (buffer_tail == buffer_head) {
5383 return(0);
5386 write_byte(0x0040, temp_tail, ascii_code);
5387 write_byte(0x0040, temp_tail+1, scan_code);
5388 write_word(0x0040, 0x001C, buffer_tail);
5389 return(1);
5393 void
5394 int74_function(make_farcall, Z, Y, X, status)
5395 Bit16u make_farcall, Z, Y, X, status;
5397 Bit16u ebda_seg=read_word(0x0040,0x000E);
5398 Bit8u in_byte, index, package_count;
5399 Bit8u mouse_flags_1, mouse_flags_2;
5401 BX_DEBUG_INT74("entering int74_function\n");
5402 make_farcall = 0;
5404 in_byte = inb(0x64);
5405 if ( (in_byte & 0x21) != 0x21 ) {
5406 return;
5408 in_byte = inb(0x60);
5409 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5411 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5412 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5414 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5415 return;
5418 package_count = mouse_flags_2 & 0x07;
5419 index = mouse_flags_1 & 0x07;
5420 write_byte(ebda_seg, 0x28 + index, in_byte);
5422 if ( (index+1) >= package_count ) {
5423 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5424 status = read_byte(ebda_seg, 0x0028 + 0);
5425 X = read_byte(ebda_seg, 0x0028 + 1);
5426 Y = read_byte(ebda_seg, 0x0028 + 2);
5427 Z = 0;
5428 mouse_flags_1 = 0;
5429 // check if far call handler installed
5430 if (mouse_flags_2 & 0x80)
5431 make_farcall = 1;
5433 else {
5434 mouse_flags_1++;
5436 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5439 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5441 #if BX_USE_ATADRV
5443 void
5444 int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5445 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5447 Bit32u lba_low, lba_high;
5448 Bit16u ebda_seg=read_word(0x0040,0x000E);
5449 Bit16u cylinder, head, sector;
5450 Bit16u segment, offset;
5451 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5452 Bit16u size, count;
5453 Bit8u device, status;
5455 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5457 write_byte(0x0040, 0x008e, 0); // clear completion flag
5459 // basic check : device has to be defined
5460 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5461 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5462 goto int13_fail;
5465 // Get the ata channel
5466 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5468 // basic check : device has to be valid
5469 if (device >= BX_MAX_ATA_DEVICES) {
5470 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5471 goto int13_fail;
5474 switch (GET_AH()) {
5476 case 0x00: /* disk controller reset */
5477 ata_reset (device);
5478 goto int13_success;
5479 break;
5481 case 0x01: /* read disk status */
5482 status = read_byte(0x0040, 0x0074);
5483 SET_AH(status);
5484 SET_DISK_RET_STATUS(0);
5485 /* set CF if error status read */
5486 if (status) goto int13_fail_nostatus;
5487 else goto int13_success_noah;
5488 break;
5490 case 0x02: // read disk sectors
5491 case 0x03: // write disk sectors
5492 case 0x04: // verify disk sectors
5494 count = GET_AL();
5495 cylinder = GET_CH();
5496 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5497 sector = (GET_CL() & 0x3f);
5498 head = GET_DH();
5500 segment = ES;
5501 offset = BX;
5503 if ((count > 128) || (count == 0) || (sector == 0)) {
5504 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5505 goto int13_fail;
5508 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5509 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5510 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5512 // sanity check on cyl heads, sec
5513 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5514 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5515 goto int13_fail;
5518 // FIXME verify
5519 if ( GET_AH() == 0x04 ) goto int13_success;
5521 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5522 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5524 // if needed, translate lchs to lba, and execute command
5525 if ( (nph != nlh) || (npspt != nlspt)) {
5526 lba_low = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5527 lba_high = 0;
5528 sector = 0; // this forces the command to be lba
5531 if ( GET_AH() == 0x02 )
5532 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
5533 else
5534 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
5536 // Set nb of sector transferred
5537 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5539 if (status != 0) {
5540 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5541 SET_AH(0x0c);
5542 goto int13_fail_noah;
5545 goto int13_success;
5546 break;
5548 case 0x05: /* format disk track */
5549 BX_INFO("format disk track called\n");
5550 goto int13_success;
5551 return;
5552 break;
5554 case 0x08: /* read disk drive parameters */
5556 // Get logical geometry from table
5557 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5558 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5559 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5560 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5562 nlc = nlc - 2; /* 0 based , last sector not used */
5563 SET_AL(0);
5564 SET_CH(nlc & 0xff);
5565 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5566 SET_DH(nlh - 1);
5567 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5569 // FIXME should set ES & DI
5571 goto int13_success;
5572 break;
5574 case 0x10: /* check drive ready */
5575 // should look at 40:8E also???
5577 // Read the status from controller
5578 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5579 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5580 goto int13_success;
5582 else {
5583 SET_AH(0xAA);
5584 goto int13_fail_noah;
5586 break;
5588 case 0x15: /* read disk drive size */
5590 // Get logical geometry from table
5591 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5592 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5593 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5595 // Compute sector count seen by int13
5596 lba_low = (Bit32u)(nlc - 1) * (Bit32u)nlh * (Bit32u)nlspt;
5597 CX = lba_low >> 16;
5598 DX = lba_low & 0xffff;
5600 SET_AH(3); // hard disk accessible
5601 goto int13_success_noah;
5602 break;
5604 case 0x41: // IBM/MS installation check
5605 BX=0xaa55; // install check
5606 SET_AH(0x30); // EDD 3.0
5607 CX=0x0007; // ext disk access and edd, removable supported
5608 goto int13_success_noah;
5609 break;
5611 case 0x42: // IBM/MS extended read
5612 case 0x43: // IBM/MS extended write
5613 case 0x44: // IBM/MS verify
5614 case 0x47: // IBM/MS extended seek
5616 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5617 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5618 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5620 // Get 32 msb lba and check
5621 lba_high=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5622 if (lba_high > read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) ) {
5623 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5624 goto int13_fail;
5627 // Get 32 lsb lba and check
5628 lba_low=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5629 if (lba_high == read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high)
5630 && lba_low >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low) ) {
5631 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5632 goto int13_fail;
5635 // If verify or seek
5636 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5637 goto int13_success;
5639 // Execute the command
5640 if ( GET_AH() == 0x42 )
5641 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
5642 else
5643 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
5645 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5646 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5648 if (status != 0) {
5649 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5650 SET_AH(0x0c);
5651 goto int13_fail_noah;
5654 goto int13_success;
5655 break;
5657 case 0x45: // IBM/MS lock/unlock drive
5658 case 0x49: // IBM/MS extended media change
5659 goto int13_success; // Always success for HD
5660 break;
5662 case 0x46: // IBM/MS eject media
5663 SET_AH(0xb2); // Volume Not Removable
5664 goto int13_fail_noah; // Always fail for HD
5665 break;
5667 case 0x48: // IBM/MS get drive parameters
5668 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5670 // Buffer is too small
5671 if(size < 0x1a)
5672 goto int13_fail;
5674 // EDD 1.x
5675 if(size >= 0x1a) {
5676 Bit16u blksize;
5678 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5679 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5680 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5681 lba_low = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low);
5682 lba_high = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high);
5683 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5685 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5686 if (lba_high || (lba_low/npspt)/nph > 0x3fff)
5688 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x00); // geometry is invalid
5689 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0x3fff);
5691 else
5693 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5694 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5696 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5697 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5698 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba_low);
5699 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, lba_high);
5700 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5703 // EDD 2.x
5704 if(size >= 0x1e) {
5705 Bit8u channel, dev, irq, mode, checksum, i, translation;
5706 Bit16u iobase1, iobase2, options;
5708 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5710 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5711 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5713 // Fill in dpte
5714 channel = device / 2;
5715 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5716 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5717 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5718 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5719 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5721 options = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
5722 options |= (1<<4); // lba translation
5723 options |= (mode==ATA_MODE_PIO32?1:0)<<7;
5724 options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
5725 options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
5727 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5728 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
5729 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5730 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5731 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5732 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5733 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5734 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5735 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5736 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5737 if (size >=0x42)
5738 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5739 else
5740 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x10);
5742 checksum=0;
5743 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
5744 checksum = ~checksum;
5745 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5748 // EDD 3.x
5749 if(size >= 0x42) {
5750 Bit8u channel, iface, checksum, i;
5751 Bit16u iobase1;
5753 channel = device / 2;
5754 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5755 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5757 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5758 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5759 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5760 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5761 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5763 if (iface==ATA_IFACE_ISA) {
5764 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5765 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5766 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5767 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5769 else {
5770 // FIXME PCI
5772 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5773 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5774 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5775 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5777 if (iface==ATA_IFACE_ISA) {
5778 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5779 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5780 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5782 else {
5783 // FIXME PCI
5785 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5786 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5787 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5788 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5790 checksum=0;
5791 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5792 checksum = ~checksum;
5793 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5796 goto int13_success;
5797 break;
5799 case 0x4e: // // IBM/MS set hardware configuration
5800 // DMA, prefetch, PIO maximum not supported
5801 switch (GET_AL()) {
5802 case 0x01:
5803 case 0x03:
5804 case 0x04:
5805 case 0x06:
5806 goto int13_success;
5807 break;
5808 default :
5809 goto int13_fail;
5811 break;
5813 case 0x09: /* initialize drive parameters */
5814 case 0x0c: /* seek to specified cylinder */
5815 case 0x0d: /* alternate disk reset */
5816 case 0x11: /* recalibrate */
5817 case 0x14: /* controller internal diagnostic */
5818 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5819 goto int13_success;
5820 break;
5822 case 0x0a: /* read disk sectors with ECC */
5823 case 0x0b: /* write disk sectors with ECC */
5824 case 0x18: // set media type for format
5825 case 0x50: // IBM/MS send packet command
5826 default:
5827 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5828 goto int13_fail;
5829 break;
5832 int13_fail:
5833 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5834 int13_fail_noah:
5835 SET_DISK_RET_STATUS(GET_AH());
5836 int13_fail_nostatus:
5837 SET_CF(); // error occurred
5838 return;
5840 int13_success:
5841 SET_AH(0x00); // no error
5842 int13_success_noah:
5843 SET_DISK_RET_STATUS(0x00);
5844 CLEAR_CF(); // no error
5845 return;
5848 // ---------------------------------------------------------------------------
5849 // Start of int13 for cdrom
5850 // ---------------------------------------------------------------------------
5852 void
5853 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5854 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5856 Bit16u ebda_seg=read_word(0x0040,0x000E);
5857 Bit8u device, status, locks;
5858 Bit8u atacmd[12];
5859 Bit32u lba;
5860 Bit16u count, segment, offset, i, size;
5862 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5864 SET_DISK_RET_STATUS(0x00);
5866 /* basic check : device should be 0xE0+ */
5867 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5868 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5869 goto int13_fail;
5872 // Get the ata channel
5873 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5875 /* basic check : device has to be valid */
5876 if (device >= BX_MAX_ATA_DEVICES) {
5877 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5878 goto int13_fail;
5881 switch (GET_AH()) {
5883 // all those functions return SUCCESS
5884 case 0x00: /* disk controller reset */
5885 case 0x09: /* initialize drive parameters */
5886 case 0x0c: /* seek to specified cylinder */
5887 case 0x0d: /* alternate disk reset */
5888 case 0x10: /* check drive ready */
5889 case 0x11: /* recalibrate */
5890 case 0x14: /* controller internal diagnostic */
5891 case 0x16: /* detect disk change */
5892 goto int13_success;
5893 break;
5895 // all those functions return disk write-protected
5896 case 0x03: /* write disk sectors */
5897 case 0x05: /* format disk track */
5898 case 0x43: // IBM/MS extended write
5899 SET_AH(0x03);
5900 goto int13_fail_noah;
5901 break;
5903 case 0x01: /* read disk status */
5904 status = read_byte(0x0040, 0x0074);
5905 SET_AH(status);
5906 SET_DISK_RET_STATUS(0);
5908 /* set CF if error status read */
5909 if (status) goto int13_fail_nostatus;
5910 else goto int13_success_noah;
5911 break;
5913 case 0x15: /* read disk drive size */
5914 SET_AH(0x02);
5915 goto int13_fail_noah;
5916 break;
5918 case 0x41: // IBM/MS installation check
5919 BX=0xaa55; // install check
5920 SET_AH(0x30); // EDD 2.1
5921 CX=0x0007; // ext disk access, removable and edd
5922 goto int13_success_noah;
5923 break;
5925 case 0x42: // IBM/MS extended read
5926 case 0x44: // IBM/MS verify sectors
5927 case 0x47: // IBM/MS extended seek
5929 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5930 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5931 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5933 // Can't use 64 bits lba
5934 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5935 if (lba != 0L) {
5936 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5937 goto int13_fail;
5940 // Get 32 bits lba
5941 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5943 // If verify or seek
5944 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5945 goto int13_success;
5947 memsetb(get_SS(),atacmd,0,12);
5948 atacmd[0]=0x28; // READ command
5949 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5950 atacmd[8]=(count & 0x00ff); // Sectors
5951 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5952 atacmd[3]=(lba & 0x00ff0000) >> 16;
5953 atacmd[4]=(lba & 0x0000ff00) >> 8;
5954 atacmd[5]=(lba & 0x000000ff);
5955 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5957 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5958 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5960 if (status != 0) {
5961 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5962 SET_AH(0x0c);
5963 goto int13_fail_noah;
5966 goto int13_success;
5967 break;
5969 case 0x45: // IBM/MS lock/unlock drive
5970 if (GET_AL() > 2) goto int13_fail;
5972 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5974 switch (GET_AL()) {
5975 case 0 : // lock
5976 if (locks == 0xff) {
5977 SET_AH(0xb4);
5978 SET_AL(1);
5979 goto int13_fail_noah;
5981 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5982 SET_AL(1);
5983 break;
5984 case 1 : // unlock
5985 if (locks == 0x00) {
5986 SET_AH(0xb0);
5987 SET_AL(0);
5988 goto int13_fail_noah;
5990 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5991 SET_AL(locks==0?0:1);
5992 break;
5993 case 2 : // status
5994 SET_AL(locks==0?0:1);
5995 break;
5997 goto int13_success;
5998 break;
6000 case 0x46: // IBM/MS eject media
6001 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6003 if (locks != 0) {
6004 SET_AH(0xb1); // media locked
6005 goto int13_fail_noah;
6007 // FIXME should handle 0x31 no media in device
6008 // FIXME should handle 0xb5 valid request failed
6010 // Call removable media eject
6011 ASM_START
6012 push bp
6013 mov bp, sp
6015 mov ah, #0x52
6016 int #0x15
6017 mov _int13_cdrom.status + 2[bp], ah
6018 jnc int13_cdrom_rme_end
6019 mov _int13_cdrom.status, #1
6020 int13_cdrom_rme_end:
6021 pop bp
6022 ASM_END
6024 if (status != 0) {
6025 SET_AH(0xb1); // media locked
6026 goto int13_fail_noah;
6029 goto int13_success;
6030 break;
6032 case 0x48: // IBM/MS get drive parameters
6033 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6035 // Buffer is too small
6036 if(size < 0x1a)
6037 goto int13_fail;
6039 // EDD 1.x
6040 if(size >= 0x1a) {
6041 Bit16u cylinders, heads, spt, blksize;
6043 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6045 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6046 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6047 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6048 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6049 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6050 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6051 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6052 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6055 // EDD 2.x
6056 if(size >= 0x1e) {
6057 Bit8u channel, dev, irq, mode, checksum, i;
6058 Bit16u iobase1, iobase2, options;
6060 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6062 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6063 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6065 // Fill in dpte
6066 channel = device / 2;
6067 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6068 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6069 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6070 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6072 // FIXME atapi device
6073 options = (1<<4); // lba translation
6074 options |= (1<<5); // removable device
6075 options |= (1<<6); // atapi device
6076 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6078 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6079 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
6080 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6081 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6082 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6083 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6084 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6085 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6086 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6087 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6088 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6090 checksum=0;
6091 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
6092 checksum = ~checksum;
6093 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6096 // EDD 3.x
6097 if(size >= 0x42) {
6098 Bit8u channel, iface, checksum, i;
6099 Bit16u iobase1;
6101 channel = device / 2;
6102 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6103 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6105 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6106 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6107 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6108 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6109 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6111 if (iface==ATA_IFACE_ISA) {
6112 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6113 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6114 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6115 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6117 else {
6118 // FIXME PCI
6120 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6121 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6122 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6123 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6125 if (iface==ATA_IFACE_ISA) {
6126 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6127 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6128 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6130 else {
6131 // FIXME PCI
6133 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6134 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6135 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6136 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6138 checksum=0;
6139 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6140 checksum = ~checksum;
6141 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6144 goto int13_success;
6145 break;
6147 case 0x49: // IBM/MS extended media change
6148 // always send changed ??
6149 SET_AH(06);
6150 goto int13_fail_nostatus;
6151 break;
6153 case 0x4e: // // IBM/MS set hardware configuration
6154 // DMA, prefetch, PIO maximum not supported
6155 switch (GET_AL()) {
6156 case 0x01:
6157 case 0x03:
6158 case 0x04:
6159 case 0x06:
6160 goto int13_success;
6161 break;
6162 default :
6163 goto int13_fail;
6165 break;
6167 // all those functions return unimplemented
6168 case 0x02: /* read sectors */
6169 case 0x04: /* verify sectors */
6170 case 0x08: /* read disk drive parameters */
6171 case 0x0a: /* read disk sectors with ECC */
6172 case 0x0b: /* write disk sectors with ECC */
6173 case 0x18: /* set media type for format */
6174 case 0x50: // ? - send packet command
6175 default:
6176 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6177 goto int13_fail;
6178 break;
6181 int13_fail:
6182 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6183 int13_fail_noah:
6184 SET_DISK_RET_STATUS(GET_AH());
6185 int13_fail_nostatus:
6186 SET_CF(); // error occurred
6187 return;
6189 int13_success:
6190 SET_AH(0x00); // no error
6191 int13_success_noah:
6192 SET_DISK_RET_STATUS(0x00);
6193 CLEAR_CF(); // no error
6194 return;
6197 // ---------------------------------------------------------------------------
6198 // End of int13 for cdrom
6199 // ---------------------------------------------------------------------------
6201 #if BX_ELTORITO_BOOT
6202 // ---------------------------------------------------------------------------
6203 // Start of int13 for eltorito functions
6204 // ---------------------------------------------------------------------------
6206 void
6207 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6208 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6210 Bit16u ebda_seg=read_word(0x0040,0x000E);
6212 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6213 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6215 switch (GET_AH()) {
6217 // FIXME ElTorito Various. Should be implemented
6218 case 0x4a: // ElTorito - Initiate disk emu
6219 case 0x4c: // ElTorito - Initiate disk emu and boot
6220 case 0x4d: // ElTorito - Return Boot catalog
6221 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6222 goto int13_fail;
6223 break;
6225 case 0x4b: // ElTorito - Terminate disk emu
6226 // FIXME ElTorito Hardcoded
6227 write_byte(DS,SI+0x00,0x13);
6228 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6229 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6230 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6231 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6232 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6233 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6234 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6235 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6236 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6237 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6238 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6240 // If we have to terminate emulation
6241 if(GET_AL() == 0x00) {
6242 // FIXME ElTorito Various. Should be handled accordingly to spec
6243 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6246 goto int13_success;
6247 break;
6249 default:
6250 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6251 goto int13_fail;
6252 break;
6255 int13_fail:
6256 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6257 SET_DISK_RET_STATUS(GET_AH());
6258 SET_CF(); // error occurred
6259 return;
6261 int13_success:
6262 SET_AH(0x00); // no error
6263 SET_DISK_RET_STATUS(0x00);
6264 CLEAR_CF(); // no error
6265 return;
6268 // ---------------------------------------------------------------------------
6269 // End of int13 for eltorito functions
6270 // ---------------------------------------------------------------------------
6272 // ---------------------------------------------------------------------------
6273 // Start of int13 when emulating a device from the cd
6274 // ---------------------------------------------------------------------------
6276 void
6277 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6278 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6280 Bit16u ebda_seg=read_word(0x0040,0x000E);
6281 Bit8u device, status;
6282 Bit16u vheads, vspt, vcylinders;
6283 Bit16u head, sector, cylinder, nbsectors;
6284 Bit32u vlba, ilba, slba, elba;
6285 Bit16u before, segment, offset;
6286 Bit8u atacmd[12];
6288 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6290 /* at this point, we are emulating a floppy/harddisk */
6292 // Recompute the device number
6293 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6294 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6296 SET_DISK_RET_STATUS(0x00);
6298 /* basic checks : emulation should be active, dl should equal the emulated drive */
6299 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6300 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6301 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6302 goto int13_fail;
6305 switch (GET_AH()) {
6307 // all those functions return SUCCESS
6308 case 0x00: /* disk controller reset */
6309 case 0x09: /* initialize drive parameters */
6310 case 0x0c: /* seek to specified cylinder */
6311 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6312 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6313 case 0x11: /* recalibrate */
6314 case 0x14: /* controller internal diagnostic */
6315 case 0x16: /* detect disk change */
6316 goto int13_success;
6317 break;
6319 // all those functions return disk write-protected
6320 case 0x03: /* write disk sectors */
6321 case 0x05: /* format disk track */
6322 SET_AH(0x03);
6323 goto int13_fail_noah;
6324 break;
6326 case 0x01: /* read disk status */
6327 status=read_byte(0x0040, 0x0074);
6328 SET_AH(status);
6329 SET_DISK_RET_STATUS(0);
6331 /* set CF if error status read */
6332 if (status) goto int13_fail_nostatus;
6333 else goto int13_success_noah;
6334 break;
6336 case 0x02: // read disk sectors
6337 case 0x04: // verify disk sectors
6338 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6339 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6340 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6342 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6344 sector = GET_CL() & 0x003f;
6345 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6346 head = GET_DH();
6347 nbsectors = GET_AL();
6348 segment = ES;
6349 offset = BX;
6351 // no sector to read ?
6352 if(nbsectors==0) goto int13_success;
6354 // sanity checks sco openserver needs this!
6355 if ((sector > vspt)
6356 || (cylinder >= vcylinders)
6357 || (head >= vheads)) {
6358 goto int13_fail;
6361 // After controls, verify do nothing
6362 if (GET_AH() == 0x04) goto int13_success;
6364 segment = ES+(BX / 16);
6365 offset = BX % 16;
6367 // calculate the virtual lba inside the image
6368 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6370 // In advance so we don't loose the count
6371 SET_AL(nbsectors);
6373 // start lba on cd
6374 slba = (Bit32u)vlba/4;
6375 before= (Bit16u)vlba%4;
6377 // end lba on cd
6378 elba = (Bit32u)(vlba+nbsectors-1)/4;
6380 memsetb(get_SS(),atacmd,0,12);
6381 atacmd[0]=0x28; // READ command
6382 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6383 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6384 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6385 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6386 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6387 atacmd[5]=(ilba+slba & 0x000000ff);
6388 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6389 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6390 SET_AH(0x02);
6391 SET_AL(0);
6392 goto int13_fail_noah;
6395 goto int13_success;
6396 break;
6398 case 0x08: /* read disk drive parameters */
6399 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6400 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6401 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6403 SET_AL( 0x00 );
6404 SET_BL( 0x00 );
6405 SET_CH( vcylinders & 0xff );
6406 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6407 SET_DH( vheads );
6408 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6409 // FIXME ElTorito Harddisk. should send the HD count
6411 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6412 case 0x01: SET_BL( 0x02 ); break;
6413 case 0x02: SET_BL( 0x04 ); break;
6414 case 0x03: SET_BL( 0x06 ); break;
6417 ASM_START
6418 push bp
6419 mov bp, sp
6420 mov ax, #diskette_param_table2
6421 mov _int13_cdemu.DI+2[bp], ax
6422 mov _int13_cdemu.ES+2[bp], cs
6423 pop bp
6424 ASM_END
6425 goto int13_success;
6426 break;
6428 case 0x15: /* read disk drive size */
6429 // FIXME ElTorito Harddisk. What geometry to send ?
6430 SET_AH(0x03);
6431 goto int13_success_noah;
6432 break;
6434 // all those functions return unimplemented
6435 case 0x0a: /* read disk sectors with ECC */
6436 case 0x0b: /* write disk sectors with ECC */
6437 case 0x18: /* set media type for format */
6438 case 0x41: // IBM/MS installation check
6439 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6440 case 0x42: // IBM/MS extended read
6441 case 0x43: // IBM/MS extended write
6442 case 0x44: // IBM/MS verify sectors
6443 case 0x45: // IBM/MS lock/unlock drive
6444 case 0x46: // IBM/MS eject media
6445 case 0x47: // IBM/MS extended seek
6446 case 0x48: // IBM/MS get drive parameters
6447 case 0x49: // IBM/MS extended media change
6448 case 0x4e: // ? - set hardware configuration
6449 case 0x50: // ? - send packet command
6450 default:
6451 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6452 goto int13_fail;
6453 break;
6456 int13_fail:
6457 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6458 int13_fail_noah:
6459 SET_DISK_RET_STATUS(GET_AH());
6460 int13_fail_nostatus:
6461 SET_CF(); // error occurred
6462 return;
6464 int13_success:
6465 SET_AH(0x00); // no error
6466 int13_success_noah:
6467 SET_DISK_RET_STATUS(0x00);
6468 CLEAR_CF(); // no error
6469 return;
6472 // ---------------------------------------------------------------------------
6473 // End of int13 when emulating a device from the cd
6474 // ---------------------------------------------------------------------------
6476 #endif // BX_ELTORITO_BOOT
6478 #else //BX_USE_ATADRV
6480 void
6481 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6482 Bit16u cylinder;
6483 Bit16u hd_heads;
6484 Bit16u head;
6485 Bit16u hd_sectors;
6486 Bit16u sector;
6487 Bit16u dl;
6489 ASM_START
6490 push bp
6491 mov bp, sp
6492 push eax
6493 push ebx
6494 push edx
6495 xor eax,eax
6496 mov ax,4[bp] // cylinder
6497 xor ebx,ebx
6498 mov bl,6[bp] // hd_heads
6499 imul ebx
6501 mov bl,8[bp] // head
6502 add eax,ebx
6503 mov bl,10[bp] // hd_sectors
6504 imul ebx
6505 mov bl,12[bp] // sector
6506 add eax,ebx
6508 dec eax
6509 mov dx,#0x1f3
6510 out dx,al
6511 mov dx,#0x1f4
6512 mov al,ah
6513 out dx,al
6514 shr eax,#16
6515 mov dx,#0x1f5
6516 out dx,al
6517 and ah,#0xf
6518 mov bl,14[bp] // dl
6519 and bl,#1
6520 shl bl,#4
6521 or ah,bl
6522 or ah,#0xe0
6523 mov al,ah
6524 mov dx,#0x01f6
6525 out dx,al
6526 pop edx
6527 pop ebx
6528 pop eax
6529 pop bp
6530 ASM_END
6533 void
6534 int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6535 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6537 Bit8u drive, num_sectors, sector, head, status, mod;
6538 Bit8u drive_map;
6539 Bit8u n_drives;
6540 Bit16u cyl_mod, ax;
6541 Bit16u max_cylinder, cylinder, total_sectors;
6542 Bit16u hd_cylinders;
6543 Bit8u hd_heads, hd_sectors;
6544 Bit16u val16;
6545 Bit8u sector_count;
6546 unsigned int i;
6547 Bit16u tempbx;
6548 Bit16u dpsize;
6550 Bit16u count, segment, offset;
6551 Bit32u lba;
6552 Bit16u error;
6554 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6556 write_byte(0x0040, 0x008e, 0); // clear completion flag
6558 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6559 handler code */
6560 /* check how many disks first (cmos reg 0x12), return an error if
6561 drive not present */
6562 drive_map = inb_cmos(0x12);
6563 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6564 (((drive_map & 0x0f)==0) ? 0 : 2);
6565 n_drives = (drive_map==0) ? 0 :
6566 ((drive_map==3) ? 2 : 1);
6568 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6569 SET_AH(0x01);
6570 SET_DISK_RET_STATUS(0x01);
6571 SET_CF(); /* error occurred */
6572 return;
6575 switch (GET_AH()) {
6577 case 0x00: /* disk controller reset */
6578 BX_DEBUG_INT13_HD("int13_f00\n");
6580 SET_AH(0);
6581 SET_DISK_RET_STATUS(0);
6582 set_diskette_ret_status(0);
6583 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6584 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6585 CLEAR_CF(); /* successful */
6586 return;
6587 break;
6589 case 0x01: /* read disk status */
6590 BX_DEBUG_INT13_HD("int13_f01\n");
6591 status = read_byte(0x0040, 0x0074);
6592 SET_AH(status);
6593 SET_DISK_RET_STATUS(0);
6594 /* set CF if error status read */
6595 if (status) SET_CF();
6596 else CLEAR_CF();
6597 return;
6598 break;
6600 case 0x04: // verify disk sectors
6601 case 0x02: // read disk sectors
6602 drive = GET_ELDL();
6603 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6605 num_sectors = GET_AL();
6606 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6607 sector = (GET_CL() & 0x3f);
6608 head = GET_DH();
6611 if (hd_cylinders > 1024) {
6612 if (hd_cylinders <= 2048) {
6613 cylinder <<= 1;
6615 else if (hd_cylinders <= 4096) {
6616 cylinder <<= 2;
6618 else if (hd_cylinders <= 8192) {
6619 cylinder <<= 3;
6621 else { // hd_cylinders <= 16384
6622 cylinder <<= 4;
6625 ax = head / hd_heads;
6626 cyl_mod = ax & 0xff;
6627 head = ax >> 8;
6628 cylinder |= cyl_mod;
6631 if ( (cylinder >= hd_cylinders) ||
6632 (sector > hd_sectors) ||
6633 (head >= hd_heads) ) {
6634 SET_AH(1);
6635 SET_DISK_RET_STATUS(1);
6636 SET_CF(); /* error occurred */
6637 return;
6640 if ( (num_sectors > 128) || (num_sectors == 0) )
6641 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6643 if (head > 15)
6644 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6646 if ( GET_AH() == 0x04 ) {
6647 SET_AH(0);
6648 SET_DISK_RET_STATUS(0);
6649 CLEAR_CF();
6650 return;
6653 status = inb(0x1f7);
6654 if (status & 0x80) {
6655 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6657 outb(0x01f2, num_sectors);
6658 /* activate LBA? (tomv) */
6659 if (hd_heads > 16) {
6660 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6661 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6663 else {
6664 outb(0x01f3, sector);
6665 outb(0x01f4, cylinder & 0x00ff);
6666 outb(0x01f5, cylinder >> 8);
6667 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6669 outb(0x01f7, 0x20);
6671 while (1) {
6672 status = inb(0x1f7);
6673 if ( !(status & 0x80) ) break;
6676 if (status & 0x01) {
6677 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6678 } else if ( !(status & 0x08) ) {
6679 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6680 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6683 sector_count = 0;
6684 tempbx = BX;
6686 ASM_START
6687 sti ;; enable higher priority interrupts
6688 ASM_END
6690 while (1) {
6691 ASM_START
6692 ;; store temp bx in real DI register
6693 push bp
6694 mov bp, sp
6695 mov di, _int13_harddisk.tempbx + 2 [bp]
6696 pop bp
6698 ;; adjust if there will be an overrun
6699 cmp di, #0xfe00
6700 jbe i13_f02_no_adjust
6701 i13_f02_adjust:
6702 sub di, #0x0200 ; sub 512 bytes from offset
6703 mov ax, es
6704 add ax, #0x0020 ; add 512 to segment
6705 mov es, ax
6707 i13_f02_no_adjust:
6708 mov cx, #0x0100 ;; counter (256 words = 512b)
6709 mov dx, #0x01f0 ;; AT data read port
6711 rep
6712 insw ;; CX words transfered from port(DX) to ES:[DI]
6714 i13_f02_done:
6715 ;; store real DI register back to temp bx
6716 push bp
6717 mov bp, sp
6718 mov _int13_harddisk.tempbx + 2 [bp], di
6719 pop bp
6720 ASM_END
6722 sector_count++;
6723 num_sectors--;
6724 if (num_sectors == 0) {
6725 status = inb(0x1f7);
6726 if ( (status & 0xc9) != 0x40 )
6727 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6728 break;
6730 else {
6731 status = inb(0x1f7);
6732 if ( (status & 0xc9) != 0x48 )
6733 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6734 continue;
6738 SET_AH(0);
6739 SET_DISK_RET_STATUS(0);
6740 SET_AL(sector_count);
6741 CLEAR_CF(); /* successful */
6742 return;
6743 break;
6746 case 0x03: /* write disk sectors */
6747 BX_DEBUG_INT13_HD("int13_f03\n");
6748 drive = GET_ELDL ();
6749 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6751 num_sectors = GET_AL();
6752 cylinder = GET_CH();
6753 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6754 sector = (GET_CL() & 0x3f);
6755 head = GET_DH();
6757 if (hd_cylinders > 1024) {
6758 if (hd_cylinders <= 2048) {
6759 cylinder <<= 1;
6761 else if (hd_cylinders <= 4096) {
6762 cylinder <<= 2;
6764 else if (hd_cylinders <= 8192) {
6765 cylinder <<= 3;
6767 else { // hd_cylinders <= 16384
6768 cylinder <<= 4;
6771 ax = head / hd_heads;
6772 cyl_mod = ax & 0xff;
6773 head = ax >> 8;
6774 cylinder |= cyl_mod;
6777 if ( (cylinder >= hd_cylinders) ||
6778 (sector > hd_sectors) ||
6779 (head >= hd_heads) ) {
6780 SET_AH( 1);
6781 SET_DISK_RET_STATUS(1);
6782 SET_CF(); /* error occurred */
6783 return;
6786 if ( (num_sectors > 128) || (num_sectors == 0) )
6787 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6789 if (head > 15)
6790 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6792 status = inb(0x1f7);
6793 if (status & 0x80) {
6794 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6796 // should check for Drive Ready Bit also in status reg
6797 outb(0x01f2, num_sectors);
6799 /* activate LBA? (tomv) */
6800 if (hd_heads > 16) {
6801 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6802 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6804 else {
6805 outb(0x01f3, sector);
6806 outb(0x01f4, cylinder & 0x00ff);
6807 outb(0x01f5, cylinder >> 8);
6808 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6810 outb(0x01f7, 0x30);
6812 // wait for busy bit to turn off after seeking
6813 while (1) {
6814 status = inb(0x1f7);
6815 if ( !(status & 0x80) ) break;
6818 if ( !(status & 0x08) ) {
6819 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6820 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6823 sector_count = 0;
6824 tempbx = BX;
6826 ASM_START
6827 sti ;; enable higher priority interrupts
6828 ASM_END
6830 while (1) {
6831 ASM_START
6832 ;; store temp bx in real SI register
6833 push bp
6834 mov bp, sp
6835 mov si, _int13_harddisk.tempbx + 2 [bp]
6836 pop bp
6838 ;; adjust if there will be an overrun
6839 cmp si, #0xfe00
6840 jbe i13_f03_no_adjust
6841 i13_f03_adjust:
6842 sub si, #0x0200 ; sub 512 bytes from offset
6843 mov ax, es
6844 add ax, #0x0020 ; add 512 to segment
6845 mov es, ax
6847 i13_f03_no_adjust:
6848 mov cx, #0x0100 ;; counter (256 words = 512b)
6849 mov dx, #0x01f0 ;; AT data read port
6851 seg ES
6852 rep
6853 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6855 ;; store real SI register back to temp bx
6856 push bp
6857 mov bp, sp
6858 mov _int13_harddisk.tempbx + 2 [bp], si
6859 pop bp
6860 ASM_END
6862 sector_count++;
6863 num_sectors--;
6864 if (num_sectors == 0) {
6865 status = inb(0x1f7);
6866 if ( (status & 0xe9) != 0x40 )
6867 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6868 break;
6870 else {
6871 status = inb(0x1f7);
6872 if ( (status & 0xc9) != 0x48 )
6873 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6874 continue;
6878 SET_AH(0);
6879 SET_DISK_RET_STATUS(0);
6880 SET_AL(sector_count);
6881 CLEAR_CF(); /* successful */
6882 return;
6883 break;
6885 case 0x05: /* format disk track */
6886 BX_DEBUG_INT13_HD("int13_f05\n");
6887 BX_PANIC("format disk track called\n");
6888 /* nop */
6889 SET_AH(0);
6890 SET_DISK_RET_STATUS(0);
6891 CLEAR_CF(); /* successful */
6892 return;
6893 break;
6895 case 0x08: /* read disk drive parameters */
6896 BX_DEBUG_INT13_HD("int13_f08\n");
6898 drive = GET_ELDL ();
6899 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6901 // translate CHS
6902 //
6903 if (hd_cylinders <= 1024) {
6904 // hd_cylinders >>= 0;
6905 // hd_heads <<= 0;
6907 else if (hd_cylinders <= 2048) {
6908 hd_cylinders >>= 1;
6909 hd_heads <<= 1;
6911 else if (hd_cylinders <= 4096) {
6912 hd_cylinders >>= 2;
6913 hd_heads <<= 2;
6915 else if (hd_cylinders <= 8192) {
6916 hd_cylinders >>= 3;
6917 hd_heads <<= 3;
6919 else { // hd_cylinders <= 16384
6920 hd_cylinders >>= 4;
6921 hd_heads <<= 4;
6924 max_cylinder = hd_cylinders - 2; /* 0 based */
6925 SET_AL(0);
6926 SET_CH(max_cylinder & 0xff);
6927 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6928 SET_DH(hd_heads - 1);
6929 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6930 SET_AH(0);
6931 SET_DISK_RET_STATUS(0);
6932 CLEAR_CF(); /* successful */
6934 return;
6935 break;
6937 case 0x09: /* initialize drive parameters */
6938 BX_DEBUG_INT13_HD("int13_f09\n");
6939 SET_AH(0);
6940 SET_DISK_RET_STATUS(0);
6941 CLEAR_CF(); /* successful */
6942 return;
6943 break;
6945 case 0x0a: /* read disk sectors with ECC */
6946 BX_DEBUG_INT13_HD("int13_f0a\n");
6947 case 0x0b: /* write disk sectors with ECC */
6948 BX_DEBUG_INT13_HD("int13_f0b\n");
6949 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6950 return;
6951 break;
6953 case 0x0c: /* seek to specified cylinder */
6954 BX_DEBUG_INT13_HD("int13_f0c\n");
6955 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6956 SET_AH(0);
6957 SET_DISK_RET_STATUS(0);
6958 CLEAR_CF(); /* successful */
6959 return;
6960 break;
6962 case 0x0d: /* alternate disk reset */
6963 BX_DEBUG_INT13_HD("int13_f0d\n");
6964 SET_AH(0);
6965 SET_DISK_RET_STATUS(0);
6966 CLEAR_CF(); /* successful */
6967 return;
6968 break;
6970 case 0x10: /* check drive ready */
6971 BX_DEBUG_INT13_HD("int13_f10\n");
6972 //SET_AH(0);
6973 //SET_DISK_RET_STATUS(0);
6974 //CLEAR_CF(); /* successful */
6975 //return;
6976 //break;
6978 // should look at 40:8E also???
6979 status = inb(0x01f7);
6980 if ( (status & 0xc0) == 0x40 ) {
6981 SET_AH(0);
6982 SET_DISK_RET_STATUS(0);
6983 CLEAR_CF(); // drive ready
6984 return;
6986 else {
6987 SET_AH(0xAA);
6988 SET_DISK_RET_STATUS(0xAA);
6989 SET_CF(); // not ready
6990 return;
6992 break;
6994 case 0x11: /* recalibrate */
6995 BX_DEBUG_INT13_HD("int13_f11\n");
6996 SET_AH(0);
6997 SET_DISK_RET_STATUS(0);
6998 CLEAR_CF(); /* successful */
6999 return;
7000 break;
7002 case 0x14: /* controller internal diagnostic */
7003 BX_DEBUG_INT13_HD("int13_f14\n");
7004 SET_AH(0);
7005 SET_DISK_RET_STATUS(0);
7006 CLEAR_CF(); /* successful */
7007 SET_AL(0);
7008 return;
7009 break;
7011 case 0x15: /* read disk drive size */
7012 drive = GET_ELDL();
7013 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7014 ASM_START
7015 push bp
7016 mov bp, sp
7017 mov al, _int13_harddisk.hd_heads + 2 [bp]
7018 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7019 mul al, ah ;; ax = heads * sectors
7020 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7021 dec bx ;; use (cylinders - 1) ???
7022 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7023 ;; now we need to move the 32bit result dx:ax to what the
7024 ;; BIOS wants which is cx:dx.
7025 ;; and then into CX:DX on the stack
7026 mov _int13_harddisk.CX + 2 [bp], dx
7027 mov _int13_harddisk.DX + 2 [bp], ax
7028 pop bp
7029 ASM_END
7030 SET_AH(3); // hard disk accessible
7031 SET_DISK_RET_STATUS(0); // ??? should this be 0
7032 CLEAR_CF(); // successful
7033 return;
7034 break;
7036 case 0x18: // set media type for format
7037 case 0x41: // IBM/MS
7038 case 0x42: // IBM/MS
7039 case 0x43: // IBM/MS
7040 case 0x44: // IBM/MS
7041 case 0x45: // IBM/MS lock/unlock drive
7042 case 0x46: // IBM/MS eject media
7043 case 0x47: // IBM/MS extended seek
7044 case 0x49: // IBM/MS extended media change
7045 case 0x50: // IBM/MS send packet command
7046 default:
7047 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7049 SET_AH(1); // code=invalid function in AH or invalid parameter
7050 SET_DISK_RET_STATUS(1);
7051 SET_CF(); /* unsuccessful */
7052 return;
7053 break;
7057 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7058 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7060 void
7061 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7062 Bit8u drive;
7063 Bit16u *hd_cylinders;
7064 Bit8u *hd_heads;
7065 Bit8u *hd_sectors;
7067 Bit8u hd_type;
7068 Bit16u ss;
7069 Bit16u cylinders;
7070 Bit8u iobase;
7072 ss = get_SS();
7073 if (drive == 0x80) {
7074 hd_type = inb_cmos(0x12) & 0xf0;
7075 if (hd_type != 0xf0)
7076 BX_INFO(panic_msg_reg12h,0);
7077 hd_type = inb_cmos(0x19); // HD0: extended type
7078 if (hd_type != 47)
7079 BX_INFO(panic_msg_reg19h,0,0x19);
7080 iobase = 0x1b;
7081 } else {
7082 hd_type = inb_cmos(0x12) & 0x0f;
7083 if (hd_type != 0x0f)
7084 BX_INFO(panic_msg_reg12h,1);
7085 hd_type = inb_cmos(0x1a); // HD1: extended type
7086 if (hd_type != 47)
7087 BX_INFO(panic_msg_reg19h,0,0x1a);
7088 iobase = 0x24;
7091 // cylinders
7092 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7093 write_word(ss, hd_cylinders, cylinders);
7095 // heads
7096 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7098 // sectors per track
7099 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7102 #endif //else BX_USE_ATADRV
7104 #if BX_SUPPORT_FLOPPY
7106 //////////////////////
7107 // FLOPPY functions //
7108 //////////////////////
7110 void floppy_reset_controller()
7112 Bit8u val8;
7114 // Reset controller
7115 val8 = inb(0x03f2);
7116 outb(0x03f2, val8 & ~0x04);
7117 outb(0x03f2, val8 | 0x04);
7119 // Wait for controller to come out of reset
7120 do {
7121 val8 = inb(0x3f4);
7122 } while ( (val8 & 0xc0) != 0x80 );
7125 void floppy_prepare_controller(drive)
7126 Bit16u drive;
7128 Bit8u val8, dor, prev_reset;
7130 // set 40:3e bit 7 to 0
7131 val8 = read_byte(0x0040, 0x003e);
7132 val8 &= 0x7f;
7133 write_byte(0x0040, 0x003e, val8);
7135 // turn on motor of selected drive, DMA & int enabled, normal operation
7136 prev_reset = inb(0x03f2) & 0x04;
7137 if (drive)
7138 dor = 0x20;
7139 else
7140 dor = 0x10;
7141 dor |= 0x0c;
7142 dor |= drive;
7143 outb(0x03f2, dor);
7145 // reset the disk motor timeout value of INT 08
7146 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7148 // wait for drive readiness
7149 do {
7150 val8 = inb(0x3f4);
7151 } while ( (val8 & 0xc0) != 0x80 );
7153 if (prev_reset == 0) {
7154 // turn on interrupts
7155 ASM_START
7156 sti
7157 ASM_END
7158 // wait on 40:3e bit 7 to become 1
7159 do {
7160 val8 = read_byte(0x0040, 0x003e);
7161 } while ( (val8 & 0x80) == 0 );
7162 val8 &= 0x7f;
7163 ASM_START
7164 cli
7165 ASM_END
7166 write_byte(0x0040, 0x003e, val8);
7170 bx_bool
7171 floppy_media_known(drive)
7172 Bit16u drive;
7174 Bit8u val8;
7175 Bit16u media_state_offset;
7177 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7178 if (drive)
7179 val8 >>= 1;
7180 val8 &= 0x01;
7181 if (val8 == 0)
7182 return(0);
7184 media_state_offset = 0x0090;
7185 if (drive)
7186 media_state_offset += 1;
7188 val8 = read_byte(0x0040, media_state_offset);
7189 val8 = (val8 >> 4) & 0x01;
7190 if (val8 == 0)
7191 return(0);
7193 // check pass, return KNOWN
7194 return(1);
7197 bx_bool
7198 floppy_media_sense(drive)
7199 Bit16u drive;
7201 bx_bool retval;
7202 Bit16u media_state_offset;
7203 Bit8u drive_type, config_data, media_state;
7205 if (floppy_drive_recal(drive) == 0) {
7206 return(0);
7209 // for now cheat and get drive type from CMOS,
7210 // assume media is same as drive type
7212 // ** config_data **
7213 // Bitfields for diskette media control:
7214 // Bit(s) Description (Table M0028)
7215 // 7-6 last data rate set by controller
7216 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7217 // 5-4 last diskette drive step rate selected
7218 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7219 // 3-2 {data rate at start of operation}
7220 // 1-0 reserved
7222 // ** media_state **
7223 // Bitfields for diskette drive media state:
7224 // Bit(s) Description (Table M0030)
7225 // 7-6 data rate
7226 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7227 // 5 double stepping required (e.g. 360kB in 1.2MB)
7228 // 4 media type established
7229 // 3 drive capable of supporting 4MB media
7230 // 2-0 on exit from BIOS, contains
7231 // 000 trying 360kB in 360kB
7232 // 001 trying 360kB in 1.2MB
7233 // 010 trying 1.2MB in 1.2MB
7234 // 011 360kB in 360kB established
7235 // 100 360kB in 1.2MB established
7236 // 101 1.2MB in 1.2MB established
7237 // 110 reserved
7238 // 111 all other formats/drives
7240 drive_type = inb_cmos(0x10);
7241 if (drive == 0)
7242 drive_type >>= 4;
7243 else
7244 drive_type &= 0x0f;
7245 if ( drive_type == 1 ) {
7246 // 360K 5.25" drive
7247 config_data = 0x00; // 0000 0000
7248 media_state = 0x25; // 0010 0101
7249 retval = 1;
7251 else if ( drive_type == 2 ) {
7252 // 1.2 MB 5.25" drive
7253 config_data = 0x00; // 0000 0000
7254 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7255 retval = 1;
7257 else if ( drive_type == 3 ) {
7258 // 720K 3.5" drive
7259 config_data = 0x00; // 0000 0000 ???
7260 media_state = 0x17; // 0001 0111
7261 retval = 1;
7263 else if ( drive_type == 4 ) {
7264 // 1.44 MB 3.5" drive
7265 config_data = 0x00; // 0000 0000
7266 media_state = 0x17; // 0001 0111
7267 retval = 1;
7269 else if ( drive_type == 5 ) {
7270 // 2.88 MB 3.5" drive
7271 config_data = 0xCC; // 1100 1100
7272 media_state = 0xD7; // 1101 0111
7273 retval = 1;
7275 //
7276 // Extended floppy size uses special cmos setting
7277 else if ( drive_type == 6 ) {
7278 // 160k 5.25" drive
7279 config_data = 0x00; // 0000 0000
7280 media_state = 0x27; // 0010 0111
7281 retval = 1;
7283 else if ( drive_type == 7 ) {
7284 // 180k 5.25" drive
7285 config_data = 0x00; // 0000 0000
7286 media_state = 0x27; // 0010 0111
7287 retval = 1;
7289 else if ( drive_type == 8 ) {
7290 // 320k 5.25" drive
7291 config_data = 0x00; // 0000 0000
7292 media_state = 0x27; // 0010 0111
7293 retval = 1;
7296 else {
7297 // not recognized
7298 config_data = 0x00; // 0000 0000
7299 media_state = 0x00; // 0000 0000
7300 retval = 0;
7303 if (drive == 0)
7304 media_state_offset = 0x90;
7305 else
7306 media_state_offset = 0x91;
7307 write_byte(0x0040, 0x008B, config_data);
7308 write_byte(0x0040, media_state_offset, media_state);
7310 return(retval);
7313 bx_bool
7314 floppy_drive_recal(drive)
7315 Bit16u drive;
7317 Bit8u val8;
7318 Bit16u curr_cyl_offset;
7320 floppy_prepare_controller(drive);
7322 // send Recalibrate command (2 bytes) to controller
7323 outb(0x03f5, 0x07); // 07: Recalibrate
7324 outb(0x03f5, drive); // 0=drive0, 1=drive1
7326 // turn on interrupts
7327 ASM_START
7328 sti
7329 ASM_END
7331 // wait on 40:3e bit 7 to become 1
7332 do {
7333 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7334 } while ( val8 == 0 );
7336 val8 = 0; // separate asm from while() loop
7337 // turn off interrupts
7338 ASM_START
7339 cli
7340 ASM_END
7342 // set 40:3e bit 7 to 0, and calibrated bit
7343 val8 = read_byte(0x0040, 0x003e);
7344 val8 &= 0x7f;
7345 if (drive) {
7346 val8 |= 0x02; // Drive 1 calibrated
7347 curr_cyl_offset = 0x0095;
7348 } else {
7349 val8 |= 0x01; // Drive 0 calibrated
7350 curr_cyl_offset = 0x0094;
7352 write_byte(0x0040, 0x003e, val8);
7353 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7355 return(1);
7360 bx_bool
7361 floppy_drive_exists(drive)
7362 Bit16u drive;
7364 Bit8u drive_type;
7366 // check CMOS to see if drive exists
7367 drive_type = inb_cmos(0x10);
7368 if (drive == 0)
7369 drive_type >>= 4;
7370 else
7371 drive_type &= 0x0f;
7372 if ( drive_type == 0 )
7373 return(0);
7374 else
7375 return(1);
7378 void
7379 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7380 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7382 Bit8u drive, num_sectors, track, sector, head, status;
7383 Bit16u base_address, base_count, base_es;
7384 Bit8u page, mode_register, val8, dor;
7385 Bit8u return_status[7];
7386 Bit8u drive_type, num_floppies, ah;
7387 Bit16u es, last_addr;
7389 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7391 ah = GET_AH();
7393 switch ( ah ) {
7394 case 0x00: // diskette controller reset
7395 BX_DEBUG_INT13_FL("floppy f00\n");
7396 drive = GET_ELDL();
7397 if (drive > 1) {
7398 SET_AH(1); // invalid param
7399 set_diskette_ret_status(1);
7400 SET_CF();
7401 return;
7403 drive_type = inb_cmos(0x10);
7405 if (drive == 0)
7406 drive_type >>= 4;
7407 else
7408 drive_type &= 0x0f;
7409 if (drive_type == 0) {
7410 SET_AH(0x80); // drive not responding
7411 set_diskette_ret_status(0x80);
7412 SET_CF();
7413 return;
7415 SET_AH(0);
7416 set_diskette_ret_status(0);
7417 CLEAR_CF(); // successful
7418 set_diskette_current_cyl(drive, 0); // current cylinder
7419 return;
7421 case 0x01: // Read Diskette Status
7422 CLEAR_CF();
7423 val8 = read_byte(0x0000, 0x0441);
7424 SET_AH(val8);
7425 if (val8) {
7426 SET_CF();
7428 return;
7430 case 0x02: // Read Diskette Sectors
7431 case 0x03: // Write Diskette Sectors
7432 case 0x04: // Verify Diskette Sectors
7433 num_sectors = GET_AL();
7434 track = GET_CH();
7435 sector = GET_CL();
7436 head = GET_DH();
7437 drive = GET_ELDL();
7439 if ((drive > 1) || (head > 1) || (sector == 0) ||
7440 (num_sectors == 0) || (num_sectors > 72)) {
7441 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
7442 SET_AH(1);
7443 set_diskette_ret_status(1);
7444 SET_AL(0); // no sectors read
7445 SET_CF(); // error occurred
7446 return;
7449 // see if drive exists
7450 if (floppy_drive_exists(drive) == 0) {
7451 SET_AH(0x80); // not responding
7452 set_diskette_ret_status(0x80);
7453 SET_AL(0); // no sectors read
7454 SET_CF(); // error occurred
7455 return;
7458 // see if media in drive, and type is known
7459 if (floppy_media_known(drive) == 0) {
7460 if (floppy_media_sense(drive) == 0) {
7461 SET_AH(0x0C); // Media type not found
7462 set_diskette_ret_status(0x0C);
7463 SET_AL(0); // no sectors read
7464 SET_CF(); // error occurred
7465 return;
7469 if (ah == 0x02) {
7470 // Read Diskette Sectors
7472 //-----------------------------------
7473 // set up DMA controller for transfer
7474 //-----------------------------------
7476 // es:bx = pointer to where to place information from diskette
7477 // port 04: DMA-1 base and current address, channel 2
7478 // port 05: DMA-1 base and current count, channel 2
7479 page = (ES >> 12); // upper 4 bits
7480 base_es = (ES << 4); // lower 16bits contributed by ES
7481 base_address = base_es + BX; // lower 16 bits of address
7482 // contributed by ES:BX
7483 if ( base_address < base_es ) {
7484 // in case of carry, adjust page by 1
7485 page++;
7487 base_count = (num_sectors * 512) - 1;
7489 // check for 64K boundary overrun
7490 last_addr = base_address + base_count;
7491 if (last_addr < base_address) {
7492 SET_AH(0x09);
7493 set_diskette_ret_status(0x09);
7494 SET_AL(0); // no sectors read
7495 SET_CF(); // error occurred
7496 return;
7499 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7500 outb(0x000a, 0x06);
7502 BX_DEBUG_INT13_FL("clear flip-flop\n");
7503 outb(0x000c, 0x00); // clear flip-flop
7504 outb(0x0004, base_address);
7505 outb(0x0004, base_address>>8);
7506 BX_DEBUG_INT13_FL("clear flip-flop\n");
7507 outb(0x000c, 0x00); // clear flip-flop
7508 outb(0x0005, base_count);
7509 outb(0x0005, base_count>>8);
7511 // port 0b: DMA-1 Mode Register
7512 mode_register = 0x46; // single mode, increment, autoinit disable,
7513 // transfer type=write, channel 2
7514 BX_DEBUG_INT13_FL("setting mode register\n");
7515 outb(0x000b, mode_register);
7517 BX_DEBUG_INT13_FL("setting page register\n");
7518 // port 81: DMA-1 Page Register, channel 2
7519 outb(0x0081, page);
7521 BX_DEBUG_INT13_FL("unmask chan 2\n");
7522 outb(0x000a, 0x02); // unmask channel 2
7524 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7525 outb(0x000a, 0x02);
7527 //--------------------------------------
7528 // set up floppy controller for transfer
7529 //--------------------------------------
7530 floppy_prepare_controller(drive);
7532 // send read-normal-data command (9 bytes) to controller
7533 outb(0x03f5, 0xe6); // e6: read normal data
7534 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7535 outb(0x03f5, track);
7536 outb(0x03f5, head);
7537 outb(0x03f5, sector);
7538 outb(0x03f5, 2); // 512 byte sector size
7539 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7540 outb(0x03f5, 0); // Gap length
7541 outb(0x03f5, 0xff); // Gap length
7543 // turn on interrupts
7544 ASM_START
7545 sti
7546 ASM_END
7548 // wait on 40:3e bit 7 to become 1
7549 do {
7550 val8 = read_byte(0x0040, 0x0040);
7551 if (val8 == 0) {
7552 floppy_reset_controller();
7553 SET_AH(0x80); // drive not ready (timeout)
7554 set_diskette_ret_status(0x80);
7555 SET_AL(0); // no sectors read
7556 SET_CF(); // error occurred
7557 return;
7559 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7560 } while ( val8 == 0 );
7562 val8 = 0; // separate asm from while() loop
7563 // turn off interrupts
7564 ASM_START
7565 cli
7566 ASM_END
7568 // set 40:3e bit 7 to 0
7569 val8 = read_byte(0x0040, 0x003e);
7570 val8 &= 0x7f;
7571 write_byte(0x0040, 0x003e, val8);
7573 // check port 3f4 for accessibility to status bytes
7574 val8 = inb(0x3f4);
7575 if ( (val8 & 0xc0) != 0xc0 )
7576 BX_PANIC("int13_diskette: ctrl not ready\n");
7578 // read 7 return status bytes from controller
7579 // using loop index broken, have to unroll...
7580 return_status[0] = inb(0x3f5);
7581 return_status[1] = inb(0x3f5);
7582 return_status[2] = inb(0x3f5);
7583 return_status[3] = inb(0x3f5);
7584 return_status[4] = inb(0x3f5);
7585 return_status[5] = inb(0x3f5);
7586 return_status[6] = inb(0x3f5);
7587 // record in BIOS Data Area
7588 write_byte(0x0040, 0x0042, return_status[0]);
7589 write_byte(0x0040, 0x0043, return_status[1]);
7590 write_byte(0x0040, 0x0044, return_status[2]);
7591 write_byte(0x0040, 0x0045, return_status[3]);
7592 write_byte(0x0040, 0x0046, return_status[4]);
7593 write_byte(0x0040, 0x0047, return_status[5]);
7594 write_byte(0x0040, 0x0048, return_status[6]);
7596 if ( (return_status[0] & 0xc0) != 0 ) {
7597 SET_AH(0x20);
7598 set_diskette_ret_status(0x20);
7599 SET_AL(0); // no sectors read
7600 SET_CF(); // error occurred
7601 return;
7604 // ??? should track be new val from return_status[3] ?
7605 set_diskette_current_cyl(drive, track);
7606 // AL = number of sectors read (same value as passed)
7607 SET_AH(0x00); // success
7608 CLEAR_CF(); // success
7609 return;
7610 } else if (ah == 0x03) {
7611 // Write Diskette Sectors
7613 //-----------------------------------
7614 // set up DMA controller for transfer
7615 //-----------------------------------
7617 // es:bx = pointer to where to place information from diskette
7618 // port 04: DMA-1 base and current address, channel 2
7619 // port 05: DMA-1 base and current count, channel 2
7620 page = (ES >> 12); // upper 4 bits
7621 base_es = (ES << 4); // lower 16bits contributed by ES
7622 base_address = base_es + BX; // lower 16 bits of address
7623 // contributed by ES:BX
7624 if ( base_address < base_es ) {
7625 // in case of carry, adjust page by 1
7626 page++;
7628 base_count = (num_sectors * 512) - 1;
7630 // check for 64K boundary overrun
7631 last_addr = base_address + base_count;
7632 if (last_addr < base_address) {
7633 SET_AH(0x09);
7634 set_diskette_ret_status(0x09);
7635 SET_AL(0); // no sectors read
7636 SET_CF(); // error occurred
7637 return;
7640 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7641 outb(0x000a, 0x06);
7643 outb(0x000c, 0x00); // clear flip-flop
7644 outb(0x0004, base_address);
7645 outb(0x0004, base_address>>8);
7646 outb(0x000c, 0x00); // clear flip-flop
7647 outb(0x0005, base_count);
7648 outb(0x0005, base_count>>8);
7650 // port 0b: DMA-1 Mode Register
7651 mode_register = 0x4a; // single mode, increment, autoinit disable,
7652 // transfer type=read, channel 2
7653 outb(0x000b, mode_register);
7655 // port 81: DMA-1 Page Register, channel 2
7656 outb(0x0081, page);
7658 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7659 outb(0x000a, 0x02);
7661 //--------------------------------------
7662 // set up floppy controller for transfer
7663 //--------------------------------------
7664 floppy_prepare_controller(drive);
7666 // send write-normal-data command (9 bytes) to controller
7667 outb(0x03f5, 0xc5); // c5: write normal data
7668 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7669 outb(0x03f5, track);
7670 outb(0x03f5, head);
7671 outb(0x03f5, sector);
7672 outb(0x03f5, 2); // 512 byte sector size
7673 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7674 outb(0x03f5, 0); // Gap length
7675 outb(0x03f5, 0xff); // Gap length
7677 // turn on interrupts
7678 ASM_START
7679 sti
7680 ASM_END
7682 // wait on 40:3e bit 7 to become 1
7683 do {
7684 val8 = read_byte(0x0040, 0x0040);
7685 if (val8 == 0) {
7686 floppy_reset_controller();
7687 SET_AH(0x80); // drive not ready (timeout)
7688 set_diskette_ret_status(0x80);
7689 SET_AL(0); // no sectors written
7690 SET_CF(); // error occurred
7691 return;
7693 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7694 } while ( val8 == 0 );
7696 val8 = 0; // separate asm from while() loop
7697 // turn off interrupts
7698 ASM_START
7699 cli
7700 ASM_END
7702 // set 40:3e bit 7 to 0
7703 val8 = read_byte(0x0040, 0x003e);
7704 val8 &= 0x7f;
7705 write_byte(0x0040, 0x003e, val8);
7707 // check port 3f4 for accessibility to status bytes
7708 val8 = inb(0x3f4);
7709 if ( (val8 & 0xc0) != 0xc0 )
7710 BX_PANIC("int13_diskette: ctrl not ready\n");
7712 // read 7 return status bytes from controller
7713 // using loop index broken, have to unroll...
7714 return_status[0] = inb(0x3f5);
7715 return_status[1] = inb(0x3f5);
7716 return_status[2] = inb(0x3f5);
7717 return_status[3] = inb(0x3f5);
7718 return_status[4] = inb(0x3f5);
7719 return_status[5] = inb(0x3f5);
7720 return_status[6] = inb(0x3f5);
7721 // record in BIOS Data Area
7722 write_byte(0x0040, 0x0042, return_status[0]);
7723 write_byte(0x0040, 0x0043, return_status[1]);
7724 write_byte(0x0040, 0x0044, return_status[2]);
7725 write_byte(0x0040, 0x0045, return_status[3]);
7726 write_byte(0x0040, 0x0046, return_status[4]);
7727 write_byte(0x0040, 0x0047, return_status[5]);
7728 write_byte(0x0040, 0x0048, return_status[6]);
7730 if ( (return_status[0] & 0xc0) != 0 ) {
7731 if ( (return_status[1] & 0x02) != 0 ) {
7732 // diskette not writable.
7733 // AH=status code=0x03 (tried to write on write-protected disk)
7734 // AL=number of sectors written=0
7735 AX = 0x0300;
7736 SET_CF();
7737 return;
7738 } else {
7739 BX_PANIC("int13_diskette_function: read error\n");
7743 // ??? should track be new val from return_status[3] ?
7744 set_diskette_current_cyl(drive, track);
7745 // AL = number of sectors read (same value as passed)
7746 SET_AH(0x00); // success
7747 CLEAR_CF(); // success
7748 return;
7749 } else { // if (ah == 0x04)
7750 // Verify Diskette Sectors
7752 // ??? should track be new val from return_status[3] ?
7753 set_diskette_current_cyl(drive, track);
7754 // AL = number of sectors verified (same value as passed)
7755 CLEAR_CF(); // success
7756 SET_AH(0x00); // success
7757 return;
7759 break;
7761 case 0x05: // format diskette track
7762 BX_DEBUG_INT13_FL("floppy f05\n");
7764 num_sectors = GET_AL();
7765 track = GET_CH();
7766 head = GET_DH();
7767 drive = GET_ELDL();
7769 if ((drive > 1) || (head > 1) || (track > 79) ||
7770 (num_sectors == 0) || (num_sectors > 18)) {
7771 SET_AH(1);
7772 set_diskette_ret_status(1);
7773 SET_CF(); // error occurred
7776 // see if drive exists
7777 if (floppy_drive_exists(drive) == 0) {
7778 SET_AH(0x80); // drive not responding
7779 set_diskette_ret_status(0x80);
7780 SET_CF(); // error occurred
7781 return;
7784 // see if media in drive, and type is known
7785 if (floppy_media_known(drive) == 0) {
7786 if (floppy_media_sense(drive) == 0) {
7787 SET_AH(0x0C); // Media type not found
7788 set_diskette_ret_status(0x0C);
7789 SET_AL(0); // no sectors read
7790 SET_CF(); // error occurred
7791 return;
7795 // set up DMA controller for transfer
7796 page = (ES >> 12); // upper 4 bits
7797 base_es = (ES << 4); // lower 16bits contributed by ES
7798 base_address = base_es + BX; // lower 16 bits of address
7799 // contributed by ES:BX
7800 if ( base_address < base_es ) {
7801 // in case of carry, adjust page by 1
7802 page++;
7804 base_count = (num_sectors * 4) - 1;
7806 // check for 64K boundary overrun
7807 last_addr = base_address + base_count;
7808 if (last_addr < base_address) {
7809 SET_AH(0x09);
7810 set_diskette_ret_status(0x09);
7811 SET_AL(0); // no sectors read
7812 SET_CF(); // error occurred
7813 return;
7816 outb(0x000a, 0x06);
7817 outb(0x000c, 0x00); // clear flip-flop
7818 outb(0x0004, base_address);
7819 outb(0x0004, base_address>>8);
7820 outb(0x000c, 0x00); // clear flip-flop
7821 outb(0x0005, base_count);
7822 outb(0x0005, base_count>>8);
7823 mode_register = 0x4a; // single mode, increment, autoinit disable,
7824 // transfer type=read, channel 2
7825 outb(0x000b, mode_register);
7826 // port 81: DMA-1 Page Register, channel 2
7827 outb(0x0081, page);
7828 outb(0x000a, 0x02);
7830 // set up floppy controller for transfer
7831 floppy_prepare_controller(drive);
7833 // send format-track command (6 bytes) to controller
7834 outb(0x03f5, 0x4d); // 4d: format track
7835 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7836 outb(0x03f5, 2); // 512 byte sector size
7837 outb(0x03f5, num_sectors); // number of sectors per track
7838 outb(0x03f5, 0); // Gap length
7839 outb(0x03f5, 0xf6); // Fill byte
7840 // turn on interrupts
7841 ASM_START
7842 sti
7843 ASM_END
7845 // wait on 40:3e bit 7 to become 1
7846 do {
7847 val8 = read_byte(0x0040, 0x0040);
7848 if (val8 == 0) {
7849 floppy_reset_controller();
7850 SET_AH(0x80); // drive not ready (timeout)
7851 set_diskette_ret_status(0x80);
7852 SET_CF(); // error occurred
7853 return;
7855 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7856 } while ( val8 == 0 );
7858 val8 = 0; // separate asm from while() loop
7859 // turn off interrupts
7860 ASM_START
7861 cli
7862 ASM_END
7863 // set 40:3e bit 7 to 0
7864 val8 = read_byte(0x0040, 0x003e);
7865 val8 &= 0x7f;
7866 write_byte(0x0040, 0x003e, val8);
7867 // check port 3f4 for accessibility to status bytes
7868 val8 = inb(0x3f4);
7869 if ( (val8 & 0xc0) != 0xc0 )
7870 BX_PANIC("int13_diskette: ctrl not ready\n");
7872 // read 7 return status bytes from controller
7873 // using loop index broken, have to unroll...
7874 return_status[0] = inb(0x3f5);
7875 return_status[1] = inb(0x3f5);
7876 return_status[2] = inb(0x3f5);
7877 return_status[3] = inb(0x3f5);
7878 return_status[4] = inb(0x3f5);
7879 return_status[5] = inb(0x3f5);
7880 return_status[6] = inb(0x3f5);
7881 // record in BIOS Data Area
7882 write_byte(0x0040, 0x0042, return_status[0]);
7883 write_byte(0x0040, 0x0043, return_status[1]);
7884 write_byte(0x0040, 0x0044, return_status[2]);
7885 write_byte(0x0040, 0x0045, return_status[3]);
7886 write_byte(0x0040, 0x0046, return_status[4]);
7887 write_byte(0x0040, 0x0047, return_status[5]);
7888 write_byte(0x0040, 0x0048, return_status[6]);
7890 if ( (return_status[0] & 0xc0) != 0 ) {
7891 if ( (return_status[1] & 0x02) != 0 ) {
7892 // diskette not writable.
7893 // AH=status code=0x03 (tried to write on write-protected disk)
7894 // AL=number of sectors written=0
7895 AX = 0x0300;
7896 SET_CF();
7897 return;
7898 } else {
7899 BX_PANIC("int13_diskette_function: write error\n");
7903 SET_AH(0);
7904 set_diskette_ret_status(0);
7905 set_diskette_current_cyl(drive, 0);
7906 CLEAR_CF(); // successful
7907 return;
7910 case 0x08: // read diskette drive parameters
7911 BX_DEBUG_INT13_FL("floppy f08\n");
7912 drive = GET_ELDL();
7914 if (drive > 1) {
7915 AX = 0;
7916 BX = 0;
7917 CX = 0;
7918 DX = 0;
7919 ES = 0;
7920 DI = 0;
7921 SET_DL(num_floppies);
7922 SET_CF();
7923 return;
7926 drive_type = inb_cmos(0x10);
7927 num_floppies = 0;
7928 if (drive_type & 0xf0)
7929 num_floppies++;
7930 if (drive_type & 0x0f)
7931 num_floppies++;
7933 if (drive == 0)
7934 drive_type >>= 4;
7935 else
7936 drive_type &= 0x0f;
7938 SET_BH(0);
7939 SET_BL(drive_type);
7940 SET_AH(0);
7941 SET_AL(0);
7942 SET_DL(num_floppies);
7944 switch (drive_type) {
7945 case 0: // none
7946 CX = 0;
7947 SET_DH(0); // max head #
7948 break;
7950 case 1: // 360KB, 5.25"
7951 CX = 0x2709; // 40 tracks, 9 sectors
7952 SET_DH(1); // max head #
7953 break;
7955 case 2: // 1.2MB, 5.25"
7956 CX = 0x4f0f; // 80 tracks, 15 sectors
7957 SET_DH(1); // max head #
7958 break;
7960 case 3: // 720KB, 3.5"
7961 CX = 0x4f09; // 80 tracks, 9 sectors
7962 SET_DH(1); // max head #
7963 break;
7965 case 4: // 1.44MB, 3.5"
7966 CX = 0x4f12; // 80 tracks, 18 sectors
7967 SET_DH(1); // max head #
7968 break;
7970 case 5: // 2.88MB, 3.5"
7971 CX = 0x4f24; // 80 tracks, 36 sectors
7972 SET_DH(1); // max head #
7973 break;
7975 case 6: // 160k, 5.25"
7976 CX = 0x2708; // 40 tracks, 8 sectors
7977 SET_DH(0); // max head #
7978 break;
7980 case 7: // 180k, 5.25"
7981 CX = 0x2709; // 40 tracks, 9 sectors
7982 SET_DH(0); // max head #
7983 break;
7985 case 8: // 320k, 5.25"
7986 CX = 0x2708; // 40 tracks, 8 sectors
7987 SET_DH(1); // max head #
7988 break;
7990 default: // ?
7991 BX_PANIC("floppy: int13: bad floppy type\n");
7994 /* set es & di to point to 11 byte diskette param table in ROM */
7995 ASM_START
7996 push bp
7997 mov bp, sp
7998 mov ax, #diskette_param_table2
7999 mov _int13_diskette_function.DI+2[bp], ax
8000 mov _int13_diskette_function.ES+2[bp], cs
8001 pop bp
8002 ASM_END
8003 CLEAR_CF(); // success
8004 /* disk status not changed upon success */
8005 return;
8008 case 0x15: // read diskette drive type
8009 BX_DEBUG_INT13_FL("floppy f15\n");
8010 drive = GET_ELDL();
8011 if (drive > 1) {
8012 SET_AH(0); // only 2 drives supported
8013 // set_diskette_ret_status here ???
8014 SET_CF();
8015 return;
8017 drive_type = inb_cmos(0x10);
8019 if (drive == 0)
8020 drive_type >>= 4;
8021 else
8022 drive_type &= 0x0f;
8023 CLEAR_CF(); // successful, not present
8024 if (drive_type==0) {
8025 SET_AH(0); // drive not present
8027 else {
8028 SET_AH(1); // drive present, does not support change line
8031 return;
8033 case 0x16: // get diskette change line status
8034 BX_DEBUG_INT13_FL("floppy f16\n");
8035 drive = GET_ELDL();
8036 if (drive > 1) {
8037 SET_AH(0x01); // invalid drive
8038 set_diskette_ret_status(0x01);
8039 SET_CF();
8040 return;
8043 SET_AH(0x06); // change line not supported
8044 set_diskette_ret_status(0x06);
8045 SET_CF();
8046 return;
8048 case 0x17: // set diskette type for format(old)
8049 BX_DEBUG_INT13_FL("floppy f17\n");
8050 /* not used for 1.44M floppies */
8051 SET_AH(0x01); // not supported
8052 set_diskette_ret_status(1); /* not supported */
8053 SET_CF();
8054 return;
8056 case 0x18: // set diskette type for format(new)
8057 BX_DEBUG_INT13_FL("floppy f18\n");
8058 SET_AH(0x01); // do later
8059 set_diskette_ret_status(1);
8060 SET_CF();
8061 return;
8063 default:
8064 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8066 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8067 SET_AH(0x01); // ???
8068 set_diskette_ret_status(1);
8069 SET_CF();
8070 return;
8071 // }
8074 #else // #if BX_SUPPORT_FLOPPY
8075 void
8076 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8077 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8079 Bit8u val8;
8081 switch ( GET_AH() ) {
8083 case 0x01: // Read Diskette Status
8084 CLEAR_CF();
8085 val8 = read_byte(0x0000, 0x0441);
8086 SET_AH(val8);
8087 if (val8) {
8088 SET_CF();
8090 return;
8092 default:
8093 SET_CF();
8094 write_byte(0x0000, 0x0441, 0x01);
8095 SET_AH(0x01);
8098 #endif // #if BX_SUPPORT_FLOPPY
8100 void
8101 set_diskette_ret_status(value)
8102 Bit8u value;
8104 write_byte(0x0040, 0x0041, value);
8107 void
8108 set_diskette_current_cyl(drive, cyl)
8109 Bit8u drive;
8110 Bit8u cyl;
8112 if (drive > 1)
8113 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8114 write_byte(0x0040, 0x0094+drive, cyl);
8117 void
8118 determine_floppy_media(drive)
8119 Bit16u drive;
8121 #if 0
8122 Bit8u val8, DOR, ctrl_info;
8124 ctrl_info = read_byte(0x0040, 0x008F);
8125 if (drive==1)
8126 ctrl_info >>= 4;
8127 else
8128 ctrl_info &= 0x0f;
8130 #if 0
8131 if (drive == 0) {
8132 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8134 else {
8135 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8137 #endif
8139 if ( (ctrl_info & 0x04) != 0x04 ) {
8140 // Drive not determined means no drive exists, done.
8141 return;
8144 #if 0
8145 // check Main Status Register for readiness
8146 val8 = inb(0x03f4) & 0x80; // Main Status Register
8147 if (val8 != 0x80)
8148 BX_PANIC("d_f_m: MRQ bit not set\n");
8150 // change line
8152 // existing BDA values
8154 // turn on drive motor
8155 outb(0x03f2, DOR); // Digital Output Register
8156 //
8157 #endif
8158 BX_PANIC("d_f_m: OK so far\n");
8159 #endif
8162 void
8163 int17_function(regs, ds, iret_addr)
8164 pusha_regs_t regs; // regs pushed from PUSHA instruction
8165 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8166 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8168 Bit16u addr,timeout;
8169 Bit8u val8;
8171 ASM_START
8172 sti
8173 ASM_END
8175 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8176 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8177 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8178 if (regs.u.r8.ah == 0) {
8179 outb(addr, regs.u.r8.al);
8180 val8 = inb(addr+2);
8181 outb(addr+2, val8 | 0x01); // send strobe
8182 ASM_START
8183 nop
8184 ASM_END
8185 outb(addr+2, val8 & ~0x01);
8186 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8187 timeout--;
8190 if (regs.u.r8.ah == 1) {
8191 val8 = inb(addr+2);
8192 outb(addr+2, val8 & ~0x04); // send init
8193 ASM_START
8194 nop
8195 ASM_END
8196 outb(addr+2, val8 | 0x04);
8198 val8 = inb(addr+1);
8199 regs.u.r8.ah = (val8 ^ 0x48);
8200 if (!timeout) regs.u.r8.ah |= 0x01;
8201 ClearCF(iret_addr.flags);
8202 } else {
8203 SetCF(iret_addr.flags); // Unsupported
8207 void
8208 int18_function(seq_nr)
8209 Bit16u seq_nr;
8211 Bit16u ebda_seg=read_word(0x0040,0x000E);
8212 Bit16u bootdev;
8213 Bit8u bootdrv;
8214 Bit8u bootchk;
8215 Bit16u bootseg;
8216 Bit16u bootip;
8217 Bit16u status;
8218 Bit16u bootfirst;
8220 ipl_entry_t e;
8222 // if BX_ELTORITO_BOOT is not defined, old behavior
8223 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8224 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8225 // 0: system boot sequence, first drive C: then A:
8226 // 1: system boot sequence, first drive A: then C:
8227 // else BX_ELTORITO_BOOT is defined
8228 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8229 // CMOS reg 0x3D & 0x0f : 1st boot device
8230 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8231 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8232 // boot device codes:
8233 // 0x00 : not defined
8234 // 0x01 : first floppy
8235 // 0x02 : first harddrive
8236 // 0x03 : first cdrom
8237 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
8238 // else : boot failure
8240 // Get the boot sequence
8241 #if BX_ELTORITO_BOOT
8242 bootdev = inb_cmos(0x3d);
8243 bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
8244 bootdev >>= 4 * seq_nr;
8245 bootdev &= 0xf;
8247 /* Read user selected device */
8248 bootfirst = read_word(ebda_seg, IPL_BOOTFIRST_OFFSET);
8249 if (bootfirst != 0xFFFF) {
8250 bootdev = bootfirst;
8251 /* User selected device not set */
8252 write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF);
8253 /* Reset boot sequence */
8254 write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xFFFF);
8255 } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
8257 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
8258 bootdev -= 1;
8259 #else
8260 if (seq_nr ==2) BX_PANIC("No more boot devices.");
8261 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
8262 /* Boot from floppy if the bit is set or it's the second boot */
8263 bootdev = 0x00;
8264 else
8265 bootdev = 0x01;
8266 #endif
8268 /* Read the boot device from the IPL table */
8269 if (get_boot_vector(bootdev, &e) == 0) {
8270 BX_INFO("Invalid boot device (0x%x)\n", bootdev);
8271 return;
8274 /* Do the loading, and set up vector as a far pointer to the boot
8275 * address, and bootdrv as the boot drive */
8276 print_boot_device(&e);
8278 switch(e.type) {
8279 case IPL_TYPE_FLOPPY: /* FDD */
8280 case IPL_TYPE_HARDDISK: /* HDD */
8282 bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
8283 bootseg = 0x07c0;
8284 status = 0;
8286 ASM_START
8287 push bp
8288 mov bp, sp
8289 push ax
8290 push bx
8291 push cx
8292 push dx
8294 mov dl, _int18_function.bootdrv + 2[bp]
8295 mov ax, _int18_function.bootseg + 2[bp]
8296 mov es, ax ;; segment
8297 xor bx, bx ;; offset
8298 mov ah, #0x02 ;; function 2, read diskette sector
8299 mov al, #0x01 ;; read 1 sector
8300 mov ch, #0x00 ;; track 0
8301 mov cl, #0x01 ;; sector 1
8302 mov dh, #0x00 ;; head 0
8303 int #0x13 ;; read sector
8304 jnc int19_load_done
8305 mov ax, #0x0001
8306 mov _int18_function.status + 2[bp], ax
8308 int19_load_done:
8309 pop dx
8310 pop cx
8311 pop bx
8312 pop ax
8313 pop bp
8314 ASM_END
8316 if (status != 0) {
8317 print_boot_failure(e.type, 1);
8318 return;
8321 /* Always check the signature on a HDD boot sector; on FDD, only do
8322 * the check if the CMOS doesn't tell us to skip it */
8323 if ((e.type != IPL_TYPE_FLOPPY) || !((inb_cmos(0x38) & 0x01))) {
8324 if (read_word(bootseg,0x1fe) != 0xaa55) {
8325 print_boot_failure(e.type, 0);
8326 return;
8330 #if BX_TCGBIOS
8331 tcpa_add_bootdevice((Bit32u)0L, (Bit32u)bootdrv);
8332 tcpa_ipl((Bit32u)0L,(Bit32u)bootseg,(Bit32u)0L,(Bit32u)512L); /* specs: 8.2.3 steps 4 and 5 */
8333 #endif
8335 /* Canonicalize bootseg:bootip */
8336 bootip = (bootseg & 0x0fff) << 4;
8337 bootseg &= 0xf000;
8338 break;
8340 #if BX_ELTORITO_BOOT
8341 case IPL_TYPE_CDROM: /* CD-ROM */
8342 status = cdrom_boot();
8344 // If failure
8345 if ( (status & 0x00ff) !=0 ) {
8346 print_cdromboot_failure(status);
8347 print_boot_failure(e.type, 1);
8348 return;
8351 bootdrv = (Bit8u)(status>>8);
8352 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8354 /* Canonicalize bootseg:bootip */
8355 bootip = (bootseg & 0x0fff) << 4;
8356 bootseg &= 0xf000;
8357 break;
8358 #endif
8360 case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
8361 bootseg = e.vector >> 16;
8362 bootip = e.vector & 0xffff;
8363 break;
8365 default: return;
8368 /* Debugging info */
8369 BX_INFO("Booting from %x:%x\n", bootseg, bootip);
8371 /* Jump to the boot vector */
8372 ASM_START
8373 mov bp, sp
8374 // push cs
8375 // push #int18_handler
8376 ;; Build an iret stack frame that will take us to the boot vector.
8377 ;; iret pops ip, then cs, then flags, so push them in the opposite order.
8378 pushf
8379 mov ax, _int18_function.bootseg + 0[bp]
8380 push ax
8381 mov ax, _int18_function.bootip + 0[bp]
8382 push ax
8383 ;; Set the magic number in ax and the boot drive in dl.
8384 mov ax, #0xaa55
8385 mov dl, _int18_function.bootdrv + 0[bp]
8386 ;; Zero some of the other registers.
8387 xor bx, bx
8388 mov ds, bx
8389 mov es, bx
8390 mov bp, bx
8391 ;; Go!
8392 iret
8393 ASM_END
8396 void
8397 int1a_function(regs, ds, iret_addr)
8398 pusha_regs_t regs; // regs pushed from PUSHA instruction
8399 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8400 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8402 Bit8u val8;
8404 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);
8406 ASM_START
8407 sti
8408 ASM_END
8410 switch (regs.u.r8.ah) {
8411 case 0: // get current clock count
8412 ASM_START
8413 cli
8414 ASM_END
8415 regs.u.r16.cx = BiosData->ticks_high;
8416 regs.u.r16.dx = BiosData->ticks_low;
8417 regs.u.r8.al = BiosData->midnight_flag;
8418 BiosData->midnight_flag = 0; // reset flag
8419 ASM_START
8420 sti
8421 ASM_END
8422 // AH already 0
8423 ClearCF(iret_addr.flags); // OK
8424 break;
8426 case 1: // Set Current Clock Count
8427 ASM_START
8428 cli
8429 ASM_END
8430 BiosData->ticks_high = regs.u.r16.cx;
8431 BiosData->ticks_low = regs.u.r16.dx;
8432 BiosData->midnight_flag = 0; // reset flag
8433 ASM_START
8434 sti
8435 ASM_END
8436 regs.u.r8.ah = 0;
8437 ClearCF(iret_addr.flags); // OK
8438 break;
8441 case 2: // Read CMOS Time
8442 if (rtc_updating()) {
8443 SetCF(iret_addr.flags);
8444 break;
8447 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8448 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8449 regs.u.r8.ch = inb_cmos(0x04); // Hours
8450 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8451 regs.u.r8.ah = 0;
8452 regs.u.r8.al = regs.u.r8.ch;
8453 ClearCF(iret_addr.flags); // OK
8454 break;
8456 case 3: // Set CMOS Time
8457 // Using a debugger, I notice the following masking/setting
8458 // of bits in Status Register B, by setting Reg B to
8459 // a few values and getting its value after INT 1A was called.
8460 //
8461 // try#1 try#2 try#3
8462 // before 1111 1101 0111 1101 0000 0000
8463 // after 0110 0010 0110 0010 0000 0010
8464 //
8465 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8466 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8467 if (rtc_updating()) {
8468 init_rtc();
8469 // fall through as if an update were not in progress
8471 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8472 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8473 outb_cmos(0x04, regs.u.r8.ch); // Hours
8474 // Set Daylight Savings time enabled bit to requested value
8475 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8476 // (reg B already selected)
8477 outb_cmos(0x0b, val8);
8478 regs.u.r8.ah = 0;
8479 regs.u.r8.al = val8; // val last written to Reg B
8480 ClearCF(iret_addr.flags); // OK
8481 break;
8483 case 4: // Read CMOS Date
8484 regs.u.r8.ah = 0;
8485 if (rtc_updating()) {
8486 SetCF(iret_addr.flags);
8487 break;
8489 regs.u.r8.cl = inb_cmos(0x09); // Year
8490 regs.u.r8.dh = inb_cmos(0x08); // Month
8491 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8492 regs.u.r8.ch = inb_cmos(0x32); // Century
8493 regs.u.r8.al = regs.u.r8.ch;
8494 ClearCF(iret_addr.flags); // OK
8495 break;
8497 case 5: // Set CMOS Date
8498 // Using a debugger, I notice the following masking/setting
8499 // of bits in Status Register B, by setting Reg B to
8500 // a few values and getting its value after INT 1A was called.
8501 //
8502 // try#1 try#2 try#3 try#4
8503 // before 1111 1101 0111 1101 0000 0010 0000 0000
8504 // after 0110 1101 0111 1101 0000 0010 0000 0000
8505 //
8506 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8507 // My assumption: RegB = (RegB & 01111111b)
8508 if (rtc_updating()) {
8509 init_rtc();
8510 SetCF(iret_addr.flags);
8511 break;
8513 outb_cmos(0x09, regs.u.r8.cl); // Year
8514 outb_cmos(0x08, regs.u.r8.dh); // Month
8515 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8516 outb_cmos(0x32, regs.u.r8.ch); // Century
8517 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8518 outb_cmos(0x0b, val8);
8519 regs.u.r8.ah = 0;
8520 regs.u.r8.al = val8; // AL = val last written to Reg B
8521 ClearCF(iret_addr.flags); // OK
8522 break;
8524 case 6: // Set Alarm Time in CMOS
8525 // Using a debugger, I notice the following masking/setting
8526 // of bits in Status Register B, by setting Reg B to
8527 // a few values and getting its value after INT 1A was called.
8528 //
8529 // try#1 try#2 try#3
8530 // before 1101 1111 0101 1111 0000 0000
8531 // after 0110 1111 0111 1111 0010 0000
8532 //
8533 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8534 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8535 val8 = inb_cmos(0x0b); // Get Status Reg B
8536 regs.u.r16.ax = 0;
8537 if (val8 & 0x20) {
8538 // Alarm interrupt enabled already
8539 SetCF(iret_addr.flags); // Error: alarm in use
8540 break;
8542 if (rtc_updating()) {
8543 init_rtc();
8544 // fall through as if an update were not in progress
8546 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8547 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8548 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8549 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8550 // enable Status Reg B alarm bit, clear halt clock bit
8551 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8552 ClearCF(iret_addr.flags); // OK
8553 break;
8555 case 7: // Turn off Alarm
8556 // Using a debugger, I notice the following masking/setting
8557 // of bits in Status Register B, by setting Reg B to
8558 // a few values and getting its value after INT 1A was called.
8559 //
8560 // try#1 try#2 try#3 try#4
8561 // before 1111 1101 0111 1101 0010 0000 0010 0010
8562 // after 0100 0101 0101 0101 0000 0000 0000 0010
8563 //
8564 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8565 // My assumption: RegB = (RegB & 01010111b)
8566 val8 = inb_cmos(0x0b); // Get Status Reg B
8567 // clear clock-halt bit, disable alarm bit
8568 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8569 regs.u.r8.ah = 0;
8570 regs.u.r8.al = val8; // val last written to Reg B
8571 ClearCF(iret_addr.flags); // OK
8572 break;
8573 #if BX_PCIBIOS
8574 case 0xb1:
8575 // real mode PCI BIOS functions now handled in assembler code
8576 // this C code handles the error code for information only
8577 if (regs.u.r8.bl == 0xff) {
8578 BX_INFO("PCI BIOS: PCI not present\n");
8579 } else if (regs.u.r8.bl == 0x81) {
8580 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8581 } else if (regs.u.r8.bl == 0x83) {
8582 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8583 } else if (regs.u.r8.bl == 0x86) {
8584 if (regs.u.r8.al == 0x02) {
8585 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8586 } else {
8587 BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", regs.u.r8.cl, regs.u.r16.dx, regs.u.r16.si);
8590 regs.u.r8.ah = regs.u.r8.bl;
8591 SetCF(iret_addr.flags);
8592 break;
8593 #endif
8595 default:
8596 SetCF(iret_addr.flags); // Unsupported
8600 void
8601 int70_function(regs, ds, iret_addr)
8602 pusha_regs_t regs; // regs pushed from PUSHA instruction
8603 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8604 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8606 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8607 Bit8u registerB = 0, registerC = 0;
8609 // Check which modes are enabled and have occurred.
8610 registerB = inb_cmos( 0xB );
8611 registerC = inb_cmos( 0xC );
8613 if( ( registerB & 0x60 ) != 0 ) {
8614 if( ( registerC & 0x20 ) != 0 ) {
8615 // Handle Alarm Interrupt.
8616 ASM_START
8617 sti
8618 int #0x4a
8619 cli
8620 ASM_END
8622 if( ( registerC & 0x40 ) != 0 ) {
8623 // Handle Periodic Interrupt.
8625 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8626 // Wait Interval (Int 15, AH=83) active.
8627 Bit32u time, toggle;
8629 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8630 if( time < 0x3D1 ) {
8631 // Done waiting.
8632 Bit16u segment, offset;
8634 segment = read_word( 0x40, 0x98 );
8635 offset = read_word( 0x40, 0x9A );
8636 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8637 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8638 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8639 } else {
8640 // Continue waiting.
8641 time -= 0x3D1;
8642 write_dword( 0x40, 0x9C, time );
8648 ASM_START
8649 call eoi_both_pics
8650 ASM_END
8654 ASM_START
8655 ;------------------------------------------
8656 ;- INT74h : PS/2 mouse hardware interrupt -
8657 ;------------------------------------------
8658 int74_handler:
8659 sti
8660 pusha
8661 push ds ;; save DS
8662 push #0x00 ;; placeholder for status
8663 push #0x00 ;; placeholder for X
8664 push #0x00 ;; placeholder for Y
8665 push #0x00 ;; placeholder for Z
8666 push #0x00 ;; placeholder for make_far_call boolean
8667 call _int74_function
8668 pop cx ;; remove make_far_call from stack
8669 jcxz int74_done
8671 ;; make far call to EBDA:0022
8672 push #0x00
8673 pop ds
8674 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8675 pop ds
8676 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8677 call far ptr[0x22]
8678 int74_done:
8679 cli
8680 call eoi_both_pics
8681 add sp, #8 ;; pop status, x, y, z
8683 pop ds ;; restore DS
8684 popa
8685 iret
8688 ;; This will perform an IRET, but will retain value of current CF
8689 ;; by altering flags on stack. Better than RETF #02.
8690 iret_modify_cf:
8691 jc carry_set
8692 push bp
8693 mov bp, sp
8694 and BYTE [bp + 0x06], #0xfe
8695 pop bp
8696 iret
8697 carry_set:
8698 push bp
8699 mov bp, sp
8700 or BYTE [bp + 0x06], #0x01
8701 pop bp
8702 iret
8705 ;----------------------
8706 ;- INT13h (relocated) -
8707 ;----------------------
8709 ; int13_relocated is a little bit messed up since I played with it
8710 ; I have to rewrite it:
8711 ; - call a function that detect which function to call
8712 ; - make all called C function get the same parameters list
8714 int13_relocated:
8716 #if BX_ELTORITO_BOOT
8717 ;; check for an eltorito function
8718 cmp ah,#0x4a
8719 jb int13_not_eltorito
8720 cmp ah,#0x4d
8721 ja int13_not_eltorito
8723 pusha
8724 push es
8725 push ds
8726 push ss
8727 pop ds
8729 push #int13_out
8730 jmp _int13_eltorito ;; ELDX not used
8732 int13_not_eltorito:
8733 push ax
8734 push bx
8735 push cx
8736 push dx
8738 ;; check if emulation active
8739 call _cdemu_isactive
8740 cmp al,#0x00
8741 je int13_cdemu_inactive
8743 ;; check if access to the emulated drive
8744 call _cdemu_emulated_drive
8745 pop dx
8746 push dx
8747 cmp al,dl ;; int13 on emulated drive
8748 jne int13_nocdemu
8750 pop dx
8751 pop cx
8752 pop bx
8753 pop ax
8755 pusha
8756 push es
8757 push ds
8758 push ss
8759 pop ds
8761 push #int13_out
8762 jmp _int13_cdemu ;; ELDX not used
8764 int13_nocdemu:
8765 and dl,#0xE0 ;; mask to get device class, including cdroms
8766 cmp al,dl ;; al is 0x00 or 0x80
8767 jne int13_cdemu_inactive ;; inactive for device class
8769 pop dx
8770 pop cx
8771 pop bx
8772 pop ax
8774 push ax
8775 push cx
8776 push dx
8777 push bx
8779 dec dl ;; real drive is dl - 1
8780 jmp int13_legacy
8782 int13_cdemu_inactive:
8783 pop dx
8784 pop cx
8785 pop bx
8786 pop ax
8788 #endif // BX_ELTORITO_BOOT
8790 int13_noeltorito:
8792 push ax
8793 push cx
8794 push dx
8795 push bx
8797 int13_legacy:
8799 push dx ;; push eltorito value of dx instead of sp
8801 push bp
8802 push si
8803 push di
8805 push es
8806 push ds
8807 push ss
8808 pop ds
8810 ;; now the 16-bit registers can be restored with:
8811 ;; pop ds; pop es; popa; iret
8812 ;; arguments passed to functions should be
8813 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8815 test dl, #0x80
8816 jnz int13_notfloppy
8818 push #int13_out
8819 jmp _int13_diskette_function
8821 int13_notfloppy:
8823 #if BX_USE_ATADRV
8825 cmp dl, #0xE0
8826 jb int13_notcdrom
8828 // ebx is modified: BSD 5.2.1 boot loader problem
8829 // someone should figure out which 32 bit register that actually are used
8831 shr ebx, #16
8832 push bx
8834 call _int13_cdrom
8836 pop bx
8837 shl ebx, #16
8839 jmp int13_out
8841 int13_notcdrom:
8843 #endif
8845 int13_disk:
8846 ;; int13_harddisk modifies high word of EAX
8847 shr eax, #16
8848 push ax
8849 call _int13_harddisk
8850 pop ax
8851 shl eax, #16
8853 int13_out:
8854 pop ds
8855 pop es
8856 popa
8857 iret
8859 ;----------
8860 ;- INT18h -
8861 ;----------
8862 int18_handler: ;; Boot Failure recovery: try the next device.
8864 ;; Reset SP and SS
8865 mov ax, #0xfffe
8866 mov sp, ax
8867 xor ax, ax
8868 mov ss, ax
8870 ;; The first time we do this it will have been set to -1 so
8871 ;; we will start from device 0.
8872 mov ds, ax
8873 mov bx, word ptr [0x40E] ;; EBDA segment
8874 mov ds, bx ;; Set segment
8875 mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number
8876 inc bx ;; ++
8877 mov IPL_SEQUENCE_OFFSET, bx ;; Write it back
8878 mov ds, ax ;; and reset the segment to zero.
8880 ;; Call the C code for the next boot device
8881 push bx
8883 call _int18_function
8885 ;; Boot failed: invoke the boot recovery function...
8886 int #0x18
8888 ;----------
8889 ;- INT19h -
8890 ;----------
8891 int19_relocated: ;; Boot function, relocated
8893 ;;
8894 ;; *** Warning: INT 19h resets the whole machine ***
8895 ;;
8896 ;; Because PV drivers in HVM guests detach some of the emulated devices,
8897 ;; it is not safe to do a soft reboot by just dropping to real mode and
8898 ;; invoking INT 19h -- the boot drives might have disappeared!
8899 ;; If the user asks for a soft reboot, the only thing we can do is
8900 ;; reset the whole machine. When it comes back up, the normal BIOS
8901 ;; boot sequence will start, which is more or less the required behaviour.
8902 ;;
8903 ;; Reset SP and SS
8905 mov ax, #0xfffe
8906 mov sp, ax
8907 xor ax, ax
8908 mov ss, ax
8910 call _machine_reset
8912 ;----------
8913 ;- INT1Ch -
8914 ;----------
8915 int1c_handler: ;; User Timer Tick
8916 iret
8919 ;----------------------
8920 ;- POST: Floppy Drive -
8921 ;----------------------
8922 floppy_drive_post:
8923 xor ax, ax
8924 mov ds, ax
8926 mov al, #0x00
8927 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8929 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8931 mov 0x0440, al ;; diskette motor timeout counter: not active
8932 mov 0x0441, al ;; diskette controller status return code
8934 mov 0x0442, al ;; disk & diskette controller status register 0
8935 mov 0x0443, al ;; diskette controller status register 1
8936 mov 0x0444, al ;; diskette controller status register 2
8937 mov 0x0445, al ;; diskette controller cylinder number
8938 mov 0x0446, al ;; diskette controller head number
8939 mov 0x0447, al ;; diskette controller sector number
8940 mov 0x0448, al ;; diskette controller bytes written
8942 mov 0x048b, al ;; diskette configuration data
8944 ;; -----------------------------------------------------------------
8945 ;; (048F) diskette controller information
8946 ;;
8947 mov al, #0x10 ;; get CMOS diskette drive type
8948 out 0x70, AL
8949 in AL, 0x71
8950 mov ah, al ;; save byte to AH
8952 look_drive0:
8953 shr al, #4 ;; look at top 4 bits for drive 0
8954 jz f0_missing ;; jump if no drive0
8955 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8956 jmp look_drive1
8957 f0_missing:
8958 mov bl, #0x00 ;; no drive0
8960 look_drive1:
8961 mov al, ah ;; restore from AH
8962 and al, #0x0f ;; look at bottom 4 bits for drive 1
8963 jz f1_missing ;; jump if no drive1
8964 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8965 f1_missing:
8966 ;; leave high bits in BL zerod
8967 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8968 ;; -----------------------------------------------------------------
8970 mov al, #0x00
8971 mov 0x0490, al ;; diskette 0 media state
8972 mov 0x0491, al ;; diskette 1 media state
8974 ;; diskette 0,1 operational starting state
8975 ;; drive type has not been determined,
8976 ;; has no changed detection line
8977 mov 0x0492, al
8978 mov 0x0493, al
8980 mov 0x0494, al ;; diskette 0 current cylinder
8981 mov 0x0495, al ;; diskette 1 current cylinder
8983 mov al, #0x02
8984 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8986 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8987 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8988 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8990 ret
8993 ;--------------------
8994 ;- POST: HARD DRIVE -
8995 ;--------------------
8996 ; relocated here because the primary POST area isnt big enough.
8997 hard_drive_post:
8998 // IRQ 14 = INT 76h
8999 // INT 76h calls INT 15h function ax=9100
9001 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9002 mov dx, #0x03f6
9003 out dx, al
9005 xor ax, ax
9006 mov ds, ax
9007 mov 0x0474, al /* hard disk status of last operation */
9008 mov 0x0477, al /* hard disk port offset (XT only ???) */
9009 mov 0x048c, al /* hard disk status register */
9010 mov 0x048d, al /* hard disk error register */
9011 mov 0x048e, al /* hard disk task complete flag */
9012 mov al, #0x01
9013 mov 0x0475, al /* hard disk number attached */
9014 mov al, #0xc0
9015 mov 0x0476, al /* hard disk control byte */
9016 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9017 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9018 ;; INT 41h: hard disk 0 configuration pointer
9019 ;; INT 46h: hard disk 1 configuration pointer
9020 SET_INT_VECTOR(0x41, word ptr [0x40E], #0x003D) /* EBDA:003D */
9021 SET_INT_VECTOR(0x46, word ptr [0x40E], #0x004D) /* EBDA:004D */
9023 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9024 mov al, #0x12
9025 out #0x70, al
9026 in al, #0x71
9027 and al, #0xf0
9028 cmp al, #0xf0
9029 je post_d0_extended
9030 jmp check_for_hd1
9031 post_d0_extended:
9032 mov al, #0x19
9033 out #0x70, al
9034 in al, #0x71
9035 cmp al, #47 ;; decimal 47 - user definable
9036 je post_d0_type47
9037 HALT(__LINE__)
9038 post_d0_type47:
9039 ;; CMOS purpose param table offset
9040 ;; 1b cylinders low 0
9041 ;; 1c cylinders high 1
9042 ;; 1d heads 2
9043 ;; 1e write pre-comp low 5
9044 ;; 1f write pre-comp high 6
9045 ;; 20 retries/bad map/heads>8 8
9046 ;; 21 landing zone low C
9047 ;; 22 landing zone high D
9048 ;; 23 sectors/track E
9050 xor ax, ax
9051 mov ds, ax
9052 mov ax, word ptr [0x40E] ;; EBDA segment
9053 mov ds, ax
9055 ;;; Filling EBDA table for hard disk 0.
9056 mov al, #0x1f
9057 out #0x70, al
9058 in al, #0x71
9059 mov ah, al
9060 mov al, #0x1e
9061 out #0x70, al
9062 in al, #0x71
9063 mov (0x003d + 0x05), ax ;; write precomp word
9065 mov al, #0x20
9066 out #0x70, al
9067 in al, #0x71
9068 mov (0x003d + 0x08), al ;; drive control byte
9070 mov al, #0x22
9071 out #0x70, al
9072 in al, #0x71
9073 mov ah, al
9074 mov al, #0x21
9075 out #0x70, al
9076 in al, #0x71
9077 mov (0x003d + 0x0C), ax ;; landing zone word
9079 mov al, #0x1c ;; get cylinders word in AX
9080 out #0x70, al
9081 in al, #0x71 ;; high byte
9082 mov ah, al
9083 mov al, #0x1b
9084 out #0x70, al
9085 in al, #0x71 ;; low byte
9086 mov bx, ax ;; BX = cylinders
9088 mov al, #0x1d
9089 out #0x70, al
9090 in al, #0x71
9091 mov cl, al ;; CL = heads
9093 mov al, #0x23
9094 out #0x70, al
9095 in al, #0x71
9096 mov dl, al ;; DL = sectors
9098 cmp bx, #1024
9099 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9101 hd0_post_physical_chs:
9102 ;; no logical CHS mapping used, just physical CHS
9103 ;; use Standard Fixed Disk Parameter Table (FDPT)
9104 mov (0x003d + 0x00), bx ;; number of physical cylinders
9105 mov (0x003d + 0x02), cl ;; number of physical heads
9106 mov (0x003d + 0x0E), dl ;; number of physical sectors
9107 jmp check_for_hd1
9109 hd0_post_logical_chs:
9110 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9111 mov (0x003d + 0x09), bx ;; number of physical cylinders
9112 mov (0x003d + 0x0b), cl ;; number of physical heads
9113 mov (0x003d + 0x04), dl ;; number of physical sectors
9114 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9115 mov al, #0xa0
9116 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9118 cmp bx, #2048
9119 jnbe hd0_post_above_2048
9120 ;; 1024 < c <= 2048 cylinders
9121 shr bx, #0x01
9122 shl cl, #0x01
9123 jmp hd0_post_store_logical
9125 hd0_post_above_2048:
9126 cmp bx, #4096
9127 jnbe hd0_post_above_4096
9128 ;; 2048 < c <= 4096 cylinders
9129 shr bx, #0x02
9130 shl cl, #0x02
9131 jmp hd0_post_store_logical
9133 hd0_post_above_4096:
9134 cmp bx, #8192
9135 jnbe hd0_post_above_8192
9136 ;; 4096 < c <= 8192 cylinders
9137 shr bx, #0x03
9138 shl cl, #0x03
9139 jmp hd0_post_store_logical
9141 hd0_post_above_8192:
9142 ;; 8192 < c <= 16384 cylinders
9143 shr bx, #0x04
9144 shl cl, #0x04
9146 hd0_post_store_logical:
9147 mov (0x003d + 0x00), bx ;; number of physical cylinders
9148 mov (0x003d + 0x02), cl ;; number of physical heads
9149 ;; checksum
9150 mov cl, #0x0f ;; repeat count
9151 mov si, #0x003d ;; offset to disk0 FDPT
9152 mov al, #0x00 ;; sum
9153 hd0_post_checksum_loop:
9154 add al, [si]
9155 inc si
9156 dec cl
9157 jnz hd0_post_checksum_loop
9158 not al ;; now take 2s complement
9159 inc al
9160 mov [si], al
9161 ;;; Done filling EBDA table for hard disk 0.
9164 check_for_hd1:
9165 ;; is there really a second hard disk? if not, return now
9166 mov al, #0x12
9167 out #0x70, al
9168 in al, #0x71
9169 and al, #0x0f
9170 jnz post_d1_exists
9171 ret
9172 post_d1_exists:
9173 ;; check that the hd type is really 0x0f.
9174 cmp al, #0x0f
9175 jz post_d1_extended
9176 HALT(__LINE__)
9177 post_d1_extended:
9178 ;; check that the extended type is 47 - user definable
9179 mov al, #0x1a
9180 out #0x70, al
9181 in al, #0x71
9182 cmp al, #47 ;; decimal 47 - user definable
9183 je post_d1_type47
9184 HALT(__LINE__)
9185 post_d1_type47:
9186 ;; Table for disk1.
9187 ;; CMOS purpose param table offset
9188 ;; 0x24 cylinders low 0
9189 ;; 0x25 cylinders high 1
9190 ;; 0x26 heads 2
9191 ;; 0x27 write pre-comp low 5
9192 ;; 0x28 write pre-comp high 6
9193 ;; 0x29 heads>8 8
9194 ;; 0x2a landing zone low C
9195 ;; 0x2b landing zone high D
9196 ;; 0x2c sectors/track E
9197 ;;; Fill EBDA table for hard disk 1.
9198 xor ax, ax
9199 mov ds, ax
9200 mov ax, word ptr [0x40E] ;; EBDA segment
9201 mov ds, ax
9202 mov al, #0x28
9203 out #0x70, al
9204 in al, #0x71
9205 mov ah, al
9206 mov al, #0x27
9207 out #0x70, al
9208 in al, #0x71
9209 mov (0x004d + 0x05), ax ;; write precomp word
9211 mov al, #0x29
9212 out #0x70, al
9213 in al, #0x71
9214 mov (0x004d + 0x08), al ;; drive control byte
9216 mov al, #0x2b
9217 out #0x70, al
9218 in al, #0x71
9219 mov ah, al
9220 mov al, #0x2a
9221 out #0x70, al
9222 in al, #0x71
9223 mov (0x004d + 0x0C), ax ;; landing zone word
9225 mov al, #0x25 ;; get cylinders word in AX
9226 out #0x70, al
9227 in al, #0x71 ;; high byte
9228 mov ah, al
9229 mov al, #0x24
9230 out #0x70, al
9231 in al, #0x71 ;; low byte
9232 mov bx, ax ;; BX = cylinders
9234 mov al, #0x26
9235 out #0x70, al
9236 in al, #0x71
9237 mov cl, al ;; CL = heads
9239 mov al, #0x2c
9240 out #0x70, al
9241 in al, #0x71
9242 mov dl, al ;; DL = sectors
9244 cmp bx, #1024
9245 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9247 hd1_post_physical_chs:
9248 ;; no logical CHS mapping used, just physical CHS
9249 ;; use Standard Fixed Disk Parameter Table (FDPT)
9250 mov (0x004d + 0x00), bx ;; number of physical cylinders
9251 mov (0x004d + 0x02), cl ;; number of physical heads
9252 mov (0x004d + 0x0E), dl ;; number of physical sectors
9253 ret
9255 hd1_post_logical_chs:
9256 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9257 mov (0x004d + 0x09), bx ;; number of physical cylinders
9258 mov (0x004d + 0x0b), cl ;; number of physical heads
9259 mov (0x004d + 0x04), dl ;; number of physical sectors
9260 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9261 mov al, #0xa0
9262 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9264 cmp bx, #2048
9265 jnbe hd1_post_above_2048
9266 ;; 1024 < c <= 2048 cylinders
9267 shr bx, #0x01
9268 shl cl, #0x01
9269 jmp hd1_post_store_logical
9271 hd1_post_above_2048:
9272 cmp bx, #4096
9273 jnbe hd1_post_above_4096
9274 ;; 2048 < c <= 4096 cylinders
9275 shr bx, #0x02
9276 shl cl, #0x02
9277 jmp hd1_post_store_logical
9279 hd1_post_above_4096:
9280 cmp bx, #8192
9281 jnbe hd1_post_above_8192
9282 ;; 4096 < c <= 8192 cylinders
9283 shr bx, #0x03
9284 shl cl, #0x03
9285 jmp hd1_post_store_logical
9287 hd1_post_above_8192:
9288 ;; 8192 < c <= 16384 cylinders
9289 shr bx, #0x04
9290 shl cl, #0x04
9292 hd1_post_store_logical:
9293 mov (0x004d + 0x00), bx ;; number of physical cylinders
9294 mov (0x004d + 0x02), cl ;; number of physical heads
9295 ;; checksum
9296 mov cl, #0x0f ;; repeat count
9297 mov si, #0x004d ;; offset to disk0 FDPT
9298 mov al, #0x00 ;; sum
9299 hd1_post_checksum_loop:
9300 add al, [si]
9301 inc si
9302 dec cl
9303 jnz hd1_post_checksum_loop
9304 not al ;; now take 2s complement
9305 inc al
9306 mov [si], al
9307 ;;; Done filling EBDA table for hard disk 1.
9309 ret
9311 ;--------------------
9312 ;- POST: EBDA segment
9313 ;--------------------
9314 ; relocated here because the primary POST area isnt big enough.
9315 ebda_post:
9316 #if BX_USE_EBDA
9317 mov ax, #EBDA_SEG
9318 mov ds, ax
9319 mov byte ptr [0x0], #EBDA_SIZE
9320 #endif
9321 xor ax, ax ; mov EBDA seg into 40E
9322 mov ds, ax
9323 mov word ptr [0x40E], #EBDA_SEG
9324 ret;;
9326 ;--------------------
9327 ;- POST: EOI + jmp via [0x40:67)
9328 ;--------------------
9329 ; relocated here because the primary POST area isnt big enough.
9330 eoi_jmp_post:
9331 mov al, #0x20
9332 out #0xA0, al ;; slave PIC EOI
9333 mov al, #0x20
9334 out #0x20, al ;; master PIC EOI
9336 jmp_post_0x467:
9337 xor ax, ax
9338 mov ds, ax
9340 jmp far ptr [0x467]
9342 iret_post_0x467:
9343 xor ax, ax
9344 mov ds, ax
9346 mov sp, [0x467]
9347 mov ss, [0x469]
9348 iret
9350 retf_post_0x467:
9351 xor ax, ax
9352 mov ds, ax
9354 mov sp, [0x467]
9355 mov ss, [0x469]
9356 retf
9358 s3_post:
9359 #if BX_ROMBIOS32
9360 call rombios32_init
9361 #endif
9362 call _s3_resume
9363 mov bl, #0x00
9364 and ax, ax
9365 jz normal_post
9366 call _s3_resume_panic
9368 ;--------------------
9369 eoi_both_pics:
9370 mov al, #0x20
9371 out #0xA0, al ;; slave PIC EOI
9372 eoi_master_pic:
9373 mov al, #0x20
9374 out #0x20, al ;; master PIC EOI
9375 ret
9377 ;--------------------
9378 BcdToBin:
9379 ;; in: AL in BCD format
9380 ;; out: AL in binary format, AH will always be 0
9381 ;; trashes BX
9382 mov bl, al
9383 and bl, #0x0f ;; bl has low digit
9384 shr al, #4 ;; al has high digit
9385 mov bh, #10
9386 mul al, bh ;; multiply high digit by 10 (result in AX)
9387 add al, bl ;; then add low digit
9388 ret
9390 ;--------------------
9391 timer_tick_post:
9392 ;; Setup the Timer Ticks Count (0x46C:dword) and
9393 ;; Timer Ticks Roller Flag (0x470:byte)
9394 ;; The Timer Ticks Count needs to be set according to
9395 ;; the current CMOS time, as if ticks have been occurring
9396 ;; at 18.2hz since midnight up to this point. Calculating
9397 ;; this is a little complicated. Here are the factors I gather
9398 ;; regarding this. 14,318,180 hz was the original clock speed,
9399 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9400 ;; at the time, or 4 to drive the CGA video adapter. The div3
9401 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9402 ;; the timer. With a maximum 16bit timer count, this is again
9403 ;; divided down by 65536 to 18.2hz.
9404 ;;
9405 ;; 14,318,180 Hz clock
9406 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9407 ;; /4 = 1,193,181 Hz fed to timer
9408 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9409 ;; 1 second = 18.20650736 ticks
9410 ;; 1 minute = 1092.390442 ticks
9411 ;; 1 hour = 65543.42651 ticks
9412 ;;
9413 ;; Given the values in the CMOS clock, one could calculate
9414 ;; the number of ticks by the following:
9415 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9416 ;; (BcdToBin(minutes) * 1092.3904)
9417 ;; (BcdToBin(hours) * 65543.427)
9418 ;; To get a little more accuracy, since Im using integer
9419 ;; arithmatic, I use:
9420 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9421 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9422 ;; (BcdToBin(hours) * 65543427) / 1000
9424 ;; assuming DS=0000
9426 ;; get CMOS seconds
9427 xor eax, eax ;; clear EAX
9428 mov al, #0x00
9429 out #0x70, al
9430 in al, #0x71 ;; AL has CMOS seconds in BCD
9431 call BcdToBin ;; EAX now has seconds in binary
9432 mov edx, #18206507
9433 mul eax, edx
9434 mov ebx, #1000000
9435 xor edx, edx
9436 div eax, ebx
9437 mov ecx, eax ;; ECX will accumulate total ticks
9439 ;; get CMOS minutes
9440 xor eax, eax ;; clear EAX
9441 mov al, #0x02
9442 out #0x70, al
9443 in al, #0x71 ;; AL has CMOS minutes in BCD
9444 call BcdToBin ;; EAX now has minutes in binary
9445 mov edx, #10923904
9446 mul eax, edx
9447 mov ebx, #10000
9448 xor edx, edx
9449 div eax, ebx
9450 add ecx, eax ;; add to total ticks
9452 ;; get CMOS hours
9453 xor eax, eax ;; clear EAX
9454 mov al, #0x04
9455 out #0x70, al
9456 in al, #0x71 ;; AL has CMOS hours in BCD
9457 call BcdToBin ;; EAX now has hours in binary
9458 mov edx, #65543427
9459 mul eax, edx
9460 mov ebx, #1000
9461 xor edx, edx
9462 div eax, ebx
9463 add ecx, eax ;; add to total ticks
9465 mov 0x46C, ecx ;; Timer Ticks Count
9466 xor al, al
9467 mov 0x470, al ;; Timer Ticks Rollover Flag
9468 ret
9470 ;--------------------
9471 int76_handler:
9472 ;; record completion in BIOS task complete flag
9473 push ax
9474 push ds
9475 mov ax, #0x0040
9476 mov ds, ax
9477 mov 0x008E, #0xff
9478 call eoi_both_pics
9479 pop ds
9480 pop ax
9481 iret
9484 ;--------------------
9485 #if BX_APM
9487 use32 386
9488 #define APM_PROT32
9489 #include "apmbios.S"
9491 use16 386
9492 #define APM_PROT16
9493 #include "apmbios.S"
9495 #define APM_REAL
9496 #include "apmbios.S"
9498 #endif
9500 #include "32bitgateway.c"
9501 ASM_END
9502 #include "tcgbios.c"
9503 ASM_START
9505 ;--------------------
9506 #if BX_PCIBIOS
9507 use32 386
9508 .align 16
9509 bios32_structure:
9510 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9511 dw bios32_entry_point, 0xf ;; 32 bit physical address
9512 db 0 ;; revision level
9513 ;; length in paragraphs and checksum stored in a word to prevent errors
9514 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9515 & 0xff) << 8) + 0x01
9516 db 0,0,0,0,0 ;; reserved
9518 .align 16
9519 bios32_entry_point:
9520 pushfd
9521 cmp eax, #0x49435024 ;; "$PCI"
9522 jne unknown_service
9523 mov eax, #0x80000000
9524 mov dx, #0x0cf8
9525 out dx, eax
9526 mov dx, #0x0cfc
9527 in eax, dx
9528 #ifdef PCI_FIXED_HOST_BRIDGE
9529 cmp eax, #PCI_FIXED_HOST_BRIDGE
9530 jne unknown_service
9531 #else
9532 ;; say ok if a device is present
9533 cmp eax, #0xffffffff
9534 je unknown_service
9535 #endif
9536 mov ebx, #0x000f0000
9537 mov ecx, #0
9538 mov edx, #pcibios_protected
9539 xor al, al
9540 jmp bios32_end
9541 unknown_service:
9542 mov al, #0x80
9543 bios32_end:
9544 #ifdef BX_QEMU
9545 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9546 #endif
9547 popfd
9548 retf
9550 .align 16
9551 pcibios_protected:
9552 pushfd
9553 cli
9554 push esi
9555 push edi
9556 cmp al, #0x01 ;; installation check
9557 jne pci_pro_f02
9558 mov bx, #0x0210
9559 mov cx, #0
9560 mov edx, #0x20494350 ;; "PCI "
9561 mov al, #0x01
9562 jmp pci_pro_ok
9563 pci_pro_f02: ;; find pci device
9564 cmp al, #0x02
9565 jne pci_pro_f03
9566 shl ecx, #16
9567 mov cx, dx
9568 xor bx, bx
9569 mov di, #0x00
9570 pci_pro_devloop:
9571 call pci_pro_select_reg
9572 mov dx, #0x0cfc
9573 in eax, dx
9574 cmp eax, ecx
9575 jne pci_pro_nextdev
9576 cmp si, #0
9577 je pci_pro_ok
9578 dec si
9579 pci_pro_nextdev:
9580 inc bx
9581 cmp bx, #0x0100
9582 jne pci_pro_devloop
9583 mov ah, #0x86
9584 jmp pci_pro_fail
9585 pci_pro_f03: ;; find class code
9586 cmp al, #0x03
9587 jne pci_pro_f08
9588 xor bx, bx
9589 mov di, #0x08
9590 pci_pro_devloop2:
9591 call pci_pro_select_reg
9592 mov dx, #0x0cfc
9593 in eax, dx
9594 shr eax, #8
9595 cmp eax, ecx
9596 jne pci_pro_nextdev2
9597 cmp si, #0
9598 je pci_pro_ok
9599 dec si
9600 pci_pro_nextdev2:
9601 inc bx
9602 cmp bx, #0x0100
9603 jne pci_pro_devloop2
9604 mov ah, #0x86
9605 jmp pci_pro_fail
9606 pci_pro_f08: ;; read configuration byte
9607 cmp al, #0x08
9608 jne pci_pro_f09
9609 call pci_pro_select_reg
9610 push edx
9611 mov dx, di
9612 and dx, #0x03
9613 add dx, #0x0cfc
9614 in al, dx
9615 pop edx
9616 mov cl, al
9617 jmp pci_pro_ok
9618 pci_pro_f09: ;; read configuration word
9619 cmp al, #0x09
9620 jne pci_pro_f0a
9621 call pci_pro_select_reg
9622 push edx
9623 mov dx, di
9624 and dx, #0x02
9625 add dx, #0x0cfc
9626 in ax, dx
9627 pop edx
9628 mov cx, ax
9629 jmp pci_pro_ok
9630 pci_pro_f0a: ;; read configuration dword
9631 cmp al, #0x0a
9632 jne pci_pro_f0b
9633 call pci_pro_select_reg
9634 push edx
9635 mov dx, #0x0cfc
9636 in eax, dx
9637 pop edx
9638 mov ecx, eax
9639 jmp pci_pro_ok
9640 pci_pro_f0b: ;; write configuration byte
9641 cmp al, #0x0b
9642 jne pci_pro_f0c
9643 call pci_pro_select_reg
9644 push edx
9645 mov dx, di
9646 and dx, #0x03
9647 add dx, #0x0cfc
9648 mov al, cl
9649 out dx, al
9650 pop edx
9651 jmp pci_pro_ok
9652 pci_pro_f0c: ;; write configuration word
9653 cmp al, #0x0c
9654 jne pci_pro_f0d
9655 call pci_pro_select_reg
9656 push edx
9657 mov dx, di
9658 and dx, #0x02
9659 add dx, #0x0cfc
9660 mov ax, cx
9661 out dx, ax
9662 pop edx
9663 jmp pci_pro_ok
9664 pci_pro_f0d: ;; write configuration dword
9665 cmp al, #0x0d
9666 jne pci_pro_unknown
9667 call pci_pro_select_reg
9668 push edx
9669 mov dx, #0x0cfc
9670 mov eax, ecx
9671 out dx, eax
9672 pop edx
9673 jmp pci_pro_ok
9674 pci_pro_unknown:
9675 mov ah, #0x81
9676 pci_pro_fail:
9677 pop edi
9678 pop esi
9679 #ifdef BX_QEMU
9680 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9681 #endif
9682 popfd
9683 stc
9684 retf
9685 pci_pro_ok:
9686 xor ah, ah
9687 pop edi
9688 pop esi
9689 #ifdef BX_QEMU
9690 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9691 #endif
9692 popfd
9693 clc
9694 retf
9696 pci_pro_select_reg:
9697 push edx
9698 mov eax, #0x800000
9699 mov ax, bx
9700 shl eax, #8
9701 and di, #0xff
9702 or ax, di
9703 and al, #0xfc
9704 mov dx, #0x0cf8
9705 out dx, eax
9706 pop edx
9707 ret
9709 use16 386
9711 pcibios_real:
9712 push eax
9713 push dx
9714 mov eax, #0x80000000
9715 mov dx, #0x0cf8
9716 out dx, eax
9717 mov dx, #0x0cfc
9718 in eax, dx
9719 #ifdef PCI_FIXED_HOST_BRIDGE
9720 cmp eax, #PCI_FIXED_HOST_BRIDGE
9721 je pci_present
9722 #else
9723 ;; say ok if a device is present
9724 cmp eax, #0xffffffff
9725 jne pci_present
9726 #endif
9727 pop dx
9728 pop eax
9729 mov ah, #0xff
9730 stc
9731 ret
9732 pci_present:
9733 pop dx
9734 pop eax
9735 cmp al, #0x01 ;; installation check
9736 jne pci_real_f02
9737 mov ax, #0x0001
9738 mov bx, #0x0210
9739 mov cx, #0
9740 mov edx, #0x20494350 ;; "PCI "
9741 mov edi, #0xf0000
9742 mov di, #pcibios_protected
9743 clc
9744 ret
9745 pci_real_f02: ;; find pci device
9746 push esi
9747 push edi
9748 cmp al, #0x02
9749 jne pci_real_f03
9750 shl ecx, #16
9751 mov cx, dx
9752 xor bx, bx
9753 mov di, #0x00
9754 pci_real_devloop:
9755 call pci_real_select_reg
9756 mov dx, #0x0cfc
9757 in eax, dx
9758 cmp eax, ecx
9759 jne pci_real_nextdev
9760 cmp si, #0
9761 je pci_real_ok
9762 dec si
9763 pci_real_nextdev:
9764 inc bx
9765 cmp bx, #0x0100
9766 jne pci_real_devloop
9767 mov dx, cx
9768 shr ecx, #16
9769 mov ax, #0x8602
9770 jmp pci_real_fail
9771 pci_real_f03: ;; find class code
9772 cmp al, #0x03
9773 jne pci_real_f08
9774 xor bx, bx
9775 mov di, #0x08
9776 pci_real_devloop2:
9777 call pci_real_select_reg
9778 mov dx, #0x0cfc
9779 in eax, dx
9780 shr eax, #8
9781 cmp eax, ecx
9782 jne pci_real_nextdev2
9783 cmp si, #0
9784 je pci_real_ok
9785 dec si
9786 pci_real_nextdev2:
9787 inc bx
9788 cmp bx, #0x0100
9789 jne pci_real_devloop2
9790 mov dx, cx
9791 shr ecx, #16
9792 mov ax, #0x8603
9793 jmp pci_real_fail
9794 pci_real_f08: ;; read configuration byte
9795 cmp al, #0x08
9796 jne pci_real_f09
9797 call pci_real_select_reg
9798 push dx
9799 mov dx, di
9800 and dx, #0x03
9801 add dx, #0x0cfc
9802 in al, dx
9803 pop dx
9804 mov cl, al
9805 jmp pci_real_ok
9806 pci_real_f09: ;; read configuration word
9807 cmp al, #0x09
9808 jne pci_real_f0a
9809 call pci_real_select_reg
9810 push dx
9811 mov dx, di
9812 and dx, #0x02
9813 add dx, #0x0cfc
9814 in ax, dx
9815 pop dx
9816 mov cx, ax
9817 jmp pci_real_ok
9818 pci_real_f0a: ;; read configuration dword
9819 cmp al, #0x0a
9820 jne pci_real_f0b
9821 call pci_real_select_reg
9822 push dx
9823 mov dx, #0x0cfc
9824 in eax, dx
9825 pop dx
9826 mov ecx, eax
9827 jmp pci_real_ok
9828 pci_real_f0b: ;; write configuration byte
9829 cmp al, #0x0b
9830 jne pci_real_f0c
9831 call pci_real_select_reg
9832 push dx
9833 mov dx, di
9834 and dx, #0x03
9835 add dx, #0x0cfc
9836 mov al, cl
9837 out dx, al
9838 pop dx
9839 jmp pci_real_ok
9840 pci_real_f0c: ;; write configuration word
9841 cmp al, #0x0c
9842 jne pci_real_f0d
9843 call pci_real_select_reg
9844 push dx
9845 mov dx, di
9846 and dx, #0x02
9847 add dx, #0x0cfc
9848 mov ax, cx
9849 out dx, ax
9850 pop dx
9851 jmp pci_real_ok
9852 pci_real_f0d: ;; write configuration dword
9853 cmp al, #0x0d
9854 jne pci_real_f0e
9855 call pci_real_select_reg
9856 push dx
9857 mov dx, #0x0cfc
9858 mov eax, ecx
9859 out dx, eax
9860 pop dx
9861 jmp pci_real_ok
9862 pci_real_f0e: ;; get irq routing options
9863 cmp al, #0x0e
9864 jne pci_real_unknown
9865 SEG ES
9866 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9867 jb pci_real_too_small
9868 SEG ES
9869 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9870 pushf
9871 push ds
9872 push es
9873 push cx
9874 push si
9875 push di
9876 cld
9877 mov si, #pci_routing_table_structure_start
9878 push cs
9879 pop ds
9880 SEG ES
9881 mov cx, [di+2]
9882 SEG ES
9883 mov es, [di+4]
9884 mov di, cx
9885 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
9886 rep
9887 movsb
9888 pop di
9889 pop si
9890 pop cx
9891 pop es
9892 pop ds
9893 popf
9894 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9895 jmp pci_real_ok
9896 pci_real_too_small:
9897 SEG ES
9898 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9899 mov ah, #0x89
9900 jmp pci_real_fail
9902 pci_real_unknown:
9903 mov ah, #0x81
9904 pci_real_fail:
9905 pop edi
9906 pop esi
9907 stc
9908 ret
9909 pci_real_ok:
9910 xor ah, ah
9911 pop edi
9912 pop esi
9913 clc
9914 ret
9916 pci_real_select_reg:
9917 push dx
9918 mov eax, #0x800000
9919 mov ax, bx
9920 shl eax, #8
9921 and di, #0xff
9922 or ax, di
9923 and al, #0xfc
9924 mov dx, #0x0cf8
9925 out dx, eax
9926 pop dx
9927 ret
9929 .align 16
9930 pci_routing_table_structure:
9931 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9932 db 0, 1 ;; version
9933 dw 32 + (6 * 16) ;; table size
9934 db 0 ;; PCI interrupt router bus
9935 db 0x08 ;; PCI interrupt router DevFunc
9936 dw 0x0000 ;; PCI exclusive IRQs
9937 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9938 dw 0x122e ;; compatible PCI interrupt router device ID
9939 dw 0,0 ;; Miniport data
9940 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9941 db 0x37 ;; checksum
9942 pci_routing_table_structure_start:
9943 ;; first slot entry PCI-to-ISA (embedded)
9944 db 0 ;; pci bus number
9945 db 0x08 ;; pci device number (bit 7-3)
9946 db 0x61 ;; link value INTA#: pointer into PCI2ISA config space
9947 dw 0x0c20 ;; IRQ bitmap INTA#
9948 db 0x62 ;; link value INTB#
9949 dw 0x0c20 ;; IRQ bitmap INTB#
9950 db 0x63 ;; link value INTC#
9951 dw 0x0c20 ;; IRQ bitmap INTC#
9952 db 0x60 ;; link value INTD#
9953 dw 0x0c20 ;; IRQ bitmap INTD#
9954 db 0 ;; physical slot (0 = embedded)
9955 db 0 ;; reserved
9956 ;; second slot entry: 1st PCI slot
9957 db 0 ;; pci bus number
9958 db 0x10 ;; pci device number (bit 7-3)
9959 db 0x62 ;; link value INTA#
9960 dw 0x0c20 ;; IRQ bitmap INTA#
9961 db 0x63 ;; link value INTB#
9962 dw 0x0c20 ;; IRQ bitmap INTB#
9963 db 0x60 ;; link value INTC#
9964 dw 0x0c20 ;; IRQ bitmap INTC#
9965 db 0x61 ;; link value INTD#
9966 dw 0x0c20 ;; IRQ bitmap INTD#
9967 db 1 ;; physical slot (0 = embedded)
9968 db 0 ;; reserved
9969 ;; third slot entry: 2nd PCI slot
9970 db 0 ;; pci bus number
9971 db 0x18 ;; pci device number (bit 7-3)
9972 db 0x63 ;; link value INTA#
9973 dw 0x0c20 ;; IRQ bitmap INTA#
9974 db 0x60 ;; link value INTB#
9975 dw 0x0c20 ;; IRQ bitmap INTB#
9976 db 0x61 ;; link value INTC#
9977 dw 0x0c20 ;; IRQ bitmap INTC#
9978 db 0x62 ;; link value INTD#
9979 dw 0x0c20 ;; IRQ bitmap INTD#
9980 db 2 ;; physical slot (0 = embedded)
9981 db 0 ;; reserved
9982 ;; 4th slot entry: 3rd PCI slot
9983 db 0 ;; pci bus number
9984 db 0x20 ;; pci device number (bit 7-3)
9985 db 0x60 ;; link value INTA#
9986 dw 0x0c20 ;; IRQ bitmap INTA#
9987 db 0x61 ;; link value INTB#
9988 dw 0x0c20 ;; IRQ bitmap INTB#
9989 db 0x62 ;; link value INTC#
9990 dw 0x0c20 ;; IRQ bitmap INTC#
9991 db 0x63 ;; link value INTD#
9992 dw 0x0c20 ;; IRQ bitmap INTD#
9993 db 3 ;; physical slot (0 = embedded)
9994 db 0 ;; reserved
9995 ;; 5th slot entry: 4rd PCI slot
9996 db 0 ;; pci bus number
9997 db 0x28 ;; pci device number (bit 7-3)
9998 db 0x61 ;; link value INTA#
9999 dw 0x0c20 ;; IRQ bitmap INTA#
10000 db 0x62 ;; link value INTB#
10001 dw 0x0c20 ;; IRQ bitmap INTB#
10002 db 0x63 ;; link value INTC#
10003 dw 0x0c20 ;; IRQ bitmap INTC#
10004 db 0x60 ;; link value INTD#
10005 dw 0x0c20 ;; IRQ bitmap INTD#
10006 db 4 ;; physical slot (0 = embedded)
10007 db 0 ;; reserved
10008 ;; 6th slot entry: 5rd PCI slot
10009 db 0 ;; pci bus number
10010 db 0x30 ;; pci device number (bit 7-3)
10011 db 0x62 ;; link value INTA#
10012 dw 0x0c20 ;; IRQ bitmap INTA#
10013 db 0x63 ;; link value INTB#
10014 dw 0x0c20 ;; IRQ bitmap INTB#
10015 db 0x60 ;; link value INTC#
10016 dw 0x0c20 ;; IRQ bitmap INTC#
10017 db 0x61 ;; link value INTD#
10018 dw 0x0c20 ;; IRQ bitmap INTD#
10019 db 5 ;; physical slot (0 = embedded)
10020 db 0 ;; reserved
10021 pci_routing_table_structure_end:
10023 #if !BX_ROMBIOS32 && !defined(HVMASSIST)
10024 pci_irq_list:
10025 db 11, 10, 9, 5;
10027 pcibios_init_sel_reg:
10028 push eax
10029 mov eax, #0x800000
10030 mov ax, bx
10031 shl eax, #8
10032 and dl, #0xfc
10033 or al, dl
10034 mov dx, #0x0cf8
10035 out dx, eax
10036 pop eax
10037 ret
10039 pcibios_init_iomem_bases:
10040 push bp
10041 mov bp, sp
10042 mov eax, #0xe0000000 ;; base for memory init
10043 push eax
10044 mov ax, #0xc000 ;; base for i/o init
10045 push ax
10046 mov ax, #0x0010 ;; start at base address #0
10047 push ax
10048 mov bx, #0x0008
10049 pci_init_io_loop1:
10050 mov dl, #0x00
10051 call pcibios_init_sel_reg
10052 mov dx, #0x0cfc
10053 in ax, dx
10054 cmp ax, #0xffff
10055 jz next_pci_dev
10056 mov dl, #0x04 ;; disable i/o and memory space access
10057 call pcibios_init_sel_reg
10058 mov dx, #0x0cfc
10059 in al, dx
10060 and al, #0xfc
10061 out dx, al
10062 pci_init_io_loop2:
10063 mov dl, [bp-8]
10064 call pcibios_init_sel_reg
10065 mov dx, #0x0cfc
10066 in eax, dx
10067 test al, #0x01
10068 jnz init_io_base
10069 mov ecx, eax
10070 mov eax, #0xffffffff
10071 out dx, eax
10072 in eax, dx
10073 cmp eax, ecx
10074 je next_pci_base
10075 xor eax, #0xffffffff
10076 mov ecx, eax
10077 mov eax, [bp-4]
10078 out dx, eax
10079 add eax, ecx ;; calculate next free mem base
10080 add eax, #0x01000000
10081 and eax, #0xff000000
10082 mov [bp-4], eax
10083 jmp next_pci_base
10084 init_io_base:
10085 mov cx, ax
10086 mov ax, #0xffff
10087 out dx, ax
10088 in ax, dx
10089 cmp ax, cx
10090 je next_pci_base
10091 xor ax, #0xfffe
10092 mov cx, ax
10093 mov ax, [bp-6]
10094 out dx, ax
10095 add ax, cx ;; calculate next free i/o base
10096 add ax, #0x0100
10097 and ax, #0xff00
10098 mov [bp-6], ax
10099 next_pci_base:
10100 mov al, [bp-8]
10101 add al, #0x04
10102 cmp al, #0x28
10103 je enable_iomem_space
10104 mov byte ptr[bp-8], al
10105 jmp pci_init_io_loop2
10106 enable_iomem_space:
10107 mov dl, #0x04 ;; enable i/o and memory space access if available
10108 call pcibios_init_sel_reg
10109 mov dx, #0x0cfc
10110 in al, dx
10111 or al, #0x07
10112 out dx, al
10113 next_pci_dev:
10114 mov byte ptr[bp-8], #0x10
10115 inc bx
10116 cmp bx, #0x0100
10117 jne pci_init_io_loop1
10118 mov sp, bp
10119 pop bp
10120 ret
10122 pcibios_init_set_elcr:
10123 push ax
10124 push cx
10125 mov dx, #0x04d0
10126 test al, #0x08
10127 jz is_master_pic
10128 inc dx
10129 and al, #0x07
10130 is_master_pic:
10131 mov cl, al
10132 mov bl, #0x01
10133 shl bl, cl
10134 in al, dx
10135 or al, bl
10136 out dx, al
10137 pop cx
10138 pop ax
10139 ret
10141 pcibios_init_irqs:
10142 push ds
10143 push bp
10144 mov ax, #0xf000
10145 mov ds, ax
10146 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10147 mov al, #0x00
10148 out dx, al
10149 inc dx
10150 out dx, al
10151 mov si, #pci_routing_table_structure
10152 mov bh, [si+8]