debuggers.hg

view tools/firmware/rombios/rombios.c @ 19692:11b3b6fafc7b

rombios: fix trying to boot from next device

If boot="ndc", rombios cannot try to boot next device.
Because rombios jump to the boot vector without pushing return
address, gPXE code and so on cannot return if it fail to boot.

Signed-off-by: Akio Takebe <takebe_akio@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed May 27 11:19:38 2009 +0100 (2009-05-27)
parents 33270c9a3d2f
children e638b32985fb
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 void enable_rom_write_access()
1423 outb(XEN_PF_IOBASE, 0);
1426 void disable_rom_write_access()
1428 outb(XEN_PF_IOBASE, PFFLAG_ROM_LOCK);
1431 #endif /* HVMASSIST */
1433 #if BX_DEBUG_SERIAL
1434 /* serial debug port*/
1435 #define BX_DEBUG_PORT 0x03f8
1437 /* data */
1438 #define UART_RBR 0x00
1439 #define UART_THR 0x00
1441 /* control */
1442 #define UART_IER 0x01
1443 #define UART_IIR 0x02
1444 #define UART_FCR 0x02
1445 #define UART_LCR 0x03
1446 #define UART_MCR 0x04
1447 #define UART_DLL 0x00
1448 #define UART_DLM 0x01
1450 /* status */
1451 #define UART_LSR 0x05
1452 #define UART_MSR 0x06
1453 #define UART_SCR 0x07
1455 int uart_can_tx_byte(base_port)
1456 Bit16u base_port;
1458 return inb(base_port + UART_LSR) & 0x20;
1461 void uart_wait_to_tx_byte(base_port)
1462 Bit16u base_port;
1464 while (!uart_can_tx_byte(base_port));
1467 void uart_wait_until_sent(base_port)
1468 Bit16u base_port;
1470 while (!(inb(base_port + UART_LSR) & 0x40));
1473 void uart_tx_byte(base_port, data)
1474 Bit16u base_port;
1475 Bit8u data;
1477 uart_wait_to_tx_byte(base_port);
1478 outb(base_port + UART_THR, data);
1479 uart_wait_until_sent(base_port);
1481 #endif
1483 void
1484 wrch(c)
1485 Bit8u c;
1487 ASM_START
1488 push bp
1489 mov bp, sp
1491 push bx
1492 mov ah, #0x0e
1493 mov al, 4[bp]
1494 xor bx,bx
1495 int #0x10
1496 pop bx
1498 pop bp
1499 ASM_END
1502 void
1503 send(action, c)
1504 Bit16u action;
1505 Bit8u c;
1507 #if BX_DEBUG_SERIAL
1508 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1509 uart_tx_byte(BX_DEBUG_PORT, c);
1510 #endif
1511 #ifdef HVMASSIST
1512 outb(0xE9, c);
1513 #endif
1514 #if BX_VIRTUAL_PORTS
1515 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1516 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1517 #endif
1518 if (action & BIOS_PRINTF_SCREEN) {
1519 if (c == '\n') wrch('\r');
1520 wrch(c);
1524 void
1525 put_int(action, val, width, neg)
1526 Bit16u action;
1527 short val, width;
1528 bx_bool neg;
1530 short nval = val / 10;
1531 if (nval)
1532 put_int(action, nval, width - 1, neg);
1533 else {
1534 while (--width > 0) send(action, ' ');
1535 if (neg) send(action, '-');
1537 send(action, val - (nval * 10) + '0');
1540 void
1541 put_uint(action, val, width, neg)
1542 Bit16u action;
1543 unsigned short val;
1544 short width;
1545 bx_bool neg;
1547 unsigned short nval = val / 10;
1548 if (nval)
1549 put_uint(action, nval, width - 1, neg);
1550 else {
1551 while (--width > 0) send(action, ' ');
1552 if (neg) send(action, '-');
1554 send(action, val - (nval * 10) + '0');
1557 void
1558 put_luint(action, val, width, neg)
1559 Bit16u action;
1560 unsigned long val;
1561 short width;
1562 bx_bool neg;
1564 unsigned long nval = val / 10;
1565 if (nval)
1566 put_luint(action, nval, width - 1, neg);
1567 else {
1568 while (--width > 0) send(action, ' ');
1569 if (neg) send(action, '-');
1571 send(action, val - (nval * 10) + '0');
1574 void put_str(action, segment, offset)
1575 Bit16u action;
1576 Bit16u segment;
1577 Bit16u offset;
1579 Bit8u c;
1581 while (c = read_byte(segment, offset)) {
1582 send(action, c);
1583 offset++;
1587 void
1588 delay_ticks(ticks)
1589 Bit16u ticks;
1591 long ticks_to_wait, delta;
1592 Bit32u prev_ticks, t;
1594 /*
1595 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
1596 * We also have to be careful about interrupt storms.
1597 */
1598 ASM_START
1599 pushf
1600 sti
1601 ASM_END
1602 ticks_to_wait = ticks;
1603 prev_ticks = read_dword(0x0, 0x46c);
1604 do
1606 ASM_START
1607 hlt
1608 ASM_END
1609 t = read_dword(0x0, 0x46c);
1610 if (t > prev_ticks)
1612 delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
1613 ticks_to_wait -= delta;
1615 else if (t < prev_ticks)
1617 ticks_to_wait -= t; /* wrapped */
1620 prev_ticks = t;
1621 } while (ticks_to_wait > 0);
1622 ASM_START
1623 cli
1624 popf
1625 ASM_END
1628 Bit8u
1629 check_for_keystroke()
1631 ASM_START
1632 mov ax, #0x100
1633 int #0x16
1634 jz no_key
1635 mov al, #1
1636 jmp done
1637 no_key:
1638 xor al, al
1639 done:
1640 ASM_END
1643 Bit8u
1644 get_keystroke()
1646 ASM_START
1647 mov ax, #0x0
1648 int #0x16
1649 xchg ah, al
1650 ASM_END
1653 void
1654 delay_ticks_and_check_for_keystroke(ticks, count)
1655 Bit16u ticks, count;
1657 Bit16u i;
1658 for (i = 1; i <= count; i++) {
1659 delay_ticks(ticks);
1660 if (check_for_keystroke())
1661 break;
1665 //--------------------------------------------------------------------------
1666 // bios_printf()
1667 // A compact variable argument printf function.
1668 //
1669 // Supports %[format_width][length]format
1670 // where format can be x,X,u,d,s,S,c
1671 // and the optional length modifier is l (ell)
1672 //--------------------------------------------------------------------------
1673 void
1674 bios_printf(action, s)
1675 Bit16u action;
1676 Bit8u *s;
1678 Bit8u c, format_char;
1679 bx_bool in_format;
1680 short i;
1681 Bit16u *arg_ptr;
1682 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1684 arg_ptr = &s;
1685 arg_seg = get_SS();
1687 in_format = 0;
1688 format_width = 0;
1690 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1691 #if BX_VIRTUAL_PORTS
1692 outb(PANIC_PORT2, 0x00);
1693 #endif
1694 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1697 while (c = read_byte(get_CS(), s)) {
1698 if ( c == '%' ) {
1699 in_format = 1;
1700 format_width = 0;
1702 else if (in_format) {
1703 if ( (c>='0') && (c<='9') ) {
1704 format_width = (format_width * 10) + (c - '0');
1706 else {
1707 arg_ptr++; // increment to next arg
1708 arg = read_word(arg_seg, arg_ptr);
1709 if (c == 'x' || c == 'X') {
1710 if (format_width == 0)
1711 format_width = 4;
1712 if (c == 'x')
1713 hexadd = 'a';
1714 else
1715 hexadd = 'A';
1716 for (i=format_width-1; i>=0; i--) {
1717 nibble = (arg >> (4 * i)) & 0x000f;
1718 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1721 else if (c == 'u') {
1722 put_uint(action, arg, format_width, 0);
1724 else if (c == 'l') {
1725 s++;
1726 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1727 arg_ptr++; /* increment to next arg */
1728 hibyte = read_word(arg_seg, arg_ptr);
1729 if (c == 'd') {
1730 if (hibyte & 0x8000)
1731 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1732 else
1733 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1735 else if (c == 'u') {
1736 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1738 else if (c == 'x' || c == 'X')
1740 if (format_width == 0)
1741 format_width = 8;
1742 if (c == 'x')
1743 hexadd = 'a';
1744 else
1745 hexadd = 'A';
1746 for (i=format_width-1; i>=0; i--) {
1747 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1748 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1752 else if (c == 'd') {
1753 if (arg & 0x8000)
1754 put_int(action, -arg, format_width - 1, 1);
1755 else
1756 put_int(action, arg, format_width, 0);
1758 else if (c == 's') {
1759 put_str(action, get_CS(), arg);
1761 else if (c == 'S') {
1762 hibyte = arg;
1763 arg_ptr++;
1764 arg = read_word(arg_seg, arg_ptr);
1765 put_str(action, hibyte, arg);
1767 else if (c == 'c') {
1768 send(action, arg);
1770 else
1771 BX_PANIC("bios_printf: unknown format\n");
1772 in_format = 0;
1775 else {
1776 send(action, c);
1778 s ++;
1781 if (action & BIOS_PRINTF_HALT) {
1782 // freeze in a busy loop.
1783 ASM_START
1784 cli
1785 halt2_loop:
1786 hlt
1787 jmp halt2_loop
1788 ASM_END
1792 //--------------------------------------------------------------------------
1793 // keyboard_init
1794 //--------------------------------------------------------------------------
1795 // this file is based on LinuxBIOS implementation of keyboard.c
1796 // could convert to #asm to gain space
1797 void
1798 keyboard_init()
1800 Bit16u max;
1802 /* ------------------- Flush buffers ------------------------*/
1803 /* Wait until buffer is empty */
1804 max=0xffff;
1805 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1807 /* flush incoming keys */
1808 max=0x2000;
1809 while (--max > 0) {
1810 outb(0x80, 0x00);
1811 if (inb(0x64) & 0x01) {
1812 inb(0x60);
1813 max = 0x2000;
1817 // Due to timer issues, and if the IPS setting is > 15000000,
1818 // the incoming keys might not be flushed here. That will
1819 // cause a panic a few lines below. See sourceforge bug report :
1820 // [ 642031 ] FATAL: Keyboard RESET error:993
1822 /* ------------------- controller side ----------------------*/
1823 /* send cmd = 0xAA, self test 8042 */
1824 outb(0x64, 0xaa);
1826 /* Wait until buffer is empty */
1827 max=0xffff;
1828 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1829 if (max==0x0) keyboard_panic(00);
1831 /* Wait for data */
1832 max=0xffff;
1833 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1834 if (max==0x0) keyboard_panic(01);
1836 /* read self-test result, 0x55 should be returned from 0x60 */
1837 if ((inb(0x60) != 0x55)){
1838 keyboard_panic(991);
1841 /* send cmd = 0xAB, keyboard interface test */
1842 outb(0x64,0xab);
1844 /* Wait until buffer is empty */
1845 max=0xffff;
1846 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1847 if (max==0x0) keyboard_panic(10);
1849 /* Wait for data */
1850 max=0xffff;
1851 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1852 if (max==0x0) keyboard_panic(11);
1854 /* read keyboard interface test result, */
1855 /* 0x00 should be returned form 0x60 */
1856 if ((inb(0x60) != 0x00)) {
1857 keyboard_panic(992);
1860 /* Enable Keyboard clock */
1861 outb(0x64,0xae);
1862 outb(0x64,0xa8);
1864 /* ------------------- keyboard side ------------------------*/
1865 /* reset kerboard and self test (keyboard side) */
1866 outb(0x60, 0xff);
1868 /* Wait until buffer is empty */
1869 max=0xffff;
1870 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1871 if (max==0x0) keyboard_panic(20);
1873 /* Wait for data */
1874 max=0xffff;
1875 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1876 if (max==0x0) keyboard_panic(21);
1878 /* keyboard should return ACK */
1879 if ((inb(0x60) != 0xfa)) {
1880 keyboard_panic(993);
1883 /* Wait for data */
1884 max=0xffff;
1885 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1886 if (max==0x0) keyboard_panic(31);
1888 if ((inb(0x60) != 0xaa)) {
1889 keyboard_panic(994);
1892 /* Disable keyboard */
1893 outb(0x60, 0xf5);
1895 /* Wait until buffer is empty */
1896 max=0xffff;
1897 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1898 if (max==0x0) keyboard_panic(40);
1900 /* Wait for data */
1901 max=0xffff;
1902 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1903 if (max==0x0) keyboard_panic(41);
1905 /* keyboard should return ACK */
1906 if ((inb(0x60) != 0xfa)) {
1907 keyboard_panic(995);
1910 /* Write Keyboard Mode */
1911 outb(0x64, 0x60);
1913 /* Wait until buffer is empty */
1914 max=0xffff;
1915 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1916 if (max==0x0) keyboard_panic(50);
1918 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1919 outb(0x60, 0x61);
1921 /* Wait until buffer is empty */
1922 max=0xffff;
1923 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1924 if (max==0x0) keyboard_panic(60);
1926 /* Enable keyboard */
1927 outb(0x60, 0xf4);
1929 /* Wait until buffer is empty */
1930 max=0xffff;
1931 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1932 if (max==0x0) keyboard_panic(70);
1934 /* Wait for data */
1935 max=0xffff;
1936 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1937 if (max==0x0) keyboard_panic(70);
1939 /* keyboard should return ACK */
1940 if ((inb(0x60) != 0xfa)) {
1941 keyboard_panic(996);
1944 outb(0x80, 0x77);
1947 //--------------------------------------------------------------------------
1948 // keyboard_panic
1949 //--------------------------------------------------------------------------
1950 void
1951 keyboard_panic(status)
1952 Bit16u status;
1954 // If you're getting a 993 keyboard panic here,
1955 // please see the comment in keyboard_init
1957 BX_PANIC("Keyboard error:%u\n",status);
1960 #define CMOS_SHUTDOWN_S3 0xFE
1961 //--------------------------------------------------------------------------
1962 // machine_reset
1963 //--------------------------------------------------------------------------
1964 void
1965 machine_reset()
1967 ASM_START
1968 ;we must check whether CMOS_SHUTDOWN_S3 is set or not
1969 ;if it is s3 resume, just jmp back to normal Post Entry
1970 ;below port io will prevent s3 resume
1971 mov al, #0x0f
1972 out 0x70, al
1973 in al, 0x71
1974 cmp al, #0xFE
1975 jz post
1976 ASM_END
1977 /* Frob the keyboard reset line to reset the processor */
1978 outb(0x64, 0x60); /* Map the flags register at data port (0x60) */
1979 outb(0x60, 0x14); /* Set the flags to system|disable */
1980 outb(0x64, 0xfe); /* Pulse output 0 (system reset) low */
1981 BX_PANIC("Couldn't reset the machine\n");
1984 //--------------------------------------------------------------------------
1985 // clobber_entry_point
1986 // Because PV drivers in HVM guests detach some of the emulated devices,
1987 // it is not safe to do a soft reboot by just dropping to real mode and
1988 // jumping at ffff:0000. -- the boot drives might have disappeared!
1989 // This rather foul function overwrites(!) the BIOS entry point
1990 // to point at machine-reset, which will cause the Xen tools to
1991 // rebuild the whole machine from scratch.
1992 //--------------------------------------------------------------------------
1993 void
1994 clobber_entry_point()
1996 /* The instruction at the entry point is one byte (0xea) for the
1997 * jump opcode, then two bytes of address, then two of segment.
1998 * Overwrite the address bytes.*/
1999 write_word(0xffff, 0x0001, machine_reset);
2003 //--------------------------------------------------------------------------
2004 // shutdown_status_panic
2005 // called when the shutdown statsu is not implemented, displays the status
2006 //--------------------------------------------------------------------------
2007 void
2008 shutdown_status_panic(status)
2009 Bit16u status;
2011 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
2014 void s3_resume_panic()
2016 BX_PANIC("Returned from s3_resume.\n");
2019 //--------------------------------------------------------------------------
2020 // print_bios_banner
2021 // displays a the bios version
2022 //--------------------------------------------------------------------------
2023 void
2024 print_bios_banner()
2026 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
2027 BIOS_BUILD_DATE, bios_cvs_version_string);
2028 printf(
2029 #if BX_APM
2030 "apmbios "
2031 #endif
2032 #if BX_PCIBIOS
2033 "pcibios "
2034 #endif
2035 #if BX_ELTORITO_BOOT
2036 "eltorito "
2037 #endif
2038 #if BX_ROMBIOS32
2039 "rombios32 "
2040 #endif
2041 #if BX_TCGBIOS
2042 "TCG-enabled "
2043 #endif
2044 #if BX_PMM
2045 "PMM "
2046 #endif
2047 "\n\n");
2050 //--------------------------------------------------------------------------
2051 // BIOS Boot Specification 1.0.1 compatibility
2052 //
2053 // Very basic support for the BIOS Boot Specification, which allows expansion
2054 // ROMs to register themselves as boot devices, instead of just stealing the
2055 // INT 19h boot vector.
2056 //
2057 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
2058 // one; we just lie to the option ROMs to make them behave correctly.
2059 // We also don't support letting option ROMs register as bootable disk
2060 // drives (BCVs), only as bootable devices (BEVs).
2061 //
2062 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
2063 //--------------------------------------------------------------------------
2065 static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
2067 static void
2068 init_boot_vectors()
2070 ipl_entry_t e;
2071 Bit16u count = 0;
2072 Bit16u ss = get_SS();
2073 Bit16u ebda_seg = read_word(0x0040, 0x000E);
2075 /* Clear out the IPL table. */
2076 memsetb(ebda_seg, IPL_TABLE_OFFSET, 0, IPL_SIZE);
2078 /* User selected device not set */
2079 write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF);
2081 /* Floppy drive */
2082 e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
2083 memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
2084 count++;
2086 /* First HDD */
2087 e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
2088 memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
2089 count++;
2091 #if BX_ELTORITO_BOOT
2092 /* CDROM */
2093 e.type = IPL_TYPE_CDROM; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
2094 memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
2095 count++;
2096 #endif
2098 /* Remember how many devices we have */
2099 write_word(ebda_seg, IPL_COUNT_OFFSET, count);
2100 /* Not tried booting anything yet */
2101 write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xffff);
2104 static Bit8u
2105 get_boot_vector(i, e)
2106 Bit16u i; ipl_entry_t *e;
2108 Bit16u count;
2109 Bit16u ss = get_SS();
2110 Bit16u ebda_seg = read_word(0x0040, 0x000E);
2111 /* Get the count of boot devices, and refuse to overrun the array */
2112 count = read_word(ebda_seg, IPL_COUNT_OFFSET);
2113 if (i >= count) return 0;
2114 /* OK to read this device */
2115 memcpyb(ss, e, ebda_seg, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
2116 return 1;
2119 #if BX_ELTORITO_BOOT
2120 void
2121 interactive_bootkey()
2123 ipl_entry_t e;
2124 Bit16u count;
2125 char description[33];
2126 Bit8u scan_code;
2127 Bit8u i;
2128 Bit16u ss = get_SS();
2129 Bit16u valid_choice = 0;
2130 Bit16u ebda_seg = read_word(0x0040, 0x000E);
2132 printf("\n\nPress F12 for boot menu.\n\n");
2134 while (check_for_keystroke())
2136 scan_code = get_keystroke();
2137 if (scan_code != 0x86) /* F12 */
2138 continue;
2140 while (check_for_keystroke())
2141 get_keystroke();
2143 printf("Select boot device:\n\n");
2145 count = read_word(ebda_seg, IPL_COUNT_OFFSET);
2146 for (i = 0; i < count; i++)
2148 memcpyb(ss, &e, ebda_seg, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e));
2149 printf("%d. ", i+1);
2150 switch(e.type)
2152 case IPL_TYPE_FLOPPY:
2153 case IPL_TYPE_HARDDISK:
2154 case IPL_TYPE_CDROM:
2155 printf("%s\n", drivetypes[e.type]);
2156 break;
2157 case IPL_TYPE_BEV:
2158 printf("%s", drivetypes[4]);
2159 if (e.description != 0)
2161 memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32);
2162 description[32] = 0;
2163 printf(" [%S]", ss, description);
2165 printf("\n");
2166 break;
2170 count++;
2171 while (!valid_choice) {
2172 scan_code = get_keystroke();
2173 if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */
2175 valid_choice = 1;
2177 else if (scan_code <= count)
2179 valid_choice = 1;
2180 scan_code -= 1;
2181 /* Set user selected device */
2182 write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, scan_code);
2186 printf("\n");
2187 break;
2190 #endif // BX_ELTORITO_BOOT
2192 //--------------------------------------------------------------------------
2193 // print_boot_device
2194 // displays the boot device
2195 //--------------------------------------------------------------------------
2197 void
2198 print_boot_device(e)
2199 ipl_entry_t *e;
2201 Bit16u type;
2202 char description[33];
2203 Bit16u ss = get_SS();
2204 type = e->type;
2205 /* NIC appears as type 0x80 */
2206 if (type == IPL_TYPE_BEV) type = 0x4;
2207 if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
2208 printf("Booting from %s", drivetypes[type]);
2209 /* print product string if BEV */
2210 if (type == 4 && e->description != 0) {
2211 /* first 32 bytes are significant */
2212 memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
2213 /* terminate string */
2214 description[32] = 0;
2215 printf(" [%S]", ss, description);
2217 printf("...\n");
2220 //--------------------------------------------------------------------------
2221 // print_boot_failure
2222 // displays the reason why boot failed
2223 //--------------------------------------------------------------------------
2224 void
2225 print_boot_failure(type, reason)
2226 Bit16u type; Bit8u reason;
2228 if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
2230 printf("Boot from %s failed", drivetypes[type]);
2231 if (type < 4) {
2232 /* Report the reason too */
2233 if (reason==0)
2234 printf(": not a bootable disk");
2235 else
2236 printf(": could not read the boot disk");
2238 printf("\n\n");
2241 //--------------------------------------------------------------------------
2242 // print_cdromboot_failure
2243 // displays the reason why boot failed
2244 //--------------------------------------------------------------------------
2245 void
2246 print_cdromboot_failure( code )
2247 Bit16u code;
2249 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2251 return;
2254 void
2255 nmi_handler_msg()
2257 BX_PANIC("NMI Handler called\n");
2260 void
2261 int18_panic_msg()
2263 BX_PANIC("INT18: BOOT FAILURE\n");
2266 void
2267 log_bios_start()
2269 #if BX_DEBUG_SERIAL
2270 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2271 #endif
2272 BX_INFO("%s\n", bios_cvs_version_string);
2275 bx_bool
2276 set_enable_a20(val)
2277 bx_bool val;
2279 Bit8u oldval;
2281 // Use PS2 System Control port A to set A20 enable
2283 // get current setting first
2284 oldval = inb(0x92);
2286 // change A20 status
2287 if (val)
2288 outb(0x92, oldval | 0x02);
2289 else
2290 outb(0x92, oldval & 0xfd);
2292 return((oldval & 0x02) != 0);
2295 void
2296 debugger_on()
2298 outb(0xfedc, 0x01);
2301 void
2302 debugger_off()
2304 outb(0xfedc, 0x00);
2307 int
2308 s3_resume()
2310 Bit32u s3_wakeup_vector;
2311 Bit8u s3_resume_flag;
2313 s3_resume_flag = read_byte(0x40, 0xb0);
2314 #ifdef HVMASSIST
2315 s3_wakeup_vector = get_s3_waking_vector();
2316 #else
2317 s3_wakeup_vector = read_dword(0x40, 0xb2);
2318 #endif
2320 BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag, s3_wakeup_vector);
2321 if (s3_resume_flag != CMOS_SHUTDOWN_S3 || !s3_wakeup_vector)
2322 return 0;
2324 write_byte(0x40, 0xb0, 0);
2326 /* setup wakeup vector */
2327 write_word(0x40, 0xb6, (s3_wakeup_vector & 0xF)); /* IP */
2328 write_word(0x40, 0xb8, (s3_wakeup_vector >> 4)); /* CS */
2330 BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector >> 4),
2331 (s3_wakeup_vector & 0xF));
2332 ASM_START
2333 jmpf [0x04b6]
2334 ASM_END
2335 return 1;
2338 #if BX_USE_ATADRV
2340 // ---------------------------------------------------------------------------
2341 // Start of ATA/ATAPI Driver
2342 // ---------------------------------------------------------------------------
2344 // Global defines -- ATA register and register bits.
2345 // command block & control block regs
2346 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2347 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2348 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2349 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2350 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2351 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2352 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2353 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2354 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2355 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2356 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2357 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2358 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2360 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2361 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2362 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2363 #define ATA_CB_ER_MC 0x20 // ATA media change
2364 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2365 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2366 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2367 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2368 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2370 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2371 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2372 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2373 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2374 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2376 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2377 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2378 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2379 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2380 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2382 // bits 7-4 of the device/head (CB_DH) reg
2383 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2384 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2385 #define ATA_CB_DH_LBA 0x40 // use LBA
2387 // status reg (CB_STAT and CB_ASTAT) bits
2388 #define ATA_CB_STAT_BSY 0x80 // busy
2389 #define ATA_CB_STAT_RDY 0x40 // ready
2390 #define ATA_CB_STAT_DF 0x20 // device fault
2391 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2392 #define ATA_CB_STAT_SKC 0x10 // seek complete
2393 #define ATA_CB_STAT_SERV 0x10 // service
2394 #define ATA_CB_STAT_DRQ 0x08 // data request
2395 #define ATA_CB_STAT_CORR 0x04 // corrected
2396 #define ATA_CB_STAT_IDX 0x02 // index
2397 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2398 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2400 // device control reg (CB_DC) bits
2401 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2402 #define ATA_CB_DC_SRST 0x04 // soft reset
2403 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2405 // Most mandtory and optional ATA commands (from ATA-3),
2406 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2407 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2408 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2409 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2410 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2411 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2412 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2413 #define ATA_CMD_DEVICE_RESET 0x08
2414 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2415 #define ATA_CMD_FLUSH_CACHE 0xE7
2416 #define ATA_CMD_FORMAT_TRACK 0x50
2417 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2418 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2419 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2420 #define ATA_CMD_IDLE1 0xE3
2421 #define ATA_CMD_IDLE2 0x97
2422 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2423 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2424 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2425 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2426 #define ATA_CMD_NOP 0x00
2427 #define ATA_CMD_PACKET 0xA0
2428 #define ATA_CMD_READ_BUFFER 0xE4
2429 #define ATA_CMD_READ_DMA 0xC8
2430 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2431 #define ATA_CMD_READ_MULTIPLE 0xC4
2432 #define ATA_CMD_READ_SECTORS 0x20
2433 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2434 #define ATA_CMD_RECALIBRATE 0x10
2435 #define ATA_CMD_REQUEST_SENSE 0x03
2436 #define ATA_CMD_SEEK 0x70
2437 #define ATA_CMD_SET_FEATURES 0xEF
2438 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2439 #define ATA_CMD_SLEEP1 0xE6
2440 #define ATA_CMD_SLEEP2 0x99
2441 #define ATA_CMD_STANDBY1 0xE2
2442 #define ATA_CMD_STANDBY2 0x96
2443 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2444 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2445 #define ATA_CMD_WRITE_BUFFER 0xE8
2446 #define ATA_CMD_WRITE_DMA 0xCA
2447 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2448 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2449 #define ATA_CMD_WRITE_SECTORS 0x30
2450 #define ATA_CMD_WRITE_VERIFY 0x3C
2452 #define ATA_IFACE_NONE 0x00
2453 #define ATA_IFACE_ISA 0x00
2454 #define ATA_IFACE_PCI 0x01
2456 #define ATA_TYPE_NONE 0x00
2457 #define ATA_TYPE_UNKNOWN 0x01
2458 #define ATA_TYPE_ATA 0x02
2459 #define ATA_TYPE_ATAPI 0x03
2461 #define ATA_DEVICE_NONE 0x00
2462 #define ATA_DEVICE_HD 0xFF
2463 #define ATA_DEVICE_CDROM 0x05
2465 #define ATA_MODE_NONE 0x00
2466 #define ATA_MODE_PIO16 0x00
2467 #define ATA_MODE_PIO32 0x01
2468 #define ATA_MODE_ISADMA 0x02
2469 #define ATA_MODE_PCIDMA 0x03
2470 #define ATA_MODE_USEIRQ 0x10
2472 #define ATA_TRANSLATION_NONE 0
2473 #define ATA_TRANSLATION_LBA 1
2474 #define ATA_TRANSLATION_LARGE 2
2475 #define ATA_TRANSLATION_RECHS 3
2477 #define ATA_DATA_NO 0x00
2478 #define ATA_DATA_IN 0x01
2479 #define ATA_DATA_OUT 0x02
2481 // ---------------------------------------------------------------------------
2482 // ATA/ATAPI driver : initialization
2483 // ---------------------------------------------------------------------------
2484 void ata_init( )
2486 Bit16u ebda_seg=read_word(0x0040,0x000E);
2487 Bit8u channel, device;
2489 // Channels info init.
2490 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2491 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2492 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2493 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2494 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2497 // Devices info init.
2498 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2499 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2500 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2501 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2502 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2503 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2504 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2505 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2506 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2507 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2508 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2509 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2510 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2511 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2513 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low,0L);
2514 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high,0L);
2517 // hdidmap and cdidmap init.
2518 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2519 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2520 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2523 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2524 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2527 #define TIMEOUT 0
2528 #define BSY 1
2529 #define NOT_BSY 2
2530 #define NOT_BSY_DRQ 3
2531 #define NOT_BSY_NOT_DRQ 4
2532 #define NOT_BSY_RDY 5
2534 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
2536 int await_ide();
2537 static int await_ide(when_done,base,timeout)
2538 Bit8u when_done;
2539 Bit16u base;
2540 Bit16u timeout;
2542 Bit32u time=0,last=0;
2543 Bit16u status;
2544 Bit8u result;
2545 status = inb(base + ATA_CB_STAT); // for the times you're supposed to throw one away
2546 for(;;) {
2547 status = inb(base+ATA_CB_STAT);
2548 time++;
2549 if (when_done == BSY)
2550 result = status & ATA_CB_STAT_BSY;
2551 else if (when_done == NOT_BSY)
2552 result = !(status & ATA_CB_STAT_BSY);
2553 else if (when_done == NOT_BSY_DRQ)
2554 result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ);
2555 else if (when_done == NOT_BSY_NOT_DRQ)
2556 result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ);
2557 else if (when_done == NOT_BSY_RDY)
2558 result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY);
2559 else if (when_done == TIMEOUT)
2560 result = 0;
2562 if (result) return 0;
2563 if (time>>16 != last) // mod 2048 each 16 ms
2565 last = time >>16;
2566 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);
2568 if (status & ATA_CB_STAT_ERR)
2570 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);
2571 return -1;
2573 if ((timeout == 0) || ((time>>11) > timeout)) break;
2575 BX_INFO("IDE time out\n");
2576 return -1;
2579 // ---------------------------------------------------------------------------
2580 // ATA/ATAPI driver : device detection
2581 // ---------------------------------------------------------------------------
2583 void ata_detect( )
2585 Bit16u ebda_seg=read_word(0x0040,0x000E);
2586 Bit8u hdcount, cdcount, device, type;
2587 Bit8u buffer[0x0200];
2589 #if BX_MAX_ATA_INTERFACES > 0
2590 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2591 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2592 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2593 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2594 #endif
2595 #if BX_MAX_ATA_INTERFACES > 1
2596 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2597 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2598 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2599 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2600 #endif
2601 #if BX_MAX_ATA_INTERFACES > 2
2602 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2603 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2604 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2605 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2606 #endif
2607 #if BX_MAX_ATA_INTERFACES > 3
2608 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2609 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2610 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2611 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2612 #endif
2613 #if BX_MAX_ATA_INTERFACES > 4
2614 #error Please fill the ATA interface informations
2615 #endif
2617 // Device detection
2618 hdcount=cdcount=0;
2620 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2621 Bit16u iobase1, iobase2;
2622 Bit8u channel, slave, shift;
2623 Bit8u sc, sn, cl, ch, st;
2625 channel = device / 2;
2626 slave = device % 2;
2628 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2629 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2631 // Disable interrupts
2632 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2634 // Look for device
2635 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2636 outb(iobase1+ATA_CB_SC, 0x55);
2637 outb(iobase1+ATA_CB_SN, 0xaa);
2638 outb(iobase1+ATA_CB_SC, 0xaa);
2639 outb(iobase1+ATA_CB_SN, 0x55);
2640 outb(iobase1+ATA_CB_SC, 0x55);
2641 outb(iobase1+ATA_CB_SN, 0xaa);
2643 // If we found something
2644 sc = inb(iobase1+ATA_CB_SC);
2645 sn = inb(iobase1+ATA_CB_SN);
2647 if ( (sc == 0x55) && (sn == 0xaa) ) {
2648 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2650 // reset the channel
2651 ata_reset(device);
2653 // check for ATA or ATAPI
2654 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2655 sc = inb(iobase1+ATA_CB_SC);
2656 sn = inb(iobase1+ATA_CB_SN);
2657 if ((sc==0x01) && (sn==0x01)) {
2658 cl = inb(iobase1+ATA_CB_CL);
2659 ch = inb(iobase1+ATA_CB_CH);
2660 st = inb(iobase1+ATA_CB_STAT);
2662 if ((cl==0x14) && (ch==0xeb)) {
2663 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2664 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2665 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2666 } else if ((cl==0xff) && (ch==0xff)) {
2667 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2672 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2674 // Now we send a IDENTIFY command to ATA device
2675 if(type == ATA_TYPE_ATA) {
2676 Bit32u sectors_low, sectors_high;
2677 Bit16u cylinders, heads, spt, blksize;
2678 Bit8u translation, removable, mode;
2680 // default mode to PIO16
2681 mode = ATA_MODE_PIO16;
2683 //Temporary values to do the transfer
2684 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2685 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2687 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) !=0 )
2688 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2690 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2691 #ifndef NO_PIO32
2692 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2693 #endif
2694 blksize = read_word(get_SS(),buffer+10);
2696 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2697 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2698 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2700 if (read_word(get_SS(),buffer+(83*2)) & (1 << 10)) { // word 83 - lba48 support
2701 sectors_low = read_dword(get_SS(),buffer+(100*2)); // word 100 and word 101
2702 sectors_high = read_dword(get_SS(),buffer+(102*2)); // word 102 and word 103
2703 } else {
2704 sectors_low = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2705 sectors_high = 0;
2708 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2709 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2710 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2711 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2712 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2713 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2714 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2715 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors_low);
2716 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high, sectors_high);
2717 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2719 translation = inb_cmos(0x39 + channel/2);
2720 for (shift=device%4; shift>0; shift--) translation >>= 2;
2721 translation &= 0x03;
2723 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2725 switch (translation) {
2726 case ATA_TRANSLATION_NONE:
2727 BX_INFO("none");
2728 break;
2729 case ATA_TRANSLATION_LBA:
2730 BX_INFO("lba");
2731 break;
2732 case ATA_TRANSLATION_LARGE:
2733 BX_INFO("large");
2734 break;
2735 case ATA_TRANSLATION_RECHS:
2736 BX_INFO("r-echs");
2737 break;
2739 switch (translation) {
2740 case ATA_TRANSLATION_NONE:
2741 break;
2742 case ATA_TRANSLATION_LBA:
2743 spt = 63;
2744 sectors_low /= 63;
2745 heads = sectors_low / 1024;
2746 if (heads>128) heads = 255;
2747 else if (heads>64) heads = 128;
2748 else if (heads>32) heads = 64;
2749 else if (heads>16) heads = 32;
2750 else heads=16;
2751 cylinders = sectors_low / heads;
2752 break;
2753 case ATA_TRANSLATION_RECHS:
2754 // Take care not to overflow
2755 if (heads==16) {
2756 if(cylinders>61439) cylinders=61439;
2757 heads=15;
2758 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2760 // then go through the large bitshift process
2761 case ATA_TRANSLATION_LARGE:
2762 while(cylinders > 1024) {
2763 cylinders >>= 1;
2764 heads <<= 1;
2766 // If we max out the head count
2767 if (heads > 127) break;
2769 break;
2771 // clip to 1024 cylinders in lchs
2772 if (cylinders > 1024) cylinders=1024;
2773 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2775 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2776 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2777 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2779 // fill hdidmap
2780 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2781 hdcount++;
2784 // Now we send a IDENTIFY command to ATAPI device
2785 if(type == ATA_TYPE_ATAPI) {
2787 Bit8u type, removable, mode;
2788 Bit16u blksize;
2790 // default mode to PIO16
2791 mode = ATA_MODE_PIO16;
2793 //Temporary values to do the transfer
2794 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2795 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2797 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) != 0)
2798 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2800 type = read_byte(get_SS(),buffer+1) & 0x1f;
2801 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2802 #ifndef NO_PIO32
2803 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2804 #endif
2805 blksize = 2048;
2807 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2808 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2809 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2810 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2812 // fill cdidmap
2813 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2814 cdcount++;
2818 Bit32u sizeinmb;
2819 Bit16u ataversion;
2820 Bit8u c, i, version, model[41];
2822 switch (type) {
2823 case ATA_TYPE_ATA:
2824 sizeinmb = (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high) << 21)
2825 | (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low) >> 11);
2826 case ATA_TYPE_ATAPI:
2827 // Read ATA/ATAPI version
2828 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2829 for(version=15;version>0;version--) {
2830 if((ataversion&(1<<version))!=0)
2831 break;
2834 // Read model name
2835 for(i=0;i<20;i++){
2836 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2837 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2840 // Reformat
2841 write_byte(get_SS(),model+40,0x00);
2842 for(i=39;i>0;i--){
2843 if(read_byte(get_SS(),model+i)==0x20)
2844 write_byte(get_SS(),model+i,0x00);
2845 else break;
2847 if (i>36) {
2848 write_byte(get_SS(),model+36,0x00);
2849 for(i=35;i>32;i--){
2850 write_byte(get_SS(),model+i,0x2E);
2853 break;
2856 switch (type) {
2857 case ATA_TYPE_ATA:
2858 printf("ata%d %s: ",channel,slave?" slave":"master");
2859 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2860 if (sizeinmb < (1UL<<16))
2861 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (Bit16u)sizeinmb);
2862 else
2863 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (Bit16u)(sizeinmb>>10));
2864 break;
2865 case ATA_TYPE_ATAPI:
2866 printf("ata%d %s: ",channel,slave?" slave":"master");
2867 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2868 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2869 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2870 else
2871 printf(" ATAPI-%d Device\n",version);
2872 break;
2873 case ATA_TYPE_UNKNOWN:
2874 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2875 break;
2880 // Store the devices counts
2881 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2882 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2883 write_byte(0x40,0x75, hdcount);
2885 printf("\n");
2887 // FIXME : should use bios=cmos|auto|disable bits
2888 // FIXME : should know about translation bits
2889 // FIXME : move hard_drive_post here
2893 // ---------------------------------------------------------------------------
2894 // ATA/ATAPI driver : software reset
2895 // ---------------------------------------------------------------------------
2896 // ATA-3
2897 // 8.2.1 Software reset - Device 0
2899 void ata_reset(device)
2900 Bit16u device;
2902 Bit16u ebda_seg=read_word(0x0040,0x000E);
2903 Bit16u iobase1, iobase2;
2904 Bit8u channel, slave, sn, sc;
2905 Bit8u type;
2906 Bit16u max;
2908 channel = device / 2;
2909 slave = device % 2;
2911 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2912 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2914 // Reset
2916 // 8.2.1 (a) -- set SRST in DC
2917 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2919 // 8.2.1 (b) -- wait for BSY
2920 await_ide(BSY, iobase1, 20);
2922 // 8.2.1 (f) -- clear SRST
2923 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2925 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2926 if (type != ATA_TYPE_NONE) {
2928 // 8.2.1 (g) -- check for sc==sn==0x01
2929 // select device
2930 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2931 sc = inb(iobase1+ATA_CB_SC);
2932 sn = inb(iobase1+ATA_CB_SN);
2934 if ( (sc==0x01) && (sn==0x01) ) {
2935 if (type == ATA_TYPE_ATA) //ATA
2936 await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT);
2937 else //ATAPI
2938 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
2941 // 8.2.1 (h) -- wait for not BSY
2942 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
2945 // Enable interrupts
2946 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2949 // ---------------------------------------------------------------------------
2950 // ATA/ATAPI driver : execute a non data command
2951 // ---------------------------------------------------------------------------
2953 Bit16u ata_cmd_non_data()
2954 {return 0;}
2956 // ---------------------------------------------------------------------------
2957 // ATA/ATAPI driver : execute a data-in command
2958 // ---------------------------------------------------------------------------
2959 // returns
2960 // 0 : no error
2961 // 1 : BUSY bit set
2962 // 2 : read error
2963 // 3 : expected DRQ=1
2964 // 4 : no sectors left to read/verify
2965 // 5 : more sectors to read/verify
2966 // 6 : no sectors left to write
2967 // 7 : more sectors to write
2968 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
2969 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2970 Bit32u lba_low, lba_high;
2972 Bit16u ebda_seg=read_word(0x0040,0x000E);
2973 Bit16u iobase1, iobase2, blksize;
2974 Bit8u channel, slave;
2975 Bit8u status, current, mode;
2977 channel = device / 2;
2978 slave = device % 2;
2980 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2981 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2982 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2983 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2984 if (mode == ATA_MODE_PIO32) blksize>>=2;
2985 else blksize>>=1;
2987 // Reset count of transferred data
2988 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2989 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2990 current = 0;
2992 status = inb(iobase1 + ATA_CB_STAT);
2993 if (status & ATA_CB_STAT_BSY) return 1;
2995 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2997 // sector will be 0 only on lba access. Convert to lba-chs
2998 if (sector == 0) {
2999 if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
3000 outb(iobase1 + ATA_CB_FR, 0x00);
3001 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
3002 outb(iobase1 + ATA_CB_SN, lba_low >> 24);
3003 outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
3004 outb(iobase1 + ATA_CB_CH, lba_high >> 8);
3005 command |= 0x04;
3006 count &= (1UL << 8) - 1;
3007 lba_low &= (1UL << 24) - 1;
3009 sector = (Bit16u) (lba_low & 0x000000ffL);
3010 cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
3011 head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
3014 outb(iobase1 + ATA_CB_FR, 0x00);
3015 outb(iobase1 + ATA_CB_SC, count);
3016 outb(iobase1 + ATA_CB_SN, sector);
3017 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3018 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3019 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3020 outb(iobase1 + ATA_CB_CMD, command);
3022 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3023 status = inb(iobase1 + ATA_CB_STAT);
3025 if (status & ATA_CB_STAT_ERR) {
3026 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
3027 return 2;
3028 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3029 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
3030 return 3;
3033 // FIXME : move seg/off translation here
3035 ASM_START
3036 sti ;; enable higher priority interrupts
3037 ASM_END
3039 while (1) {
3041 ASM_START
3042 push bp
3043 mov bp, sp
3044 mov di, _ata_cmd_data_in.offset + 2[bp]
3045 mov ax, _ata_cmd_data_in.segment + 2[bp]
3046 mov cx, _ata_cmd_data_in.blksize + 2[bp]
3048 ;; adjust if there will be an overrun. 2K max sector size
3049 cmp di, #0xf800 ;;
3050 jbe ata_in_no_adjust
3052 ata_in_adjust:
3053 sub di, #0x0800 ;; sub 2 kbytes from offset
3054 add ax, #0x0080 ;; add 2 Kbytes to segment
3056 ata_in_no_adjust:
3057 mov es, ax ;; segment in es
3059 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
3061 mov ah, _ata_cmd_data_in.mode + 2[bp]
3062 cmp ah, #ATA_MODE_PIO32
3063 je ata_in_32
3065 ata_in_16:
3066 rep
3067 insw ;; CX words transfered from port(DX) to ES:[DI]
3068 jmp ata_in_done
3070 ata_in_32:
3071 rep
3072 insd ;; CX dwords transfered from port(DX) to ES:[DI]
3074 ata_in_done:
3075 mov _ata_cmd_data_in.offset + 2[bp], di
3076 mov _ata_cmd_data_in.segment + 2[bp], es
3077 pop bp
3078 ASM_END
3080 current++;
3081 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3082 count--;
3083 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
3084 status = inb(iobase1 + ATA_CB_STAT);
3085 if (count == 0) {
3086 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3087 != ATA_CB_STAT_RDY ) {
3088 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3089 return 4;
3091 break;
3093 else {
3094 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3095 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3096 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3097 return 5;
3099 continue;
3102 // Enable interrupts
3103 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3104 return 0;
3107 // ---------------------------------------------------------------------------
3108 // ATA/ATAPI driver : execute a data-out command
3109 // ---------------------------------------------------------------------------
3110 // returns
3111 // 0 : no error
3112 // 1 : BUSY bit set
3113 // 2 : read error
3114 // 3 : expected DRQ=1
3115 // 4 : no sectors left to read/verify
3116 // 5 : more sectors to read/verify
3117 // 6 : no sectors left to write
3118 // 7 : more sectors to write
3119 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
3120 Bit16u device, command, count, cylinder, head, sector, segment, offset;
3121 Bit32u lba_low, lba_high;
3123 Bit16u ebda_seg=read_word(0x0040,0x000E);
3124 Bit16u iobase1, iobase2, blksize;
3125 Bit8u channel, slave;
3126 Bit8u status, current, mode;
3128 channel = device / 2;
3129 slave = device % 2;
3131 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3132 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3133 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3134 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3135 if (mode == ATA_MODE_PIO32) blksize>>=2;
3136 else blksize>>=1;
3138 // Reset count of transferred data
3139 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3140 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3141 current = 0;
3143 status = inb(iobase1 + ATA_CB_STAT);
3144 if (status & ATA_CB_STAT_BSY) return 1;
3146 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3148 // sector will be 0 only on lba access. Convert to lba-chs
3149 if (sector == 0) {
3150 if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
3151 outb(iobase1 + ATA_CB_FR, 0x00);
3152 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
3153 outb(iobase1 + ATA_CB_SN, lba_low >> 24);
3154 outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
3155 outb(iobase1 + ATA_CB_CH, lba_high >> 8);
3156 command |= 0x04;
3157 count &= (1UL << 8) - 1;
3158 lba_low &= (1UL << 24) - 1;
3160 sector = (Bit16u) (lba_low & 0x000000ffL);
3161 cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
3162 head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
3165 outb(iobase1 + ATA_CB_FR, 0x00);
3166 outb(iobase1 + ATA_CB_SC, count);
3167 outb(iobase1 + ATA_CB_SN, sector);
3168 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3169 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3170 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3171 outb(iobase1 + ATA_CB_CMD, command);
3173 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3174 status = inb(iobase1 + ATA_CB_STAT);
3176 if (status & ATA_CB_STAT_ERR) {
3177 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3178 return 2;
3179 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3180 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3181 return 3;
3184 // FIXME : move seg/off translation here
3186 ASM_START
3187 sti ;; enable higher priority interrupts
3188 ASM_END
3190 while (1) {
3192 ASM_START
3193 push bp
3194 mov bp, sp
3195 mov si, _ata_cmd_data_out.offset + 2[bp]
3196 mov ax, _ata_cmd_data_out.segment + 2[bp]
3197 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3199 ;; adjust if there will be an overrun. 2K max sector size
3200 cmp si, #0xf800 ;;
3201 jbe ata_out_no_adjust
3203 ata_out_adjust:
3204 sub si, #0x0800 ;; sub 2 kbytes from offset
3205 add ax, #0x0080 ;; add 2 Kbytes to segment
3207 ata_out_no_adjust:
3208 mov es, ax ;; segment in es
3210 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3212 mov ah, _ata_cmd_data_out.mode + 2[bp]
3213 cmp ah, #ATA_MODE_PIO32
3214 je ata_out_32
3216 ata_out_16:
3217 seg ES
3218 rep
3219 outsw ;; CX words transfered from port(DX) to ES:[SI]
3220 jmp ata_out_done
3222 ata_out_32:
3223 seg ES
3224 rep
3225 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3227 ata_out_done:
3228 mov _ata_cmd_data_out.offset + 2[bp], si
3229 mov _ata_cmd_data_out.segment + 2[bp], es
3230 pop bp
3231 ASM_END
3233 current++;
3234 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3235 count--;
3236 status = inb(iobase1 + ATA_CB_STAT);
3237 if (count == 0) {
3238 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3239 != ATA_CB_STAT_RDY ) {
3240 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3241 return 6;
3243 break;
3245 else {
3246 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3247 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3248 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3249 return 7;
3251 continue;
3254 // Enable interrupts
3255 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3256 return 0;
3259 // ---------------------------------------------------------------------------
3260 // ATA/ATAPI driver : execute a packet command
3261 // ---------------------------------------------------------------------------
3262 // returns
3263 // 0 : no error
3264 // 1 : error in parameters
3265 // 2 : BUSY bit set
3266 // 3 : error
3267 // 4 : not ready
3268 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3269 Bit8u cmdlen,inout;
3270 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3271 Bit16u header;
3272 Bit32u length;
3274 Bit16u ebda_seg=read_word(0x0040,0x000E);
3275 Bit16u iobase1, iobase2;
3276 Bit16u lcount, lbefore, lafter, count;
3277 Bit8u channel, slave;
3278 Bit8u status, mode, lmode;
3279 Bit32u total, transfer;
3281 channel = device / 2;
3282 slave = device % 2;
3284 // Data out is not supported yet
3285 if (inout == ATA_DATA_OUT) {
3286 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3287 return 1;
3290 // The header length must be even
3291 if (header & 1) {
3292 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3293 return 1;
3296 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3297 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3298 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3299 transfer= 0L;
3301 if (cmdlen < 12) cmdlen=12;
3302 if (cmdlen > 12) cmdlen=16;
3303 cmdlen>>=1;
3305 // Reset count of transferred data
3306 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3307 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3309 status = inb(iobase1 + ATA_CB_STAT);
3310 if (status & ATA_CB_STAT_BSY) return 2;
3312 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3313 outb(iobase1 + ATA_CB_FR, 0x00);
3314 outb(iobase1 + ATA_CB_SC, 0x00);
3315 outb(iobase1 + ATA_CB_SN, 0x00);
3316 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3317 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3318 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3319 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3321 // Device should ok to receive command
3322 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3323 status = inb(iobase1 + ATA_CB_STAT);
3325 if (status & ATA_CB_STAT_ERR) {
3326 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3327 return 3;
3328 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3329 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3330 return 4;
3333 // Normalize address
3334 cmdseg += (cmdoff / 16);
3335 cmdoff %= 16;
3337 // Send command to device
3338 ASM_START
3339 sti ;; enable higher priority interrupts
3341 push bp
3342 mov bp, sp
3344 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3345 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3346 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3347 mov es, ax ;; segment in es
3349 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3351 seg ES
3352 rep
3353 outsw ;; CX words transfered from port(DX) to ES:[SI]
3355 pop bp
3356 ASM_END
3358 if (inout == ATA_DATA_NO) {
3359 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
3360 status = inb(iobase1 + ATA_CB_STAT);
3362 else {
3363 Bit16u loops = 0;
3364 Bit8u sc;
3365 while (1) {
3367 if (loops == 0) {//first time through
3368 status = inb(iobase2 + ATA_CB_ASTAT);
3369 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
3371 else
3372 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
3373 loops++;
3375 status = inb(iobase1 + ATA_CB_STAT);
3376 sc = inb(iobase1 + ATA_CB_SC);
3378 // Check if command completed
3379 if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) &&
3380 ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) break;
3382 if (status & ATA_CB_STAT_ERR) {
3383 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3384 return 3;
3387 // Normalize address
3388 bufseg += (bufoff / 16);
3389 bufoff %= 16;
3391 // Get the byte count
3392 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3394 // adjust to read what we want
3395 if(header>lcount) {
3396 lbefore=lcount;
3397 header-=lcount;
3398 lcount=0;
3400 else {
3401 lbefore=header;
3402 header=0;
3403 lcount-=lbefore;
3406 if(lcount>length) {
3407 lafter=lcount-length;
3408 lcount=length;
3409 length=0;
3411 else {
3412 lafter=0;
3413 length-=lcount;
3416 // Save byte count
3417 count = lcount;
3419 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3420 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3422 // If counts not dividable by 4, use 16bits mode
3423 lmode = mode;
3424 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3425 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3426 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3428 // adds an extra byte if count are odd. before is always even
3429 if (lcount & 0x01) {
3430 lcount+=1;
3431 if ((lafter > 0) && (lafter & 0x01)) {
3432 lafter-=1;
3436 if (lmode == ATA_MODE_PIO32) {
3437 lcount>>=2; lbefore>>=2; lafter>>=2;
3439 else {
3440 lcount>>=1; lbefore>>=1; lafter>>=1;
3443 ; // FIXME bcc bug
3445 ASM_START
3446 push bp
3447 mov bp, sp
3449 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3451 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3452 jcxz ata_packet_no_before
3454 mov ah, _ata_cmd_packet.lmode + 2[bp]
3455 cmp ah, #ATA_MODE_PIO32
3456 je ata_packet_in_before_32
3458 ata_packet_in_before_16:
3459 in ax, dx
3460 loop ata_packet_in_before_16
3461 jmp ata_packet_no_before
3463 ata_packet_in_before_32:
3464 push eax
3465 ata_packet_in_before_32_loop:
3466 in eax, dx
3467 loop ata_packet_in_before_32_loop
3468 pop eax
3470 ata_packet_no_before:
3471 mov cx, _ata_cmd_packet.lcount + 2[bp]
3472 jcxz ata_packet_after
3474 mov di, _ata_cmd_packet.bufoff + 2[bp]
3475 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3476 mov es, ax
3478 mov ah, _ata_cmd_packet.lmode + 2[bp]
3479 cmp ah, #ATA_MODE_PIO32
3480 je ata_packet_in_32
3482 ata_packet_in_16:
3483 rep
3484 insw ;; CX words transfered tp port(DX) to ES:[DI]
3485 jmp ata_packet_after
3487 ata_packet_in_32:
3488 rep
3489 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3491 ata_packet_after:
3492 mov cx, _ata_cmd_packet.lafter + 2[bp]
3493 jcxz ata_packet_done
3495 mov ah, _ata_cmd_packet.lmode + 2[bp]
3496 cmp ah, #ATA_MODE_PIO32
3497 je ata_packet_in_after_32
3499 ata_packet_in_after_16:
3500 in ax, dx
3501 loop ata_packet_in_after_16
3502 jmp ata_packet_done
3504 ata_packet_in_after_32:
3505 push eax
3506 ata_packet_in_after_32_loop:
3507 in eax, dx
3508 loop ata_packet_in_after_32_loop
3509 pop eax
3511 ata_packet_done:
3512 pop bp
3513 ASM_END
3515 // Compute new buffer address
3516 bufoff += count;
3518 // Save transferred bytes count
3519 transfer += count;
3520 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3524 // Final check, device must be ready
3525 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3526 != ATA_CB_STAT_RDY ) {
3527 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3528 return 4;
3531 // Enable interrupts
3532 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3533 return 0;
3536 // ---------------------------------------------------------------------------
3537 // End of ATA/ATAPI Driver
3538 // ---------------------------------------------------------------------------
3540 // ---------------------------------------------------------------------------
3541 // Start of ATA/ATAPI generic functions
3542 // ---------------------------------------------------------------------------
3544 Bit16u
3545 atapi_get_sense(device, seg, asc, ascq)
3546 Bit16u device;
3548 Bit8u atacmd[12];
3549 Bit8u buffer[18];
3550 Bit8u i;
3552 memsetb(get_SS(),atacmd,0,12);
3554 // Request SENSE
3555 atacmd[0]=ATA_CMD_REQUEST_SENSE;
3556 atacmd[4]=sizeof(buffer);
3557 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 18L, ATA_DATA_IN, get_SS(), buffer) != 0)
3558 return 0x0002;
3560 write_byte(seg,asc,buffer[12]);
3561 write_byte(seg,ascq,buffer[13]);
3563 return 0;
3566 Bit16u
3567 atapi_is_ready(device)
3568 Bit16u device;
3570 Bit8u packet[12];
3571 Bit8u buf[8];
3572 Bit32u block_len;
3573 Bit32u sectors;
3574 Bit32u timeout; //measured in ms
3575 Bit32u time;
3576 Bit8u asc, ascq;
3577 Bit8u in_progress;
3578 Bit16u ebda_seg = read_word(0x0040,0x000E);
3579 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) {
3580 printf("not implemented for non-ATAPI device\n");
3581 return -1;
3584 BX_DEBUG_ATA("ata_detect_medium: begin\n");
3585 memsetb(get_SS(),packet, 0, sizeof packet);
3586 packet[0] = 0x25; /* READ CAPACITY */
3588 /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
3589 * is reported by the device. If the device reports "IN PROGRESS",
3590 * 30 seconds is added. */
3591 timeout = 5000;
3592 time = 0;
3593 in_progress = 0;
3594 while (time < timeout) {
3595 if (ata_cmd_packet(device, sizeof(packet), get_SS(), packet, 0, 8L, ATA_DATA_IN, get_SS(), buf) == 0)
3596 goto ok;
3598 if (atapi_get_sense(device, get_SS(), &asc, &ascq) == 0) {
3599 if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
3600 BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
3601 return -1;
3604 if (asc == 0x04 && ascq == 0x01 && !in_progress) {
3605 /* IN PROGRESS OF BECOMING READY */
3606 printf("Waiting for device to detect medium... ");
3607 /* Allow 30 seconds more */
3608 timeout = 30000;
3609 in_progress = 1;
3612 time += 100;
3614 BX_DEBUG_ATA("read capacity failed\n");
3615 return -1;
3616 ok:
3618 block_len = (Bit32u) buf[4] << 24
3619 | (Bit32u) buf[5] << 16
3620 | (Bit32u) buf[6] << 8
3621 | (Bit32u) buf[7] << 0;
3622 BX_DEBUG_ATA("block_len=%u\n", block_len);
3624 if (block_len!= 2048 && block_len!= 512)
3626 printf("Unsupported sector size %u\n", block_len);
3627 return -1;
3629 write_dword(ebda_seg,&EbdaData->ata.devices[device].blksize, block_len);
3631 sectors = (Bit32u) buf[0] << 24
3632 | (Bit32u) buf[1] << 16
3633 | (Bit32u) buf[2] << 8
3634 | (Bit32u) buf[3] << 0;
3636 BX_DEBUG_ATA("sectors=%u\n", sectors);
3637 if (block_len == 2048)
3638 sectors <<= 2; /* # of sectors in 512-byte "soft" sector */
3639 if (sectors != read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low))
3640 printf("%dMB medium detected\n", sectors>>(20-9));
3641 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors);
3642 return 0;
3645 Bit16u
3646 atapi_is_cdrom(device)
3647 Bit8u device;
3649 Bit16u ebda_seg=read_word(0x0040,0x000E);
3651 if (device >= BX_MAX_ATA_DEVICES)
3652 return 0;
3654 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3655 return 0;
3657 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3658 return 0;
3660 return 1;
3663 // ---------------------------------------------------------------------------
3664 // End of ATA/ATAPI generic functions
3665 // ---------------------------------------------------------------------------
3667 #endif // BX_USE_ATADRV
3669 #if BX_ELTORITO_BOOT
3671 // ---------------------------------------------------------------------------
3672 // Start of El-Torito boot functions
3673 // ---------------------------------------------------------------------------
3675 void
3676 cdemu_init()
3678 Bit16u ebda_seg=read_word(0x0040,0x000E);
3680 // the only important data is this one for now
3681 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3684 Bit8u
3685 cdemu_isactive()
3687 Bit16u ebda_seg=read_word(0x0040,0x000E);
3689 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3692 Bit8u
3693 cdemu_emulated_drive()
3695 Bit16u ebda_seg=read_word(0x0040,0x000E);
3697 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3700 static char isotag[6]="CD001";
3701 static char eltorito[24]="EL TORITO SPECIFICATION";
3702 //
3703 // Returns ah: emulated drive, al: error code
3704 //
3705 Bit16u
3706 cdrom_boot()
3708 Bit16u ebda_seg=read_word(0x0040,0x000E);
3709 Bit8u atacmd[12], buffer[2048];
3710 Bit32u lba;
3711 Bit16u boot_segment, nbsectors, i, error;
3712 Bit8u device;
3714 // Find out the first cdrom
3715 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3716 if (atapi_is_cdrom(device)) break;
3719 // if not found
3720 if(device >= BX_MAX_ATA_DEVICES) return 2;
3722 if(error = atapi_is_ready(device) != 0)
3723 BX_INFO("ata_is_ready returned %d\n",error);
3725 // Read the Boot Record Volume Descriptor
3726 memsetb(get_SS(),atacmd,0,12);
3727 atacmd[0]=0x28; // READ command
3728 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3729 atacmd[8]=(0x01 & 0x00ff); // Sectors
3730 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3731 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3732 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3733 atacmd[5]=(0x11 & 0x000000ff);
3734 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3735 return 3;
3737 // Validity checks
3738 if(buffer[0]!=0)return 4;
3739 for(i=0;i<5;i++){
3740 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3742 for(i=0;i<23;i++)
3743 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3745 // ok, now we calculate the Boot catalog address
3746 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3748 // And we read the Boot Catalog
3749 memsetb(get_SS(),atacmd,0,12);
3750 atacmd[0]=0x28; // READ command
3751 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3752 atacmd[8]=(0x01 & 0x00ff); // Sectors
3753 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3754 atacmd[3]=(lba & 0x00ff0000) >> 16;
3755 atacmd[4]=(lba & 0x0000ff00) >> 8;
3756 atacmd[5]=(lba & 0x000000ff);
3757 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3758 return 7;
3760 // Validation entry
3761 if(buffer[0x00]!=0x01)return 8; // Header
3762 if(buffer[0x01]!=0x00)return 9; // Platform
3763 if(buffer[0x1E]!=0x55)return 10; // key 1
3764 if(buffer[0x1F]!=0xAA)return 10; // key 2
3766 // Initial/Default Entry
3767 if(buffer[0x20]!=0x88)return 11; // Bootable
3769 #if BX_TCGBIOS
3770 /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
3771 /* measure 2048 bytes (one sector) */
3772 tcpa_add_bootdevice((Bit32u)1L, (Bit32u)0L); /* bootcd = 1 */
3773 tcpa_ipl((Bit32u)2L,(Bit32u)get_SS(),(Bit32u)buffer,(Bit32u)2048L);
3774 #endif
3776 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3777 if(buffer[0x21]==0){
3778 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3779 // Win2000 cd boot needs to know it booted from cd
3780 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3782 else if(buffer[0x21]<4)
3783 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3784 else
3785 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3787 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3788 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3790 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3791 if(boot_segment==0x0000)boot_segment=0x07C0;
3793 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3794 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3796 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3797 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3799 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3800 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3802 // And we read the image in memory
3803 memsetb(get_SS(),atacmd,0,12);
3804 atacmd[0]=0x28; // READ command
3805 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3806 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3807 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3808 atacmd[3]=(lba & 0x00ff0000) >> 16;
3809 atacmd[4]=(lba & 0x0000ff00) >> 8;
3810 atacmd[5]=(lba & 0x000000ff);
3811 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3812 return 12;
3814 #if BX_TCGBIOS
3815 /* specs: 8.2.3 step 4 and 8.2.5.6, measure El Torito boot image */
3816 /* measure 1st 512 bytes */
3817 tcpa_ipl((Bit32u)1L,(Bit32u)boot_segment,(Bit32u)0L,(Bit32u)512L);
3818 #endif
3820 // Remember the media type
3821 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3822 case 0x01: // 1.2M floppy
3823 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3824 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3825 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3826 break;
3827 case 0x02: // 1.44M floppy
3828 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3829 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3830 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3831 break;
3832 case 0x03: // 2.88M floppy
3833 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3834 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3835 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3836 break;
3837 case 0x04: // Harddrive
3838 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3839 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3840 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3841 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3842 break;
3845 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3846 // Increase bios installed hardware number of devices
3847 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3848 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3849 else
3850 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3854 // everything is ok, so from now on, the emulation is active
3855 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3856 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3858 // return the boot drive + no error
3859 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3862 // ---------------------------------------------------------------------------
3863 // End of El-Torito boot functions
3864 // ---------------------------------------------------------------------------
3865 #endif // BX_ELTORITO_BOOT
3867 void
3868 int14_function(regs, ds, iret_addr)
3869 pusha_regs_t regs; // regs pushed from PUSHA instruction
3870 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3871 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3873 Bit16u addr,timer,val16;
3874 Bit8u timeout;
3876 ASM_START
3877 sti
3878 ASM_END
3880 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3881 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3882 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3883 switch (regs.u.r8.ah) {
3884 case 0:
3885 outb(addr+3, inb(addr+3) | 0x80);
3886 if (regs.u.r8.al & 0xE0 == 0) {
3887 outb(addr, 0x17);
3888 outb(addr+1, 0x04);
3889 } else {
3890 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3891 outb(addr, val16 & 0xFF);
3892 outb(addr+1, val16 >> 8);
3894 outb(addr+3, regs.u.r8.al & 0x1F);
3895 regs.u.r8.ah = inb(addr+5);
3896 regs.u.r8.al = inb(addr+6);
3897 ClearCF(iret_addr.flags);
3898 break;
3899 case 1:
3900 timer = read_word(0x0040, 0x006C);
3901 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3902 val16 = read_word(0x0040, 0x006C);
3903 if (val16 != timer) {
3904 timer = val16;
3905 timeout--;
3908 if (timeout) outb(addr, regs.u.r8.al);
3909 regs.u.r8.ah = inb(addr+5);
3910 if (!timeout) regs.u.r8.ah |= 0x80;
3911 ClearCF(iret_addr.flags);
3912 break;
3913 case 2:
3914 timer = read_word(0x0040, 0x006C);
3915 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3916 val16 = read_word(0x0040, 0x006C);
3917 if (val16 != timer) {
3918 timer = val16;
3919 timeout--;
3922 if (timeout) {
3923 regs.u.r8.ah = 0;
3924 regs.u.r8.al = inb(addr);
3925 } else {
3926 regs.u.r8.ah = inb(addr+5);
3928 ClearCF(iret_addr.flags);
3929 break;
3930 case 3:
3931 regs.u.r8.ah = inb(addr+5);
3932 regs.u.r8.al = inb(addr+6);
3933 ClearCF(iret_addr.flags);
3934 break;
3935 default:
3936 SetCF(iret_addr.flags); // Unsupported
3938 } else {
3939 SetCF(iret_addr.flags); // Unsupported
3943 void
3944 int15_function(regs, ES, DS, FLAGS)
3945 pusha_regs_t regs; // REGS pushed via pusha
3946 Bit16u ES, DS, FLAGS;
3948 Bit16u ebda_seg=read_word(0x0040,0x000E);
3949 bx_bool prev_a20_enable;
3950 Bit16u base15_00;
3951 Bit8u base23_16;
3952 Bit16u ss;
3953 Bit16u CX,DX;
3955 Bit16u bRegister;
3956 Bit8u irqDisable;
3958 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3960 switch (regs.u.r8.ah) {
3961 case 0x24: /* A20 Control */
3962 switch (regs.u.r8.al) {
3963 case 0x00:
3964 set_enable_a20(0);
3965 CLEAR_CF();
3966 regs.u.r8.ah = 0;
3967 break;
3968 case 0x01:
3969 set_enable_a20(1);
3970 CLEAR_CF();
3971 regs.u.r8.ah = 0;
3972 break;
3973 case 0x02:
3974 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3975 CLEAR_CF();
3976 regs.u.r8.ah = 0;
3977 break;
3978 case 0x03:
3979 CLEAR_CF();
3980 regs.u.r8.ah = 0;
3981 regs.u.r16.bx = 3;
3982 break;
3983 default:
3984 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3985 SET_CF();
3986 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3988 break;
3990 case 0x41:
3991 SET_CF();
3992 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3993 break;
3995 case 0x4f:
3996 /* keyboard intercept */
3997 #if BX_CPU < 2
3998 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3999 #else
4000 // nop
4001 #endif
4002 SET_CF();
4003 break;
4005 case 0x52: // removable media eject
4006 CLEAR_CF();
4007 regs.u.r8.ah = 0; // "ok ejection may proceed"
4008 break;
4010 case 0x83: {
4011 if( regs.u.r8.al == 0 ) {
4012 // Set Interval requested.
4013 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
4014 // Interval not already set.
4015 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
4016 write_word( 0x40, 0x98, ES ); // Byte location, segment
4017 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
4018 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
4019 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
4020 CLEAR_CF( );
4021 irqDisable = inb( 0xA1 );
4022 outb( 0xA1, irqDisable & 0xFE );
4023 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
4024 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
4025 } else {
4026 // Interval already set.
4027 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
4028 SET_CF();
4029 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4031 } else if( regs.u.r8.al == 1 ) {
4032 // Clear Interval requested
4033 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
4034 CLEAR_CF( );
4035 bRegister = inb_cmos( 0xB );
4036 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
4037 } else {
4038 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
4039 SET_CF();
4040 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4041 regs.u.r8.al--;
4044 break;
4047 case 0x87:
4048 #if BX_CPU < 3
4049 # error "Int15 function 87h not supported on < 80386"
4050 #endif
4051 // +++ should probably have descriptor checks
4052 // +++ should have exception handlers
4054 // turn off interrupts
4055 ASM_START
4056 cli
4057 ASM_END
4059 prev_a20_enable = set_enable_a20(1); // enable A20 line
4061 // 128K max of transfer on 386+ ???
4062 // source == destination ???
4064 // ES:SI points to descriptor table
4065 // offset use initially comments
4066 // ==============================================
4067 // 00..07 Unused zeros Null descriptor
4068 // 08..0f GDT zeros filled in by BIOS
4069 // 10..17 source ssssssss source of data
4070 // 18..1f dest dddddddd destination of data
4071 // 20..27 CS zeros filled in by BIOS
4072 // 28..2f SS zeros filled in by BIOS
4074 //es:si
4075 //eeee0
4076 //0ssss
4077 //-----
4079 // check for access rights of source & dest here
4081 // Initialize GDT descriptor
4082 base15_00 = (ES << 4) + regs.u.r16.si;
4083 base23_16 = ES >> 12;
4084 if (base15_00 < (ES<<4))
4085 base23_16++;
4086 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4087 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4088 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4089 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4090 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4092 // Initialize CS descriptor
4093 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4094 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4095 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4096 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4097 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4099 // Initialize SS descriptor
4100 ss = get_SS();
4101 base15_00 = ss << 4;
4102 base23_16 = ss >> 12;
4103 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4104 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4105 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4106 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4107 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4109 CX = regs.u.r16.cx;
4110 ASM_START
4111 // Compile generates locals offset info relative to SP.
4112 // Get CX (word count) from stack.
4113 mov bx, sp
4114 SEG SS
4115 mov cx, _int15_function.CX [bx]
4117 // since we need to set SS:SP, save them to the BDA
4118 // for future restore
4119 push eax
4120 xor eax, eax
4121 mov ds, ax
4122 mov 0x0469, ss
4123 mov 0x0467, sp
4125 SEG ES
4126 lgdt [si + 0x08]
4127 SEG CS
4128 lidt [pmode_IDT_info]
4129 ;; perhaps do something with IDT here
4131 ;; set PE bit in CR0
4132 mov eax, cr0
4133 or al, #0x01
4134 mov cr0, eax
4135 ;; far jump to flush CPU queue after transition to protected mode
4136 JMP_AP(0x0020, protected_mode)
4138 protected_mode:
4139 ;; GDT points to valid descriptor table, now load SS, DS, ES
4140 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4141 mov ss, ax
4142 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4143 mov ds, ax
4144 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4145 mov es, ax
4146 xor si, si
4147 xor di, di
4148 cld
4149 rep
4150 movsw ;; move CX words from DS:SI to ES:DI
4152 ;; make sure DS and ES limits are 64KB
4153 mov ax, #0x28
4154 mov ds, ax
4155 mov es, ax
4157 ;; reset PG bit in CR0 ???
4158 mov eax, cr0
4159 and al, #0xFE
4160 mov cr0, eax
4162 ;; far jump to flush CPU queue after transition to real mode
4163 JMP_AP(0xf000, real_mode)
4165 real_mode:
4166 ;; restore IDT to normal real-mode defaults
4167 SEG CS
4168 lidt [rmode_IDT_info]
4170 // restore SS:SP from the BDA
4171 xor ax, ax
4172 mov ds, ax
4173 mov ss, 0x0469
4174 mov sp, 0x0467
4175 pop eax
4176 ASM_END
4178 set_enable_a20(prev_a20_enable);
4180 // turn back on interrupts
4181 ASM_START
4182 sti
4183 ASM_END
4185 regs.u.r8.ah = 0;
4186 CLEAR_CF();
4187 break;
4190 case 0x88:
4191 // Get the amount of extended memory (above 1M)
4192 #if BX_CPU < 2
4193 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4194 SET_CF();
4195 #else
4196 regs.u.r8.al = inb_cmos(0x30);
4197 regs.u.r8.ah = inb_cmos(0x31);
4199 // According to Ralf Brown's interrupt the limit should be 15M,
4200 // but real machines mostly return max. 63M.
4201 if(regs.u.r16.ax > 0xffc0)
4202 regs.u.r16.ax = 0xffc0;
4204 CLEAR_CF();
4205 #endif
4206 break;
4208 case 0x90:
4209 /* Device busy interrupt. Called by Int 16h when no key available */
4210 break;
4212 case 0x91:
4213 /* Interrupt complete. Called by Int 16h when key becomes available */
4214 break;
4216 case 0xbf:
4217 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4218 SET_CF();
4219 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4220 break;
4222 case 0xC0:
4223 #if 0
4224 SET_CF();
4225 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4226 break;
4227 #endif
4228 CLEAR_CF();
4229 regs.u.r8.ah = 0;
4230 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4231 ES = 0xF000;
4232 break;
4234 case 0xc1:
4235 ES = ebda_seg;
4236 CLEAR_CF();
4237 break;
4239 case 0xd8:
4240 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4241 SET_CF();
4242 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4243 break;
4245 default:
4246 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4247 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4248 SET_CF();
4249 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4250 break;
4254 #if BX_USE_PS2_MOUSE
4255 void
4256 int15_function_mouse(regs, ES, DS, FLAGS)
4257 pusha_regs_t regs; // REGS pushed via pusha
4258 Bit16u ES, DS, FLAGS;
4260 Bit16u ebda_seg=read_word(0x0040,0x000E);
4261 Bit8u mouse_flags_1, mouse_flags_2;
4262 Bit16u mouse_driver_seg;
4263 Bit16u mouse_driver_offset;
4264 Bit8u comm_byte, prev_command_byte;
4265 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4267 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4269 switch (regs.u.r8.ah) {
4270 case 0xC2:
4271 // Return Codes status in AH
4272 // =========================
4273 // 00: success
4274 // 01: invalid subfunction (AL > 7)
4275 // 02: invalid input value (out of allowable range)
4276 // 03: interface error
4277 // 04: resend command received from mouse controller,
4278 // device driver should attempt command again
4279 // 05: cannot enable mouse, since no far call has been installed
4280 // 80/86: mouse service not implemented
4282 switch (regs.u.r8.al) {
4283 case 0: // Disable/Enable Mouse
4284 BX_DEBUG_INT15("case 0:\n");
4285 switch (regs.u.r8.bh) {
4286 case 0: // Disable Mouse
4287 BX_DEBUG_INT15("case 0: disable mouse\n");
4288 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4289 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
4290 if (ret == 0) {
4291 ret = get_mouse_data(&mouse_data1);
4292 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4293 CLEAR_CF();
4294 regs.u.r8.ah = 0;
4295 return;
4299 // error
4300 SET_CF();
4301 regs.u.r8.ah = ret;
4302 return;
4303 break;
4305 case 1: // Enable Mouse
4306 BX_DEBUG_INT15("case 1: enable mouse\n");
4307 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4308 if ( (mouse_flags_2 & 0x80) == 0 ) {
4309 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4310 SET_CF(); // error
4311 regs.u.r8.ah = 5; // no far call installed
4312 return;
4314 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4315 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
4316 if (ret == 0) {
4317 ret = get_mouse_data(&mouse_data1);
4318 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
4319 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4320 CLEAR_CF();
4321 regs.u.r8.ah = 0;
4322 return;
4325 SET_CF();
4326 regs.u.r8.ah = ret;
4327 return;
4329 default: // invalid subfunction
4330 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4331 SET_CF(); // error
4332 regs.u.r8.ah = 1; // invalid subfunction
4333 return;
4335 break;
4337 case 1: // Reset Mouse
4338 case 5: // Initialize Mouse
4339 BX_DEBUG_INT15("case 1 or 5:\n");
4340 if (regs.u.r8.al == 5) {
4341 if (regs.u.r8.bh != 3) {
4342 SET_CF();
4343 regs.u.r8.ah = 0x02; // invalid input
4344 return;
4346 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4347 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
4348 mouse_flags_1 = 0x00;
4349 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4350 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4353 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4354 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4355 if (ret == 0) {
4356 ret = get_mouse_data(&mouse_data3);
4357 // if no mouse attached, it will return RESEND
4358 if (mouse_data3 == 0xfe) {
4359 SET_CF();
4360 return;
4362 if (mouse_data3 != 0xfa)
4363 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4364 if ( ret == 0 ) {
4365 ret = get_mouse_data(&mouse_data1);
4366 if ( ret == 0 ) {
4367 ret = get_mouse_data(&mouse_data2);
4368 if ( ret == 0 ) {
4369 // turn IRQ12 and packet generation on
4370 enable_mouse_int_and_events();
4371 CLEAR_CF();
4372 regs.u.r8.ah = 0;
4373 regs.u.r8.bl = mouse_data1;
4374 regs.u.r8.bh = mouse_data2;
4375 return;
4381 // error
4382 SET_CF();
4383 regs.u.r8.ah = ret;
4384 return;
4386 case 2: // Set Sample Rate
4387 BX_DEBUG_INT15("case 2:\n");
4388 switch (regs.u.r8.bh) {
4389 case 0: mouse_data1 = 10; break; // 10 reports/sec
4390 case 1: mouse_data1 = 20; break; // 20 reports/sec
4391 case 2: mouse_data1 = 40; break; // 40 reports/sec
4392 case 3: mouse_data1 = 60; break; // 60 reports/sec
4393 case 4: mouse_data1 = 80; break; // 80 reports/sec
4394 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4395 case 6: mouse_data1 = 200; break; // 200 reports/sec
4396 default: mouse_data1 = 0;
4398 if (mouse_data1 > 0) {
4399 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4400 if (ret == 0) {
4401 ret = get_mouse_data(&mouse_data2);
4402 ret = send_to_mouse_ctrl(mouse_data1);
4403 ret = get_mouse_data(&mouse_data2);
4404 CLEAR_CF();
4405 regs.u.r8.ah = 0;
4406 } else {
4407 // error
4408 SET_CF();
4409 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4411 } else {
4412 // error
4413 SET_CF();
4414 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4416 break;
4418 case 3: // Set Resolution
4419 BX_DEBUG_INT15("case 3:\n");
4420 // BH:
4421 // 0 = 25 dpi, 1 count per millimeter
4422 // 1 = 50 dpi, 2 counts per millimeter
4423 // 2 = 100 dpi, 4 counts per millimeter
4424 // 3 = 200 dpi, 8 counts per millimeter
4425 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4426 if (regs.u.r8.bh < 4) {
4427 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4428 if (ret == 0) {
4429 ret = get_mouse_data(&mouse_data1);
4430 if (mouse_data1 != 0xfa)
4431 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4432 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4433 ret = get_mouse_data(&mouse_data1);
4434 if (mouse_data1 != 0xfa)
4435 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4436 CLEAR_CF();
4437 regs.u.r8.ah = 0;
4438 } else {
4439 // error
4440 SET_CF();
4441 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4443 } else {
4444 // error
4445 SET_CF();
4446 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4448 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4449 break;
4451 case 4: // Get Device ID
4452 BX_DEBUG_INT15("case 4:\n");
4453 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4454 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4455 if (ret == 0) {
4456 ret = get_mouse_data(&mouse_data1);
4457 ret = get_mouse_data(&mouse_data2);
4458 CLEAR_CF();
4459 regs.u.r8.ah = 0;
4460 regs.u.r8.bh = mouse_data2;
4461 } else {
4462 // error
4463 SET_CF();
4464 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4466 break;
4468 case 6: // Return Status & Set Scaling Factor...
4469 BX_DEBUG_INT15("case 6:\n");
4470 switch (regs.u.r8.bh) {
4471 case 0: // Return Status
4472 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4473 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4474 if (ret == 0) {
4475 ret = get_mouse_data(&mouse_data1);
4476 if (mouse_data1 != 0xfa)
4477 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4478 if (ret == 0) {
4479 ret = get_mouse_data(&mouse_data1);
4480 if ( ret == 0 ) {
4481 ret = get_mouse_data(&mouse_data2);
4482 if ( ret == 0 ) {
4483 ret = get_mouse_data(&mouse_data3);
4484 if ( ret == 0 ) {
4485 CLEAR_CF();
4486 regs.u.r8.ah = 0;
4487 regs.u.r8.bl = mouse_data1;
4488 regs.u.r8.cl = mouse_data2;
4489 regs.u.r8.dl = mouse_data3;
4490 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4491 return;
4498 // error
4499 SET_CF();
4500 regs.u.r8.ah = ret;
4501 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4502 return;
4504 case 1: // Set Scaling Factor to 1:1
4505 case 2: // Set Scaling Factor to 2:1
4506 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4507 if (regs.u.r8.bh == 1) {
4508 ret = send_to_mouse_ctrl(0xE6);
4509 } else {
4510 ret = send_to_mouse_ctrl(0xE7);
4512 if (ret == 0) {
4513 get_mouse_data(&mouse_data1);
4514 ret = (mouse_data1 != 0xFA);
4516 if (ret == 0) {
4517 CLEAR_CF();
4518 regs.u.r8.ah = 0;
4519 } else {
4520 // error
4521 SET_CF();
4522 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4524 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4525 break;
4527 default:
4528 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4530 break;
4532 case 7: // Set Mouse Handler Address
4533 BX_DEBUG_INT15("case 7:\n");
4534 mouse_driver_seg = ES;
4535 mouse_driver_offset = regs.u.r16.bx;
4536 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4537 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4538 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4539 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4540 /* remove handler */
4541 if ( (mouse_flags_2 & 0x80) != 0 ) {
4542 mouse_flags_2 &= ~0x80;
4543 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4546 else {
4547 /* install handler */
4548 mouse_flags_2 |= 0x80;
4550 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4551 CLEAR_CF();
4552 regs.u.r8.ah = 0;
4553 break;
4555 default:
4556 BX_DEBUG_INT15("case default:\n");
4557 regs.u.r8.ah = 1; // invalid function
4558 SET_CF();
4560 break;
4562 default:
4563 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4564 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4565 SET_CF();
4566 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4567 break;
4570 #endif // BX_USE_PS2_MOUSE
4573 void set_e820_range(ES, DI, start, end, type)
4574 Bit16u ES;
4575 Bit16u DI;
4576 Bit32u start;
4577 Bit32u end;
4578 Bit16u type;
4580 write_word(ES, DI, start);
4581 write_word(ES, DI+2, start >> 16);
4582 write_word(ES, DI+4, 0x00);
4583 write_word(ES, DI+6, 0x00);
4585 end -= start;
4586 write_word(ES, DI+8, end);
4587 write_word(ES, DI+10, end >> 16);
4588 write_word(ES, DI+12, 0x0000);
4589 write_word(ES, DI+14, 0x0000);
4591 write_word(ES, DI+16, type);
4592 write_word(ES, DI+18, 0x0);
4595 void
4596 int15_function32(regs, ES, DS, FLAGS)
4597 pushad_regs_t regs; // REGS pushed via pushad
4598 Bit16u ES, DS, FLAGS;
4600 Bit32u extended_memory_size=0; // 64bits long
4601 Bit16u CX,DX;
4602 #ifdef HVMASSIST
4603 Bit16u off, e820_table_size;
4604 Bit32u base, type, size;
4605 #endif
4607 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4609 switch (regs.u.r8.ah) {
4610 case 0x86:
4611 // Wait for CX:DX microseconds. currently using the
4612 // refresh request port 0x61 bit4, toggling every 15usec
4614 CX = regs.u.r16.cx;
4615 DX = regs.u.r16.dx;
4617 ASM_START
4618 sti
4620 ;; Get the count in eax
4621 mov bx, sp
4622 SEG SS
4623 mov ax, _int15_function32.CX [bx]
4624 shl eax, #16
4625 SEG SS
4626 mov ax, _int15_function32.DX [bx]
4628 ;; convert to numbers of 15usec ticks
4629 mov ebx, #15
4630 xor edx, edx
4631 div eax, ebx
4632 mov ecx, eax
4634 ;; wait for ecx number of refresh requests
4635 in al, #0x61
4636 and al,#0x10
4637 mov ah, al
4639 or ecx, ecx
4640 je int1586_tick_end
4641 int1586_tick:
4642 in al, #0x61
4643 and al,#0x10
4644 cmp al, ah
4645 je int1586_tick
4646 mov ah, al
4647 dec ecx
4648 jnz int1586_tick
4649 int1586_tick_end:
4650 ASM_END
4652 break;
4654 case 0xe8:
4655 switch(regs.u.r8.al)
4657 #ifdef HVMASSIST
4658 case 0x20: {
4659 e820_table_size = read_word(E820_SEG, E820_NR_OFFSET) * 0x14;
4661 if (regs.u.r32.edx != 0x534D4150) /* SMAP */
4662 goto int15_unimplemented;
4664 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4665 if (regs.u.r16.bx + 0x14 <= e820_table_size)
4666 memcpyb(ES, regs.u.r16.di,
4667 E820_SEG, E820_OFFSET + regs.u.r16.bx, 0x14);
4668 regs.u.r32.ebx += 0x14;
4669 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4670 regs.u.r32.ebx = 0;
4671 } else if (regs.u.r16.bx == 1) {
4672 for (off = 0; off < e820_table_size; off += 0x14) {
4673 base = read_dword(E820_SEG, E820_OFFSET + off);
4674 type = read_dword(E820_SEG, E820_OFFSET + 0x10 + off);
4675 if ((base >= 0x100000) && (type == 1))
4676 break;
4678 if (off == e820_table_size) {
4679 SET_CF();
4680 break;
4682 memcpyb(ES, regs.u.r16.di, E820_SEG, E820_OFFSET + off, 0x14);
4683 regs.u.r32.ebx = 0;
4684 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4685 goto int15_unimplemented;
4688 regs.u.r32.eax = 0x534D4150;
4689 regs.u.r32.ecx = 0x14;
4690 CLEAR_CF();
4691 break;
4694 case 0x01: {
4695 e820_table_size = read_word(E820_SEG, E820_NR_OFFSET) * 0x14;
4697 // do we have any reason to fail here ?
4698 CLEAR_CF();
4700 // Get the amount of extended memory (above 1M)
4701 regs.u.r8.cl = inb_cmos(0x30);
4702 regs.u.r8.ch = inb_cmos(0x31);
4704 // limit to 15M
4705 if (regs.u.r16.cx > (15*1024))
4706 regs.u.r16.cx = 15*1024;
4708 // Find first RAM E820 entry >= 1MB.
4709 for (off = 0; off < e820_table_size; off += 0x14) {
4710 base = read_dword(E820_SEG, E820_OFFSET + off);
4711 type = read_dword(E820_SEG, E820_OFFSET + 0x10 + off);
4712 if ((base >= 0x100000) && (type == 1))
4713 break;
4716 // If there is RAM above 16MB, return amount in 64kB chunks.
4717 regs.u.r16.dx = 0;
4718 if (off != e820_table_size) {
4719 size = base + read_dword(E820_SEG, E820_OFFSET + 0x8 + off);
4720 if (size > 0x1000000) {
4721 size -= 0x1000000;
4722 regs.u.r16.dx = (Bit16u)(size >> 16);
4726 // Set configured memory equal to extended memory
4727 regs.u.r16.ax = regs.u.r16.cx;
4728 regs.u.r16.bx = regs.u.r16.dx;
4729 break;
4731 default: /* AH=0xE8?? but not implemented */
4732 goto int15_unimplemented;
4734 break;
4735 int15_unimplemented:
4736 // fall into the default
4737 default:
4738 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4739 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4740 SET_CF();
4741 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4742 break;
4744 #else
4745 case 0x20: // coded by osmaker aka K.J.
4746 if(regs.u.r32.edx == 0x534D4150)
4748 extended_memory_size = inb_cmos(0x35);
4749 extended_memory_size <<= 8;
4750 extended_memory_size |= inb_cmos(0x34);
4751 extended_memory_size *= 64;
4752 // greater than EFF00000???
4753 if(extended_memory_size > 0x3bc000) {
4754 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4756 extended_memory_size *= 1024;
4757 extended_memory_size += (16L * 1024 * 1024);
4759 if(extended_memory_size <= (16L * 1024 * 1024)) {
4760 extended_memory_size = inb_cmos(0x31);
4761 extended_memory_size <<= 8;
4762 extended_memory_size |= inb_cmos(0x30);
4763 extended_memory_size *= 1024;
4764 extended_memory_size += (1L * 1024 * 1024);
4767 switch(regs.u.r16.bx)
4769 case 0:
4770 set_e820_range(ES, regs.u.r16.di,
4771 0x0000000L, 0x0009f000L, 1);
4772 regs.u.r32.ebx = 1;
4773 regs.u.r32.eax = 0x534D4150;
4774 regs.u.r32.ecx = 0x14;
4775 CLEAR_CF();
4776 return;
4777 break;
4778 case 1:
4779 set_e820_range(ES, regs.u.r16.di,
4780 0x0009f000L, 0x000a0000L, 2);
4781 regs.u.r32.ebx = 2;
4782 regs.u.r32.eax = 0x534D4150;
4783 regs.u.r32.ecx = 0x14;
4784 CLEAR_CF();
4785 return;
4786 break;
4787 case 2:
4788 set_e820_range(ES, regs.u.r16.di,
4789 0x000e8000L, 0x00100000L, 2);
4790 regs.u.r32.ebx = 3;
4791 regs.u.r32.eax = 0x534D4150;
4792 regs.u.r32.ecx = 0x14;
4793 CLEAR_CF();
4794 return;
4795 break;
4796 case 3:
4797 #if BX_ROMBIOS32
4798 set_e820_range(ES, regs.u.r16.di,
4799 0x00100000L,
4800 extended_memory_size - ACPI_DATA_SIZE, 1);
4801 regs.u.r32.ebx = 4;
4802 #else
4803 set_e820_range(ES, regs.u.r16.di,
4804 0x00100000L,
4805 extended_memory_size, 1);
4806 regs.u.r32.ebx = 5;
4807 #endif
4808 regs.u.r32.eax = 0x534D4150;
4809 regs.u.r32.ecx = 0x14;
4810 CLEAR_CF();
4811 return;
4812 break;
4813 case 4:
4814 set_e820_range(ES, regs.u.r16.di,
4815 extended_memory_size - ACPI_DATA_SIZE,
4816 extended_memory_size, 3); // ACPI RAM
4817 regs.u.r32.ebx = 5;
4818 regs.u.r32.eax = 0x534D4150;
4819 regs.u.r32.ecx = 0x14;
4820 CLEAR_CF();
4821 return;
4822 break;
4823 case 5:
4824 /* 256KB BIOS area at the end of 4 GB */
4825 set_e820_range(ES, regs.u.r16.di,
4826 0xfffc0000L, 0x00000000L, 2);
4827 regs.u.r32.ebx = 0;
4828 regs.u.r32.eax = 0x534D4150;
4829 regs.u.r32.ecx = 0x14;
4830 CLEAR_CF();
4831 return;
4832 default: /* AX=E820, DX=534D4150, BX unrecognized */
4833 goto int15_unimplemented;
4834 break;
4836 } else {
4837 // if DX != 0x534D4150)
4838 goto int15_unimplemented;
4840 break;
4842 case 0x01:
4843 // do we have any reason to fail here ?
4844 CLEAR_CF();
4846 // my real system sets ax and bx to 0
4847 // this is confirmed by Ralph Brown list
4848 // but syslinux v1.48 is known to behave
4849 // strangely if ax is set to 0
4850 // regs.u.r16.ax = 0;
4851 // regs.u.r16.bx = 0;
4853 // Get the amount of extended memory (above 1M)
4854 regs.u.r8.cl = inb_cmos(0x30);
4855 regs.u.r8.ch = inb_cmos(0x31);
4857 // limit to 15M
4858 if(regs.u.r16.cx > 0x3c00)
4860 regs.u.r16.cx = 0x3c00;
4863 // Get the amount of extended memory above 16M in 64k blocs
4864 regs.u.r8.dl = inb_cmos(0x34);
4865 regs.u.r8.dh = inb_cmos(0x35);
4867 // Set configured memory equal to extended memory
4868 regs.u.r16.ax = regs.u.r16.cx;
4869 regs.u.r16.bx = regs.u.r16.dx;
4870 break;
4871 default: /* AH=0xE8?? but not implemented */
4872 goto int15_unimplemented;
4874 break;
4875 int15_unimplemented:
4876 // fall into the default
4877 default:
4878 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4879 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4880 SET_CF();
4881 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4882 break;
4884 #endif /* HVMASSIST */
4887 void
4888 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4889 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4891 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4892 Bit16u kbd_code, max;
4894 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4896 shift_flags = read_byte(0x0040, 0x17);
4897 led_flags = read_byte(0x0040, 0x97);
4898 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4899 ASM_START
4900 cli
4901 ASM_END
4902 outb(0x60, 0xed);
4903 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4904 if ((inb(0x60) == 0xfa)) {
4905 led_flags &= 0xf8;
4906 led_flags |= ((shift_flags >> 4) & 0x07);
4907 outb(0x60, led_flags & 0x07);
4908 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4909 inb(0x60);
4910 write_byte(0x0040, 0x97, led_flags);
4912 ASM_START
4913 sti
4914 ASM_END
4917 switch (GET_AH()) {
4918 case 0x00: /* read keyboard input */
4920 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4921 BX_PANIC("KBD: int16h: out of keyboard input\n");
4923 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4924 else if (ascii_code == 0xE0) ascii_code = 0;
4925 AX = (scan_code << 8) | ascii_code;
4926 break;
4928 case 0x01: /* check keyboard status */
4929 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4930 SET_ZF();
4931 return;
4933 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4934 else if (ascii_code == 0xE0) ascii_code = 0;
4935 AX = (scan_code << 8) | ascii_code;
4936 CLEAR_ZF();
4937 break;
4939 case 0x02: /* get shift flag status */
4940 shift_flags = read_byte(0x0040, 0x17);
4941 SET_AL(shift_flags);
4942 break;
4944 case 0x05: /* store key-stroke into buffer */
4945 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4946 SET_AL(1);
4948 else {
4949 SET_AL(0);
4951 break;
4953 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4954 // bit Bochs Description
4955 // 7 0 reserved
4956 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4957 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4958 // 4 1 INT 16/AH=0Ah supported
4959 // 3 0 INT 16/AX=0306h supported
4960 // 2 0 INT 16/AX=0305h supported
4961 // 1 0 INT 16/AX=0304h supported
4962 // 0 0 INT 16/AX=0300h supported
4963 //
4964 SET_AL(0x30);
4965 break;
4967 case 0x0A: /* GET KEYBOARD ID */
4968 count = 2;
4969 kbd_code = 0x0;
4970 outb(0x60, 0xf2);
4971 /* Wait for data */
4972 max=0xffff;
4973 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4974 if (max>0x0) {
4975 if ((inb(0x60) == 0xfa)) {
4976 do {
4977 max=0xffff;
4978 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4979 if (max>0x0) {
4980 kbd_code >>= 8;
4981 kbd_code |= (inb(0x60) << 8);
4983 } while (--count>0);
4986 BX=kbd_code;
4987 break;
4989 case 0x10: /* read MF-II keyboard input */
4991 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4992 BX_PANIC("KBD: int16h: out of keyboard input\n");
4994 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4995 AX = (scan_code << 8) | ascii_code;
4996 break;
4998 case 0x11: /* check MF-II keyboard status */
4999 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5000 SET_ZF();
5001 return;
5003 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5004 AX = (scan_code << 8) | ascii_code;
5005 CLEAR_ZF();
5006 break;
5008 case 0x12: /* get extended keyboard status */
5009 shift_flags = read_byte(0x0040, 0x17);
5010 SET_AL(shift_flags);
5011 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5012 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5013 SET_AH(shift_flags);
5014 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5015 break;
5017 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5018 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5019 break;
5021 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5022 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5023 break;
5025 case 0x6F:
5026 if (GET_AL() == 0x08)
5027 SET_AH(0x02); // unsupported, aka normal keyboard
5029 default:
5030 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5034 unsigned int
5035 dequeue_key(scan_code, ascii_code, incr)
5036 Bit8u *scan_code;
5037 Bit8u *ascii_code;
5038 unsigned int incr;
5040 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5041 Bit16u ss;
5042 Bit8u acode, scode;
5044 #if BX_CPU < 2
5045 buffer_start = 0x001E;
5046 buffer_end = 0x003E;
5047 #else
5048 buffer_start = read_word(0x0040, 0x0080);
5049 buffer_end = read_word(0x0040, 0x0082);
5050 #endif
5052 buffer_head = read_word(0x0040, 0x001a);
5053 buffer_tail = read_word(0x0040, 0x001c);
5055 if (buffer_head != buffer_tail) {
5056 ss = get_SS();
5057 acode = read_byte(0x0040, buffer_head);
5058 scode = read_byte(0x0040, buffer_head+1);
5059 write_byte(ss, ascii_code, acode);
5060 write_byte(ss, scan_code, scode);
5062 if (incr) {
5063 buffer_head += 2;
5064 if (buffer_head >= buffer_end)
5065 buffer_head = buffer_start;
5066 write_word(0x0040, 0x001a, buffer_head);
5068 return(1);
5070 else {
5071 return(0);
5075 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5077 Bit8u
5078 inhibit_mouse_int_and_events()
5080 Bit8u command_byte, prev_command_byte;
5082 // Turn off IRQ generation and aux data line
5083 if ( inb(0x64) & 0x02 )
5084 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
5085 outb(0x64, 0x20); // get command byte
5086 while ( (inb(0x64) & 0x01) != 0x01 );
5087 prev_command_byte = inb(0x60);
5088 command_byte = prev_command_byte;
5089 //while ( (inb(0x64) & 0x02) );
5090 if ( inb(0x64) & 0x02 )
5091 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
5092 command_byte &= 0xfd; // turn off IRQ 12 generation
5093 command_byte |= 0x20; // disable mouse serial clock line
5094 outb(0x64, 0x60); // write command byte
5095 outb(0x60, command_byte);
5096 return(prev_command_byte);
5099 void
5100 enable_mouse_int_and_events()
5102 Bit8u command_byte;
5104 // Turn on IRQ generation and aux data line
5105 if ( inb(0x64) & 0x02 )
5106 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
5107 outb(0x64, 0x20); // get command byte
5108 while ( (inb(0x64) & 0x01) != 0x01 );
5109 command_byte = inb(0x60);
5110 //while ( (inb(0x64) & 0x02) );
5111 if ( inb(0x64) & 0x02 )
5112 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
5113 command_byte |= 0x02; // turn on IRQ 12 generation
5114 command_byte &= 0xdf; // enable mouse serial clock line
5115 outb(0x64, 0x60); // write command byte
5116 outb(0x60, command_byte);
5119 Bit8u
5120 send_to_mouse_ctrl(sendbyte)
5121 Bit8u sendbyte;
5123 Bit8u response;
5125 // wait for chance to write to ctrl
5126 if ( inb(0x64) & 0x02 )
5127 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5128 outb(0x64, 0xD4);
5129 outb(0x60, sendbyte);
5130 return(0);
5134 Bit8u
5135 get_mouse_data(data)
5136 Bit8u *data;
5138 Bit8u response;
5139 Bit16u ss;
5141 while ( (inb(0x64) & 0x21) != 0x21 ) {
5144 response = inb(0x60);
5146 ss = get_SS();
5147 write_byte(ss, data, response);
5148 return(0);
5151 void
5152 set_kbd_command_byte(command_byte)
5153 Bit8u command_byte;
5155 if ( inb(0x64) & 0x02 )
5156 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5157 outb(0x64, 0xD4);
5159 outb(0x64, 0x60); // write command byte
5160 outb(0x60, command_byte);
5163 void
5164 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5165 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5167 Bit8u scancode, asciicode, shift_flags;
5168 Bit8u mf2_flags, mf2_state;
5170 //
5171 // DS has been set to F000 before call
5172 //
5175 scancode = GET_AL();
5177 if (scancode == 0) {
5178 BX_INFO("KBD: int09 handler: AL=0\n");
5179 return;
5183 shift_flags = read_byte(0x0040, 0x17);
5184 mf2_flags = read_byte(0x0040, 0x18);
5185 mf2_state = read_byte(0x0040, 0x96);
5186 asciicode = 0;
5188 switch (scancode) {
5189 case 0x3a: /* Caps Lock press */
5190 shift_flags ^= 0x40;
5191 write_byte(0x0040, 0x17, shift_flags);
5192 mf2_flags |= 0x40;
5193 write_byte(0x0040, 0x18, mf2_flags);
5194 break;
5195 case 0xba: /* Caps Lock release */
5196 mf2_flags &= ~0x40;
5197 write_byte(0x0040, 0x18, mf2_flags);
5198 break;
5200 case 0x2a: /* L Shift press */
5201 shift_flags |= 0x02;
5202 write_byte(0x0040, 0x17, shift_flags);
5203 break;
5204 case 0xaa: /* L Shift release */
5205 shift_flags &= ~0x02;
5206 write_byte(0x0040, 0x17, shift_flags);
5207 break;
5209 case 0x36: /* R Shift press */
5210 shift_flags |= 0x01;
5211 write_byte(0x0040, 0x17, shift_flags);
5212 break;
5213 case 0xb6: /* R Shift release */
5214 shift_flags &= ~0x01;
5215 write_byte(0x0040, 0x17, shift_flags);
5216 break;
5218 case 0x1d: /* Ctrl press */
5219 if ((mf2_state & 0x01) == 0) {
5220 shift_flags |= 0x04;
5221 write_byte(0x0040, 0x17, shift_flags);
5222 if (mf2_state & 0x02) {
5223 mf2_state |= 0x04;
5224 write_byte(0x0040, 0x96, mf2_state);
5225 } else {
5226 mf2_flags |= 0x01;
5227 write_byte(0x0040, 0x18, mf2_flags);
5230 break;
5231 case 0x9d: /* Ctrl release */
5232 if ((mf2_state & 0x01) == 0) {
5233 shift_flags &= ~0x04;
5234 write_byte(0x0040, 0x17, shift_flags);
5235 if (mf2_state & 0x02) {
5236 mf2_state &= ~0x04;
5237 write_byte(0x0040, 0x96, mf2_state);
5238 } else {
5239 mf2_flags &= ~0x01;
5240 write_byte(0x0040, 0x18, mf2_flags);
5243 break;
5245 case 0x38: /* Alt press */
5246 shift_flags |= 0x08;
5247 write_byte(0x0040, 0x17, shift_flags);
5248 if (mf2_state & 0x02) {
5249 mf2_state |= 0x08;
5250 write_byte(0x0040, 0x96, mf2_state);
5251 } else {
5252 mf2_flags |= 0x02;
5253 write_byte(0x0040, 0x18, mf2_flags);
5255 break;
5256 case 0xb8: /* Alt release */
5257 shift_flags &= ~0x08;
5258 write_byte(0x0040, 0x17, shift_flags);
5259 if (mf2_state & 0x02) {
5260 mf2_state &= ~0x08;
5261 write_byte(0x0040, 0x96, mf2_state);
5262 } else {
5263 mf2_flags &= ~0x02;
5264 write_byte(0x0040, 0x18, mf2_flags);
5266 break;
5268 case 0x45: /* Num Lock press */
5269 if ((mf2_state & 0x03) == 0) {
5270 mf2_flags |= 0x20;
5271 write_byte(0x0040, 0x18, mf2_flags);
5272 shift_flags ^= 0x20;
5273 write_byte(0x0040, 0x17, shift_flags);
5275 break;
5276 case 0xc5: /* Num Lock release */
5277 if ((mf2_state & 0x03) == 0) {
5278 mf2_flags &= ~0x20;
5279 write_byte(0x0040, 0x18, mf2_flags);
5281 break;
5283 case 0x46: /* Scroll Lock press */
5284 mf2_flags |= 0x10;
5285 write_byte(0x0040, 0x18, mf2_flags);
5286 shift_flags ^= 0x10;
5287 write_byte(0x0040, 0x17, shift_flags);
5288 break;
5290 case 0xc6: /* Scroll Lock release */
5291 mf2_flags &= ~0x10;
5292 write_byte(0x0040, 0x18, mf2_flags);
5293 break;
5295 case 0x53: /* Del */
5296 if ((shift_flags & 0x0c) == 0x0c) /* Ctrl + Alt */
5297 machine_reset();
5298 /* Fall through */
5299 default:
5300 if (scancode & 0x80) {
5301 break; /* toss key releases ... */
5303 if (scancode > MAX_SCAN_CODE) {
5304 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5305 return;
5307 if (shift_flags & 0x08) { /* ALT */
5308 asciicode = scan_to_scanascii[scancode].alt;
5309 scancode = scan_to_scanascii[scancode].alt >> 8;
5310 } else if (shift_flags & 0x04) { /* CONTROL */
5311 asciicode = scan_to_scanascii[scancode].control;
5312 scancode = scan_to_scanascii[scancode].control >> 8;
5313 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5314 /* extended keys handling */
5315 asciicode = 0xe0;
5316 scancode = scan_to_scanascii[scancode].normal >> 8;
5317 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5318 /* check if lock state should be ignored
5319 * because a SHIFT key are pressed */
5321 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5322 asciicode = scan_to_scanascii[scancode].normal;
5323 scancode = scan_to_scanascii[scancode].normal >> 8;
5324 } else {
5325 asciicode = scan_to_scanascii[scancode].shift;
5326 scancode = scan_to_scanascii[scancode].shift >> 8;
5328 } else {
5329 /* check if lock is on */
5330 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5331 asciicode = scan_to_scanascii[scancode].shift;
5332 scancode = scan_to_scanascii[scancode].shift >> 8;
5333 } else {
5334 asciicode = scan_to_scanascii[scancode].normal;
5335 scancode = scan_to_scanascii[scancode].normal >> 8;
5338 if (scancode==0 && asciicode==0) {
5339 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5341 enqueue_key(scancode, asciicode);
5342 break;
5344 if ((scancode & 0x7f) != 0x1d) {
5345 mf2_state &= ~0x01;
5347 mf2_state &= ~0x02;
5348 write_byte(0x0040, 0x96, mf2_state);
5351 unsigned int
5352 enqueue_key(scan_code, ascii_code)
5353 Bit8u scan_code, ascii_code;
5355 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5357 #if BX_CPU < 2
5358 buffer_start = 0x001E;
5359 buffer_end = 0x003E;
5360 #else
5361 buffer_start = read_word(0x0040, 0x0080);
5362 buffer_end = read_word(0x0040, 0x0082);
5363 #endif
5365 buffer_head = read_word(0x0040, 0x001A);
5366 buffer_tail = read_word(0x0040, 0x001C);
5368 temp_tail = buffer_tail;
5369 buffer_tail += 2;
5370 if (buffer_tail >= buffer_end)
5371 buffer_tail = buffer_start;
5373 if (buffer_tail == buffer_head) {
5374 return(0);
5377 write_byte(0x0040, temp_tail, ascii_code);
5378 write_byte(0x0040, temp_tail+1, scan_code);
5379 write_word(0x0040, 0x001C, buffer_tail);
5380 return(1);
5384 void
5385 int74_function(make_farcall, Z, Y, X, status)
5386 Bit16u make_farcall, Z, Y, X, status;
5388 Bit16u ebda_seg=read_word(0x0040,0x000E);
5389 Bit8u in_byte, index, package_count;
5390 Bit8u mouse_flags_1, mouse_flags_2;
5392 BX_DEBUG_INT74("entering int74_function\n");
5393 make_farcall = 0;
5395 in_byte = inb(0x64);
5396 if ( (in_byte & 0x21) != 0x21 ) {
5397 return;
5399 in_byte = inb(0x60);
5400 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5402 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5403 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5405 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5406 return;
5409 package_count = mouse_flags_2 & 0x07;
5410 index = mouse_flags_1 & 0x07;
5411 write_byte(ebda_seg, 0x28 + index, in_byte);
5413 if ( (index+1) >= package_count ) {
5414 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5415 status = read_byte(ebda_seg, 0x0028 + 0);
5416 X = read_byte(ebda_seg, 0x0028 + 1);
5417 Y = read_byte(ebda_seg, 0x0028 + 2);
5418 Z = 0;
5419 mouse_flags_1 = 0;
5420 // check if far call handler installed
5421 if (mouse_flags_2 & 0x80)
5422 make_farcall = 1;
5424 else {
5425 mouse_flags_1++;
5427 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5430 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5432 #if BX_USE_ATADRV
5434 void
5435 int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5436 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5438 Bit32u lba_low, lba_high;
5439 Bit16u ebda_seg=read_word(0x0040,0x000E);
5440 Bit16u cylinder, head, sector;
5441 Bit16u segment, offset;
5442 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5443 Bit16u size, count;
5444 Bit8u device, status;
5446 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5448 write_byte(0x0040, 0x008e, 0); // clear completion flag
5450 // basic check : device has to be defined
5451 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5452 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5453 goto int13_fail;
5456 // Get the ata channel
5457 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5459 // basic check : device has to be valid
5460 if (device >= BX_MAX_ATA_DEVICES) {
5461 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5462 goto int13_fail;
5465 switch (GET_AH()) {
5467 case 0x00: /* disk controller reset */
5468 ata_reset (device);
5469 goto int13_success;
5470 break;
5472 case 0x01: /* read disk status */
5473 status = read_byte(0x0040, 0x0074);
5474 SET_AH(status);
5475 SET_DISK_RET_STATUS(0);
5476 /* set CF if error status read */
5477 if (status) goto int13_fail_nostatus;
5478 else goto int13_success_noah;
5479 break;
5481 case 0x02: // read disk sectors
5482 case 0x03: // write disk sectors
5483 case 0x04: // verify disk sectors
5485 count = GET_AL();
5486 cylinder = GET_CH();
5487 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5488 sector = (GET_CL() & 0x3f);
5489 head = GET_DH();
5491 segment = ES;
5492 offset = BX;
5494 if ((count > 128) || (count == 0) || (sector == 0)) {
5495 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
5496 goto int13_fail;
5499 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5500 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5501 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5503 // sanity check on cyl heads, sec
5504 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5505 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5506 goto int13_fail;
5509 // FIXME verify
5510 if ( GET_AH() == 0x04 ) goto int13_success;
5512 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5513 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5515 // if needed, translate lchs to lba, and execute command
5516 if ( (nph != nlh) || (npspt != nlspt)) {
5517 lba_low = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5518 lba_high = 0;
5519 sector = 0; // this forces the command to be lba
5522 if ( GET_AH() == 0x02 )
5523 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
5524 else
5525 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
5527 // Set nb of sector transferred
5528 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5530 if (status != 0) {
5531 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5532 SET_AH(0x0c);
5533 goto int13_fail_noah;
5536 goto int13_success;
5537 break;
5539 case 0x05: /* format disk track */
5540 BX_INFO("format disk track called\n");
5541 goto int13_success;
5542 return;
5543 break;
5545 case 0x08: /* read disk drive parameters */
5547 // Get logical geometry from table
5548 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5549 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5550 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5551 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5553 nlc = nlc - 2; /* 0 based , last sector not used */
5554 SET_AL(0);
5555 SET_CH(nlc & 0xff);
5556 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5557 SET_DH(nlh - 1);
5558 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5560 // FIXME should set ES & DI
5562 goto int13_success;
5563 break;
5565 case 0x10: /* check drive ready */
5566 // should look at 40:8E also???
5568 // Read the status from controller
5569 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5570 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5571 goto int13_success;
5573 else {
5574 SET_AH(0xAA);
5575 goto int13_fail_noah;
5577 break;
5579 case 0x15: /* read disk drive size */
5581 // Get logical geometry from table
5582 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5583 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5584 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5586 // Compute sector count seen by int13
5587 lba_low = (Bit32u)(nlc - 1) * (Bit32u)nlh * (Bit32u)nlspt;
5588 CX = lba_low >> 16;
5589 DX = lba_low & 0xffff;
5591 SET_AH(3); // hard disk accessible
5592 goto int13_success_noah;
5593 break;
5595 case 0x41: // IBM/MS installation check
5596 BX=0xaa55; // install check
5597 SET_AH(0x30); // EDD 3.0
5598 CX=0x0007; // ext disk access and edd, removable supported
5599 goto int13_success_noah;
5600 break;
5602 case 0x42: // IBM/MS extended read
5603 case 0x43: // IBM/MS extended write
5604 case 0x44: // IBM/MS verify
5605 case 0x47: // IBM/MS extended seek
5607 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5608 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5609 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5611 // Get 32 msb lba and check
5612 lba_high=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5613 if (lba_high > read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) ) {
5614 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5615 goto int13_fail;
5618 // Get 32 lsb lba and check
5619 lba_low=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5620 if (lba_high == read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high)
5621 && lba_low >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low) ) {
5622 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5623 goto int13_fail;
5626 // If verify or seek
5627 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5628 goto int13_success;
5630 // Execute the command
5631 if ( GET_AH() == 0x42 )
5632 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
5633 else
5634 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
5636 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5637 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5639 if (status != 0) {
5640 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5641 SET_AH(0x0c);
5642 goto int13_fail_noah;
5645 goto int13_success;
5646 break;
5648 case 0x45: // IBM/MS lock/unlock drive
5649 case 0x49: // IBM/MS extended media change
5650 goto int13_success; // Always success for HD
5651 break;
5653 case 0x46: // IBM/MS eject media
5654 SET_AH(0xb2); // Volume Not Removable
5655 goto int13_fail_noah; // Always fail for HD
5656 break;
5658 case 0x48: // IBM/MS get drive parameters
5659 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5661 // Buffer is too small
5662 if(size < 0x1a)
5663 goto int13_fail;
5665 // EDD 1.x
5666 if(size >= 0x1a) {
5667 Bit16u blksize;
5669 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5670 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5671 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5672 lba_low = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low);
5673 lba_high = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high);
5674 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5676 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5677 if (lba_high || (lba_low/npspt)/nph > 0x3fff)
5679 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x00); // geometry is invalid
5680 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0x3fff);
5682 else
5684 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5685 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5687 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5688 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5689 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba_low);
5690 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, lba_high);
5691 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5694 // EDD 2.x
5695 if(size >= 0x1e) {
5696 Bit8u channel, dev, irq, mode, checksum, i, translation;
5697 Bit16u iobase1, iobase2, options;
5699 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5701 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5702 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5704 // Fill in dpte
5705 channel = device / 2;
5706 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5707 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5708 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5709 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5710 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5712 options = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
5713 options |= (1<<4); // lba translation
5714 options |= (mode==ATA_MODE_PIO32?1:0)<<7;
5715 options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
5716 options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
5718 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5719 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
5720 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5721 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5722 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5723 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5724 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5725 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5726 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5727 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5728 if (size >=0x42)
5729 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5730 else
5731 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x10);
5733 checksum=0;
5734 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
5735 checksum = ~checksum;
5736 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5739 // EDD 3.x
5740 if(size >= 0x42) {
5741 Bit8u channel, iface, checksum, i;
5742 Bit16u iobase1;
5744 channel = device / 2;
5745 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5746 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5748 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5749 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5750 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5751 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5752 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5754 if (iface==ATA_IFACE_ISA) {
5755 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5756 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5757 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5758 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5760 else {
5761 // FIXME PCI
5763 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5764 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5765 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5766 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5768 if (iface==ATA_IFACE_ISA) {
5769 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5770 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5771 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5773 else {
5774 // FIXME PCI
5776 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5777 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5778 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5779 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5781 checksum=0;
5782 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5783 checksum = ~checksum;
5784 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5787 goto int13_success;
5788 break;
5790 case 0x4e: // // IBM/MS set hardware configuration
5791 // DMA, prefetch, PIO maximum not supported
5792 switch (GET_AL()) {
5793 case 0x01:
5794 case 0x03:
5795 case 0x04:
5796 case 0x06:
5797 goto int13_success;
5798 break;
5799 default :
5800 goto int13_fail;
5802 break;
5804 case 0x09: /* initialize drive parameters */
5805 case 0x0c: /* seek to specified cylinder */
5806 case 0x0d: /* alternate disk reset */
5807 case 0x11: /* recalibrate */
5808 case 0x14: /* controller internal diagnostic */
5809 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5810 goto int13_success;
5811 break;
5813 case 0x0a: /* read disk sectors with ECC */
5814 case 0x0b: /* write disk sectors with ECC */
5815 case 0x18: // set media type for format
5816 case 0x50: // IBM/MS send packet command
5817 default:
5818 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5819 goto int13_fail;
5820 break;
5823 int13_fail:
5824 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5825 int13_fail_noah:
5826 SET_DISK_RET_STATUS(GET_AH());
5827 int13_fail_nostatus:
5828 SET_CF(); // error occurred
5829 return;
5831 int13_success:
5832 SET_AH(0x00); // no error
5833 int13_success_noah:
5834 SET_DISK_RET_STATUS(0x00);
5835 CLEAR_CF(); // no error
5836 return;
5839 // ---------------------------------------------------------------------------
5840 // Start of int13 for cdrom
5841 // ---------------------------------------------------------------------------
5843 void
5844 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5845 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5847 Bit16u ebda_seg=read_word(0x0040,0x000E);
5848 Bit8u device, status, locks;
5849 Bit8u atacmd[12];
5850 Bit32u lba;
5851 Bit16u count, segment, offset, i, size;
5853 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5855 SET_DISK_RET_STATUS(0x00);
5857 /* basic check : device should be 0xE0+ */
5858 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5859 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5860 goto int13_fail;
5863 // Get the ata channel
5864 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5866 /* basic check : device has to be valid */
5867 if (device >= BX_MAX_ATA_DEVICES) {
5868 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5869 goto int13_fail;
5872 switch (GET_AH()) {
5874 // all those functions return SUCCESS
5875 case 0x00: /* disk controller reset */
5876 case 0x09: /* initialize drive parameters */
5877 case 0x0c: /* seek to specified cylinder */
5878 case 0x0d: /* alternate disk reset */
5879 case 0x10: /* check drive ready */
5880 case 0x11: /* recalibrate */
5881 case 0x14: /* controller internal diagnostic */
5882 case 0x16: /* detect disk change */
5883 goto int13_success;
5884 break;
5886 // all those functions return disk write-protected
5887 case 0x03: /* write disk sectors */
5888 case 0x05: /* format disk track */
5889 case 0x43: // IBM/MS extended write
5890 SET_AH(0x03);
5891 goto int13_fail_noah;
5892 break;
5894 case 0x01: /* read disk status */
5895 status = read_byte(0x0040, 0x0074);
5896 SET_AH(status);
5897 SET_DISK_RET_STATUS(0);
5899 /* set CF if error status read */
5900 if (status) goto int13_fail_nostatus;
5901 else goto int13_success_noah;
5902 break;
5904 case 0x15: /* read disk drive size */
5905 SET_AH(0x02);
5906 goto int13_fail_noah;
5907 break;
5909 case 0x41: // IBM/MS installation check
5910 BX=0xaa55; // install check
5911 SET_AH(0x30); // EDD 2.1
5912 CX=0x0007; // ext disk access, removable and edd
5913 goto int13_success_noah;
5914 break;
5916 case 0x42: // IBM/MS extended read
5917 case 0x44: // IBM/MS verify sectors
5918 case 0x47: // IBM/MS extended seek
5920 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5921 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5922 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5924 // Can't use 64 bits lba
5925 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5926 if (lba != 0L) {
5927 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5928 goto int13_fail;
5931 // Get 32 bits lba
5932 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5934 // If verify or seek
5935 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5936 goto int13_success;
5938 memsetb(get_SS(),atacmd,0,12);
5939 atacmd[0]=0x28; // READ command
5940 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5941 atacmd[8]=(count & 0x00ff); // Sectors
5942 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5943 atacmd[3]=(lba & 0x00ff0000) >> 16;
5944 atacmd[4]=(lba & 0x0000ff00) >> 8;
5945 atacmd[5]=(lba & 0x000000ff);
5946 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5948 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5949 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5951 if (status != 0) {
5952 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5953 SET_AH(0x0c);
5954 goto int13_fail_noah;
5957 goto int13_success;
5958 break;
5960 case 0x45: // IBM/MS lock/unlock drive
5961 if (GET_AL() > 2) goto int13_fail;
5963 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5965 switch (GET_AL()) {
5966 case 0 : // lock
5967 if (locks == 0xff) {
5968 SET_AH(0xb4);
5969 SET_AL(1);
5970 goto int13_fail_noah;
5972 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5973 SET_AL(1);
5974 break;
5975 case 1 : // unlock
5976 if (locks == 0x00) {
5977 SET_AH(0xb0);
5978 SET_AL(0);
5979 goto int13_fail_noah;
5981 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5982 SET_AL(locks==0?0:1);
5983 break;
5984 case 2 : // status
5985 SET_AL(locks==0?0:1);
5986 break;
5988 goto int13_success;
5989 break;
5991 case 0x46: // IBM/MS eject media
5992 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5994 if (locks != 0) {
5995 SET_AH(0xb1); // media locked
5996 goto int13_fail_noah;
5998 // FIXME should handle 0x31 no media in device
5999 // FIXME should handle 0xb5 valid request failed
6001 // Call removable media eject
6002 ASM_START
6003 push bp
6004 mov bp, sp
6006 mov ah, #0x52
6007 int #0x15
6008 mov _int13_cdrom.status + 2[bp], ah
6009 jnc int13_cdrom_rme_end
6010 mov _int13_cdrom.status, #1
6011 int13_cdrom_rme_end:
6012 pop bp
6013 ASM_END
6015 if (status != 0) {
6016 SET_AH(0xb1); // media locked
6017 goto int13_fail_noah;
6020 goto int13_success;
6021 break;
6023 case 0x48: // IBM/MS get drive parameters
6024 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6026 // Buffer is too small
6027 if(size < 0x1a)
6028 goto int13_fail;
6030 // EDD 1.x
6031 if(size >= 0x1a) {
6032 Bit16u cylinders, heads, spt, blksize;
6034 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6036 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6037 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6038 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6039 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6040 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6041 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6042 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6043 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6046 // EDD 2.x
6047 if(size >= 0x1e) {
6048 Bit8u channel, dev, irq, mode, checksum, i;
6049 Bit16u iobase1, iobase2, options;
6051 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6053 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6054 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6056 // Fill in dpte
6057 channel = device / 2;
6058 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6059 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6060 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6061 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6063 // FIXME atapi device
6064 options = (1<<4); // lba translation
6065 options |= (1<<5); // removable device
6066 options |= (1<<6); // atapi device
6067 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6069 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6070 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
6071 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6072 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6073 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6074 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6075 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6076 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6077 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6078 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6079 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6081 checksum=0;
6082 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
6083 checksum = ~checksum;
6084 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6087 // EDD 3.x
6088 if(size >= 0x42) {
6089 Bit8u channel, iface, checksum, i;
6090 Bit16u iobase1;
6092 channel = device / 2;
6093 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6094 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6096 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6097 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6098 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6099 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6100 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6102 if (iface==ATA_IFACE_ISA) {
6103 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6104 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6105 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6106 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6108 else {
6109 // FIXME PCI
6111 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6112 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6113 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6114 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6116 if (iface==ATA_IFACE_ISA) {
6117 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6118 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6119 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6121 else {
6122 // FIXME PCI
6124 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6125 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6126 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6127 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6129 checksum=0;
6130 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6131 checksum = ~checksum;
6132 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6135 goto int13_success;
6136 break;
6138 case 0x49: // IBM/MS extended media change
6139 // always send changed ??
6140 SET_AH(06);
6141 goto int13_fail_nostatus;
6142 break;
6144 case 0x4e: // // IBM/MS set hardware configuration
6145 // DMA, prefetch, PIO maximum not supported
6146 switch (GET_AL()) {
6147 case 0x01:
6148 case 0x03:
6149 case 0x04:
6150 case 0x06:
6151 goto int13_success;
6152 break;
6153 default :
6154 goto int13_fail;
6156 break;
6158 // all those functions return unimplemented
6159 case 0x02: /* read sectors */
6160 case 0x04: /* verify sectors */
6161 case 0x08: /* read disk drive parameters */
6162 case 0x0a: /* read disk sectors with ECC */
6163 case 0x0b: /* write disk sectors with ECC */
6164 case 0x18: /* set media type for format */
6165 case 0x50: // ? - send packet command
6166 default:
6167 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6168 goto int13_fail;
6169 break;
6172 int13_fail:
6173 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6174 int13_fail_noah:
6175 SET_DISK_RET_STATUS(GET_AH());
6176 int13_fail_nostatus:
6177 SET_CF(); // error occurred
6178 return;
6180 int13_success:
6181 SET_AH(0x00); // no error
6182 int13_success_noah:
6183 SET_DISK_RET_STATUS(0x00);
6184 CLEAR_CF(); // no error
6185 return;
6188 // ---------------------------------------------------------------------------
6189 // End of int13 for cdrom
6190 // ---------------------------------------------------------------------------
6192 #if BX_ELTORITO_BOOT
6193 // ---------------------------------------------------------------------------
6194 // Start of int13 for eltorito functions
6195 // ---------------------------------------------------------------------------
6197 void
6198 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6199 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6201 Bit16u ebda_seg=read_word(0x0040,0x000E);
6203 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6204 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6206 switch (GET_AH()) {
6208 // FIXME ElTorito Various. Should be implemented
6209 case 0x4a: // ElTorito - Initiate disk emu
6210 case 0x4c: // ElTorito - Initiate disk emu and boot
6211 case 0x4d: // ElTorito - Return Boot catalog
6212 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6213 goto int13_fail;
6214 break;
6216 case 0x4b: // ElTorito - Terminate disk emu
6217 // FIXME ElTorito Hardcoded
6218 write_byte(DS,SI+0x00,0x13);
6219 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6220 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6221 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6222 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6223 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6224 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6225 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6226 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6227 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6228 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6229 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6231 // If we have to terminate emulation
6232 if(GET_AL() == 0x00) {
6233 // FIXME ElTorito Various. Should be handled accordingly to spec
6234 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6237 goto int13_success;
6238 break;
6240 default:
6241 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6242 goto int13_fail;
6243 break;
6246 int13_fail:
6247 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6248 SET_DISK_RET_STATUS(GET_AH());
6249 SET_CF(); // error occurred
6250 return;
6252 int13_success:
6253 SET_AH(0x00); // no error
6254 SET_DISK_RET_STATUS(0x00);
6255 CLEAR_CF(); // no error
6256 return;
6259 // ---------------------------------------------------------------------------
6260 // End of int13 for eltorito functions
6261 // ---------------------------------------------------------------------------
6263 // ---------------------------------------------------------------------------
6264 // Start of int13 when emulating a device from the cd
6265 // ---------------------------------------------------------------------------
6267 void
6268 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6269 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6271 Bit16u ebda_seg=read_word(0x0040,0x000E);
6272 Bit8u device, status;
6273 Bit16u vheads, vspt, vcylinders;
6274 Bit16u head, sector, cylinder, nbsectors;
6275 Bit32u vlba, ilba, slba, elba;
6276 Bit16u before, segment, offset;
6277 Bit8u atacmd[12];
6279 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6281 /* at this point, we are emulating a floppy/harddisk */
6283 // Recompute the device number
6284 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6285 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6287 SET_DISK_RET_STATUS(0x00);
6289 /* basic checks : emulation should be active, dl should equal the emulated drive */
6290 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6291 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6292 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6293 goto int13_fail;
6296 switch (GET_AH()) {
6298 // all those functions return SUCCESS
6299 case 0x00: /* disk controller reset */
6300 case 0x09: /* initialize drive parameters */
6301 case 0x0c: /* seek to specified cylinder */
6302 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6303 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6304 case 0x11: /* recalibrate */
6305 case 0x14: /* controller internal diagnostic */
6306 case 0x16: /* detect disk change */
6307 goto int13_success;
6308 break;
6310 // all those functions return disk write-protected
6311 case 0x03: /* write disk sectors */
6312 case 0x05: /* format disk track */
6313 SET_AH(0x03);
6314 goto int13_fail_noah;
6315 break;
6317 case 0x01: /* read disk status */
6318 status=read_byte(0x0040, 0x0074);
6319 SET_AH(status);
6320 SET_DISK_RET_STATUS(0);
6322 /* set CF if error status read */
6323 if (status) goto int13_fail_nostatus;
6324 else goto int13_success_noah;
6325 break;
6327 case 0x02: // read disk sectors
6328 case 0x04: // verify disk sectors
6329 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6330 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6331 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6333 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6335 sector = GET_CL() & 0x003f;
6336 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6337 head = GET_DH();
6338 nbsectors = GET_AL();
6339 segment = ES;
6340 offset = BX;
6342 // no sector to read ?
6343 if(nbsectors==0) goto int13_success;
6345 // sanity checks sco openserver needs this!
6346 if ((sector > vspt)
6347 || (cylinder >= vcylinders)
6348 || (head >= vheads)) {
6349 goto int13_fail;
6352 // After controls, verify do nothing
6353 if (GET_AH() == 0x04) goto int13_success;
6355 segment = ES+(BX / 16);
6356 offset = BX % 16;
6358 // calculate the virtual lba inside the image
6359 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6361 // In advance so we don't loose the count
6362 SET_AL(nbsectors);
6364 // start lba on cd
6365 slba = (Bit32u)vlba/4;
6366 before= (Bit16u)vlba%4;
6368 // end lba on cd
6369 elba = (Bit32u)(vlba+nbsectors-1)/4;
6371 memsetb(get_SS(),atacmd,0,12);
6372 atacmd[0]=0x28; // READ command
6373 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6374 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6375 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6376 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6377 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6378 atacmd[5]=(ilba+slba & 0x000000ff);
6379 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6380 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6381 SET_AH(0x02);
6382 SET_AL(0);
6383 goto int13_fail_noah;
6386 goto int13_success;
6387 break;
6389 case 0x08: /* read disk drive parameters */
6390 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6391 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6392 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6394 SET_AL( 0x00 );
6395 SET_BL( 0x00 );
6396 SET_CH( vcylinders & 0xff );
6397 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6398 SET_DH( vheads );
6399 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6400 // FIXME ElTorito Harddisk. should send the HD count
6402 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6403 case 0x01: SET_BL( 0x02 ); break;
6404 case 0x02: SET_BL( 0x04 ); break;
6405 case 0x03: SET_BL( 0x06 ); break;
6408 ASM_START
6409 push bp
6410 mov bp, sp
6411 mov ax, #diskette_param_table2
6412 mov _int13_cdemu.DI+2[bp], ax
6413 mov _int13_cdemu.ES+2[bp], cs
6414 pop bp
6415 ASM_END
6416 goto int13_success;
6417 break;
6419 case 0x15: /* read disk drive size */
6420 // FIXME ElTorito Harddisk. What geometry to send ?
6421 SET_AH(0x03);
6422 goto int13_success_noah;
6423 break;
6425 // all those functions return unimplemented
6426 case 0x0a: /* read disk sectors with ECC */
6427 case 0x0b: /* write disk sectors with ECC */
6428 case 0x18: /* set media type for format */
6429 case 0x41: // IBM/MS installation check
6430 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6431 case 0x42: // IBM/MS extended read
6432 case 0x43: // IBM/MS extended write
6433 case 0x44: // IBM/MS verify sectors
6434 case 0x45: // IBM/MS lock/unlock drive
6435 case 0x46: // IBM/MS eject media
6436 case 0x47: // IBM/MS extended seek
6437 case 0x48: // IBM/MS get drive parameters
6438 case 0x49: // IBM/MS extended media change
6439 case 0x4e: // ? - set hardware configuration
6440 case 0x50: // ? - send packet command
6441 default:
6442 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6443 goto int13_fail;
6444 break;
6447 int13_fail:
6448 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6449 int13_fail_noah:
6450 SET_DISK_RET_STATUS(GET_AH());
6451 int13_fail_nostatus:
6452 SET_CF(); // error occurred
6453 return;
6455 int13_success:
6456 SET_AH(0x00); // no error
6457 int13_success_noah:
6458 SET_DISK_RET_STATUS(0x00);
6459 CLEAR_CF(); // no error
6460 return;
6463 // ---------------------------------------------------------------------------
6464 // End of int13 when emulating a device from the cd
6465 // ---------------------------------------------------------------------------
6467 #endif // BX_ELTORITO_BOOT
6469 #else //BX_USE_ATADRV
6471 void
6472 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6473 Bit16u cylinder;
6474 Bit16u hd_heads;
6475 Bit16u head;
6476 Bit16u hd_sectors;
6477 Bit16u sector;
6478 Bit16u dl;
6480 ASM_START
6481 push bp
6482 mov bp, sp
6483 push eax
6484 push ebx
6485 push edx
6486 xor eax,eax
6487 mov ax,4[bp] // cylinder
6488 xor ebx,ebx
6489 mov bl,6[bp] // hd_heads
6490 imul ebx
6492 mov bl,8[bp] // head
6493 add eax,ebx
6494 mov bl,10[bp] // hd_sectors
6495 imul ebx
6496 mov bl,12[bp] // sector
6497 add eax,ebx
6499 dec eax
6500 mov dx,#0x1f3
6501 out dx,al
6502 mov dx,#0x1f4
6503 mov al,ah
6504 out dx,al
6505 shr eax,#16
6506 mov dx,#0x1f5
6507 out dx,al
6508 and ah,#0xf
6509 mov bl,14[bp] // dl
6510 and bl,#1
6511 shl bl,#4
6512 or ah,bl
6513 or ah,#0xe0
6514 mov al,ah
6515 mov dx,#0x01f6
6516 out dx,al
6517 pop edx
6518 pop ebx
6519 pop eax
6520 pop bp
6521 ASM_END
6524 void
6525 int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6526 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6528 Bit8u drive, num_sectors, sector, head, status, mod;
6529 Bit8u drive_map;
6530 Bit8u n_drives;
6531 Bit16u cyl_mod, ax;
6532 Bit16u max_cylinder, cylinder, total_sectors;
6533 Bit16u hd_cylinders;
6534 Bit8u hd_heads, hd_sectors;
6535 Bit16u val16;
6536 Bit8u sector_count;
6537 unsigned int i;
6538 Bit16u tempbx;
6539 Bit16u dpsize;
6541 Bit16u count, segment, offset;
6542 Bit32u lba;
6543 Bit16u error;
6545 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6547 write_byte(0x0040, 0x008e, 0); // clear completion flag
6549 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6550 handler code */
6551 /* check how many disks first (cmos reg 0x12), return an error if
6552 drive not present */
6553 drive_map = inb_cmos(0x12);
6554 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6555 (((drive_map & 0x0f)==0) ? 0 : 2);
6556 n_drives = (drive_map==0) ? 0 :
6557 ((drive_map==3) ? 2 : 1);
6559 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6560 SET_AH(0x01);
6561 SET_DISK_RET_STATUS(0x01);
6562 SET_CF(); /* error occurred */
6563 return;
6566 switch (GET_AH()) {
6568 case 0x00: /* disk controller reset */
6569 BX_DEBUG_INT13_HD("int13_f00\n");
6571 SET_AH(0);
6572 SET_DISK_RET_STATUS(0);
6573 set_diskette_ret_status(0);
6574 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6575 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6576 CLEAR_CF(); /* successful */
6577 return;
6578 break;
6580 case 0x01: /* read disk status */
6581 BX_DEBUG_INT13_HD("int13_f01\n");
6582 status = read_byte(0x0040, 0x0074);
6583 SET_AH(status);
6584 SET_DISK_RET_STATUS(0);
6585 /* set CF if error status read */
6586 if (status) SET_CF();
6587 else CLEAR_CF();
6588 return;
6589 break;
6591 case 0x04: // verify disk sectors
6592 case 0x02: // read disk sectors
6593 drive = GET_ELDL();
6594 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6596 num_sectors = GET_AL();
6597 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6598 sector = (GET_CL() & 0x3f);
6599 head = GET_DH();
6602 if (hd_cylinders > 1024) {
6603 if (hd_cylinders <= 2048) {
6604 cylinder <<= 1;
6606 else if (hd_cylinders <= 4096) {
6607 cylinder <<= 2;
6609 else if (hd_cylinders <= 8192) {
6610 cylinder <<= 3;
6612 else { // hd_cylinders <= 16384
6613 cylinder <<= 4;
6616 ax = head / hd_heads;
6617 cyl_mod = ax & 0xff;
6618 head = ax >> 8;
6619 cylinder |= cyl_mod;
6622 if ( (cylinder >= hd_cylinders) ||
6623 (sector > hd_sectors) ||
6624 (head >= hd_heads) ) {
6625 SET_AH(1);
6626 SET_DISK_RET_STATUS(1);
6627 SET_CF(); /* error occurred */
6628 return;
6631 if ( (num_sectors > 128) || (num_sectors == 0) )
6632 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6634 if (head > 15)
6635 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6637 if ( GET_AH() == 0x04 ) {
6638 SET_AH(0);
6639 SET_DISK_RET_STATUS(0);
6640 CLEAR_CF();
6641 return;
6644 status = inb(0x1f7);
6645 if (status & 0x80) {
6646 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6648 outb(0x01f2, num_sectors);
6649 /* activate LBA? (tomv) */
6650 if (hd_heads > 16) {
6651 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6652 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6654 else {
6655 outb(0x01f3, sector);
6656 outb(0x01f4, cylinder & 0x00ff);
6657 outb(0x01f5, cylinder >> 8);
6658 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6660 outb(0x01f7, 0x20);
6662 while (1) {
6663 status = inb(0x1f7);
6664 if ( !(status & 0x80) ) break;
6667 if (status & 0x01) {
6668 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6669 } else if ( !(status & 0x08) ) {
6670 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6671 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6674 sector_count = 0;
6675 tempbx = BX;
6677 ASM_START
6678 sti ;; enable higher priority interrupts
6679 ASM_END
6681 while (1) {
6682 ASM_START
6683 ;; store temp bx in real DI register
6684 push bp
6685 mov bp, sp
6686 mov di, _int13_harddisk.tempbx + 2 [bp]
6687 pop bp
6689 ;; adjust if there will be an overrun
6690 cmp di, #0xfe00
6691 jbe i13_f02_no_adjust
6692 i13_f02_adjust:
6693 sub di, #0x0200 ; sub 512 bytes from offset
6694 mov ax, es
6695 add ax, #0x0020 ; add 512 to segment
6696 mov es, ax
6698 i13_f02_no_adjust:
6699 mov cx, #0x0100 ;; counter (256 words = 512b)
6700 mov dx, #0x01f0 ;; AT data read port
6702 rep
6703 insw ;; CX words transfered from port(DX) to ES:[DI]
6705 i13_f02_done:
6706 ;; store real DI register back to temp bx
6707 push bp
6708 mov bp, sp
6709 mov _int13_harddisk.tempbx + 2 [bp], di
6710 pop bp
6711 ASM_END
6713 sector_count++;
6714 num_sectors--;
6715 if (num_sectors == 0) {
6716 status = inb(0x1f7);
6717 if ( (status & 0xc9) != 0x40 )
6718 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6719 break;
6721 else {
6722 status = inb(0x1f7);
6723 if ( (status & 0xc9) != 0x48 )
6724 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6725 continue;
6729 SET_AH(0);
6730 SET_DISK_RET_STATUS(0);
6731 SET_AL(sector_count);
6732 CLEAR_CF(); /* successful */
6733 return;
6734 break;
6737 case 0x03: /* write disk sectors */
6738 BX_DEBUG_INT13_HD("int13_f03\n");
6739 drive = GET_ELDL ();
6740 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6742 num_sectors = GET_AL();
6743 cylinder = GET_CH();
6744 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6745 sector = (GET_CL() & 0x3f);
6746 head = GET_DH();
6748 if (hd_cylinders > 1024) {
6749 if (hd_cylinders <= 2048) {
6750 cylinder <<= 1;
6752 else if (hd_cylinders <= 4096) {
6753 cylinder <<= 2;
6755 else if (hd_cylinders <= 8192) {
6756 cylinder <<= 3;
6758 else { // hd_cylinders <= 16384
6759 cylinder <<= 4;
6762 ax = head / hd_heads;
6763 cyl_mod = ax & 0xff;
6764 head = ax >> 8;
6765 cylinder |= cyl_mod;
6768 if ( (cylinder >= hd_cylinders) ||
6769 (sector > hd_sectors) ||
6770 (head >= hd_heads) ) {
6771 SET_AH( 1);
6772 SET_DISK_RET_STATUS(1);
6773 SET_CF(); /* error occurred */
6774 return;
6777 if ( (num_sectors > 128) || (num_sectors == 0) )
6778 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6780 if (head > 15)
6781 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6783 status = inb(0x1f7);
6784 if (status & 0x80) {
6785 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6787 // should check for Drive Ready Bit also in status reg
6788 outb(0x01f2, num_sectors);
6790 /* activate LBA? (tomv) */
6791 if (hd_heads > 16) {
6792 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6793 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6795 else {
6796 outb(0x01f3, sector);
6797 outb(0x01f4, cylinder & 0x00ff);
6798 outb(0x01f5, cylinder >> 8);
6799 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6801 outb(0x01f7, 0x30);
6803 // wait for busy bit to turn off after seeking
6804 while (1) {
6805 status = inb(0x1f7);
6806 if ( !(status & 0x80) ) break;
6809 if ( !(status & 0x08) ) {
6810 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6811 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6814 sector_count = 0;
6815 tempbx = BX;
6817 ASM_START
6818 sti ;; enable higher priority interrupts
6819 ASM_END
6821 while (1) {
6822 ASM_START
6823 ;; store temp bx in real SI register
6824 push bp
6825 mov bp, sp
6826 mov si, _int13_harddisk.tempbx + 2 [bp]
6827 pop bp
6829 ;; adjust if there will be an overrun
6830 cmp si, #0xfe00
6831 jbe i13_f03_no_adjust
6832 i13_f03_adjust:
6833 sub si, #0x0200 ; sub 512 bytes from offset
6834 mov ax, es
6835 add ax, #0x0020 ; add 512 to segment
6836 mov es, ax
6838 i13_f03_no_adjust:
6839 mov cx, #0x0100 ;; counter (256 words = 512b)
6840 mov dx, #0x01f0 ;; AT data read port
6842 seg ES
6843 rep
6844 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6846 ;; store real SI register back to temp bx
6847 push bp
6848 mov bp, sp
6849 mov _int13_harddisk.tempbx + 2 [bp], si
6850 pop bp
6851 ASM_END
6853 sector_count++;
6854 num_sectors--;
6855 if (num_sectors == 0) {
6856 status = inb(0x1f7);
6857 if ( (status & 0xe9) != 0x40 )
6858 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6859 break;
6861 else {
6862 status = inb(0x1f7);
6863 if ( (status & 0xc9) != 0x48 )
6864 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6865 continue;
6869 SET_AH(0);
6870 SET_DISK_RET_STATUS(0);
6871 SET_AL(sector_count);
6872 CLEAR_CF(); /* successful */
6873 return;
6874 break;
6876 case 0x05: /* format disk track */
6877 BX_DEBUG_INT13_HD("int13_f05\n");
6878 BX_PANIC("format disk track called\n");
6879 /* nop */
6880 SET_AH(0);
6881 SET_DISK_RET_STATUS(0);
6882 CLEAR_CF(); /* successful */
6883 return;
6884 break;
6886 case 0x08: /* read disk drive parameters */
6887 BX_DEBUG_INT13_HD("int13_f08\n");
6889 drive = GET_ELDL ();
6890 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6892 // translate CHS
6893 //
6894 if (hd_cylinders <= 1024) {
6895 // hd_cylinders >>= 0;
6896 // hd_heads <<= 0;
6898 else if (hd_cylinders <= 2048) {
6899 hd_cylinders >>= 1;
6900 hd_heads <<= 1;
6902 else if (hd_cylinders <= 4096) {
6903 hd_cylinders >>= 2;
6904 hd_heads <<= 2;
6906 else if (hd_cylinders <= 8192) {
6907 hd_cylinders >>= 3;
6908 hd_heads <<= 3;
6910 else { // hd_cylinders <= 16384
6911 hd_cylinders >>= 4;
6912 hd_heads <<= 4;
6915 max_cylinder = hd_cylinders - 2; /* 0 based */
6916 SET_AL(0);
6917 SET_CH(max_cylinder & 0xff);
6918 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6919 SET_DH(hd_heads - 1);
6920 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6921 SET_AH(0);
6922 SET_DISK_RET_STATUS(0);
6923 CLEAR_CF(); /* successful */
6925 return;
6926 break;
6928 case 0x09: /* initialize drive parameters */
6929 BX_DEBUG_INT13_HD("int13_f09\n");
6930 SET_AH(0);
6931 SET_DISK_RET_STATUS(0);
6932 CLEAR_CF(); /* successful */
6933 return;
6934 break;
6936 case 0x0a: /* read disk sectors with ECC */
6937 BX_DEBUG_INT13_HD("int13_f0a\n");
6938 case 0x0b: /* write disk sectors with ECC */
6939 BX_DEBUG_INT13_HD("int13_f0b\n");
6940 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6941 return;
6942 break;
6944 case 0x0c: /* seek to specified cylinder */
6945 BX_DEBUG_INT13_HD("int13_f0c\n");
6946 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6947 SET_AH(0);
6948 SET_DISK_RET_STATUS(0);
6949 CLEAR_CF(); /* successful */
6950 return;
6951 break;
6953 case 0x0d: /* alternate disk reset */
6954 BX_DEBUG_INT13_HD("int13_f0d\n");
6955 SET_AH(0);
6956 SET_DISK_RET_STATUS(0);
6957 CLEAR_CF(); /* successful */
6958 return;
6959 break;
6961 case 0x10: /* check drive ready */
6962 BX_DEBUG_INT13_HD("int13_f10\n");
6963 //SET_AH(0);
6964 //SET_DISK_RET_STATUS(0);
6965 //CLEAR_CF(); /* successful */
6966 //return;
6967 //break;
6969 // should look at 40:8E also???
6970 status = inb(0x01f7);
6971 if ( (status & 0xc0) == 0x40 ) {
6972 SET_AH(0);
6973 SET_DISK_RET_STATUS(0);
6974 CLEAR_CF(); // drive ready
6975 return;
6977 else {
6978 SET_AH(0xAA);
6979 SET_DISK_RET_STATUS(0xAA);
6980 SET_CF(); // not ready
6981 return;
6983 break;
6985 case 0x11: /* recalibrate */
6986 BX_DEBUG_INT13_HD("int13_f11\n");
6987 SET_AH(0);
6988 SET_DISK_RET_STATUS(0);
6989 CLEAR_CF(); /* successful */
6990 return;
6991 break;
6993 case 0x14: /* controller internal diagnostic */
6994 BX_DEBUG_INT13_HD("int13_f14\n");
6995 SET_AH(0);
6996 SET_DISK_RET_STATUS(0);
6997 CLEAR_CF(); /* successful */
6998 SET_AL(0);
6999 return;
7000 break;
7002 case 0x15: /* read disk drive size */
7003 drive = GET_ELDL();
7004 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7005 ASM_START
7006 push bp
7007 mov bp, sp
7008 mov al, _int13_harddisk.hd_heads + 2 [bp]
7009 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7010 mul al, ah ;; ax = heads * sectors
7011 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7012 dec bx ;; use (cylinders - 1) ???
7013 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7014 ;; now we need to move the 32bit result dx:ax to what the
7015 ;; BIOS wants which is cx:dx.
7016 ;; and then into CX:DX on the stack
7017 mov _int13_harddisk.CX + 2 [bp], dx
7018 mov _int13_harddisk.DX + 2 [bp], ax
7019 pop bp
7020 ASM_END
7021 SET_AH(3); // hard disk accessible
7022 SET_DISK_RET_STATUS(0); // ??? should this be 0
7023 CLEAR_CF(); // successful
7024 return;
7025 break;
7027 case 0x18: // set media type for format
7028 case 0x41: // IBM/MS
7029 case 0x42: // IBM/MS
7030 case 0x43: // IBM/MS
7031 case 0x44: // IBM/MS
7032 case 0x45: // IBM/MS lock/unlock drive
7033 case 0x46: // IBM/MS eject media
7034 case 0x47: // IBM/MS extended seek
7035 case 0x49: // IBM/MS extended media change
7036 case 0x50: // IBM/MS send packet command
7037 default:
7038 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7040 SET_AH(1); // code=invalid function in AH or invalid parameter
7041 SET_DISK_RET_STATUS(1);
7042 SET_CF(); /* unsuccessful */
7043 return;
7044 break;
7048 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7049 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7051 void
7052 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7053 Bit8u drive;
7054 Bit16u *hd_cylinders;
7055 Bit8u *hd_heads;
7056 Bit8u *hd_sectors;
7058 Bit8u hd_type;
7059 Bit16u ss;
7060 Bit16u cylinders;
7061 Bit8u iobase;
7063 ss = get_SS();
7064 if (drive == 0x80) {
7065 hd_type = inb_cmos(0x12) & 0xf0;
7066 if (hd_type != 0xf0)
7067 BX_INFO(panic_msg_reg12h,0);
7068 hd_type = inb_cmos(0x19); // HD0: extended type
7069 if (hd_type != 47)
7070 BX_INFO(panic_msg_reg19h,0,0x19);
7071 iobase = 0x1b;
7072 } else {
7073 hd_type = inb_cmos(0x12) & 0x0f;
7074 if (hd_type != 0x0f)
7075 BX_INFO(panic_msg_reg12h,1);
7076 hd_type = inb_cmos(0x1a); // HD1: extended type
7077 if (hd_type != 47)
7078 BX_INFO(panic_msg_reg19h,0,0x1a);
7079 iobase = 0x24;
7082 // cylinders
7083 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7084 write_word(ss, hd_cylinders, cylinders);
7086 // heads
7087 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7089 // sectors per track
7090 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7093 #endif //else BX_USE_ATADRV
7095 #if BX_SUPPORT_FLOPPY
7097 //////////////////////
7098 // FLOPPY functions //
7099 //////////////////////
7101 void floppy_reset_controller()
7103 Bit8u val8;
7105 // Reset controller
7106 val8 = inb(0x03f2);
7107 outb(0x03f2, val8 & ~0x04);
7108 outb(0x03f2, val8 | 0x04);
7110 // Wait for controller to come out of reset
7111 do {
7112 val8 = inb(0x3f4);
7113 } while ( (val8 & 0xc0) != 0x80 );
7116 void floppy_prepare_controller(drive)
7117 Bit16u drive;
7119 Bit8u val8, dor, prev_reset;
7121 // set 40:3e bit 7 to 0
7122 val8 = read_byte(0x0040, 0x003e);
7123 val8 &= 0x7f;
7124 write_byte(0x0040, 0x003e, val8);
7126 // turn on motor of selected drive, DMA & int enabled, normal operation
7127 prev_reset = inb(0x03f2) & 0x04;
7128 if (drive)
7129 dor = 0x20;
7130 else
7131 dor = 0x10;
7132 dor |= 0x0c;
7133 dor |= drive;
7134 outb(0x03f2, dor);
7136 // reset the disk motor timeout value of INT 08
7137 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7139 // wait for drive readiness
7140 do {
7141 val8 = inb(0x3f4);
7142 } while ( (val8 & 0xc0) != 0x80 );
7144 if (prev_reset == 0) {
7145 // turn on interrupts
7146 ASM_START
7147 sti
7148 ASM_END
7149 // wait on 40:3e bit 7 to become 1
7150 do {
7151 val8 = read_byte(0x0040, 0x003e);
7152 } while ( (val8 & 0x80) == 0 );
7153 val8 &= 0x7f;
7154 ASM_START
7155 cli
7156 ASM_END
7157 write_byte(0x0040, 0x003e, val8);
7161 bx_bool
7162 floppy_media_known(drive)
7163 Bit16u drive;
7165 Bit8u val8;
7166 Bit16u media_state_offset;
7168 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7169 if (drive)
7170 val8 >>= 1;
7171 val8 &= 0x01;
7172 if (val8 == 0)
7173 return(0);
7175 media_state_offset = 0x0090;
7176 if (drive)
7177 media_state_offset += 1;
7179 val8 = read_byte(0x0040, media_state_offset);
7180 val8 = (val8 >> 4) & 0x01;
7181 if (val8 == 0)
7182 return(0);
7184 // check pass, return KNOWN
7185 return(1);
7188 bx_bool
7189 floppy_media_sense(drive)
7190 Bit16u drive;
7192 bx_bool retval;
7193 Bit16u media_state_offset;
7194 Bit8u drive_type, config_data, media_state;
7196 if (floppy_drive_recal(drive) == 0) {
7197 return(0);
7200 // for now cheat and get drive type from CMOS,
7201 // assume media is same as drive type
7203 // ** config_data **
7204 // Bitfields for diskette media control:
7205 // Bit(s) Description (Table M0028)
7206 // 7-6 last data rate set by controller
7207 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7208 // 5-4 last diskette drive step rate selected
7209 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7210 // 3-2 {data rate at start of operation}
7211 // 1-0 reserved
7213 // ** media_state **
7214 // Bitfields for diskette drive media state:
7215 // Bit(s) Description (Table M0030)
7216 // 7-6 data rate
7217 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7218 // 5 double stepping required (e.g. 360kB in 1.2MB)
7219 // 4 media type established
7220 // 3 drive capable of supporting 4MB media
7221 // 2-0 on exit from BIOS, contains
7222 // 000 trying 360kB in 360kB
7223 // 001 trying 360kB in 1.2MB
7224 // 010 trying 1.2MB in 1.2MB
7225 // 011 360kB in 360kB established
7226 // 100 360kB in 1.2MB established
7227 // 101 1.2MB in 1.2MB established
7228 // 110 reserved
7229 // 111 all other formats/drives
7231 drive_type = inb_cmos(0x10);
7232 if (drive == 0)
7233 drive_type >>= 4;
7234 else
7235 drive_type &= 0x0f;
7236 if ( drive_type == 1 ) {
7237 // 360K 5.25" drive
7238 config_data = 0x00; // 0000 0000
7239 media_state = 0x25; // 0010 0101
7240 retval = 1;
7242 else if ( drive_type == 2 ) {
7243 // 1.2 MB 5.25" drive
7244 config_data = 0x00; // 0000 0000
7245 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7246 retval = 1;
7248 else if ( drive_type == 3 ) {
7249 // 720K 3.5" drive
7250 config_data = 0x00; // 0000 0000 ???
7251 media_state = 0x17; // 0001 0111
7252 retval = 1;
7254 else if ( drive_type == 4 ) {
7255 // 1.44 MB 3.5" drive
7256 config_data = 0x00; // 0000 0000
7257 media_state = 0x17; // 0001 0111
7258 retval = 1;
7260 else if ( drive_type == 5 ) {
7261 // 2.88 MB 3.5" drive
7262 config_data = 0xCC; // 1100 1100
7263 media_state = 0xD7; // 1101 0111
7264 retval = 1;
7266 //
7267 // Extended floppy size uses special cmos setting
7268 else if ( drive_type == 6 ) {
7269 // 160k 5.25" drive
7270 config_data = 0x00; // 0000 0000
7271 media_state = 0x27; // 0010 0111
7272 retval = 1;
7274 else if ( drive_type == 7 ) {
7275 // 180k 5.25" drive
7276 config_data = 0x00; // 0000 0000
7277 media_state = 0x27; // 0010 0111
7278 retval = 1;
7280 else if ( drive_type == 8 ) {
7281 // 320k 5.25" drive
7282 config_data = 0x00; // 0000 0000
7283 media_state = 0x27; // 0010 0111
7284 retval = 1;
7287 else {
7288 // not recognized
7289 config_data = 0x00; // 0000 0000
7290 media_state = 0x00; // 0000 0000
7291 retval = 0;
7294 if (drive == 0)
7295 media_state_offset = 0x90;
7296 else
7297 media_state_offset = 0x91;
7298 write_byte(0x0040, 0x008B, config_data);
7299 write_byte(0x0040, media_state_offset, media_state);
7301 return(retval);
7304 bx_bool
7305 floppy_drive_recal(drive)
7306 Bit16u drive;
7308 Bit8u val8;
7309 Bit16u curr_cyl_offset;
7311 floppy_prepare_controller(drive);
7313 // send Recalibrate command (2 bytes) to controller
7314 outb(0x03f5, 0x07); // 07: Recalibrate
7315 outb(0x03f5, drive); // 0=drive0, 1=drive1
7317 // turn on interrupts
7318 ASM_START
7319 sti
7320 ASM_END
7322 // wait on 40:3e bit 7 to become 1
7323 do {
7324 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7325 } while ( val8 == 0 );
7327 val8 = 0; // separate asm from while() loop
7328 // turn off interrupts
7329 ASM_START
7330 cli
7331 ASM_END
7333 // set 40:3e bit 7 to 0, and calibrated bit
7334 val8 = read_byte(0x0040, 0x003e);
7335 val8 &= 0x7f;
7336 if (drive) {
7337 val8 |= 0x02; // Drive 1 calibrated
7338 curr_cyl_offset = 0x0095;
7339 } else {
7340 val8 |= 0x01; // Drive 0 calibrated
7341 curr_cyl_offset = 0x0094;
7343 write_byte(0x0040, 0x003e, val8);
7344 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7346 return(1);
7351 bx_bool
7352 floppy_drive_exists(drive)
7353 Bit16u drive;
7355 Bit8u drive_type;
7357 // check CMOS to see if drive exists
7358 drive_type = inb_cmos(0x10);
7359 if (drive == 0)
7360 drive_type >>= 4;
7361 else
7362 drive_type &= 0x0f;
7363 if ( drive_type == 0 )
7364 return(0);
7365 else
7366 return(1);
7369 void
7370 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7371 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7373 Bit8u drive, num_sectors, track, sector, head, status;
7374 Bit16u base_address, base_count, base_es;
7375 Bit8u page, mode_register, val8, dor;
7376 Bit8u return_status[7];
7377 Bit8u drive_type, num_floppies, ah;
7378 Bit16u es, last_addr;
7380 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7382 ah = GET_AH();
7384 switch ( ah ) {
7385 case 0x00: // diskette controller reset
7386 BX_DEBUG_INT13_FL("floppy f00\n");
7387 drive = GET_ELDL();
7388 if (drive > 1) {
7389 SET_AH(1); // invalid param
7390 set_diskette_ret_status(1);
7391 SET_CF();
7392 return;
7394 drive_type = inb_cmos(0x10);
7396 if (drive == 0)
7397 drive_type >>= 4;
7398 else
7399 drive_type &= 0x0f;
7400 if (drive_type == 0) {
7401 SET_AH(0x80); // drive not responding
7402 set_diskette_ret_status(0x80);
7403 SET_CF();
7404 return;
7406 SET_AH(0);
7407 set_diskette_ret_status(0);
7408 CLEAR_CF(); // successful
7409 set_diskette_current_cyl(drive, 0); // current cylinder
7410 return;
7412 case 0x01: // Read Diskette Status
7413 CLEAR_CF();
7414 val8 = read_byte(0x0000, 0x0441);
7415 SET_AH(val8);
7416 if (val8) {
7417 SET_CF();
7419 return;
7421 case 0x02: // Read Diskette Sectors
7422 case 0x03: // Write Diskette Sectors
7423 case 0x04: // Verify Diskette Sectors
7424 num_sectors = GET_AL();
7425 track = GET_CH();
7426 sector = GET_CL();
7427 head = GET_DH();
7428 drive = GET_ELDL();
7430 if ((drive > 1) || (head > 1) || (sector == 0) ||
7431 (num_sectors == 0) || (num_sectors > 72)) {
7432 BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
7433 SET_AH(1);
7434 set_diskette_ret_status(1);
7435 SET_AL(0); // no sectors read
7436 SET_CF(); // error occurred
7437 return;
7440 // see if drive exists
7441 if (floppy_drive_exists(drive) == 0) {
7442 SET_AH(0x80); // not responding
7443 set_diskette_ret_status(0x80);
7444 SET_AL(0); // no sectors read
7445 SET_CF(); // error occurred
7446 return;
7449 // see if media in drive, and type is known
7450 if (floppy_media_known(drive) == 0) {
7451 if (floppy_media_sense(drive) == 0) {
7452 SET_AH(0x0C); // Media type not found
7453 set_diskette_ret_status(0x0C);
7454 SET_AL(0); // no sectors read
7455 SET_CF(); // error occurred
7456 return;
7460 if (ah == 0x02) {
7461 // Read Diskette Sectors
7463 //-----------------------------------
7464 // set up DMA controller for transfer
7465 //-----------------------------------
7467 // es:bx = pointer to where to place information from diskette
7468 // port 04: DMA-1 base and current address, channel 2
7469 // port 05: DMA-1 base and current count, channel 2
7470 page = (ES >> 12); // upper 4 bits
7471 base_es = (ES << 4); // lower 16bits contributed by ES
7472 base_address = base_es + BX; // lower 16 bits of address
7473 // contributed by ES:BX
7474 if ( base_address < base_es ) {
7475 // in case of carry, adjust page by 1
7476 page++;
7478 base_count = (num_sectors * 512) - 1;
7480 // check for 64K boundary overrun
7481 last_addr = base_address + base_count;
7482 if (last_addr < base_address) {
7483 SET_AH(0x09);
7484 set_diskette_ret_status(0x09);
7485 SET_AL(0); // no sectors read
7486 SET_CF(); // error occurred
7487 return;
7490 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7491 outb(0x000a, 0x06);
7493 BX_DEBUG_INT13_FL("clear flip-flop\n");
7494 outb(0x000c, 0x00); // clear flip-flop
7495 outb(0x0004, base_address);
7496 outb(0x0004, base_address>>8);
7497 BX_DEBUG_INT13_FL("clear flip-flop\n");
7498 outb(0x000c, 0x00); // clear flip-flop
7499 outb(0x0005, base_count);
7500 outb(0x0005, base_count>>8);
7502 // port 0b: DMA-1 Mode Register
7503 mode_register = 0x46; // single mode, increment, autoinit disable,
7504 // transfer type=write, channel 2
7505 BX_DEBUG_INT13_FL("setting mode register\n");
7506 outb(0x000b, mode_register);
7508 BX_DEBUG_INT13_FL("setting page register\n");
7509 // port 81: DMA-1 Page Register, channel 2
7510 outb(0x0081, page);
7512 BX_DEBUG_INT13_FL("unmask chan 2\n");
7513 outb(0x000a, 0x02); // unmask channel 2
7515 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7516 outb(0x000a, 0x02);
7518 //--------------------------------------
7519 // set up floppy controller for transfer
7520 //--------------------------------------
7521 floppy_prepare_controller(drive);
7523 // send read-normal-data command (9 bytes) to controller
7524 outb(0x03f5, 0xe6); // e6: read normal data
7525 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7526 outb(0x03f5, track);
7527 outb(0x03f5, head);
7528 outb(0x03f5, sector);
7529 outb(0x03f5, 2); // 512 byte sector size
7530 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7531 outb(0x03f5, 0); // Gap length
7532 outb(0x03f5, 0xff); // Gap length
7534 // turn on interrupts
7535 ASM_START
7536 sti
7537 ASM_END
7539 // wait on 40:3e bit 7 to become 1
7540 do {
7541 val8 = read_byte(0x0040, 0x0040);
7542 if (val8 == 0) {
7543 floppy_reset_controller();
7544 SET_AH(0x80); // drive not ready (timeout)
7545 set_diskette_ret_status(0x80);
7546 SET_AL(0); // no sectors read
7547 SET_CF(); // error occurred
7548 return;
7550 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7551 } while ( val8 == 0 );
7553 val8 = 0; // separate asm from while() loop
7554 // turn off interrupts
7555 ASM_START
7556 cli
7557 ASM_END
7559 // set 40:3e bit 7 to 0
7560 val8 = read_byte(0x0040, 0x003e);
7561 val8 &= 0x7f;
7562 write_byte(0x0040, 0x003e, val8);
7564 // check port 3f4 for accessibility to status bytes
7565 val8 = inb(0x3f4);
7566 if ( (val8 & 0xc0) != 0xc0 )
7567 BX_PANIC("int13_diskette: ctrl not ready\n");
7569 // read 7 return status bytes from controller
7570 // using loop index broken, have to unroll...
7571 return_status[0] = inb(0x3f5);
7572 return_status[1] = inb(0x3f5);
7573 return_status[2] = inb(0x3f5);
7574 return_status[3] = inb(0x3f5);
7575 return_status[4] = inb(0x3f5);
7576 return_status[5] = inb(0x3f5);
7577 return_status[6] = inb(0x3f5);
7578 // record in BIOS Data Area
7579 write_byte(0x0040, 0x0042, return_status[0]);
7580 write_byte(0x0040, 0x0043, return_status[1]);
7581 write_byte(0x0040, 0x0044, return_status[2]);
7582 write_byte(0x0040, 0x0045, return_status[3]);
7583 write_byte(0x0040, 0x0046, return_status[4]);
7584 write_byte(0x0040, 0x0047, return_status[5]);
7585 write_byte(0x0040, 0x0048, return_status[6]);
7587 if ( (return_status[0] & 0xc0) != 0 ) {
7588 SET_AH(0x20);
7589 set_diskette_ret_status(0x20);
7590 SET_AL(0); // no sectors read
7591 SET_CF(); // error occurred
7592 return;
7595 // ??? should track be new val from return_status[3] ?
7596 set_diskette_current_cyl(drive, track);
7597 // AL = number of sectors read (same value as passed)
7598 SET_AH(0x00); // success
7599 CLEAR_CF(); // success
7600 return;
7601 } else if (ah == 0x03) {
7602 // Write Diskette Sectors
7604 //-----------------------------------
7605 // set up DMA controller for transfer
7606 //-----------------------------------
7608 // es:bx = pointer to where to place information from diskette
7609 // port 04: DMA-1 base and current address, channel 2
7610 // port 05: DMA-1 base and current count, channel 2
7611 page = (ES >> 12); // upper 4 bits
7612 base_es = (ES << 4); // lower 16bits contributed by ES
7613 base_address = base_es + BX; // lower 16 bits of address
7614 // contributed by ES:BX
7615 if ( base_address < base_es ) {
7616 // in case of carry, adjust page by 1
7617 page++;
7619 base_count = (num_sectors * 512) - 1;
7621 // check for 64K boundary overrun
7622 last_addr = base_address + base_count;
7623 if (last_addr < base_address) {
7624 SET_AH(0x09);
7625 set_diskette_ret_status(0x09);
7626 SET_AL(0); // no sectors read
7627 SET_CF(); // error occurred
7628 return;
7631 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7632 outb(0x000a, 0x06);
7634 outb(0x000c, 0x00); // clear flip-flop
7635 outb(0x0004, base_address);
7636 outb(0x0004, base_address>>8);
7637 outb(0x000c, 0x00); // clear flip-flop
7638 outb(0x0005, base_count);
7639 outb(0x0005, base_count>>8);
7641 // port 0b: DMA-1 Mode Register
7642 mode_register = 0x4a; // single mode, increment, autoinit disable,
7643 // transfer type=read, channel 2
7644 outb(0x000b, mode_register);
7646 // port 81: DMA-1 Page Register, channel 2
7647 outb(0x0081, page);
7649 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7650 outb(0x000a, 0x02);
7652 //--------------------------------------
7653 // set up floppy controller for transfer
7654 //--------------------------------------
7655 floppy_prepare_controller(drive);
7657 // send write-normal-data command (9 bytes) to controller
7658 outb(0x03f5, 0xc5); // c5: write normal data
7659 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7660 outb(0x03f5, track);
7661 outb(0x03f5, head);
7662 outb(0x03f5, sector);
7663 outb(0x03f5, 2); // 512 byte sector size
7664 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7665 outb(0x03f5, 0); // Gap length
7666 outb(0x03f5, 0xff); // Gap length
7668 // turn on interrupts
7669 ASM_START
7670 sti
7671 ASM_END
7673 // wait on 40:3e bit 7 to become 1
7674 do {
7675 val8 = read_byte(0x0040, 0x0040);
7676 if (val8 == 0) {
7677 floppy_reset_controller();
7678 SET_AH(0x80); // drive not ready (timeout)
7679 set_diskette_ret_status(0x80);
7680 SET_AL(0); // no sectors written
7681 SET_CF(); // error occurred
7682 return;
7684 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7685 } while ( val8 == 0 );
7687 val8 = 0; // separate asm from while() loop
7688 // turn off interrupts
7689 ASM_START
7690 cli
7691 ASM_END
7693 // set 40:3e bit 7 to 0
7694 val8 = read_byte(0x0040, 0x003e);
7695 val8 &= 0x7f;
7696 write_byte(0x0040, 0x003e, val8);
7698 // check port 3f4 for accessibility to status bytes
7699 val8 = inb(0x3f4);
7700 if ( (val8 & 0xc0) != 0xc0 )
7701 BX_PANIC("int13_diskette: ctrl not ready\n");
7703 // read 7 return status bytes from controller
7704 // using loop index broken, have to unroll...
7705 return_status[0] = inb(0x3f5);
7706 return_status[1] = inb(0x3f5);
7707 return_status[2] = inb(0x3f5);
7708 return_status[3] = inb(0x3f5);
7709 return_status[4] = inb(0x3f5);
7710 return_status[5] = inb(0x3f5);
7711 return_status[6] = inb(0x3f5);
7712 // record in BIOS Data Area
7713 write_byte(0x0040, 0x0042, return_status[0]);
7714 write_byte(0x0040, 0x0043, return_status[1]);
7715 write_byte(0x0040, 0x0044, return_status[2]);
7716 write_byte(0x0040, 0x0045, return_status[3]);
7717 write_byte(0x0040, 0x0046, return_status[4]);
7718 write_byte(0x0040, 0x0047, return_status[5]);
7719 write_byte(0x0040, 0x0048, return_status[6]);
7721 if ( (return_status[0] & 0xc0) != 0 ) {
7722 if ( (return_status[1] & 0x02) != 0 ) {
7723 // diskette not writable.
7724 // AH=status code=0x03 (tried to write on write-protected disk)
7725 // AL=number of sectors written=0
7726 AX = 0x0300;
7727 SET_CF();
7728 return;
7729 } else {
7730 BX_PANIC("int13_diskette_function: read error\n");
7734 // ??? should track be new val from return_status[3] ?
7735 set_diskette_current_cyl(drive, track);
7736 // AL = number of sectors read (same value as passed)
7737 SET_AH(0x00); // success
7738 CLEAR_CF(); // success
7739 return;
7740 } else { // if (ah == 0x04)
7741 // Verify Diskette Sectors
7743 // ??? should track be new val from return_status[3] ?
7744 set_diskette_current_cyl(drive, track);
7745 // AL = number of sectors verified (same value as passed)
7746 CLEAR_CF(); // success
7747 SET_AH(0x00); // success
7748 return;
7750 break;
7752 case 0x05: // format diskette track
7753 BX_DEBUG_INT13_FL("floppy f05\n");
7755 num_sectors = GET_AL();
7756 track = GET_CH();
7757 head = GET_DH();
7758 drive = GET_ELDL();
7760 if ((drive > 1) || (head > 1) || (track > 79) ||
7761 (num_sectors == 0) || (num_sectors > 18)) {
7762 SET_AH(1);
7763 set_diskette_ret_status(1);
7764 SET_CF(); // error occurred
7767 // see if drive exists
7768 if (floppy_drive_exists(drive) == 0) {
7769 SET_AH(0x80); // drive not responding
7770 set_diskette_ret_status(0x80);
7771 SET_CF(); // error occurred
7772 return;
7775 // see if media in drive, and type is known
7776 if (floppy_media_known(drive) == 0) {
7777 if (floppy_media_sense(drive) == 0) {
7778 SET_AH(0x0C); // Media type not found
7779 set_diskette_ret_status(0x0C);
7780 SET_AL(0); // no sectors read
7781 SET_CF(); // error occurred
7782 return;
7786 // set up DMA controller for transfer
7787 page = (ES >> 12); // upper 4 bits
7788 base_es = (ES << 4); // lower 16bits contributed by ES
7789 base_address = base_es + BX; // lower 16 bits of address
7790 // contributed by ES:BX
7791 if ( base_address < base_es ) {
7792 // in case of carry, adjust page by 1
7793 page++;
7795 base_count = (num_sectors * 4) - 1;
7797 // check for 64K boundary overrun
7798 last_addr = base_address + base_count;
7799 if (last_addr < base_address) {
7800 SET_AH(0x09);
7801 set_diskette_ret_status(0x09);
7802 SET_AL(0); // no sectors read
7803 SET_CF(); // error occurred
7804 return;
7807 outb(0x000a, 0x06);
7808 outb(0x000c, 0x00); // clear flip-flop
7809 outb(0x0004, base_address);
7810 outb(0x0004, base_address>>8);
7811 outb(0x000c, 0x00); // clear flip-flop
7812 outb(0x0005, base_count);
7813 outb(0x0005, base_count>>8);
7814 mode_register = 0x4a; // single mode, increment, autoinit disable,
7815 // transfer type=read, channel 2
7816 outb(0x000b, mode_register);
7817 // port 81: DMA-1 Page Register, channel 2
7818 outb(0x0081, page);
7819 outb(0x000a, 0x02);
7821 // set up floppy controller for transfer
7822 floppy_prepare_controller(drive);
7824 // send format-track command (6 bytes) to controller
7825 outb(0x03f5, 0x4d); // 4d: format track
7826 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7827 outb(0x03f5, 2); // 512 byte sector size
7828 outb(0x03f5, num_sectors); // number of sectors per track
7829 outb(0x03f5, 0); // Gap length
7830 outb(0x03f5, 0xf6); // Fill byte
7831 // turn on interrupts
7832 ASM_START
7833 sti
7834 ASM_END
7836 // wait on 40:3e bit 7 to become 1
7837 do {
7838 val8 = read_byte(0x0040, 0x0040);
7839 if (val8 == 0) {
7840 floppy_reset_controller();
7841 SET_AH(0x80); // drive not ready (timeout)
7842 set_diskette_ret_status(0x80);
7843 SET_CF(); // error occurred
7844 return;
7846 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7847 } while ( val8 == 0 );
7849 val8 = 0; // separate asm from while() loop
7850 // turn off interrupts
7851 ASM_START
7852 cli
7853 ASM_END
7854 // set 40:3e bit 7 to 0
7855 val8 = read_byte(0x0040, 0x003e);
7856 val8 &= 0x7f;
7857 write_byte(0x0040, 0x003e, val8);
7858 // check port 3f4 for accessibility to status bytes
7859 val8 = inb(0x3f4);
7860 if ( (val8 & 0xc0) != 0xc0 )
7861 BX_PANIC("int13_diskette: ctrl not ready\n");
7863 // read 7 return status bytes from controller
7864 // using loop index broken, have to unroll...
7865 return_status[0] = inb(0x3f5);
7866 return_status[1] = inb(0x3f5);
7867 return_status[2] = inb(0x3f5);
7868 return_status[3] = inb(0x3f5);
7869 return_status[4] = inb(0x3f5);
7870 return_status[5] = inb(0x3f5);
7871 return_status[6] = inb(0x3f5);
7872 // record in BIOS Data Area
7873 write_byte(0x0040, 0x0042, return_status[0]);
7874 write_byte(0x0040, 0x0043, return_status[1]);
7875 write_byte(0x0040, 0x0044, return_status[2]);
7876 write_byte(0x0040, 0x0045, return_status[3]);
7877 write_byte(0x0040, 0x0046, return_status[4]);
7878 write_byte(0x0040, 0x0047, return_status[5]);
7879 write_byte(0x0040, 0x0048, return_status[6]);
7881 if ( (return_status[0] & 0xc0) != 0 ) {
7882 if ( (return_status[1] & 0x02) != 0 ) {
7883 // diskette not writable.
7884 // AH=status code=0x03 (tried to write on write-protected disk)
7885 // AL=number of sectors written=0
7886 AX = 0x0300;
7887 SET_CF();
7888 return;
7889 } else {
7890 BX_PANIC("int13_diskette_function: write error\n");
7894 SET_AH(0);
7895 set_diskette_ret_status(0);
7896 set_diskette_current_cyl(drive, 0);
7897 CLEAR_CF(); // successful
7898 return;
7901 case 0x08: // read diskette drive parameters
7902 BX_DEBUG_INT13_FL("floppy f08\n");
7903 drive = GET_ELDL();
7905 if (drive > 1) {
7906 AX = 0;
7907 BX = 0;
7908 CX = 0;
7909 DX = 0;
7910 ES = 0;
7911 DI = 0;
7912 SET_DL(num_floppies);
7913 SET_CF();
7914 return;
7917 drive_type = inb_cmos(0x10);
7918 num_floppies = 0;
7919 if (drive_type & 0xf0)
7920 num_floppies++;
7921 if (drive_type & 0x0f)
7922 num_floppies++;
7924 if (drive == 0)
7925 drive_type >>= 4;
7926 else
7927 drive_type &= 0x0f;
7929 SET_BH(0);
7930 SET_BL(drive_type);
7931 SET_AH(0);
7932 SET_AL(0);
7933 SET_DL(num_floppies);
7935 switch (drive_type) {
7936 case 0: // none
7937 CX = 0;
7938 SET_DH(0); // max head #
7939 break;
7941 case 1: // 360KB, 5.25"
7942 CX = 0x2709; // 40 tracks, 9 sectors
7943 SET_DH(1); // max head #
7944 break;
7946 case 2: // 1.2MB, 5.25"
7947 CX = 0x4f0f; // 80 tracks, 15 sectors
7948 SET_DH(1); // max head #
7949 break;
7951 case 3: // 720KB, 3.5"
7952 CX = 0x4f09; // 80 tracks, 9 sectors
7953 SET_DH(1); // max head #
7954 break;
7956 case 4: // 1.44MB, 3.5"
7957 CX = 0x4f12; // 80 tracks, 18 sectors
7958 SET_DH(1); // max head #
7959 break;
7961 case 5: // 2.88MB, 3.5"
7962 CX = 0x4f24; // 80 tracks, 36 sectors
7963 SET_DH(1); // max head #
7964 break;
7966 case 6: // 160k, 5.25"
7967 CX = 0x2708; // 40 tracks, 8 sectors
7968 SET_DH(0); // max head #
7969 break;
7971 case 7: // 180k, 5.25"
7972 CX = 0x2709; // 40 tracks, 9 sectors
7973 SET_DH(0); // max head #
7974 break;
7976 case 8: // 320k, 5.25"
7977 CX = 0x2708; // 40 tracks, 8 sectors
7978 SET_DH(1); // max head #
7979 break;
7981 default: // ?
7982 BX_PANIC("floppy: int13: bad floppy type\n");
7985 /* set es & di to point to 11 byte diskette param table in ROM */
7986 ASM_START
7987 push bp
7988 mov bp, sp
7989 mov ax, #diskette_param_table2
7990 mov _int13_diskette_function.DI+2[bp], ax
7991 mov _int13_diskette_function.ES+2[bp], cs
7992 pop bp
7993 ASM_END
7994 CLEAR_CF(); // success
7995 /* disk status not changed upon success */
7996 return;
7999 case 0x15: // read diskette drive type
8000 BX_DEBUG_INT13_FL("floppy f15\n");
8001 drive = GET_ELDL();
8002 if (drive > 1) {
8003 SET_AH(0); // only 2 drives supported
8004 // set_diskette_ret_status here ???
8005 SET_CF();
8006 return;
8008 drive_type = inb_cmos(0x10);
8010 if (drive == 0)
8011 drive_type >>= 4;
8012 else
8013 drive_type &= 0x0f;
8014 CLEAR_CF(); // successful, not present
8015 if (drive_type==0) {
8016 SET_AH(0); // drive not present
8018 else {
8019 SET_AH(1); // drive present, does not support change line
8022 return;
8024 case 0x16: // get diskette change line status
8025 BX_DEBUG_INT13_FL("floppy f16\n");
8026 drive = GET_ELDL();
8027 if (drive > 1) {
8028 SET_AH(0x01); // invalid drive
8029 set_diskette_ret_status(0x01);
8030 SET_CF();
8031 return;
8034 SET_AH(0x06); // change line not supported
8035 set_diskette_ret_status(0x06);
8036 SET_CF();
8037 return;
8039 case 0x17: // set diskette type for format(old)
8040 BX_DEBUG_INT13_FL("floppy f17\n");
8041 /* not used for 1.44M floppies */
8042 SET_AH(0x01); // not supported
8043 set_diskette_ret_status(1); /* not supported */
8044 SET_CF();
8045 return;
8047 case 0x18: // set diskette type for format(new)
8048 BX_DEBUG_INT13_FL("floppy f18\n");
8049 SET_AH(0x01); // do later
8050 set_diskette_ret_status(1);
8051 SET_CF();
8052 return;
8054 default:
8055 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8057 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8058 SET_AH(0x01); // ???
8059 set_diskette_ret_status(1);
8060 SET_CF();
8061 return;
8062 // }
8065 #else // #if BX_SUPPORT_FLOPPY
8066 void
8067 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8068 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8070 Bit8u val8;
8072 switch ( GET_AH() ) {
8074 case 0x01: // Read Diskette Status
8075 CLEAR_CF();
8076 val8 = read_byte(0x0000, 0x0441);
8077 SET_AH(val8);
8078 if (val8) {
8079 SET_CF();
8081 return;
8083 default:
8084 SET_CF();
8085 write_byte(0x0000, 0x0441, 0x01);
8086 SET_AH(0x01);
8089 #endif // #if BX_SUPPORT_FLOPPY
8091 void
8092 set_diskette_ret_status(value)
8093 Bit8u value;
8095 write_byte(0x0040, 0x0041, value);
8098 void
8099 set_diskette_current_cyl(drive, cyl)
8100 Bit8u drive;
8101 Bit8u cyl;
8103 if (drive > 1)
8104 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8105 write_byte(0x0040, 0x0094+drive, cyl);
8108 void
8109 determine_floppy_media(drive)
8110 Bit16u drive;
8112 #if 0
8113 Bit8u val8, DOR, ctrl_info;
8115 ctrl_info = read_byte(0x0040, 0x008F);
8116 if (drive==1)
8117 ctrl_info >>= 4;
8118 else
8119 ctrl_info &= 0x0f;
8121 #if 0
8122 if (drive == 0) {
8123 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8125 else {
8126 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8128 #endif
8130 if ( (ctrl_info & 0x04) != 0x04 ) {
8131 // Drive not determined means no drive exists, done.
8132 return;
8135 #if 0
8136 // check Main Status Register for readiness
8137 val8 = inb(0x03f4) & 0x80; // Main Status Register
8138 if (val8 != 0x80)
8139 BX_PANIC("d_f_m: MRQ bit not set\n");
8141 // change line
8143 // existing BDA values
8145 // turn on drive motor
8146 outb(0x03f2, DOR); // Digital Output Register
8147 //
8148 #endif
8149 BX_PANIC("d_f_m: OK so far\n");
8150 #endif
8153 void
8154 int17_function(regs, ds, iret_addr)
8155 pusha_regs_t regs; // regs pushed from PUSHA instruction
8156 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8157 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8159 Bit16u addr,timeout;
8160 Bit8u val8;
8162 ASM_START
8163 sti
8164 ASM_END
8166 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8167 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8168 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8169 if (regs.u.r8.ah == 0) {
8170 outb(addr, regs.u.r8.al);
8171 val8 = inb(addr+2);
8172 outb(addr+2, val8 | 0x01); // send strobe
8173 ASM_START
8174 nop
8175 ASM_END
8176 outb(addr+2, val8 & ~0x01);
8177 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8178 timeout--;
8181 if (regs.u.r8.ah == 1) {
8182 val8 = inb(addr+2);
8183 outb(addr+2, val8 & ~0x04); // send init
8184 ASM_START
8185 nop
8186 ASM_END
8187 outb(addr+2, val8 | 0x04);
8189 val8 = inb(addr+1);
8190 regs.u.r8.ah = (val8 ^ 0x48);
8191 if (!timeout) regs.u.r8.ah |= 0x01;
8192 ClearCF(iret_addr.flags);
8193 } else {
8194 SetCF(iret_addr.flags); // Unsupported
8198 void
8199 int18_function(seq_nr)
8200 Bit16u seq_nr;
8202 Bit16u ebda_seg=read_word(0x0040,0x000E);
8203 Bit16u bootdev;
8204 Bit8u bootdrv;
8205 Bit8u bootchk;
8206 Bit16u bootseg;
8207 Bit16u bootip;
8208 Bit16u status;
8209 Bit16u bootfirst;
8211 ipl_entry_t e;
8213 // if BX_ELTORITO_BOOT is not defined, old behavior
8214 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8215 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8216 // 0: system boot sequence, first drive C: then A:
8217 // 1: system boot sequence, first drive A: then C:
8218 // else BX_ELTORITO_BOOT is defined
8219 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8220 // CMOS reg 0x3D & 0x0f : 1st boot device
8221 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8222 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8223 // boot device codes:
8224 // 0x00 : not defined
8225 // 0x01 : first floppy
8226 // 0x02 : first harddrive
8227 // 0x03 : first cdrom
8228 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
8229 // else : boot failure
8231 // Get the boot sequence
8232 #if BX_ELTORITO_BOOT
8233 bootdev = inb_cmos(0x3d);
8234 bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
8235 bootdev >>= 4 * seq_nr;
8236 bootdev &= 0xf;
8238 /* Read user selected device */
8239 bootfirst = read_word(ebda_seg, IPL_BOOTFIRST_OFFSET);
8240 if (bootfirst != 0xFFFF) {
8241 bootdev = bootfirst;
8242 /* User selected device not set */
8243 write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF);
8244 /* Reset boot sequence */
8245 write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xFFFF);
8246 } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
8248 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
8249 bootdev -= 1;
8250 #else
8251 if (seq_nr ==2) BX_PANIC("No more boot devices.");
8252 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
8253 /* Boot from floppy if the bit is set or it's the second boot */
8254 bootdev = 0x00;
8255 else
8256 bootdev = 0x01;
8257 #endif
8259 /* Read the boot device from the IPL table */
8260 if (get_boot_vector(bootdev, &e) == 0) {
8261 BX_INFO("Invalid boot device (0x%x)\n", bootdev);
8262 return;
8265 /* Do the loading, and set up vector as a far pointer to the boot
8266 * address, and bootdrv as the boot drive */
8267 print_boot_device(&e);
8269 switch(e.type) {
8270 case IPL_TYPE_FLOPPY: /* FDD */
8271 case IPL_TYPE_HARDDISK: /* HDD */
8273 bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
8274 bootseg = 0x07c0;
8275 status = 0;
8277 ASM_START
8278 push bp
8279 mov bp, sp
8280 push ax
8281 push bx
8282 push cx
8283 push dx
8285 mov dl, _int18_function.bootdrv + 2[bp]
8286 mov ax, _int18_function.bootseg + 2[bp]
8287 mov es, ax ;; segment
8288 xor bx, bx ;; offset
8289 mov ah, #0x02 ;; function 2, read diskette sector
8290 mov al, #0x01 ;; read 1 sector
8291 mov ch, #0x00 ;; track 0
8292 mov cl, #0x01 ;; sector 1
8293 mov dh, #0x00 ;; head 0
8294 int #0x13 ;; read sector
8295 jnc int19_load_done
8296 mov ax, #0x0001
8297 mov _int18_function.status + 2[bp], ax
8299 int19_load_done:
8300 pop dx
8301 pop cx
8302 pop bx
8303 pop ax
8304 pop bp
8305 ASM_END
8307 if (status != 0) {
8308 print_boot_failure(e.type, 1);
8309 return;
8312 /* Always check the signature on a HDD boot sector; on FDD, only do
8313 * the check if the CMOS doesn't tell us to skip it */
8314 if ((e.type != IPL_TYPE_FLOPPY) || !((inb_cmos(0x38) & 0x01))) {
8315 if (read_word(bootseg,0x1fe) != 0xaa55) {
8316 print_boot_failure(e.type, 0);
8317 return;
8321 #if BX_TCGBIOS
8322 tcpa_add_bootdevice((Bit32u)0L, (Bit32u)bootdrv);
8323 tcpa_ipl((Bit32u)0L,(Bit32u)bootseg,(Bit32u)0L,(Bit32u)512L); /* specs: 8.2.3 steps 4 and 5 */
8324 #endif
8326 /* Canonicalize bootseg:bootip */
8327 bootip = (bootseg & 0x0fff) << 4;
8328 bootseg &= 0xf000;
8329 break;
8331 #if BX_ELTORITO_BOOT
8332 case IPL_TYPE_CDROM: /* CD-ROM */
8333 status = cdrom_boot();
8335 // If failure
8336 if ( (status & 0x00ff) !=0 ) {
8337 print_cdromboot_failure(status);
8338 print_boot_failure(e.type, 1);
8339 return;
8342 bootdrv = (Bit8u)(status>>8);
8343 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8345 /* Canonicalize bootseg:bootip */
8346 bootip = (bootseg & 0x0fff) << 4;
8347 bootseg &= 0xf000;
8348 break;
8349 #endif
8351 case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
8352 bootseg = e.vector >> 16;
8353 bootip = e.vector & 0xffff;
8354 break;
8356 default: return;
8359 /* Debugging info */
8360 BX_INFO("Booting from %x:%x\n", bootseg, bootip);
8362 /* Jump to the boot vector */
8363 ASM_START
8364 mov bp, sp
8365 push cs
8366 push #int18_handler
8367 ;; Build an iret stack frame that will take us to the boot vector.
8368 ;; iret pops ip, then cs, then flags, so push them in the opposite order.
8369 pushf
8370 mov ax, _int18_function.bootseg + 0[bp]
8371 push ax
8372 mov ax, _int18_function.bootip + 0[bp]
8373 push ax
8374 ;; Set the magic number in ax and the boot drive in dl.
8375 mov ax, #0xaa55
8376 mov dl, _int18_function.bootdrv + 0[bp]
8377 ;; Zero some of the other registers.
8378 xor bx, bx
8379 mov ds, bx
8380 mov es, bx
8381 mov bp, bx
8382 ;; Go!
8383 iret
8384 ASM_END
8387 void
8388 int1a_function(regs, ds, iret_addr)
8389 pusha_regs_t regs; // regs pushed from PUSHA instruction
8390 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8391 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8393 Bit8u val8;
8395 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);
8397 ASM_START
8398 sti
8399 ASM_END
8401 switch (regs.u.r8.ah) {
8402 case 0: // get current clock count
8403 ASM_START
8404 cli
8405 ASM_END
8406 regs.u.r16.cx = BiosData->ticks_high;
8407 regs.u.r16.dx = BiosData->ticks_low;
8408 regs.u.r8.al = BiosData->midnight_flag;
8409 BiosData->midnight_flag = 0; // reset flag
8410 ASM_START
8411 sti
8412 ASM_END
8413 // AH already 0
8414 ClearCF(iret_addr.flags); // OK
8415 break;
8417 case 1: // Set Current Clock Count
8418 ASM_START
8419 cli
8420 ASM_END
8421 BiosData->ticks_high = regs.u.r16.cx;
8422 BiosData->ticks_low = regs.u.r16.dx;
8423 BiosData->midnight_flag = 0; // reset flag
8424 ASM_START
8425 sti
8426 ASM_END
8427 regs.u.r8.ah = 0;
8428 ClearCF(iret_addr.flags); // OK
8429 break;
8432 case 2: // Read CMOS Time
8433 if (rtc_updating()) {
8434 SetCF(iret_addr.flags);
8435 break;
8438 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8439 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8440 regs.u.r8.ch = inb_cmos(0x04); // Hours
8441 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8442 regs.u.r8.ah = 0;
8443 regs.u.r8.al = regs.u.r8.ch;
8444 ClearCF(iret_addr.flags); // OK
8445 break;
8447 case 3: // Set CMOS Time
8448 // Using a debugger, I notice the following masking/setting
8449 // of bits in Status Register B, by setting Reg B to
8450 // a few values and getting its value after INT 1A was called.
8451 //
8452 // try#1 try#2 try#3
8453 // before 1111 1101 0111 1101 0000 0000
8454 // after 0110 0010 0110 0010 0000 0010
8455 //
8456 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8457 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8458 if (rtc_updating()) {
8459 init_rtc();
8460 // fall through as if an update were not in progress
8462 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8463 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8464 outb_cmos(0x04, regs.u.r8.ch); // Hours
8465 // Set Daylight Savings time enabled bit to requested value
8466 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8467 // (reg B already selected)
8468 outb_cmos(0x0b, val8);
8469 regs.u.r8.ah = 0;
8470 regs.u.r8.al = val8; // val last written to Reg B
8471 ClearCF(iret_addr.flags); // OK
8472 break;
8474 case 4: // Read CMOS Date
8475 regs.u.r8.ah = 0;
8476 if (rtc_updating()) {
8477 SetCF(iret_addr.flags);
8478 break;
8480 regs.u.r8.cl = inb_cmos(0x09); // Year
8481 regs.u.r8.dh = inb_cmos(0x08); // Month
8482 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8483 regs.u.r8.ch = inb_cmos(0x32); // Century
8484 regs.u.r8.al = regs.u.r8.ch;
8485 ClearCF(iret_addr.flags); // OK
8486 break;
8488 case 5: // Set CMOS Date
8489 // Using a debugger, I notice the following masking/setting
8490 // of bits in Status Register B, by setting Reg B to
8491 // a few values and getting its value after INT 1A was called.
8492 //
8493 // try#1 try#2 try#3 try#4
8494 // before 1111 1101 0111 1101 0000 0010 0000 0000
8495 // after 0110 1101 0111 1101 0000 0010 0000 0000
8496 //
8497 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8498 // My assumption: RegB = (RegB & 01111111b)
8499 if (rtc_updating()) {
8500 init_rtc();
8501 SetCF(iret_addr.flags);
8502 break;
8504 outb_cmos(0x09, regs.u.r8.cl); // Year
8505 outb_cmos(0x08, regs.u.r8.dh); // Month
8506 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8507 outb_cmos(0x32, regs.u.r8.ch); // Century
8508 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8509 outb_cmos(0x0b, val8);
8510 regs.u.r8.ah = 0;
8511 regs.u.r8.al = val8; // AL = val last written to Reg B
8512 ClearCF(iret_addr.flags); // OK
8513 break;
8515 case 6: // Set Alarm Time in CMOS
8516 // Using a debugger, I notice the following masking/setting
8517 // of bits in Status Register B, by setting Reg B to
8518 // a few values and getting its value after INT 1A was called.
8519 //
8520 // try#1 try#2 try#3
8521 // before 1101 1111 0101 1111 0000 0000
8522 // after 0110 1111 0111 1111 0010 0000
8523 //
8524 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8525 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8526 val8 = inb_cmos(0x0b); // Get Status Reg B
8527 regs.u.r16.ax = 0;
8528 if (val8 & 0x20) {
8529 // Alarm interrupt enabled already
8530 SetCF(iret_addr.flags); // Error: alarm in use
8531 break;
8533 if (rtc_updating()) {
8534 init_rtc();
8535 // fall through as if an update were not in progress
8537 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8538 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8539 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8540 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8541 // enable Status Reg B alarm bit, clear halt clock bit
8542 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8543 ClearCF(iret_addr.flags); // OK
8544 break;
8546 case 7: // Turn off Alarm
8547 // Using a debugger, I notice the following masking/setting
8548 // of bits in Status Register B, by setting Reg B to
8549 // a few values and getting its value after INT 1A was called.
8550 //
8551 // try#1 try#2 try#3 try#4
8552 // before 1111 1101 0111 1101 0010 0000 0010 0010
8553 // after 0100 0101 0101 0101 0000 0000 0000 0010
8554 //
8555 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8556 // My assumption: RegB = (RegB & 01010111b)
8557 val8 = inb_cmos(0x0b); // Get Status Reg B
8558 // clear clock-halt bit, disable alarm bit
8559 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8560 regs.u.r8.ah = 0;
8561 regs.u.r8.al = val8; // val last written to Reg B
8562 ClearCF(iret_addr.flags); // OK
8563 break;
8564 #if BX_PCIBIOS
8565 case 0xb1:
8566 // real mode PCI BIOS functions now handled in assembler code
8567 // this C code handles the error code for information only
8568 if (regs.u.r8.bl == 0xff) {
8569 BX_INFO("PCI BIOS: PCI not present\n");
8570 } else if (regs.u.r8.bl == 0x81) {
8571 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8572 } else if (regs.u.r8.bl == 0x83) {
8573 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8574 } else if (regs.u.r8.bl == 0x86) {
8575 if (regs.u.r8.al == 0x02) {
8576 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8577 } else {
8578 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);
8581 regs.u.r8.ah = regs.u.r8.bl;
8582 SetCF(iret_addr.flags);
8583 break;
8584 #endif
8586 default:
8587 SetCF(iret_addr.flags); // Unsupported
8591 void
8592 int70_function(regs, ds, iret_addr)
8593 pusha_regs_t regs; // regs pushed from PUSHA instruction
8594 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8595 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8597 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8598 Bit8u registerB = 0, registerC = 0;
8600 // Check which modes are enabled and have occurred.
8601 registerB = inb_cmos( 0xB );
8602 registerC = inb_cmos( 0xC );
8604 if( ( registerB & 0x60 ) != 0 ) {
8605 if( ( registerC & 0x20 ) != 0 ) {
8606 // Handle Alarm Interrupt.
8607 ASM_START
8608 sti
8609 int #0x4a
8610 cli
8611 ASM_END
8613 if( ( registerC & 0x40 ) != 0 ) {
8614 // Handle Periodic Interrupt.
8616 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8617 // Wait Interval (Int 15, AH=83) active.
8618 Bit32u time, toggle;
8620 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8621 if( time < 0x3D1 ) {
8622 // Done waiting.
8623 Bit16u segment, offset;
8625 segment = read_word( 0x40, 0x98 );
8626 offset = read_word( 0x40, 0x9A );
8627 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8628 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8629 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8630 } else {
8631 // Continue waiting.
8632 time -= 0x3D1;
8633 write_dword( 0x40, 0x9C, time );
8639 ASM_START
8640 call eoi_both_pics
8641 ASM_END
8645 ASM_START
8646 ;------------------------------------------
8647 ;- INT74h : PS/2 mouse hardware interrupt -
8648 ;------------------------------------------
8649 int74_handler:
8650 sti
8651 pusha
8652 push ds ;; save DS
8653 push #0x00 ;; placeholder for status
8654 push #0x00 ;; placeholder for X
8655 push #0x00 ;; placeholder for Y
8656 push #0x00 ;; placeholder for Z
8657 push #0x00 ;; placeholder for make_far_call boolean
8658 call _int74_function
8659 pop cx ;; remove make_far_call from stack
8660 jcxz int74_done
8662 ;; make far call to EBDA:0022
8663 push #0x00
8664 pop ds
8665 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8666 pop ds
8667 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8668 call far ptr[0x22]
8669 int74_done:
8670 cli
8671 call eoi_both_pics
8672 add sp, #8 ;; pop status, x, y, z
8674 pop ds ;; restore DS
8675 popa
8676 iret
8679 ;; This will perform an IRET, but will retain value of current CF
8680 ;; by altering flags on stack. Better than RETF #02.
8681 iret_modify_cf:
8682 jc carry_set
8683 push bp
8684 mov bp, sp
8685 and BYTE [bp + 0x06], #0xfe
8686 pop bp
8687 iret
8688 carry_set:
8689 push bp
8690 mov bp, sp
8691 or BYTE [bp + 0x06], #0x01
8692 pop bp
8693 iret
8696 ;----------------------
8697 ;- INT13h (relocated) -
8698 ;----------------------
8700 ; int13_relocated is a little bit messed up since I played with it
8701 ; I have to rewrite it:
8702 ; - call a function that detect which function to call
8703 ; - make all called C function get the same parameters list
8705 int13_relocated:
8707 #if BX_ELTORITO_BOOT
8708 ;; check for an eltorito function
8709 cmp ah,#0x4a
8710 jb int13_not_eltorito
8711 cmp ah,#0x4d
8712 ja int13_not_eltorito
8714 pusha
8715 push es
8716 push ds
8717 push ss
8718 pop ds
8720 push #int13_out
8721 jmp _int13_eltorito ;; ELDX not used
8723 int13_not_eltorito:
8724 push ax
8725 push bx
8726 push cx
8727 push dx
8729 ;; check if emulation active
8730 call _cdemu_isactive
8731 cmp al,#0x00
8732 je int13_cdemu_inactive
8734 ;; check if access to the emulated drive
8735 call _cdemu_emulated_drive
8736 pop dx
8737 push dx
8738 cmp al,dl ;; int13 on emulated drive
8739 jne int13_nocdemu
8741 pop dx
8742 pop cx
8743 pop bx
8744 pop ax
8746 pusha
8747 push es
8748 push ds
8749 push ss
8750 pop ds
8752 push #int13_out
8753 jmp _int13_cdemu ;; ELDX not used
8755 int13_nocdemu:
8756 and dl,#0xE0 ;; mask to get device class, including cdroms
8757 cmp al,dl ;; al is 0x00 or 0x80
8758 jne int13_cdemu_inactive ;; inactive for device class
8760 pop dx
8761 pop cx
8762 pop bx
8763 pop ax
8765 push ax
8766 push cx
8767 push dx
8768 push bx
8770 dec dl ;; real drive is dl - 1
8771 jmp int13_legacy
8773 int13_cdemu_inactive:
8774 pop dx
8775 pop cx
8776 pop bx
8777 pop ax
8779 #endif // BX_ELTORITO_BOOT
8781 int13_noeltorito:
8783 push ax
8784 push cx
8785 push dx
8786 push bx
8788 int13_legacy:
8790 push dx ;; push eltorito value of dx instead of sp
8792 push bp
8793 push si
8794 push di
8796 push es
8797 push ds
8798 push ss
8799 pop ds
8801 ;; now the 16-bit registers can be restored with:
8802 ;; pop ds; pop es; popa; iret
8803 ;; arguments passed to functions should be
8804 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8806 test dl, #0x80
8807 jnz int13_notfloppy
8809 push #int13_out
8810 jmp _int13_diskette_function
8812 int13_notfloppy:
8814 #if BX_USE_ATADRV
8816 cmp dl, #0xE0
8817 jb int13_notcdrom
8819 // ebx is modified: BSD 5.2.1 boot loader problem
8820 // someone should figure out which 32 bit register that actually are used
8822 shr ebx, #16
8823 push bx
8825 call _int13_cdrom
8827 pop bx
8828 shl ebx, #16
8830 jmp int13_out
8832 int13_notcdrom:
8834 #endif
8836 int13_disk:
8837 ;; int13_harddisk modifies high word of EAX
8838 shr eax, #16
8839 push ax
8840 call _int13_harddisk
8841 pop ax
8842 shl eax, #16
8844 int13_out:
8845 pop ds
8846 pop es
8847 popa
8848 iret
8850 ;----------
8851 ;- INT18h -
8852 ;----------
8853 int18_handler: ;; Boot Failure recovery: try the next device.
8855 ;; Reset SP and SS
8856 mov ax, #0xfffe
8857 mov sp, ax
8858 xor ax, ax
8859 mov ss, ax
8861 ;; The first time we do this it will have been set to -1 so
8862 ;; we will start from device 0.
8863 mov ds, ax
8864 mov bx, word ptr [0x40E] ;; EBDA segment
8865 mov ds, bx ;; Set segment
8866 mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number
8867 inc bx ;; ++
8868 mov IPL_SEQUENCE_OFFSET, bx ;; Write it back
8869 mov ds, ax ;; and reset the segment to zero.
8871 ;; Call the C code for the next boot device
8872 push bx
8874 call _int18_function
8876 ;; Boot failed: invoke the boot recovery function...
8877 int #0x18
8879 ;----------
8880 ;- INT19h -
8881 ;----------
8882 int19_relocated: ;; Boot function, relocated
8884 ;;
8885 ;; *** Warning: INT 19h resets the whole machine ***
8886 ;;
8887 ;; Because PV drivers in HVM guests detach some of the emulated devices,
8888 ;; it is not safe to do a soft reboot by just dropping to real mode and
8889 ;; invoking INT 19h -- the boot drives might have disappeared!
8890 ;; If the user asks for a soft reboot, the only thing we can do is
8891 ;; reset the whole machine. When it comes back up, the normal BIOS
8892 ;; boot sequence will start, which is more or less the required behaviour.
8893 ;;
8894 ;; Reset SP and SS
8896 mov ax, #0xfffe
8897 mov sp, ax
8898 xor ax, ax
8899 mov ss, ax
8901 call _machine_reset
8903 ;----------
8904 ;- INT1Ch -
8905 ;----------
8906 int1c_handler: ;; User Timer Tick
8907 iret
8910 ;----------------------
8911 ;- POST: Floppy Drive -
8912 ;----------------------
8913 floppy_drive_post:
8914 xor ax, ax
8915 mov ds, ax
8917 mov al, #0x00
8918 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8920 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8922 mov 0x0440, al ;; diskette motor timeout counter: not active
8923 mov 0x0441, al ;; diskette controller status return code
8925 mov 0x0442, al ;; disk & diskette controller status register 0
8926 mov 0x0443, al ;; diskette controller status register 1
8927 mov 0x0444, al ;; diskette controller status register 2
8928 mov 0x0445, al ;; diskette controller cylinder number
8929 mov 0x0446, al ;; diskette controller head number
8930 mov 0x0447, al ;; diskette controller sector number
8931 mov 0x0448, al ;; diskette controller bytes written
8933 mov 0x048b, al ;; diskette configuration data
8935 ;; -----------------------------------------------------------------
8936 ;; (048F) diskette controller information
8937 ;;
8938 mov al, #0x10 ;; get CMOS diskette drive type
8939 out 0x70, AL
8940 in AL, 0x71
8941 mov ah, al ;; save byte to AH
8943 look_drive0:
8944 shr al, #4 ;; look at top 4 bits for drive 0
8945 jz f0_missing ;; jump if no drive0
8946 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8947 jmp look_drive1
8948 f0_missing:
8949 mov bl, #0x00 ;; no drive0
8951 look_drive1:
8952 mov al, ah ;; restore from AH
8953 and al, #0x0f ;; look at bottom 4 bits for drive 1
8954 jz f1_missing ;; jump if no drive1
8955 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8956 f1_missing:
8957 ;; leave high bits in BL zerod
8958 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8959 ;; -----------------------------------------------------------------
8961 mov al, #0x00
8962 mov 0x0490, al ;; diskette 0 media state
8963 mov 0x0491, al ;; diskette 1 media state
8965 ;; diskette 0,1 operational starting state
8966 ;; drive type has not been determined,
8967 ;; has no changed detection line
8968 mov 0x0492, al
8969 mov 0x0493, al
8971 mov 0x0494, al ;; diskette 0 current cylinder
8972 mov 0x0495, al ;; diskette 1 current cylinder
8974 mov al, #0x02
8975 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8977 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8978 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8979 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8981 ret
8984 ;--------------------
8985 ;- POST: HARD DRIVE -
8986 ;--------------------
8987 ; relocated here because the primary POST area isnt big enough.
8988 hard_drive_post:
8989 // IRQ 14 = INT 76h
8990 // INT 76h calls INT 15h function ax=9100
8992 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8993 mov dx, #0x03f6
8994 out dx, al
8996 xor ax, ax
8997 mov ds, ax
8998 mov 0x0474, al /* hard disk status of last operation */
8999 mov 0x0477, al /* hard disk port offset (XT only ???) */
9000 mov 0x048c, al /* hard disk status register */
9001 mov 0x048d, al /* hard disk error register */
9002 mov 0x048e, al /* hard disk task complete flag */
9003 mov al, #0x01
9004 mov 0x0475, al /* hard disk number attached */
9005 mov al, #0xc0
9006 mov 0x0476, al /* hard disk control byte */
9007 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9008 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9009 ;; INT 41h: hard disk 0 configuration pointer
9010 ;; INT 46h: hard disk 1 configuration pointer
9011 SET_INT_VECTOR(0x41, word ptr [0x40E], #0x003D) /* EBDA:003D */
9012 SET_INT_VECTOR(0x46, word ptr [0x40E], #0x004D) /* EBDA:004D */
9014 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9015 mov al, #0x12
9016 out #0x70, al
9017 in al, #0x71
9018 and al, #0xf0
9019 cmp al, #0xf0
9020 je post_d0_extended
9021 jmp check_for_hd1
9022 post_d0_extended:
9023 mov al, #0x19
9024 out #0x70, al
9025 in al, #0x71
9026 cmp al, #47 ;; decimal 47 - user definable
9027 je post_d0_type47
9028 HALT(__LINE__)
9029 post_d0_type47:
9030 ;; CMOS purpose param table offset
9031 ;; 1b cylinders low 0
9032 ;; 1c cylinders high 1
9033 ;; 1d heads 2
9034 ;; 1e write pre-comp low 5
9035 ;; 1f write pre-comp high 6
9036 ;; 20 retries/bad map/heads>8 8
9037 ;; 21 landing zone low C
9038 ;; 22 landing zone high D
9039 ;; 23 sectors/track E
9041 xor ax, ax
9042 mov ds, ax
9043 mov ax, word ptr [0x40E] ;; EBDA segment
9044 mov ds, ax
9046 ;;; Filling EBDA table for hard disk 0.
9047 mov al, #0x1f
9048 out #0x70, al
9049 in al, #0x71
9050 mov ah, al
9051 mov al, #0x1e
9052 out #0x70, al
9053 in al, #0x71
9054 mov (0x003d + 0x05), ax ;; write precomp word
9056 mov al, #0x20
9057 out #0x70, al
9058 in al, #0x71
9059 mov (0x003d + 0x08), al ;; drive control byte
9061 mov al, #0x22
9062 out #0x70, al
9063 in al, #0x71
9064 mov ah, al
9065 mov al, #0x21
9066 out #0x70, al
9067 in al, #0x71
9068 mov (0x003d + 0x0C), ax ;; landing zone word
9070 mov al, #0x1c ;; get cylinders word in AX
9071 out #0x70, al
9072 in al, #0x71 ;; high byte
9073 mov ah, al
9074 mov al, #0x1b
9075 out #0x70, al
9076 in al, #0x71 ;; low byte
9077 mov bx, ax ;; BX = cylinders
9079 mov al, #0x1d
9080 out #0x70, al
9081 in al, #0x71
9082 mov cl, al ;; CL = heads
9084 mov al, #0x23
9085 out #0x70, al
9086 in al, #0x71
9087 mov dl, al ;; DL = sectors
9089 cmp bx, #1024
9090 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9092 hd0_post_physical_chs:
9093 ;; no logical CHS mapping used, just physical CHS
9094 ;; use Standard Fixed Disk Parameter Table (FDPT)
9095 mov (0x003d + 0x00), bx ;; number of physical cylinders
9096 mov (0x003d + 0x02), cl ;; number of physical heads
9097 mov (0x003d + 0x0E), dl ;; number of physical sectors
9098 jmp check_for_hd1
9100 hd0_post_logical_chs:
9101 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9102 mov (0x003d + 0x09), bx ;; number of physical cylinders
9103 mov (0x003d + 0x0b), cl ;; number of physical heads
9104 mov (0x003d + 0x04), dl ;; number of physical sectors
9105 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9106 mov al, #0xa0
9107 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9109 cmp bx, #2048
9110 jnbe hd0_post_above_2048
9111 ;; 1024 < c <= 2048 cylinders
9112 shr bx, #0x01
9113 shl cl, #0x01
9114 jmp hd0_post_store_logical
9116 hd0_post_above_2048:
9117 cmp bx, #4096
9118 jnbe hd0_post_above_4096
9119 ;; 2048 < c <= 4096 cylinders
9120 shr bx, #0x02
9121 shl cl, #0x02
9122 jmp hd0_post_store_logical
9124 hd0_post_above_4096:
9125 cmp bx, #8192
9126 jnbe hd0_post_above_8192
9127 ;; 4096 < c <= 8192 cylinders
9128 shr bx, #0x03
9129 shl cl, #0x03
9130 jmp hd0_post_store_logical
9132 hd0_post_above_8192:
9133 ;; 8192 < c <= 16384 cylinders
9134 shr bx, #0x04
9135 shl cl, #0x04
9137 hd0_post_store_logical:
9138 mov (0x003d + 0x00), bx ;; number of physical cylinders
9139 mov (0x003d + 0x02), cl ;; number of physical heads
9140 ;; checksum
9141 mov cl, #0x0f ;; repeat count
9142 mov si, #0x003d ;; offset to disk0 FDPT
9143 mov al, #0x00 ;; sum
9144 hd0_post_checksum_loop:
9145 add al, [si]
9146 inc si
9147 dec cl
9148 jnz hd0_post_checksum_loop
9149 not al ;; now take 2s complement
9150 inc al
9151 mov [si], al
9152 ;;; Done filling EBDA table for hard disk 0.
9155 check_for_hd1:
9156 ;; is there really a second hard disk? if not, return now
9157 mov al, #0x12
9158 out #0x70, al
9159 in al, #0x71
9160 and al, #0x0f
9161 jnz post_d1_exists
9162 ret
9163 post_d1_exists:
9164 ;; check that the hd type is really 0x0f.
9165 cmp al, #0x0f
9166 jz post_d1_extended
9167 HALT(__LINE__)
9168 post_d1_extended:
9169 ;; check that the extended type is 47 - user definable
9170 mov al, #0x1a
9171 out #0x70, al
9172 in al, #0x71
9173 cmp al, #47 ;; decimal 47 - user definable
9174 je post_d1_type47
9175 HALT(__LINE__)
9176 post_d1_type47:
9177 ;; Table for disk1.
9178 ;; CMOS purpose param table offset
9179 ;; 0x24 cylinders low 0
9180 ;; 0x25 cylinders high 1
9181 ;; 0x26 heads 2
9182 ;; 0x27 write pre-comp low 5
9183 ;; 0x28 write pre-comp high 6
9184 ;; 0x29 heads>8 8
9185 ;; 0x2a landing zone low C
9186 ;; 0x2b landing zone high D
9187 ;; 0x2c sectors/track E
9188 ;;; Fill EBDA table for hard disk 1.
9189 xor ax, ax
9190 mov ds, ax
9191 mov ax, word ptr [0x40E] ;; EBDA segment
9192 mov ds, ax
9193 mov al, #0x28
9194 out #0x70, al
9195 in al, #0x71
9196 mov ah, al
9197 mov al, #0x27
9198 out #0x70, al
9199 in al, #0x71
9200 mov (0x004d + 0x05), ax ;; write precomp word
9202 mov al, #0x29
9203 out #0x70, al
9204 in al, #0x71
9205 mov (0x004d + 0x08), al ;; drive control byte
9207 mov al, #0x2b
9208 out #0x70, al
9209 in al, #0x71
9210 mov ah, al
9211 mov al, #0x2a
9212 out #0x70, al
9213 in al, #0x71
9214 mov (0x004d + 0x0C), ax ;; landing zone word
9216 mov al, #0x25 ;; get cylinders word in AX
9217 out #0x70, al
9218 in al, #0x71 ;; high byte
9219 mov ah, al
9220 mov al, #0x24
9221 out #0x70, al
9222 in al, #0x71 ;; low byte
9223 mov bx, ax ;; BX = cylinders
9225 mov al, #0x26
9226 out #0x70, al
9227 in al, #0x71
9228 mov cl, al ;; CL = heads
9230 mov al, #0x2c
9231 out #0x70, al
9232 in al, #0x71
9233 mov dl, al ;; DL = sectors
9235 cmp bx, #1024
9236 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9238 hd1_post_physical_chs:
9239 ;; no logical CHS mapping used, just physical CHS
9240 ;; use Standard Fixed Disk Parameter Table (FDPT)
9241 mov (0x004d + 0x00), bx ;; number of physical cylinders
9242 mov (0x004d + 0x02), cl ;; number of physical heads
9243 mov (0x004d + 0x0E), dl ;; number of physical sectors
9244 ret
9246 hd1_post_logical_chs:
9247 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9248 mov (0x004d + 0x09), bx ;; number of physical cylinders
9249 mov (0x004d + 0x0b), cl ;; number of physical heads
9250 mov (0x004d + 0x04), dl ;; number of physical sectors
9251 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9252 mov al, #0xa0
9253 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9255 cmp bx, #2048
9256 jnbe hd1_post_above_2048
9257 ;; 1024 < c <= 2048 cylinders
9258 shr bx, #0x01
9259 shl cl, #0x01
9260 jmp hd1_post_store_logical
9262 hd1_post_above_2048:
9263 cmp bx, #4096
9264 jnbe hd1_post_above_4096
9265 ;; 2048 < c <= 4096 cylinders
9266 shr bx, #0x02
9267 shl cl, #0x02
9268 jmp hd1_post_store_logical
9270 hd1_post_above_4096:
9271 cmp bx, #8192
9272 jnbe hd1_post_above_8192
9273 ;; 4096 < c <= 8192 cylinders
9274 shr bx, #0x03
9275 shl cl, #0x03
9276 jmp hd1_post_store_logical
9278 hd1_post_above_8192:
9279 ;; 8192 < c <= 16384 cylinders
9280 shr bx, #0x04
9281 shl cl, #0x04
9283 hd1_post_store_logical:
9284 mov (0x004d + 0x00), bx ;; number of physical cylinders
9285 mov (0x004d + 0x02), cl ;; number of physical heads
9286 ;; checksum
9287 mov cl, #0x0f ;; repeat count
9288 mov si, #0x004d ;; offset to disk0 FDPT
9289 mov al, #0x00 ;; sum
9290 hd1_post_checksum_loop:
9291 add al, [si]
9292 inc si
9293 dec cl
9294 jnz hd1_post_checksum_loop
9295 not al ;; now take 2s complement
9296 inc al
9297 mov [si], al
9298 ;;; Done filling EBDA table for hard disk 1.
9300 ret
9302 ;--------------------
9303 ;- POST: EBDA segment
9304 ;--------------------
9305 ; relocated here because the primary POST area isnt big enough.
9306 ebda_post:
9307 #if BX_USE_EBDA
9308 mov ax, #EBDA_SEG
9309 mov ds, ax
9310 mov byte ptr [0x0], #EBDA_SIZE
9311 #endif
9312 xor ax, ax ; mov EBDA seg into 40E
9313 mov ds, ax
9314 mov word ptr [0x40E], #EBDA_SEG
9315 ret;;
9317 ;--------------------
9318 ;- POST: EOI + jmp via [0x40:67)
9319 ;--------------------
9320 ; relocated here because the primary POST area isnt big enough.
9321 eoi_jmp_post:
9322 mov al, #0x20
9323 out #0xA0, al ;; slave PIC EOI
9324 mov al, #0x20
9325 out #0x20, al ;; master PIC EOI
9327 jmp_post_0x467:
9328 xor ax, ax
9329 mov ds, ax
9331 jmp far ptr [0x467]
9333 iret_post_0x467:
9334 xor ax, ax
9335 mov ds, ax
9337 mov sp, [0x467]
9338 mov ss, [0x469]
9339 iret
9341 retf_post_0x467:
9342 xor ax, ax
9343 mov ds, ax
9345 mov sp, [0x467]
9346 mov ss, [0x469]
9347 retf
9349 s3_post:
9350 #if BX_ROMBIOS32
9351 call rombios32_init
9352 #endif
9353 call _s3_resume
9354 mov bl, #0x00
9355 and ax, ax
9356 jz normal_post
9357 call _s3_resume_panic
9359 ;--------------------
9360 eoi_both_pics:
9361 mov al, #0x20
9362 out #0xA0, al ;; slave PIC EOI
9363 eoi_master_pic:
9364 mov al, #0x20
9365 out #0x20, al ;; master PIC EOI
9366 ret
9368 ;--------------------
9369 BcdToBin:
9370 ;; in: AL in BCD format
9371 ;; out: AL in binary format, AH will always be 0
9372 ;; trashes BX
9373 mov bl, al
9374 and bl, #0x0f ;; bl has low digit
9375 shr al, #4 ;; al has high digit
9376 mov bh, #10
9377 mul al, bh ;; multiply high digit by 10 (result in AX)
9378 add al, bl ;; then add low digit
9379 ret
9381 ;--------------------
9382 timer_tick_post:
9383 ;; Setup the Timer Ticks Count (0x46C:dword) and
9384 ;; Timer Ticks Roller Flag (0x470:byte)
9385 ;; The Timer Ticks Count needs to be set according to
9386 ;; the current CMOS time, as if ticks have been occurring
9387 ;; at 18.2hz since midnight up to this point. Calculating
9388 ;; this is a little complicated. Here are the factors I gather
9389 ;; regarding this. 14,318,180 hz was the original clock speed,
9390 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9391 ;; at the time, or 4 to drive the CGA video adapter. The div3
9392 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9393 ;; the timer. With a maximum 16bit timer count, this is again
9394 ;; divided down by 65536 to 18.2hz.
9395 ;;
9396 ;; 14,318,180 Hz clock
9397 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9398 ;; /4 = 1,193,181 Hz fed to timer
9399 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9400 ;; 1 second = 18.20650736 ticks
9401 ;; 1 minute = 1092.390442 ticks
9402 ;; 1 hour = 65543.42651 ticks
9403 ;;
9404 ;; Given the values in the CMOS clock, one could calculate
9405 ;; the number of ticks by the following:
9406 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9407 ;; (BcdToBin(minutes) * 1092.3904)
9408 ;; (BcdToBin(hours) * 65543.427)
9409 ;; To get a little more accuracy, since Im using integer
9410 ;; arithmatic, I use:
9411 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9412 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9413 ;; (BcdToBin(hours) * 65543427) / 1000
9415 ;; assuming DS=0000
9417 ;; get CMOS seconds
9418 xor eax, eax ;; clear EAX
9419 mov al, #0x00
9420 out #0x70, al
9421 in al, #0x71 ;; AL has CMOS seconds in BCD
9422 call BcdToBin ;; EAX now has seconds in binary
9423 mov edx, #18206507
9424 mul eax, edx
9425 mov ebx, #1000000
9426 xor edx, edx
9427 div eax, ebx
9428 mov ecx, eax ;; ECX will accumulate total ticks
9430 ;; get CMOS minutes
9431 xor eax, eax ;; clear EAX
9432 mov al, #0x02
9433 out #0x70, al
9434 in al, #0x71 ;; AL has CMOS minutes in BCD
9435 call BcdToBin ;; EAX now has minutes in binary
9436 mov edx, #10923904
9437 mul eax, edx
9438 mov ebx, #10000
9439 xor edx, edx
9440 div eax, ebx
9441 add ecx, eax ;; add to total ticks
9443 ;; get CMOS hours
9444 xor eax, eax ;; clear EAX
9445 mov al, #0x04
9446 out #0x70, al
9447 in al, #0x71 ;; AL has CMOS hours in BCD
9448 call BcdToBin ;; EAX now has hours in binary
9449 mov edx, #65543427
9450 mul eax, edx
9451 mov ebx, #1000
9452 xor edx, edx
9453 div eax, ebx
9454 add ecx, eax ;; add to total ticks
9456 mov 0x46C, ecx ;; Timer Ticks Count
9457 xor al, al
9458 mov 0x470, al ;; Timer Ticks Rollover Flag
9459 ret
9461 ;--------------------
9462 int76_handler:
9463 ;; record completion in BIOS task complete flag
9464 push ax
9465 push ds
9466 mov ax, #0x0040
9467 mov ds, ax
9468 mov 0x008E, #0xff
9469 call eoi_both_pics
9470 pop ds
9471 pop ax
9472 iret
9475 ;--------------------
9476 #if BX_APM
9478 use32 386
9479 #define APM_PROT32
9480 #include "apmbios.S"
9482 use16 386
9483 #define APM_PROT16
9484 #include "apmbios.S"
9486 #define APM_REAL
9487 #include "apmbios.S"
9489 #endif
9491 #include "32bitgateway.c"
9492 ASM_END
9493 #include "tcgbios.c"
9494 ASM_START
9496 ;--------------------
9497 #if BX_PCIBIOS
9498 use32 386
9499 .align 16
9500 bios32_structure:
9501 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9502 dw bios32_entry_point, 0xf ;; 32 bit physical address
9503 db 0 ;; revision level
9504 ;; length in paragraphs and checksum stored in a word to prevent errors
9505 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9506 & 0xff) << 8) + 0x01
9507 db 0,0,0,0,0 ;; reserved
9509 .align 16
9510 bios32_entry_point:
9511 pushfd
9512 cmp eax, #0x49435024 ;; "$PCI"
9513 jne unknown_service
9514 mov eax, #0x80000000
9515 mov dx, #0x0cf8
9516 out dx, eax
9517 mov dx, #0x0cfc
9518 in eax, dx
9519 #ifdef PCI_FIXED_HOST_BRIDGE
9520 cmp eax, #PCI_FIXED_HOST_BRIDGE
9521 jne unknown_service
9522 #else
9523 ;; say ok if a device is present
9524 cmp eax, #0xffffffff
9525 je unknown_service
9526 #endif
9527 mov ebx, #0x000f0000
9528 mov ecx, #0
9529 mov edx, #pcibios_protected
9530 xor al, al
9531 jmp bios32_end
9532 unknown_service:
9533 mov al, #0x80
9534 bios32_end:
9535 #ifdef BX_QEMU
9536 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9537 #endif
9538 popfd
9539 retf
9541 .align 16
9542 pcibios_protected:
9543 pushfd
9544 cli
9545 push esi
9546 push edi
9547 cmp al, #0x01 ;; installation check
9548 jne pci_pro_f02
9549 mov bx, #0x0210
9550 mov cx, #0
9551 mov edx, #0x20494350 ;; "PCI "
9552 mov al, #0x01
9553 jmp pci_pro_ok
9554 pci_pro_f02: ;; find pci device
9555 cmp al, #0x02
9556 jne pci_pro_f03
9557 shl ecx, #16
9558 mov cx, dx
9559 xor bx, bx
9560 mov di, #0x00
9561 pci_pro_devloop:
9562 call pci_pro_select_reg
9563 mov dx, #0x0cfc
9564 in eax, dx
9565 cmp eax, ecx
9566 jne pci_pro_nextdev
9567 cmp si, #0
9568 je pci_pro_ok
9569 dec si
9570 pci_pro_nextdev:
9571 inc bx
9572 cmp bx, #0x0100
9573 jne pci_pro_devloop
9574 mov ah, #0x86
9575 jmp pci_pro_fail
9576 pci_pro_f03: ;; find class code
9577 cmp al, #0x03
9578 jne pci_pro_f08
9579 xor bx, bx
9580 mov di, #0x08
9581 pci_pro_devloop2:
9582 call pci_pro_select_reg
9583 mov dx, #0x0cfc
9584 in eax, dx
9585 shr eax, #8
9586 cmp eax, ecx
9587 jne pci_pro_nextdev2
9588 cmp si, #0
9589 je pci_pro_ok
9590 dec si
9591 pci_pro_nextdev2:
9592 inc bx
9593 cmp bx, #0x0100
9594 jne pci_pro_devloop2
9595 mov ah, #0x86
9596 jmp pci_pro_fail
9597 pci_pro_f08: ;; read configuration byte
9598 cmp al, #0x08
9599 jne pci_pro_f09
9600 call pci_pro_select_reg
9601 push edx
9602 mov dx, di
9603 and dx, #0x03
9604 add dx, #0x0cfc
9605 in al, dx
9606 pop edx
9607 mov cl, al
9608 jmp pci_pro_ok
9609 pci_pro_f09: ;; read configuration word
9610 cmp al, #0x09
9611 jne pci_pro_f0a
9612 call pci_pro_select_reg
9613 push edx
9614 mov dx, di
9615 and dx, #0x02
9616 add dx, #0x0cfc
9617 in ax, dx
9618 pop edx
9619 mov cx, ax
9620 jmp pci_pro_ok
9621 pci_pro_f0a: ;; read configuration dword
9622 cmp al, #0x0a
9623 jne pci_pro_f0b
9624 call pci_pro_select_reg
9625 push edx
9626 mov dx, #0x0cfc
9627 in eax, dx
9628 pop edx
9629 mov ecx, eax
9630 jmp pci_pro_ok
9631 pci_pro_f0b: ;; write configuration byte
9632 cmp al, #0x0b
9633 jne pci_pro_f0c
9634 call pci_pro_select_reg
9635 push edx
9636 mov dx, di
9637 and dx, #0x03
9638 add dx, #0x0cfc
9639 mov al, cl
9640 out dx, al
9641 pop edx
9642 jmp pci_pro_ok
9643 pci_pro_f0c: ;; write configuration word
9644 cmp al, #0x0c
9645 jne pci_pro_f0d
9646 call pci_pro_select_reg
9647 push edx
9648 mov dx, di
9649 and dx, #0x02
9650 add dx, #0x0cfc
9651 mov ax, cx
9652 out dx, ax
9653 pop edx
9654 jmp pci_pro_ok
9655 pci_pro_f0d: ;; write configuration dword
9656 cmp al, #0x0d
9657 jne pci_pro_unknown
9658 call pci_pro_select_reg
9659 push edx
9660 mov dx, #0x0cfc
9661 mov eax, ecx
9662 out dx, eax
9663 pop edx
9664 jmp pci_pro_ok
9665 pci_pro_unknown:
9666 mov ah, #0x81
9667 pci_pro_fail:
9668 pop edi
9669 pop esi
9670 #ifdef BX_QEMU
9671 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9672 #endif
9673 popfd
9674 stc
9675 retf
9676 pci_pro_ok:
9677 xor ah, ah
9678 pop edi
9679 pop esi
9680 #ifdef BX_QEMU
9681 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9682 #endif
9683 popfd
9684 clc
9685 retf
9687 pci_pro_select_reg:
9688 push edx
9689 mov eax, #0x800000
9690 mov ax, bx
9691 shl eax, #8
9692 and di, #0xff
9693 or ax, di
9694 and al, #0xfc
9695 mov dx, #0x0cf8
9696 out dx, eax
9697 pop edx
9698 ret
9700 use16 386
9702 pcibios_real:
9703 push eax
9704 push dx
9705 mov eax, #0x80000000
9706 mov dx, #0x0cf8
9707 out dx, eax
9708 mov dx, #0x0cfc
9709 in eax, dx
9710 #ifdef PCI_FIXED_HOST_BRIDGE
9711 cmp eax, #PCI_FIXED_HOST_BRIDGE
9712 je pci_present
9713 #else
9714 ;; say ok if a device is present
9715 cmp eax, #0xffffffff
9716 jne pci_present
9717 #endif
9718 pop dx
9719 pop eax
9720 mov ah, #0xff
9721 stc
9722 ret
9723 pci_present:
9724 pop dx
9725 pop eax
9726 cmp al, #0x01 ;; installation check
9727 jne pci_real_f02
9728 mov ax, #0x0001
9729 mov bx, #0x0210
9730 mov cx, #0
9731 mov edx, #0x20494350 ;; "PCI "
9732 mov edi, #0xf0000
9733 mov di, #pcibios_protected
9734 clc
9735 ret
9736 pci_real_f02: ;; find pci device
9737 push esi
9738 push edi
9739 cmp al, #0x02
9740 jne pci_real_f03
9741 shl ecx, #16
9742 mov cx, dx
9743 xor bx, bx
9744 mov di, #0x00
9745 pci_real_devloop:
9746 call pci_real_select_reg
9747 mov dx, #0x0cfc
9748 in eax, dx
9749 cmp eax, ecx
9750 jne pci_real_nextdev
9751 cmp si, #0
9752 je pci_real_ok
9753 dec si
9754 pci_real_nextdev:
9755 inc bx
9756 cmp bx, #0x0100
9757 jne pci_real_devloop
9758 mov dx, cx
9759 shr ecx, #16
9760 mov ax, #0x8602
9761 jmp pci_real_fail
9762 pci_real_f03: ;; find class code
9763 cmp al, #0x03
9764 jne pci_real_f08
9765 xor bx, bx
9766 mov di, #0x08
9767 pci_real_devloop2:
9768 call pci_real_select_reg
9769 mov dx, #0x0cfc
9770 in eax, dx
9771 shr eax, #8
9772 cmp eax, ecx
9773 jne pci_real_nextdev2
9774 cmp si, #0
9775 je pci_real_ok
9776 dec si
9777 pci_real_nextdev2:
9778 inc bx
9779 cmp bx, #0x0100
9780 jne pci_real_devloop2
9781 mov dx, cx
9782 shr ecx, #16
9783 mov ax, #0x8603
9784 jmp pci_real_fail
9785 pci_real_f08: ;; read configuration byte
9786 cmp al, #0x08
9787 jne pci_real_f09
9788 call pci_real_select_reg
9789 push dx
9790 mov dx, di
9791 and dx, #0x03
9792 add dx, #0x0cfc
9793 in al, dx
9794 pop dx
9795 mov cl, al
9796 jmp pci_real_ok
9797 pci_real_f09: ;; read configuration word
9798 cmp al, #0x09
9799 jne pci_real_f0a
9800 call pci_real_select_reg
9801 push dx
9802 mov dx, di
9803 and dx, #0x02
9804 add dx, #0x0cfc
9805 in ax, dx
9806 pop dx
9807 mov cx, ax
9808 jmp pci_real_ok
9809 pci_real_f0a: ;; read configuration dword
9810 cmp al, #0x0a
9811 jne pci_real_f0b
9812 call pci_real_select_reg
9813 push dx
9814 mov dx, #0x0cfc
9815 in eax, dx
9816 pop dx
9817 mov ecx, eax
9818 jmp pci_real_ok
9819 pci_real_f0b: ;; write configuration byte
9820 cmp al, #0x0b
9821 jne pci_real_f0c
9822 call pci_real_select_reg
9823 push dx
9824 mov dx, di
9825 and dx, #0x03
9826 add dx, #0x0cfc
9827 mov al, cl
9828 out dx, al
9829 pop dx
9830 jmp pci_real_ok
9831 pci_real_f0c: ;; write configuration word
9832 cmp al, #0x0c
9833 jne pci_real_f0d
9834 call pci_real_select_reg
9835 push dx
9836 mov dx, di
9837 and dx, #0x02
9838 add dx, #0x0cfc
9839 mov ax, cx
9840 out dx, ax
9841 pop dx
9842 jmp pci_real_ok
9843 pci_real_f0d: ;; write configuration dword
9844 cmp al, #0x0d
9845 jne pci_real_f0e
9846 call pci_real_select_reg
9847 push dx
9848 mov dx, #0x0cfc
9849 mov eax, ecx
9850 out dx, eax
9851 pop dx
9852 jmp pci_real_ok
9853 pci_real_f0e: ;; get irq routing options
9854 cmp al, #0x0e
9855 jne pci_real_unknown
9856 SEG ES
9857 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9858 jb pci_real_too_small
9859 SEG ES
9860 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9861 pushf
9862 push ds
9863 push es
9864 push cx
9865 push si
9866 push di
9867 cld
9868 mov si, #pci_routing_table_structure_start
9869 push cs
9870 pop ds
9871 SEG ES
9872 mov cx, [di+2]
9873 SEG ES
9874 mov es, [di+4]
9875 mov di, cx
9876 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
9877 rep
9878 movsb
9879 pop di
9880 pop si
9881 pop cx
9882 pop es
9883 pop ds
9884 popf
9885 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9886 jmp pci_real_ok
9887 pci_real_too_small:
9888 SEG ES
9889 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9890 mov ah, #0x89
9891 jmp pci_real_fail
9893 pci_real_unknown:
9894 mov ah, #0x81
9895 pci_real_fail:
9896 pop edi
9897 pop esi
9898 stc
9899 ret
9900 pci_real_ok:
9901 xor ah, ah
9902 pop edi
9903 pop esi
9904 clc
9905 ret
9907 pci_real_select_reg:
9908 push dx
9909 mov eax, #0x800000
9910 mov ax, bx
9911 shl eax, #8
9912 and di, #0xff
9913 or ax, di
9914 and al, #0xfc
9915 mov dx, #0x0cf8
9916 out dx, eax
9917 pop dx
9918 ret
9920 .align 16
9921 pci_routing_table_structure:
9922 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9923 db 0, 1 ;; version
9924 dw 32 + (6 * 16) ;; table size
9925 db 0 ;; PCI interrupt router bus
9926 db 0x08 ;; PCI interrupt router DevFunc
9927 dw 0x0000 ;; PCI exclusive IRQs
9928 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9929 dw 0x122e ;; compatible PCI interrupt router device ID
9930 dw 0,0 ;; Miniport data
9931 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9932 db 0x37 ;; checksum
9933 pci_routing_table_structure_start:
9934 ;; first slot entry PCI-to-ISA (embedded)
9935 db 0 ;; pci bus number
9936 db 0x08 ;; pci device number (bit 7-3)
9937 db 0x61 ;; link value INTA#: pointer into PCI2ISA config space
9938 dw 0x0c20 ;; IRQ bitmap INTA#
9939 db 0x62 ;; link value INTB#
9940 dw 0x0c20 ;; IRQ bitmap INTB#
9941 db 0x63 ;; link value INTC#
9942 dw 0x0c20 ;; IRQ bitmap INTC#
9943 db 0x60 ;; link value INTD#
9944 dw 0x0c20 ;; IRQ bitmap INTD#
9945 db 0 ;; physical slot (0 = embedded)
9946 db 0 ;; reserved
9947 ;; second slot entry: 1st PCI slot
9948 db 0 ;; pci bus number
9949 db 0x10 ;; pci device number (bit 7-3)
9950 db 0x62 ;; link value INTA#
9951 dw 0x0c20 ;; IRQ bitmap INTA#
9952 db 0x63 ;; link value INTB#
9953 dw 0x0c20 ;; IRQ bitmap INTB#
9954 db 0x60 ;; link value INTC#
9955 dw 0x0c20 ;; IRQ bitmap INTC#
9956 db 0x61 ;; link value INTD#
9957 dw 0x0c20 ;; IRQ bitmap INTD#
9958 db 1 ;; physical slot (0 = embedded)
9959 db 0 ;; reserved
9960 ;; third slot entry: 2nd PCI slot
9961 db 0 ;; pci bus number
9962 db 0x18 ;; pci device number (bit 7-3)
9963 db 0x63 ;; link value INTA#
9964 dw 0x0c20 ;; IRQ bitmap INTA#
9965 db 0x60 ;; link value INTB#
9966 dw 0x0c20 ;; IRQ bitmap INTB#
9967 db 0x61 ;; link value INTC#
9968 dw 0x0c20 ;; IRQ bitmap INTC#
9969 db 0x62 ;; link value INTD#
9970 dw 0x0c20 ;; IRQ bitmap INTD#
9971 db 2 ;; physical slot (0 = embedded)
9972 db 0 ;; reserved
9973 ;; 4th slot entry: 3rd PCI slot
9974 db 0 ;; pci bus number
9975 db 0x20 ;; pci device number (bit 7-3)
9976 db 0x60 ;; link value INTA#
9977 dw 0x0c20 ;; IRQ bitmap INTA#
9978 db 0x61 ;; link value INTB#
9979 dw 0x0c20 ;; IRQ bitmap INTB#
9980 db 0x62 ;; link value INTC#
9981 dw 0x0c20 ;; IRQ bitmap INTC#
9982 db 0x63 ;; link value INTD#
9983 dw 0x0c20 ;; IRQ bitmap INTD#
9984 db 3 ;; physical slot (0 = embedded)
9985 db 0 ;; reserved
9986 ;; 5th slot entry: 4rd PCI slot
9987 db 0 ;; pci bus number
9988 db 0x28 ;; pci device number (bit 7-3)
9989 db 0x61 ;; link value INTA#
9990 dw 0x0c20 ;; IRQ bitmap INTA#
9991 db 0x62 ;; link value INTB#
9992 dw 0x0c20 ;; IRQ bitmap INTB#
9993 db 0x63 ;; link value INTC#
9994 dw 0x0c20 ;; IRQ bitmap INTC#
9995 db 0x60 ;; link value INTD#
9996 dw 0x0c20 ;; IRQ bitmap INTD#
9997 db 4 ;; physical slot (0 = embedded)
9998 db 0 ;; reserved
9999 ;; 6th slot entry: 5rd PCI slot
10000 db 0 ;; pci bus number
10001 db 0x30 ;; pci device number (bit 7-3)
10002 db 0x62 ;; link value INTA#
10003 dw 0x0c20 ;; IRQ bitmap INTA#
10004 db 0x63 ;; link value INTB#
10005 dw 0x0c20 ;; IRQ bitmap INTB#
10006 db 0x60 ;; link value INTC#
10007 dw 0x0c20 ;; IRQ bitmap INTC#
10008 db 0x61 ;; link value INTD#
10009 dw 0x0c20 ;; IRQ bitmap INTD#
10010 db 5 ;; physical slot (0 = embedded)
10011 db 0 ;; reserved
10012 pci_routing_table_structure_end:
10014 #if !BX_ROMBIOS32 && !defined(HVMASSIST)
10015 pci_irq_list:
10016 db 11, 10, 9, 5;
10018 pcibios_init_sel_reg:
10019 push eax
10020 mov eax, #0x800000
10021 mov ax, bx
10022 shl eax, #8
10023 and dl, #0xfc
10024 or al, dl
10025 mov dx, #0x0cf8
10026 out dx, eax
10027 pop eax
10028 ret
10030 pcibios_init_iomem_bases:
10031 push bp
10032 mov bp, sp
10033 mov eax, #0xe0000000 ;; base for memory init
10034 push eax
10035 mov ax, #0xc000 ;; base for i/o init
10036 push ax
10037 mov ax, #0x0010 ;; start at base address #0
10038 push ax
10039 mov bx, #0x0008
10040 pci_init_io_loop1:
10041 mov dl, #0x00
10042 call pcibios_init_sel_reg
10043 mov dx, #0x0cfc
10044 in ax, dx
10045 cmp ax, #0xffff
10046 jz next_pci_dev
10047 mov dl, #0x04 ;; disable i/o and memory space access
10048 call pcibios_init_sel_reg
10049 mov dx, #0x0cfc
10050 in al, dx
10051 and al, #0xfc
10052 out dx, al
10053 pci_init_io_loop2:
10054 mov dl, [bp-8]
10055 call pcibios_init_sel_reg
10056 mov dx, #0x0cfc
10057 in eax, dx
10058 test al, #0x01
10059 jnz init_io_base
10060 mov ecx, eax
10061 mov eax, #0xffffffff
10062 out dx, eax
10063 in eax, dx
10064 cmp eax, ecx
10065 je next_pci_base
10066 xor eax, #0xffffffff
10067 mov ecx, eax
10068 mov eax, [bp-4]
10069 out dx, eax
10070 add eax, ecx ;; calculate next free mem base
10071 add eax, #0x01000000
10072 and eax, #0xff000000
10073 mov [bp-4], eax
10074 jmp next_pci_base
10075 init_io_base:
10076 mov cx, ax
10077 mov ax, #0xffff
10078 out dx, ax
10079 in ax, dx
10080 cmp ax, cx
10081 je next_pci_base
10082 xor ax, #0xfffe
10083 mov cx, ax
10084 mov ax, [bp-6]
10085 out dx, ax
10086 add ax, cx ;; calculate next free i/o base
10087 add ax, #0x0100
10088 and ax, #0xff00
10089 mov [bp-6], ax
10090 next_pci_base:
10091 mov al, [bp-8]
10092 add al, #0x04
10093 cmp al, #0x28
10094 je enable_iomem_space
10095 mov byte ptr[bp-8], al
10096 jmp pci_init_io_loop2
10097 enable_iomem_space:
10098 mov dl, #0x04 ;; enable i/o and memory space access if available
10099 call pcibios_init_sel_reg
10100 mov dx, #0x0cfc
10101 in al, dx
10102 or al, #0x07
10103 out dx, al
10104 next_pci_dev:
10105 mov byte ptr[bp-8], #0x10
10106 inc bx
10107 cmp bx, #0x0100
10108 jne pci_init_io_loop1
10109 mov sp, bp
10110 pop bp
10111 ret
10113 pcibios_init_set_elcr:
10114 push ax
10115 push cx
10116 mov dx, #0x04d0
10117 test al, #0x08
10118 jz is_master_pic
10119 inc dx
10120 and al, #0x07
10121 is_master_pic:
10122 mov cl, al
10123 mov bl, #0x01
10124 shl bl, cl
10125 in al, dx
10126 or al, bl
10127 out dx, al
10128 pop cx
10129 pop ax
10130 ret
10132 pcibios_init_irqs:
10133 push ds
10134 push bp
10135 mov ax, #0xf000
10136 mov ds, ax
10137 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10138 mov al, #0x00
10139 out dx, al
10140 inc dx
10141 out dx, al
10142 mov si, #pci_routing_table_structure
10143 mov bh, [si+8]
10144 mov bl, [si+9]
10145 mov dl, #0x00
10146 call pcibios_init_sel_reg
10147 mov dx, #0x0cfc
10148 in eax, dx
10149 cmp eax, [si+12] ;; check irq router
10150 jne pci_init_end
10151 mov dl, [si+34]
10152 call pcibios_init_sel_reg
10153 push bx ;; save irq router bus + devfunc