VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/rombios.c@ 12559

Last change on this file since 12559 was 12494, checked in by vboxsync, 16 years ago

BIOS: moved some code around to allow more init calls

  • Property svn:eol-style set to native
File size: 320.1 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
37
38
39// ROM BIOS compatability entry points:
40// ===================================
41// $e05b ; POST Entry Point
42// $e2c3 ; NMI Handler Entry Point
43// $e3fe ; INT 13h Fixed Disk Services Entry Point
44// $e401 ; Fixed Disk Parameter Table
45// $e6f2 ; INT 19h Boot Load Service Entry Point
46// $e6f5 ; Configuration Data Table
47// $e729 ; Baud Rate Generator Table
48// $e739 ; INT 14h Serial Communications Service Entry Point
49// $e82e ; INT 16h Keyboard Service Entry Point
50// $e987 ; INT 09h Keyboard Service Entry Point
51// $ec59 ; INT 13h Diskette Service Entry Point
52// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
53// $efc7 ; Diskette Controller Parameter Table
54// $efd2 ; INT 17h Printer Service Entry Point
55// $f045 ; INT 10 Functions 0-Fh Entry Point
56// $f065 ; INT 10h Video Support Service Entry Point
57// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
58// $f841 ; INT 12h Memory Size Service Entry Point
59// $f84d ; INT 11h Equipment List Service Entry Point
60// $f859 ; INT 15h System Services Entry Point
61// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
62// $fe6e ; INT 1Ah Time-of-day Service Entry Point
63// $fea5 ; INT 08h System Timer ISR Entry Point
64// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
65// $ff53 ; IRET Instruction for Dummy Interrupt Handler
66// $ff54 ; INT 05h Print Screen Service Entry Point
67// $fff0 ; Power-up Entry Point
68// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
69// $fffe ; System Model ID
70
71// NOTES for ATA/ATAPI driver (cbbochs@free.fr)
72// Features
73// - supports up to 4 ATA interfaces
74// - device/geometry detection
75// - 16bits/32bits device access
76// - pchs/lba access
77// - datain/dataout/packet command support
78//
79// NOTES for El-Torito Boot (cbbochs@free.fr)
80// - CD-ROM booting is only available if ATA/ATAPI Driver is available
81// - Current code is only able to boot mono-session cds
82// - Current code can not boot and emulate a hard-disk
83// the bios will panic otherwise
84// - Current code also use memory in EBDA segement.
85// - I used cmos byte 0x3D to store extended information on boot-device
86// - Code has to be modified modified to handle multiple cdrom drives
87// - Here are the cdrom boot failure codes:
88// 1 : no atapi device found
89// 2 : no atapi cdrom found
90// 3 : can not read cd - BRVD
91// 4 : cd is not eltorito (BRVD)
92// 5 : cd is not eltorito (ISO TAG)
93// 6 : cd is not eltorito (ELTORITO TAG)
94// 7 : can not read cd - boot catalog
95// 8 : boot catalog : bad header
96// 9 : boot catalog : bad platform
97// 10 : boot catalog : bad signature
98// 11 : boot catalog : bootable flag not set
99// 12 : can not read cd - boot image
100//
101// ATA driver
102// - EBDA segment.
103// I used memory starting at 0x121 in the segment
104#ifndef VBOX
105// - the translation policy is defined in cmos regs 0x39 & 0x3a
106#endif /* !VBOX */
107//
108// TODO :
109//
110// int74
111// - needs to be reworked. Uses direct [bp] offsets. (?)
112//
113// int13:
114// - f04 (verify sectors) isn't complete (?)
115// - f02/03/04 should set current cyl,etc in BDA (?)
116// - rewrite int13_relocated & clean up int13 entry code
117//
118// NOTES:
119// - NMI access (bit7 of addr written to 70h)
120//
121// ATA driver
122// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
123// - could send the multiple-sector read/write commands
124//
125// El-Torito
126// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
127// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
128// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
129// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
130// This is ok. But DL should be reincremented afterwards.
131// - Fix all "FIXME ElTorito Various"
132// - should be able to boot any cdrom instead of the first one
133//
134// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
135
136#ifdef VBOX
137#include "DevPcBios.h"
138#include <VBox/version.h>
139#endif
140
141#define BX_ROMBIOS32 0
142#define DEBUG_ROMBIOS 0
143
144#define DEBUG_ATA 0
145#define DEBUG_INT13_HD 0
146#define DEBUG_INT13_CD 0
147#define DEBUG_INT13_ET 0
148#define DEBUG_INT13_FL 0
149#define DEBUG_INT15 0
150#define DEBUG_INT16 0
151#define DEBUG_INT1A 0
152#define DEBUG_INT74 0
153#define DEBUG_APM 0
154
155#define BX_CPU 3
156#define BX_USE_PS2_MOUSE 1
157#define BX_CALL_INT15_4F 1
158#define BX_USE_EBDA 1
159#define BX_SUPPORT_FLOPPY 1
160#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
161#define BX_PCIBIOS 1
162#define BX_APM 1
163
164#define BX_USE_ATADRV 1
165#define BX_ELTORITO_BOOT 1
166
167#define BX_MAX_ATA_INTERFACES 4
168#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
169
170#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
171#define BX_DEBUG_SERIAL 0 /* output to COM1 */
172
173 /* model byte 0xFC = AT */
174#define SYS_MODEL_ID 0xFC
175#define SYS_SUBMODEL_ID 0x00
176#define BIOS_REVISION 1
177#define BIOS_CONFIG_TABLE 0xe6f5
178
179#ifndef BIOS_BUILD_DATE
180# define BIOS_BUILD_DATE "06/23/99"
181#endif
182
183 // 1K of base memory used for Extended Bios Data Area (EBDA)
184 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
185#define EBDA_SEG 0x9FC0
186#define EBDA_SIZE 1 // In KiB
187#define BASE_MEM_IN_K (640 - EBDA_SIZE)
188
189#define ACPI_DATA_SIZE 0x00010000L
190
191 // Define the application NAME
192#if defined(BX_QEMU)
193# define BX_APPNAME "QEMU"
194#elif defined(PLEX86)
195# define BX_APPNAME "Plex86"
196#else
197# define BX_APPNAME "Bochs"
198#endif
199
200 // Sanity Checks
201#if BX_USE_ATADRV && BX_CPU<3
202# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
203#endif
204#if BX_USE_ATADRV && !BX_USE_EBDA
205# error ATA/ATAPI Driver can only be used if EBDA is available
206#endif
207#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
208# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
209#endif
210#if BX_PCIBIOS && BX_CPU<3
211# error PCI BIOS can only be used with 386+ cpu
212#endif
213#if BX_APM && BX_CPU<3
214# error APM BIOS can only be used with 386+ cpu
215#endif
216
217#if defined(VBOX) && !BX_USE_ATADRV
218# error VBOX requires enabling the ATA/ATAPI driver
219#endif
220
221#if defined(VBOX) && (defined(VBOX_WITH_BUSLOGIC) || defined(VBOX_WITH_LSILOGIC))
222# define BX_MAX_SCSI_DEVICES 16
223#endif
224
225#ifndef VBOX
226#define PANIC_PORT 0x400
227#define PANIC_PORT2 0x401
228#define INFO_PORT 0x402
229#define DEBUG_PORT 0x403
230#else /* VBOX */
231/* Redirect INFO output to backdoor logging port. */
232#define PANIC_PORT 0x400
233#define PANIC_PORT2 0x401
234#define INFO_PORT 0x504
235#define DEBUG_PORT 0x403
236#endif /* VBOX */
237
238// define this if you want to make PCIBIOS working on a specific bridge only
239// undef enables PCIBIOS when at least one PCI device is found
240// i440FX is emulated by Bochs and QEMU
241#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
242
243// #20 is dec 20
244// #$20 is hex 20 = 32
245// #0x20 is hex 20 = 32
246// LDA #$20
247// JSR $E820
248// LDD .i,S
249// JSR $C682
250// mov al, #$20
251
252// all hex literals should be prefixed with '0x'
253// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
254// no mov SEG-REG, #value, must mov register into seg-reg
255// grep -i "mov[ ]*.s" rombios.c
256
257// This is for compiling with gcc2 and gcc3
258#define ASM_START #asm
259#define ASM_END #endasm
260
261ASM_START
262.rom
263
264.org 0x0000
265
266#if BX_CPU >= 3
267use16 386
268#else
269use16 286
270#endif
271
272MACRO HALT
273 ;; the HALT macro is called with the line number of the HALT call.
274 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
275 ;; to print a BX_PANIC message. This will normally halt the simulation
276 ;; with a message such as "BIOS panic at rombios.c, line 4091".
277 ;; However, users can choose to make panics non-fatal and continue.
278#if BX_VIRTUAL_PORTS
279 mov dx,#PANIC_PORT
280 mov ax,#?1
281 out dx,ax
282#else
283 mov dx,#0x80
284 mov ax,#?1
285 out dx,al
286#endif
287MEND
288
289MACRO JMP_AP
290 db 0xea
291 dw ?2
292 dw ?1
293MEND
294
295MACRO SET_INT_VECTOR
296 mov ax, ?3
297 mov ?1*4, ax
298 mov ax, ?2
299 mov ?1*4+2, ax
300MEND
301
302ASM_END
303
304typedef unsigned char Bit8u;
305typedef unsigned short Bit16u;
306typedef unsigned short bx_bool;
307typedef unsigned long Bit32u;
308
309#if BX_USE_ATADRV
310
311 void memsetb(seg,offset,value,count);
312 void memcpyb(dseg,doffset,sseg,soffset,count);
313 void memcpyd(dseg,doffset,sseg,soffset,count);
314
315 // memset of count bytes
316 void
317 memsetb(seg,offset,value,count)
318 Bit16u seg;
319 Bit16u offset;
320 Bit16u value;
321 Bit16u count;
322 {
323 ASM_START
324 push bp
325 mov bp, sp
326
327 push ax
328 push cx
329 push es
330 push di
331
332 mov cx, 10[bp] ; count
333 cmp cx, #0x00
334 je memsetb_end
335 mov ax, 4[bp] ; segment
336 mov es, ax
337 mov ax, 6[bp] ; offset
338 mov di, ax
339 mov al, 8[bp] ; value
340 cld
341 rep
342 stosb
343
344 memsetb_end:
345 pop di
346 pop es
347 pop cx
348 pop ax
349
350 pop bp
351 ASM_END
352 }
353
354#if 0
355 // memcpy of count bytes
356 void
357 memcpyb(dseg,doffset,sseg,soffset,count)
358 Bit16u dseg;
359 Bit16u doffset;
360 Bit16u sseg;
361 Bit16u soffset;
362 Bit16u count;
363 {
364 ASM_START
365 push bp
366 mov bp, sp
367
368 push ax
369 push cx
370 push es
371 push di
372 push ds
373 push si
374
375 mov cx, 12[bp] ; count
376 cmp cx, #0x0000
377 je memcpyb_end
378 mov ax, 4[bp] ; dsegment
379 mov es, ax
380 mov ax, 6[bp] ; doffset
381 mov di, ax
382 mov ax, 8[bp] ; ssegment
383 mov ds, ax
384 mov ax, 10[bp] ; soffset
385 mov si, ax
386 cld
387 rep
388 movsb
389
390 memcpyb_end:
391 pop si
392 pop ds
393 pop di
394 pop es
395 pop cx
396 pop ax
397
398 pop bp
399 ASM_END
400 }
401
402 // memcpy of count dword
403 void
404 memcpyd(dseg,doffset,sseg,soffset,count)
405 Bit16u dseg;
406 Bit16u doffset;
407 Bit16u sseg;
408 Bit16u soffset;
409 Bit16u count;
410 {
411 ASM_START
412 push bp
413 mov bp, sp
414
415 push ax
416 push cx
417 push es
418 push di
419 push ds
420 push si
421
422 mov cx, 12[bp] ; count
423 cmp cx, #0x0000
424 je memcpyd_end
425 mov ax, 4[bp] ; dsegment
426 mov es, ax
427 mov ax, 6[bp] ; doffset
428 mov di, ax
429 mov ax, 8[bp] ; ssegment
430 mov ds, ax
431 mov ax, 10[bp] ; soffset
432 mov si, ax
433 cld
434 rep
435 movsd
436
437 memcpyd_end:
438 pop si
439 pop ds
440 pop di
441 pop es
442 pop cx
443 pop ax
444
445 pop bp
446 ASM_END
447 }
448#endif
449#endif //BX_USE_ATADRV
450
451 // read_dword and write_dword functions
452 static Bit32u read_dword();
453 static void write_dword();
454
455 Bit32u
456 read_dword(seg, offset)
457 Bit16u seg;
458 Bit16u offset;
459 {
460 ASM_START
461 push bp
462 mov bp, sp
463
464 push bx
465 push ds
466 mov ax, 4[bp] ; segment
467 mov ds, ax
468 mov bx, 6[bp] ; offset
469 mov ax, [bx]
470 inc bx
471 inc bx
472 mov dx, [bx]
473 ;; ax = return value (word)
474 ;; dx = return value (word)
475 pop ds
476 pop bx
477
478 pop bp
479 ASM_END
480 }
481
482 void
483 write_dword(seg, offset, data)
484 Bit16u seg;
485 Bit16u offset;
486 Bit32u data;
487 {
488 ASM_START
489 push bp
490 mov bp, sp
491
492 push ax
493 push bx
494 push ds
495 mov ax, 4[bp] ; segment
496 mov ds, ax
497 mov bx, 6[bp] ; offset
498 mov ax, 8[bp] ; data word
499 mov [bx], ax ; write data word
500 inc bx
501 inc bx
502 mov ax, 10[bp] ; data word
503 mov [bx], ax ; write data word
504 pop ds
505 pop bx
506 pop ax
507
508 pop bp
509 ASM_END
510 }
511
512 // Bit32u (unsigned long) and long helper functions
513 ASM_START
514
515 ;; and function
516 landl:
517 landul:
518 SEG SS
519 and ax,[di]
520 SEG SS
521 and bx,2[di]
522 ret
523
524 ;; add function
525 laddl:
526 laddul:
527 SEG SS
528 add ax,[di]
529 SEG SS
530 adc bx,2[di]
531 ret
532
533 ;; cmp function
534 lcmpl:
535 lcmpul:
536 and eax, #0x0000FFFF
537 shl ebx, #16
538 add eax, ebx
539 shr ebx, #16
540 SEG SS
541 cmp eax, dword ptr [di]
542 ret
543
544 ;; sub function
545 lsubl:
546 lsubul:
547 SEG SS
548 sub ax,[di]
549 SEG SS
550 sbb bx,2[di]
551 ret
552
553 ;; mul function
554 lmull:
555 lmulul:
556 and eax, #0x0000FFFF
557 shl ebx, #16
558 add eax, ebx
559 SEG SS
560 mul eax, dword ptr [di]
561 mov ebx, eax
562 shr ebx, #16
563 ret
564
565 ;; dec function
566 ldecl:
567 ldecul:
568 SEG SS
569 dec dword ptr [bx]
570 ret
571
572 ;; or function
573 lorl:
574 lorul:
575 SEG SS
576 or ax,[di]
577 SEG SS
578 or bx,2[di]
579 ret
580
581 ;; inc function
582 lincl:
583 lincul:
584 SEG SS
585 inc dword ptr [bx]
586 ret
587
588 ;; tst function
589 ltstl:
590 ltstul:
591 and eax, #0x0000FFFF
592 shl ebx, #16
593 add eax, ebx
594 shr ebx, #16
595 test eax, eax
596 ret
597
598 ;; sr function
599 lsrul:
600 mov cx,di
601 jcxz lsr_exit
602 and eax, #0x0000FFFF
603 shl ebx, #16
604 add eax, ebx
605 lsr_loop:
606 shr eax, #1
607 loop lsr_loop
608 mov ebx, eax
609 shr ebx, #16
610 lsr_exit:
611 ret
612
613 ;; sl function
614 lsll:
615 lslul:
616 mov cx,di
617 jcxz lsl_exit
618 and eax, #0x0000FFFF
619 shl ebx, #16
620 add eax, ebx
621 lsl_loop:
622 shl eax, #1
623 loop lsl_loop
624 mov ebx, eax
625 shr ebx, #16
626 lsl_exit:
627 ret
628
629 idiv_:
630 cwd
631 idiv bx
632 ret
633
634 idiv_u:
635 xor dx,dx
636 div bx
637 ret
638
639 ldivul:
640 and eax, #0x0000FFFF
641 shl ebx, #16
642 add eax, ebx
643 xor edx, edx
644 SEG SS
645 mov bx, 2[di]
646 shl ebx, #16
647 SEG SS
648 mov bx, [di]
649 div ebx
650 mov ebx, eax
651 shr ebx, #16
652 ret
653
654 ASM_END
655
656// for access to RAM area which is used by interrupt vectors
657// and BIOS Data Area
658
659typedef struct {
660 unsigned char filler1[0x400];
661 unsigned char filler2[0x6c];
662 Bit16u ticks_low;
663 Bit16u ticks_high;
664 Bit8u midnight_flag;
665 } bios_data_t;
666
667#define BiosData ((bios_data_t *) 0)
668
669#if BX_USE_ATADRV
670 typedef struct {
671 Bit16u heads; // # heads
672 Bit16u cylinders; // # cylinders
673 Bit16u spt; // # sectors / track
674 } chs_t;
675
676 // DPTE definition
677 typedef struct {
678 Bit16u iobase1;
679 Bit16u iobase2;
680 Bit8u prefix;
681 Bit8u unused;
682 Bit8u irq;
683 Bit8u blkcount;
684 Bit8u dma;
685 Bit8u pio;
686 Bit16u options;
687 Bit16u reserved;
688 Bit8u revision;
689 Bit8u checksum;
690 } dpte_t;
691
692 typedef struct {
693 Bit8u iface; // ISA or PCI
694 Bit16u iobase1; // IO Base 1
695 Bit16u iobase2; // IO Base 2
696 Bit8u irq; // IRQ
697 } ata_channel_t;
698
699 typedef struct {
700 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
701 Bit8u device; // Detected type of attached devices (hd/cd/none)
702 Bit8u removable; // Removable device flag
703 Bit8u lock; // Locks for removable devices
704 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
705 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
706 Bit16u blksize; // block size
707
708 Bit8u translation; // type of translation
709 chs_t lchs; // Logical CHS
710 chs_t pchs; // Physical CHS
711
712 Bit32u sectors; // Total sectors count
713 } ata_device_t;
714
715 typedef struct {
716 // ATA channels info
717 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
718
719 // ATA devices info
720 ata_device_t devices[BX_MAX_ATA_DEVICES];
721 //
722 // map between (bios hd id - 0x80) and ata channels
723 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
724
725 // map between (bios cd id - 0xE0) and ata channels
726 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
727
728 // Buffer for DPTE table
729 dpte_t dpte;
730
731 // Count of transferred sectors and bytes
732 Bit16u trsfsectors;
733 Bit32u trsfbytes;
734
735 } ata_t;
736
737#if BX_ELTORITO_BOOT
738 // ElTorito Device Emulation data
739 typedef struct {
740 Bit8u active;
741 Bit8u media;
742 Bit8u emulated_drive;
743 Bit8u controller_index;
744 Bit16u device_spec;
745 Bit32u ilba;
746 Bit16u buffer_segment;
747 Bit16u load_segment;
748 Bit16u sector_count;
749
750 // Virtual device
751 chs_t vdevice;
752 } cdemu_t;
753#endif // BX_ELTORITO_BOOT
754
755#ifdef VBOX
756# if defined(VBOX_WITH_BUSLOGIC) || defined(VBOX_WITH_LSILOGIC)
757 typedef struct {
758 // I/O port this device is attached to.
759 Bit16u io_base;
760 // Target Id.
761 Bit8u target_id;
762 // SCSI devices info
763 ata_device_t device_info;
764 } scsi_device_t;
765
766 typedef struct {
767 // SCSi device info
768 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
769 // map between (bios hd id - 0x80) and scsi devices
770 Bit8u hdcount, hdidmap[BX_MAX_SCSI_DEVICES];
771 } scsi_t;
772# endif
773#endif
774
775 // for access to EBDA area
776 // The EBDA structure should conform to
777 // http://www.frontiernet.net/~fys/rombios.htm document
778 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
779 typedef struct {
780 unsigned char filler1[0x3D];
781
782 // FDPT - Can be splitted in data members if needed
783 unsigned char fdpt0[0x10];
784 unsigned char fdpt1[0x10];
785
786 unsigned char filler2[0xC4];
787
788 // ATA Driver data
789 ata_t ata;
790
791#if BX_ELTORITO_BOOT
792 // El Torito Emulation data
793 cdemu_t cdemu;
794#endif // BX_ELTORITO_BOOT
795#ifdef VBOX
796# if defined(VBOX_WITH_BUSLOGIC) || defined(VBOX_WITH_LSILOGIC)
797 // SCSI Driver data
798 //scsi_t scsi;
799# endif
800
801 unsigned char uForceBootDrive;
802 unsigned char uForceBootDevice;
803#endif /* VBOX */
804
805 } ebda_data_t;
806
807#ifdef VBOX
808 // the last 16 bytes of the EBDA segment are used for the MPS floating
809 // pointer structure (only if an IOAPIC is present)
810#endif
811
812 #define EbdaData ((ebda_data_t *) 0)
813
814 // for access to the int13ext structure
815 typedef struct {
816 Bit8u size;
817 Bit8u reserved;
818 Bit16u count;
819 Bit16u offset;
820 Bit16u segment;
821 Bit32u lba1;
822 Bit32u lba2;
823 } int13ext_t;
824
825 #define Int13Ext ((int13ext_t *) 0)
826
827 // Disk Physical Table definition
828 typedef struct {
829 Bit16u size;
830 Bit16u infos;
831 Bit32u cylinders;
832 Bit32u heads;
833 Bit32u spt;
834 Bit32u sector_count1;
835 Bit32u sector_count2;
836 Bit16u blksize;
837 Bit16u dpte_segment;
838 Bit16u dpte_offset;
839 Bit16u key;
840 Bit8u dpi_length;
841 Bit8u reserved1;
842 Bit16u reserved2;
843 Bit8u host_bus[4];
844 Bit8u iface_type[8];
845 Bit8u iface_path[8];
846 Bit8u device_path[8];
847 Bit8u reserved3;
848 Bit8u checksum;
849 } dpt_t;
850
851 #define Int13DPT ((dpt_t *) 0)
852
853#endif // BX_USE_ATADRV
854
855typedef struct {
856 union {
857 struct {
858 Bit16u di, si, bp, sp;
859 Bit16u bx, dx, cx, ax;
860 } r16;
861 struct {
862 Bit16u filler[4];
863 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
864 } r8;
865 } u;
866 } pusha_regs_t;
867
868typedef struct {
869 union {
870 struct {
871 Bit32u edi, esi, ebp, esp;
872 Bit32u ebx, edx, ecx, eax;
873 } r32;
874 struct {
875 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
876 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
877 } r16;
878 struct {
879 Bit32u filler[4];
880 Bit8u bl, bh;
881 Bit16u filler1;
882 Bit8u dl, dh;
883 Bit16u filler2;
884 Bit8u cl, ch;
885 Bit16u filler3;
886 Bit8u al, ah;
887 Bit16u filler4;
888 } r8;
889 } u;
890} pushad_regs_t;
891
892typedef struct {
893 union {
894 struct {
895 Bit16u flags;
896 } r16;
897 struct {
898 Bit8u flagsl;
899 Bit8u flagsh;
900 } r8;
901 } u;
902 } flags_t;
903
904#define SetCF(x) x.u.r8.flagsl |= 0x01
905#define SetZF(x) x.u.r8.flagsl |= 0x40
906#define ClearCF(x) x.u.r8.flagsl &= 0xfe
907#define ClearZF(x) x.u.r8.flagsl &= 0xbf
908#define GetCF(x) (x.u.r8.flagsl & 0x01)
909
910typedef struct {
911 Bit16u ip;
912 Bit16u cs;
913 flags_t flags;
914 } iret_addr_t;
915
916
917
918static Bit8u inb();
919static Bit8u inb_cmos();
920static void outb();
921static void outb_cmos();
922static Bit16u inw();
923static void outw();
924static void init_rtc();
925static bx_bool rtc_updating();
926
927static Bit8u read_byte();
928static Bit16u read_word();
929static void write_byte();
930static void write_word();
931static void bios_printf();
932
933static Bit8u send_to_mouse_ctrl();
934static Bit8u get_mouse_data();
935static void set_kbd_command_byte();
936
937static void int09_function();
938static void int13_harddisk();
939static void int13_cdrom();
940static void int13_cdemu();
941static void int13_eltorito();
942static void int13_diskette_function();
943static void int14_function();
944static void int15_function();
945static void int16_function();
946static void int17_function();
947static Bit32u int19_function();
948static void int1a_function();
949static void int70_function();
950static void int74_function();
951static void dummy_isr_function();
952static Bit16u get_CS();
953static Bit16u get_SS();
954static unsigned int enqueue_key();
955static unsigned int dequeue_key();
956static void get_hd_geometry();
957static void set_diskette_ret_status();
958static void set_diskette_current_cyl();
959static void determine_floppy_media();
960static bx_bool floppy_drive_exists();
961static bx_bool floppy_drive_recal();
962static bx_bool floppy_media_known();
963static bx_bool floppy_media_sense();
964static bx_bool set_enable_a20();
965static void debugger_on();
966static void debugger_off();
967static void keyboard_init();
968static void keyboard_panic();
969static void shutdown_status_panic();
970static void nmi_handler_msg();
971
972static void print_bios_banner();
973static void print_boot_device();
974static void print_boot_failure();
975static void print_cdromboot_failure();
976
977# if BX_USE_ATADRV
978
979// ATA / ATAPI driver
980void ata_init();
981void ata_detect();
982void ata_reset();
983
984Bit16u ata_cmd_non_data();
985Bit16u ata_cmd_data_in();
986Bit16u ata_cmd_data_out();
987Bit16u ata_cmd_packet();
988
989Bit16u atapi_get_sense();
990Bit16u atapi_is_ready();
991Bit16u atapi_is_cdrom();
992
993#endif // BX_USE_ATADRV
994
995#if BX_ELTORITO_BOOT
996
997void cdemu_init();
998Bit8u cdemu_isactive();
999Bit8u cdemu_emulated_drive();
1000
1001Bit16u cdrom_boot();
1002
1003#endif // BX_ELTORITO_BOOT
1004
1005#ifdef VBOX
1006static char bios_prefix_string[] = "BIOS: ";
1007/* Do not use build timestamps in this string. Otherwise even rebuilding the
1008 * very same code will lead to compare errors when restoring saved state. */
1009static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1010#define BIOS_COPYRIGHT_STRING "Sun xVM VirtualBox BIOS"
1011#else /* !VBOX */
1012static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1013
1014#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1015#endif /* !VBOX */
1016
1017#define BIOS_PRINTF_HALT 1
1018#define BIOS_PRINTF_SCREEN 2
1019#define BIOS_PRINTF_INFO 4
1020#define BIOS_PRINTF_DEBUG 8
1021#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1022#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1023
1024#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1025
1026// Defines the output macros.
1027// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1028// per-device basis. Debug info are sent only in debug mode
1029#if DEBUG_ROMBIOS
1030# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1031#else
1032# define BX_DEBUG(format, p...)
1033#endif
1034#ifdef VBOX
1035#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
1036#else /* !VBOX */
1037#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1038#endif /* !VBOX */
1039#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1040
1041#if DEBUG_ATA
1042# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1043#else
1044# define BX_DEBUG_ATA(a...)
1045#endif
1046#if DEBUG_INT13_HD
1047# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1048#else
1049# define BX_DEBUG_INT13_HD(a...)
1050#endif
1051#if DEBUG_INT13_CD
1052# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1053#else
1054# define BX_DEBUG_INT13_CD(a...)
1055#endif
1056#if DEBUG_INT13_ET
1057# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1058#else
1059# define BX_DEBUG_INT13_ET(a...)
1060#endif
1061#if DEBUG_INT13_FL
1062# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1063#else
1064# define BX_DEBUG_INT13_FL(a...)
1065#endif
1066#if DEBUG_INT15
1067# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1068#else
1069# define BX_DEBUG_INT15(a...)
1070#endif
1071#if DEBUG_INT16
1072# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1073#else
1074# define BX_DEBUG_INT16(a...)
1075#endif
1076#if DEBUG_INT1A
1077# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1078#else
1079# define BX_DEBUG_INT1A(a...)
1080#endif
1081#if DEBUG_INT74
1082# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1083#else
1084# define BX_DEBUG_INT74(a...)
1085#endif
1086
1087#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1088#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1089#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1090#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1091#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1092#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1093#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1094#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1095
1096#define GET_AL() ( AX & 0x00ff )
1097#define GET_BL() ( BX & 0x00ff )
1098#define GET_CL() ( CX & 0x00ff )
1099#define GET_DL() ( DX & 0x00ff )
1100#define GET_AH() ( AX >> 8 )
1101#define GET_BH() ( BX >> 8 )
1102#define GET_CH() ( CX >> 8 )
1103#define GET_DH() ( DX >> 8 )
1104
1105#define GET_ELDL() ( ELDX & 0x00ff )
1106#define GET_ELDH() ( ELDX >> 8 )
1107
1108#define SET_CF() FLAGS |= 0x0001
1109#define CLEAR_CF() FLAGS &= 0xfffe
1110#define GET_CF() (FLAGS & 0x0001)
1111
1112#define SET_ZF() FLAGS |= 0x0040
1113#define CLEAR_ZF() FLAGS &= 0xffbf
1114#define GET_ZF() (FLAGS & 0x0040)
1115
1116#define UNSUPPORTED_FUNCTION 0x86
1117
1118#define none 0
1119#define MAX_SCAN_CODE 0x58
1120
1121static struct {
1122 Bit16u normal;
1123 Bit16u shift;
1124 Bit16u control;
1125 Bit16u alt;
1126 Bit8u lock_flags;
1127 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1128 { none, none, none, none, none },
1129 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1130 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1131 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1132 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1133 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1134 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1135 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1136 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1137 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1138 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1139 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1140 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1141 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1142 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1143 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1144 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1145 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1146 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1147 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1148 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1149 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1150 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1151 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1152 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1153 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1154 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1155 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1156 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1157 { none, none, none, none, none }, /* L Ctrl */
1158 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1159 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1160 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1161 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1162 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1163 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1164 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1165 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1166 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1167 { 0x273b, 0x273a, none, none, none }, /* ;: */
1168 { 0x2827, 0x2822, none, none, none }, /* '" */
1169 { 0x2960, 0x297e, none, none, none }, /* `~ */
1170 { none, none, none, none, none }, /* L shift */
1171 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1172 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1173 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1174 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1175 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1176 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1177 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1178 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1179 { 0x332c, 0x333c, none, none, none }, /* ,< */
1180 { 0x342e, 0x343e, none, none, none }, /* .> */
1181 { 0x352f, 0x353f, none, none, none }, /* /? */
1182 { none, none, none, none, none }, /* R Shift */
1183 { 0x372a, 0x372a, none, none, none }, /* * */
1184 { none, none, none, none, none }, /* L Alt */
1185 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1186 { none, none, none, none, none }, /* caps lock */
1187 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1188 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1189 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1190 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1191 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1192 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1193 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1194 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1195 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1196 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1197 { none, none, none, none, none }, /* Num Lock */
1198 { none, none, none, none, none }, /* Scroll Lock */
1199 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1200 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1201 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1202 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1203 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1204 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1205 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1206 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1207 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1208 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1209 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1210 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1211 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1212 { none, none, none, none, none },
1213 { none, none, none, none, none },
1214 { 0x565c, 0x567c, none, none, none }, /* \| */
1215#ifndef VBOX
1216 { 0x5700, 0x5700, none, none, none }, /* F11 */
1217 { 0x5800, 0x5800, none, none, none } /* F12 */
1218#else
1219 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1220 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1221#endif
1222 };
1223
1224 Bit8u
1225inb(port)
1226 Bit16u port;
1227{
1228ASM_START
1229 push bp
1230 mov bp, sp
1231
1232 push dx
1233 mov dx, 4[bp]
1234 in al, dx
1235 pop dx
1236
1237 pop bp
1238ASM_END
1239}
1240
1241#if BX_USE_ATADRV
1242 Bit16u
1243inw(port)
1244 Bit16u port;
1245{
1246ASM_START
1247 push bp
1248 mov bp, sp
1249
1250 push dx
1251 mov dx, 4[bp]
1252 in ax, dx
1253 pop dx
1254
1255 pop bp
1256ASM_END
1257}
1258#endif
1259
1260 void
1261outb(port, val)
1262 Bit16u port;
1263 Bit8u val;
1264{
1265ASM_START
1266 push bp
1267 mov bp, sp
1268
1269 push ax
1270 push dx
1271 mov dx, 4[bp]
1272 mov al, 6[bp]
1273 out dx, al
1274 pop dx
1275 pop ax
1276
1277 pop bp
1278ASM_END
1279}
1280
1281#if BX_USE_ATADRV
1282 void
1283outw(port, val)
1284 Bit16u port;
1285 Bit16u val;
1286{
1287ASM_START
1288 push bp
1289 mov bp, sp
1290
1291 push ax
1292 push dx
1293 mov dx, 4[bp]
1294 mov ax, 6[bp]
1295 out dx, ax
1296 pop dx
1297 pop ax
1298
1299 pop bp
1300ASM_END
1301}
1302#endif
1303
1304 void
1305outb_cmos(cmos_reg, val)
1306 Bit8u cmos_reg;
1307 Bit8u val;
1308{
1309ASM_START
1310 push bp
1311 mov bp, sp
1312
1313 mov al, 4[bp] ;; cmos_reg
1314 out 0x70, al
1315 mov al, 6[bp] ;; val
1316 out 0x71, al
1317
1318 pop bp
1319ASM_END
1320}
1321
1322 Bit8u
1323inb_cmos(cmos_reg)
1324 Bit8u cmos_reg;
1325{
1326ASM_START
1327 push bp
1328 mov bp, sp
1329
1330 mov al, 4[bp] ;; cmos_reg
1331 out 0x70, al
1332 in al, 0x71
1333
1334 pop bp
1335ASM_END
1336}
1337
1338 void
1339init_rtc()
1340{
1341 outb_cmos(0x0a, 0x26);
1342 outb_cmos(0x0b, 0x02);
1343 inb_cmos(0x0c);
1344 inb_cmos(0x0d);
1345}
1346
1347 bx_bool
1348rtc_updating()
1349{
1350 // This function checks to see if the update-in-progress bit
1351 // is set in CMOS Status Register A. If not, it returns 0.
1352 // If it is set, it tries to wait until there is a transition
1353 // to 0, and will return 0 if such a transition occurs. A 1
1354 // is returned only after timing out. The maximum period
1355 // that this bit should be set is constrained to 244useconds.
1356 // The count I use below guarantees coverage or more than
1357 // this time, with any reasonable IPS setting.
1358
1359 Bit16u count;
1360
1361 count = 25000;
1362 while (--count != 0) {
1363 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1364 return(0);
1365 }
1366 return(1); // update-in-progress never transitioned to 0
1367}
1368
1369
1370 Bit8u
1371read_byte(seg, offset)
1372 Bit16u seg;
1373 Bit16u offset;
1374{
1375ASM_START
1376 push bp
1377 mov bp, sp
1378
1379 push bx
1380 push ds
1381 mov ax, 4[bp] ; segment
1382 mov ds, ax
1383 mov bx, 6[bp] ; offset
1384 mov al, [bx]
1385 ;; al = return value (byte)
1386 pop ds
1387 pop bx
1388
1389 pop bp
1390ASM_END
1391}
1392
1393 Bit16u
1394read_word(seg, offset)
1395 Bit16u seg;
1396 Bit16u offset;
1397{
1398ASM_START
1399 push bp
1400 mov bp, sp
1401
1402 push bx
1403 push ds
1404 mov ax, 4[bp] ; segment
1405 mov ds, ax
1406 mov bx, 6[bp] ; offset
1407 mov ax, [bx]
1408 ;; ax = return value (word)
1409 pop ds
1410 pop bx
1411
1412 pop bp
1413ASM_END
1414}
1415
1416 void
1417write_byte(seg, offset, data)
1418 Bit16u seg;
1419 Bit16u offset;
1420 Bit8u data;
1421{
1422ASM_START
1423 push bp
1424 mov bp, sp
1425
1426 push ax
1427 push bx
1428 push ds
1429 mov ax, 4[bp] ; segment
1430 mov ds, ax
1431 mov bx, 6[bp] ; offset
1432 mov al, 8[bp] ; data byte
1433 mov [bx], al ; write data byte
1434 pop ds
1435 pop bx
1436 pop ax
1437
1438 pop bp
1439ASM_END
1440}
1441
1442 void
1443write_word(seg, offset, data)
1444 Bit16u seg;
1445 Bit16u offset;
1446 Bit16u data;
1447{
1448ASM_START
1449 push bp
1450 mov bp, sp
1451
1452 push ax
1453 push bx
1454 push ds
1455 mov ax, 4[bp] ; segment
1456 mov ds, ax
1457 mov bx, 6[bp] ; offset
1458 mov ax, 8[bp] ; data word
1459 mov [bx], ax ; write data word
1460 pop ds
1461 pop bx
1462 pop ax
1463
1464 pop bp
1465ASM_END
1466}
1467
1468 Bit16u
1469get_CS()
1470{
1471ASM_START
1472 mov ax, cs
1473ASM_END
1474}
1475
1476 Bit16u
1477get_SS()
1478{
1479ASM_START
1480 mov ax, ss
1481ASM_END
1482}
1483
1484#if BX_DEBUG_SERIAL
1485/* serial debug port*/
1486#define BX_DEBUG_PORT 0x03f8
1487
1488/* data */
1489#define UART_RBR 0x00
1490#define UART_THR 0x00
1491
1492/* control */
1493#define UART_IER 0x01
1494#define UART_IIR 0x02
1495#define UART_FCR 0x02
1496#define UART_LCR 0x03
1497#define UART_MCR 0x04
1498#define UART_DLL 0x00
1499#define UART_DLM 0x01
1500
1501/* status */
1502#define UART_LSR 0x05
1503#define UART_MSR 0x06
1504#define UART_SCR 0x07
1505
1506int uart_can_tx_byte(base_port)
1507 Bit16u base_port;
1508{
1509 return inb(base_port + UART_LSR) & 0x20;
1510}
1511
1512void uart_wait_to_tx_byte(base_port)
1513 Bit16u base_port;
1514{
1515 while (!uart_can_tx_byte(base_port));
1516}
1517
1518void uart_wait_until_sent(base_port)
1519 Bit16u base_port;
1520{
1521 while (!(inb(base_port + UART_LSR) & 0x40));
1522}
1523
1524void uart_tx_byte(base_port, data)
1525 Bit16u base_port;
1526 Bit8u data;
1527{
1528 uart_wait_to_tx_byte(base_port);
1529 outb(base_port + UART_THR, data);
1530 uart_wait_until_sent(base_port);
1531}
1532#endif
1533
1534 void
1535wrch(c)
1536 Bit8u c;
1537{
1538 ASM_START
1539 push bp
1540 mov bp, sp
1541
1542 push bx
1543 mov ah, #0x0e
1544 mov al, 4[bp]
1545 xor bx,bx
1546 int #0x10
1547 pop bx
1548
1549 pop bp
1550 ASM_END
1551}
1552
1553 void
1554send(action, c)
1555 Bit16u action;
1556 Bit8u c;
1557{
1558#if BX_DEBUG_SERIAL
1559 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1560 uart_tx_byte(BX_DEBUG_PORT, c);
1561#endif
1562#if BX_VIRTUAL_PORTS
1563 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1564 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1565#endif
1566 if (action & BIOS_PRINTF_SCREEN) {
1567 if (c == '\n') wrch('\r');
1568 wrch(c);
1569 }
1570}
1571
1572 void
1573put_int(action, val, width, neg)
1574 Bit16u action;
1575 short val, width;
1576 bx_bool neg;
1577{
1578 short nval = val / 10;
1579 if (nval)
1580 put_int(action, nval, width - 1, neg);
1581 else {
1582 while (--width > 0) send(action, ' ');
1583 if (neg) send(action, '-');
1584 }
1585 send(action, val - (nval * 10) + '0');
1586}
1587
1588 void
1589put_uint(action, val, width, neg)
1590 Bit16u action;
1591 unsigned short val;
1592 short width;
1593 bx_bool neg;
1594{
1595 unsigned short nval = val / 10;
1596 if (nval)
1597 put_uint(action, nval, width - 1, neg);
1598 else {
1599 while (--width > 0) send(action, ' ');
1600 if (neg) send(action, '-');
1601 }
1602 send(action, val - (nval * 10) + '0');
1603}
1604
1605 void
1606put_luint(action, val, width, neg)
1607 Bit16u action;
1608 unsigned long val;
1609 short width;
1610 bx_bool neg;
1611{
1612 unsigned long nval = val / 10;
1613 if (nval)
1614 put_luint(action, nval, width - 1, neg);
1615 else {
1616 while (--width > 0) send(action, ' ');
1617 if (neg) send(action, '-');
1618 }
1619 send(action, val - (nval * 10) + '0');
1620}
1621
1622#ifdef VBOX
1623void put_str(action, s)
1624 Bit16u action;
1625 Bit8u *s;
1626{
1627 Bit8u c;
1628 if (!s)
1629 s = "<NULL>";
1630
1631 while (c = read_byte(get_CS(), s)) {
1632 send(action, c);
1633 s++;
1634 }
1635}
1636#endif /* VBOX */
1637
1638//--------------------------------------------------------------------------
1639// bios_printf()
1640// A compact variable argument printf function which prints its output via
1641// an I/O port so that it can be logged by Bochs/Plex.
1642// Currently, only %x is supported (or %02x, %04x, etc).
1643//
1644// Supports %[format_width][format]
1645// where format can be d,x,c,s
1646//--------------------------------------------------------------------------
1647 void
1648bios_printf(action, s)
1649 Bit16u action;
1650 Bit8u *s;
1651{
1652 Bit8u c, format_char;
1653 bx_bool in_format;
1654 short i;
1655 Bit16u *arg_ptr;
1656 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width;
1657
1658 arg_ptr = &s;
1659 arg_seg = get_SS();
1660
1661 in_format = 0;
1662 format_width = 0;
1663
1664 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1665#if BX_VIRTUAL_PORTS
1666 outb(PANIC_PORT2, 0x00);
1667#endif
1668 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1669 }
1670
1671 while (c = read_byte(get_CS(), s)) {
1672 if ( c == '%' ) {
1673 in_format = 1;
1674 format_width = 0;
1675 }
1676 else if (in_format) {
1677 if ( (c>='0') && (c<='9') ) {
1678 format_width = (format_width * 10) + (c - '0');
1679 }
1680 else {
1681 arg_ptr++; // increment to next arg
1682 arg = read_word(arg_seg, arg_ptr);
1683 if (c == 'x') {
1684 if (format_width == 0)
1685 format_width = 4;
1686 for (i=format_width-1; i>=0; i--) {
1687 nibble = (arg >> (4 * i)) & 0x000f;
1688 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1689 }
1690 }
1691 else if (c == 'u') {
1692 put_uint(action, arg, format_width, 0);
1693 }
1694 else if (c == 'l') {
1695 s++;
1696 arg_ptr++; /* increment to next arg */
1697 hibyte = read_word(arg_seg, arg_ptr);
1698 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1699 }
1700 else if (c == 'd') {
1701 if (arg & 0x8000)
1702 put_int(action, -arg, format_width - 1, 1);
1703 else
1704 put_int(action, arg, format_width, 0);
1705 }
1706 else if (c == 's') {
1707#ifndef VBOX
1708 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1709#else /* VBOX */
1710 put_str(action, arg);
1711#endif /* VBOX */
1712 }
1713 else if (c == 'c') {
1714 send(action, arg);
1715 }
1716 else
1717 BX_PANIC("bios_printf: unknown format\n");
1718 in_format = 0;
1719 }
1720 }
1721 else {
1722 send(action, c);
1723 }
1724 s ++;
1725 }
1726
1727 if (action & BIOS_PRINTF_HALT) {
1728 // freeze in a busy loop.
1729ASM_START
1730 cli
1731 halt2_loop:
1732 hlt
1733 jmp halt2_loop
1734ASM_END
1735 }
1736}
1737
1738//--------------------------------------------------------------------------
1739// keyboard_init
1740//--------------------------------------------------------------------------
1741// this file is based on LinuxBIOS implementation of keyboard.c
1742// could convert to #asm to gain space
1743 void
1744keyboard_init()
1745{
1746 Bit16u max;
1747
1748 /* ------------------- Flush buffers ------------------------*/
1749 /* Wait until buffer is empty */
1750 max=0xffff;
1751 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1752
1753 /* flush incoming keys */
1754 max=0x2000;
1755 while (--max > 0) {
1756 outb(0x80, 0x00);
1757 if (inb(0x64) & 0x01) {
1758 inb(0x60);
1759 max = 0x2000;
1760 }
1761 }
1762
1763 // Due to timer issues, and if the IPS setting is > 15000000,
1764 // the incoming keys might not be flushed here. That will
1765 // cause a panic a few lines below. See sourceforge bug report :
1766 // [ 642031 ] FATAL: Keyboard RESET error:993
1767
1768 /* ------------------- controller side ----------------------*/
1769 /* send cmd = 0xAA, self test 8042 */
1770 outb(0x64, 0xaa);
1771
1772 /* Wait until buffer is empty */
1773 max=0xffff;
1774 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1775 if (max==0x0) keyboard_panic(00);
1776
1777 /* Wait for data */
1778 max=0xffff;
1779 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1780 if (max==0x0) keyboard_panic(01);
1781
1782 /* read self-test result, 0x55 should be returned from 0x60 */
1783 if ((inb(0x60) != 0x55)){
1784 keyboard_panic(991);
1785 }
1786
1787 /* send cmd = 0xAB, keyboard interface test */
1788 outb(0x64,0xab);
1789
1790 /* Wait until buffer is empty */
1791 max=0xffff;
1792 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1793 if (max==0x0) keyboard_panic(10);
1794
1795 /* Wait for data */
1796 max=0xffff;
1797 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1798 if (max==0x0) keyboard_panic(11);
1799
1800 /* read keyboard interface test result, */
1801 /* 0x00 should be returned form 0x60 */
1802 if ((inb(0x60) != 0x00)) {
1803 keyboard_panic(992);
1804 }
1805
1806 /* Enable Keyboard clock */
1807 outb(0x64,0xae);
1808 outb(0x64,0xa8);
1809
1810 /* ------------------- keyboard side ------------------------*/
1811 /* reset kerboard and self test (keyboard side) */
1812 outb(0x60, 0xff);
1813
1814 /* Wait until buffer is empty */
1815 max=0xffff;
1816 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1817 if (max==0x0) keyboard_panic(20);
1818
1819 /* Wait for data */
1820 max=0xffff;
1821 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1822 if (max==0x0) keyboard_panic(21);
1823
1824 /* keyboard should return ACK */
1825 if ((inb(0x60) != 0xfa)) {
1826 keyboard_panic(993);
1827 }
1828
1829 /* Wait for data */
1830 max=0xffff;
1831 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1832 if (max==0x0) keyboard_panic(31);
1833
1834 if ((inb(0x60) != 0xaa)) {
1835 keyboard_panic(994);
1836 }
1837
1838 /* Disable keyboard */
1839 outb(0x60, 0xf5);
1840
1841 /* Wait until buffer is empty */
1842 max=0xffff;
1843 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1844 if (max==0x0) keyboard_panic(40);
1845
1846 /* Wait for data */
1847 max=0xffff;
1848 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1849 if (max==0x0) keyboard_panic(41);
1850
1851 /* keyboard should return ACK */
1852 if ((inb(0x60) != 0xfa)) {
1853 keyboard_panic(995);
1854 }
1855
1856 /* Write Keyboard Mode */
1857 outb(0x64, 0x60);
1858
1859 /* Wait until buffer is empty */
1860 max=0xffff;
1861 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1862 if (max==0x0) keyboard_panic(50);
1863
1864 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1865 outb(0x60, 0x65);
1866
1867 /* Wait until buffer is empty */
1868 max=0xffff;
1869 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1870 if (max==0x0) keyboard_panic(60);
1871
1872 /* Enable keyboard */
1873 outb(0x60, 0xf4);
1874
1875 /* Wait until buffer is empty */
1876 max=0xffff;
1877 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1878 if (max==0x0) keyboard_panic(70);
1879
1880 /* Wait for data */
1881 max=0xffff;
1882 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1883 if (max==0x0) keyboard_panic(70);
1884
1885 /* keyboard should return ACK */
1886 if ((inb(0x60) != 0xfa)) {
1887 keyboard_panic(996);
1888 }
1889
1890 outb(0x80, 0x77);
1891}
1892
1893//--------------------------------------------------------------------------
1894// keyboard_panic
1895//--------------------------------------------------------------------------
1896 void
1897keyboard_panic(status)
1898 Bit16u status;
1899{
1900 // If you're getting a 993 keyboard panic here,
1901 // please see the comment in keyboard_init
1902
1903 BX_PANIC("Keyboard error:%u\n",status);
1904}
1905
1906//--------------------------------------------------------------------------
1907// shutdown_status_panic
1908// called when the shutdown statsu is not implemented, displays the status
1909//--------------------------------------------------------------------------
1910 void
1911shutdown_status_panic(status)
1912 Bit16u status;
1913{
1914 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1915}
1916
1917#ifdef VBOX
1918#include "logo.c"
1919#endif /* VBOX */
1920
1921//--------------------------------------------------------------------------
1922// print_bios_banner
1923// displays a the bios version
1924//--------------------------------------------------------------------------
1925void
1926print_bios_banner()
1927{
1928#ifdef VBOX
1929 // Skip the logo if a warm boot is requested.
1930 Bit16u warm_boot = read_word(0x0040,0x0072);
1931 write_word(0x0040,0x0072, 0);
1932 if (warm_boot == 0x1234)
1933 return;
1934#if !defined(DEBUG) || defined(DEBUG_sunlover)
1935 /* show graphical logo */
1936 show_logo();
1937#else
1938 /* set text mode */
1939 ASM_START
1940 mov ax, #0x0003
1941 int #0x10
1942 ASM_END
1943#endif /* !DEBUG */
1944#else /* !VBOX */
1945 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1946 BIOS_BUILD_DATE, bios_cvs_version_string);
1947 printf(
1948#if BX_APM
1949 "apmbios "
1950#endif
1951#if BX_PCIBIOS
1952 "pcibios "
1953#endif
1954#if BX_ELTORITO_BOOT
1955 "eltorito "
1956#endif
1957#if BX_ROMBIOS32
1958 "rombios32 "
1959#endif
1960 "\n\n");
1961#endif /* VBOX */
1962}
1963
1964//--------------------------------------------------------------------------
1965// print_boot_device
1966// displays the boot device
1967//--------------------------------------------------------------------------
1968
1969#ifdef VBOX
1970static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
1971#else /* !VBOX */
1972static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1973#endif /* !VBOX */
1974
1975#ifdef VBOX
1976void
1977print_boot_device(cdboot, lanboot, drive)
1978 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
1979#else /* !VBOX */
1980void
1981print_boot_device(cdboot, drive)
1982 Bit8u cdboot; Bit16u drive;
1983#endif /* !VBOX */
1984{
1985 Bit8u i;
1986
1987#ifdef VBOX
1988 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
1989 // lanboot contains 0 if floppy/harddisk, 1 otherwise
1990#else /* !VBOX */
1991 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1992#endif /* !VBOX */
1993 // drive contains real/emulated boot drive
1994
1995 if(cdboot)i=2; // CD-Rom
1996#ifdef VBOX
1997 else if(lanboot)i=3; // LAN
1998#endif /* VBOX */
1999 else if((drive&0x0080)==0x00)i=0; // Floppy
2000 else if((drive&0x0080)==0x80)i=1; // Hard drive
2001 else return;
2002
2003#ifdef VBOX
2004 BX_INFO("Booting from %s...\n",drivetypes[i]);
2005#else /* !VBOX */
2006 printf("Booting from %s...\n",drivetypes[i]);
2007#endif /* !VBOX */
2008}
2009
2010//--------------------------------------------------------------------------
2011// print_boot_failure
2012// displays the reason why boot failed
2013//--------------------------------------------------------------------------
2014#ifdef VBOX
2015 void
2016print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2017 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2018#else /* !VBOX */
2019 void
2020print_boot_failure(cdboot, drive, reason, lastdrive)
2021 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2022#endif /* !VBOX */
2023{
2024 Bit16u drivenum = drive&0x7f;
2025
2026 // cdboot: 1 if boot from cd, 0 otherwise
2027#ifdef VBOX
2028 // lanboot: 1 if boot from lan, 0 otherwise
2029#endif /* VBOX */
2030 // drive : drive number
2031 // reason: 0 signature check failed, 1 read error
2032 // lastdrive: 1 boot drive is the last one in boot sequence
2033
2034 if (cdboot)
2035#ifndef VBOX
2036 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2037#else /* VBOX */
2038 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2039 else if (lanboot)
2040 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2041#endif /* VBOX */
2042 else if (drive & 0x80)
2043#ifndef VBOX
2044 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2045#else /* VBOX */
2046 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2047#endif /* VBOX */
2048 else
2049#ifndef VBOX
2050 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2051#else /* VBOX */
2052 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2053#endif /* VBOX */
2054
2055 if (lastdrive==1) {
2056 if (reason==0)
2057#ifndef VBOX
2058 BX_PANIC("Not a bootable disk\n");
2059#else /* VBOX */
2060 BX_PANIC("No bootable medium found! System halted.\n");
2061#endif /* VBOX */
2062 else
2063#ifndef VBOX
2064 BX_PANIC("Could not read the boot disk\n");
2065#else /* VBOX */
2066 BX_PANIC("Could not read from the boot medium! System halted.\n");
2067#endif /* VBOX */
2068 }
2069}
2070
2071//--------------------------------------------------------------------------
2072// print_cdromboot_failure
2073// displays the reason why boot failed
2074//--------------------------------------------------------------------------
2075 void
2076print_cdromboot_failure( code )
2077 Bit16u code;
2078{
2079#ifndef VBOX
2080 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2081#else /* VBOX */
2082 BX_INFO("CDROM boot failure code : %04x\n",code);
2083#endif /* VBOX */
2084
2085 return;
2086}
2087
2088void
2089nmi_handler_msg()
2090{
2091 BX_PANIC("NMI Handler called\n");
2092}
2093
2094void
2095int18_panic_msg()
2096{
2097 BX_PANIC("INT18: BOOT FAILURE\n");
2098}
2099
2100void
2101log_bios_start()
2102{
2103#if BX_DEBUG_SERIAL
2104 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2105#endif
2106 BX_INFO("%s\n", bios_cvs_version_string);
2107}
2108
2109 bx_bool
2110set_enable_a20(val)
2111 bx_bool val;
2112{
2113 Bit8u oldval;
2114
2115 // Use PS2 System Control port A to set A20 enable
2116
2117 // get current setting first
2118 oldval = inb(0x92);
2119
2120 // change A20 status
2121 if (val)
2122 outb(0x92, oldval | 0x02);
2123 else
2124 outb(0x92, oldval & 0xfd);
2125
2126 return((oldval & 0x02) != 0);
2127}
2128
2129 void
2130debugger_on()
2131{
2132 outb(0xfedc, 0x01);
2133}
2134
2135 void
2136debugger_off()
2137{
2138 outb(0xfedc, 0x00);
2139}
2140
2141#if VBOX
2142# if VBOX_WITH_BUSLOGIC || VBOX_WITH_LSILOGIC
2143# include "scsi.c"
2144# endif
2145#endif
2146
2147#if BX_USE_ATADRV
2148
2149// ---------------------------------------------------------------------------
2150// Start of ATA/ATAPI Driver
2151// ---------------------------------------------------------------------------
2152
2153// Global defines -- ATA register and register bits.
2154// command block & control block regs
2155#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2156#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2157#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2158#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2159#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2160#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2161#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2162#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2163#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2164#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2165#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2166#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2167#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2168
2169#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2170#define ATA_CB_ER_BBK 0x80 // ATA bad block
2171#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2172#define ATA_CB_ER_MC 0x20 // ATA media change
2173#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2174#define ATA_CB_ER_MCR 0x08 // ATA media change request
2175#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2176#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2177#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2178
2179#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2180#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2181#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2182#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2183#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2184
2185// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2186#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2187#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2188#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2189#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2190
2191// bits 7-4 of the device/head (CB_DH) reg
2192#define ATA_CB_DH_DEV0 0xa0 // select device 0
2193#define ATA_CB_DH_DEV1 0xb0 // select device 1
2194
2195// status reg (CB_STAT and CB_ASTAT) bits
2196#define ATA_CB_STAT_BSY 0x80 // busy
2197#define ATA_CB_STAT_RDY 0x40 // ready
2198#define ATA_CB_STAT_DF 0x20 // device fault
2199#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2200#define ATA_CB_STAT_SKC 0x10 // seek complete
2201#define ATA_CB_STAT_SERV 0x10 // service
2202#define ATA_CB_STAT_DRQ 0x08 // data request
2203#define ATA_CB_STAT_CORR 0x04 // corrected
2204#define ATA_CB_STAT_IDX 0x02 // index
2205#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2206#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2207
2208// device control reg (CB_DC) bits
2209#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2210#define ATA_CB_DC_SRST 0x04 // soft reset
2211#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2212
2213// Most mandtory and optional ATA commands (from ATA-3),
2214#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2215#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2216#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2217#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2218#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2219#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2220#define ATA_CMD_CHECK_POWER_MODE2 0x98
2221#define ATA_CMD_DEVICE_RESET 0x08
2222#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2223#define ATA_CMD_FLUSH_CACHE 0xE7
2224#define ATA_CMD_FORMAT_TRACK 0x50
2225#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2226#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2227#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2228#define ATA_CMD_IDLE1 0xE3
2229#define ATA_CMD_IDLE2 0x97
2230#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2231#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2232#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2233#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2234#define ATA_CMD_NOP 0x00
2235#define ATA_CMD_PACKET 0xA0
2236#define ATA_CMD_READ_BUFFER 0xE4
2237#define ATA_CMD_READ_DMA 0xC8
2238#define ATA_CMD_READ_DMA_QUEUED 0xC7
2239#define ATA_CMD_READ_MULTIPLE 0xC4
2240#define ATA_CMD_READ_SECTORS 0x20
2241#ifdef VBOX
2242#define ATA_CMD_READ_SECTORS_EXT 0x24
2243#endif /* VBOX */
2244#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2245#define ATA_CMD_RECALIBRATE 0x10
2246#define ATA_CMD_SEEK 0x70
2247#define ATA_CMD_SET_FEATURES 0xEF
2248#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2249#define ATA_CMD_SLEEP1 0xE6
2250#define ATA_CMD_SLEEP2 0x99
2251#define ATA_CMD_STANDBY1 0xE2
2252#define ATA_CMD_STANDBY2 0x96
2253#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2254#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2255#define ATA_CMD_WRITE_BUFFER 0xE8
2256#define ATA_CMD_WRITE_DMA 0xCA
2257#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2258#define ATA_CMD_WRITE_MULTIPLE 0xC5
2259#define ATA_CMD_WRITE_SECTORS 0x30
2260#ifdef VBOX
2261#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2262#endif /* VBOX */
2263#define ATA_CMD_WRITE_VERIFY 0x3C
2264
2265#define ATA_IFACE_NONE 0x00
2266#define ATA_IFACE_ISA 0x00
2267#define ATA_IFACE_PCI 0x01
2268
2269#define ATA_TYPE_NONE 0x00
2270#define ATA_TYPE_UNKNOWN 0x01
2271#define ATA_TYPE_ATA 0x02
2272#define ATA_TYPE_ATAPI 0x03
2273#define ATA_TYPE_SCSI 0x04 // SCSI disk
2274
2275#define ATA_DEVICE_NONE 0x00
2276#define ATA_DEVICE_HD 0xFF
2277#define ATA_DEVICE_CDROM 0x05
2278
2279#define ATA_MODE_NONE 0x00
2280#define ATA_MODE_PIO16 0x00
2281#define ATA_MODE_PIO32 0x01
2282#define ATA_MODE_ISADMA 0x02
2283#define ATA_MODE_PCIDMA 0x03
2284#define ATA_MODE_USEIRQ 0x10
2285
2286#define ATA_TRANSLATION_NONE 0
2287#define ATA_TRANSLATION_LBA 1
2288#define ATA_TRANSLATION_LARGE 2
2289#define ATA_TRANSLATION_RECHS 3
2290
2291#define ATA_DATA_NO 0x00
2292#define ATA_DATA_IN 0x01
2293#define ATA_DATA_OUT 0x02
2294
2295// ---------------------------------------------------------------------------
2296// ATA/ATAPI driver : initialization
2297// ---------------------------------------------------------------------------
2298void ata_init( )
2299{
2300 Bit16u ebda_seg=read_word(0x0040,0x000E);
2301 Bit8u channel, device;
2302
2303 // Channels info init.
2304 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2305 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2306 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2307 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2308 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2309 }
2310
2311 // Devices info init.
2312 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2313 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2314 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2315 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2316 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2317 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2318 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2319 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2320 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2321 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2322 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2323 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2324 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2325 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2326
2327 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2328 }
2329
2330 // hdidmap and cdidmap init.
2331 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2332 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2333 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2334 }
2335
2336 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2337 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2338}
2339
2340// ---------------------------------------------------------------------------
2341// ATA/ATAPI driver : device detection
2342// ---------------------------------------------------------------------------
2343
2344void ata_detect( )
2345{
2346 Bit16u ebda_seg=read_word(0x0040,0x000E);
2347 Bit8u hdcount, cdcount, device, type;
2348 Bit8u buffer[0x0200];
2349
2350#if BX_MAX_ATA_INTERFACES > 0
2351 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2352 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2353 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2354 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2355#endif
2356#if BX_MAX_ATA_INTERFACES > 1
2357 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2358 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2359 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2360 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2361#endif
2362#if BX_MAX_ATA_INTERFACES > 2
2363 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2364 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2365 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2366 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2367#endif
2368#if BX_MAX_ATA_INTERFACES > 3
2369 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2370 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2371 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2372 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2373#endif
2374#if BX_MAX_ATA_INTERFACES > 4
2375#error Please fill the ATA interface informations
2376#endif
2377
2378 // Device detection
2379 hdcount=cdcount=0;
2380
2381 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2382 Bit16u iobase1, iobase2;
2383 Bit8u channel, slave, shift;
2384 Bit8u sc, sn, cl, ch, st;
2385
2386 channel = device / 2;
2387 slave = device % 2;
2388
2389 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2390 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2391
2392 // Disable interrupts
2393 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2394
2395 // Look for device
2396 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2397 outb(iobase1+ATA_CB_SC, 0x55);
2398 outb(iobase1+ATA_CB_SN, 0xaa);
2399 outb(iobase1+ATA_CB_SC, 0xaa);
2400 outb(iobase1+ATA_CB_SN, 0x55);
2401 outb(iobase1+ATA_CB_SC, 0x55);
2402 outb(iobase1+ATA_CB_SN, 0xaa);
2403
2404 // If we found something
2405 sc = inb(iobase1+ATA_CB_SC);
2406 sn = inb(iobase1+ATA_CB_SN);
2407
2408 if ( (sc == 0x55) && (sn == 0xaa) ) {
2409 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2410
2411 // reset the channel
2412 ata_reset(device);
2413
2414 // check for ATA or ATAPI
2415 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2416 sc = inb(iobase1+ATA_CB_SC);
2417 sn = inb(iobase1+ATA_CB_SN);
2418
2419 if ((sc==0x01) && (sn==0x01)) {
2420 cl = inb(iobase1+ATA_CB_CL);
2421 ch = inb(iobase1+ATA_CB_CH);
2422 st = inb(iobase1+ATA_CB_STAT);
2423
2424 if ((cl==0x14) && (ch==0xeb)) {
2425 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2426 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2427 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2428 } else if ((cl==0xff) && (ch==0xff)) {
2429 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2430 }
2431 }
2432 }
2433
2434#ifdef VBOX
2435 // Enable interrupts
2436 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2437#endif /* VBOX */
2438
2439 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2440
2441 // Now we send a IDENTIFY command to ATA device
2442 if(type == ATA_TYPE_ATA) {
2443 Bit32u sectors;
2444 Bit16u cylinders, heads, spt, blksize;
2445#ifdef VBOX
2446 Bit16u lcylinders, lheads, lspt;
2447 Bit8u chsgeo_base;
2448#endif /* VBOX */
2449 Bit8u translation, removable, mode;
2450
2451 //Temporary values to do the transfer
2452 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2453 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2454
2455 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2456 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2457
2458 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2459 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2460#ifdef VBOX
2461 blksize = 512; /* There is no sector size field any more. */
2462#else /* !VBOX */
2463 blksize = read_word(get_SS(),buffer+10);
2464#endif /* !VBOX */
2465
2466 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2467 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2468 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2469
2470 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2471#ifdef VBOX
2472 /** @todo update sectors to be a 64 bit number (also lba...). */
2473 if (sectors == 268435455)
2474 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2475 switch (device)
2476 {
2477 case 0:
2478 chsgeo_base = 0x1e;
2479 break;
2480 case 1:
2481 chsgeo_base = 0x26;
2482 break;
2483 case 2:
2484 chsgeo_base = 0x67;
2485 break;
2486 case 3:
2487 chsgeo_base = 0x70;
2488 break;
2489 case 4:
2490 chsgeo_base = 0x40;
2491 break;
2492 case 5:
2493 chsgeo_base = 0x48;
2494 break;
2495 case 6:
2496 chsgeo_base = 0x50;
2497 break;
2498 case 7:
2499 chsgeo_base = 0x58;
2500 break;
2501 default:
2502 chsgeo_base = 0;
2503 }
2504 if (chsgeo_base != 0)
2505 {
2506 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2507 lheads = inb_cmos(chsgeo_base+2);
2508 lspt = inb_cmos(chsgeo_base+7);
2509 }
2510 else
2511 {
2512 lcylinders = 0;
2513 lheads = 0;
2514 lspt = 0;
2515 }
2516 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2517#endif /* VBOX */
2518
2519 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2520 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2521 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2522 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2523 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2524 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2525 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2526 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2527#ifdef VBOX
2528 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2529 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2530 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2531 if (device < 2)
2532 {
2533 Bit8u sum, i;
2534 unsigned char *fdpt;
2535 if (device == 0)
2536 fdpt = &EbdaData->fdpt0;
2537 else
2538 fdpt = &EbdaData->fdpt1;
2539
2540 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2541 * to be done at POST time with lots of ugly assembler code, which
2542 * isn't worth the effort of converting from AMI to Award CMOS
2543 * format. Just do it here. */
2544 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2545 write_byte(ebda_seg, fdpt + 0x02, lheads);
2546 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2547 write_word(ebda_seg, fdpt + 0x09, cylinders);
2548 write_byte(ebda_seg, fdpt + 0x0b, heads);
2549 write_byte(ebda_seg, fdpt + 0x04, spt);
2550 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2551 sum = 0;
2552 for (i = 0; i < 0xf; i++)
2553 sum += read_byte(ebda_seg, fdpt + i);
2554 sum = 1 - sum;
2555 write_byte(ebda_seg, fdpt + 0x0f, sum);
2556 }
2557#else /* !VBOX */
2558 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2559
2560 translation = inb_cmos(0x39 + channel/2);
2561 for (shift=device%4; shift>0; shift--) translation >>= 2;
2562 translation &= 0x03;
2563
2564 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2565
2566 switch (translation) {
2567 case ATA_TRANSLATION_NONE:
2568 BX_INFO("none");
2569 break;
2570 case ATA_TRANSLATION_LBA:
2571 BX_INFO("lba");
2572 break;
2573 case ATA_TRANSLATION_LARGE:
2574 BX_INFO("large");
2575 break;
2576 case ATA_TRANSLATION_RECHS:
2577 BX_INFO("r-echs");
2578 break;
2579 }
2580 switch (translation) {
2581 case ATA_TRANSLATION_NONE:
2582 break;
2583 case ATA_TRANSLATION_LBA:
2584 spt = 63;
2585 sectors /= 63;
2586 heads = sectors / 1024;
2587 if (heads>128) heads = 255;
2588 else if (heads>64) heads = 128;
2589 else if (heads>32) heads = 64;
2590 else if (heads>16) heads = 32;
2591 else heads=16;
2592 cylinders = sectors / heads;
2593 break;
2594 case ATA_TRANSLATION_RECHS:
2595 // Take care not to overflow
2596 if (heads==16) {
2597 if(cylinders>61439) cylinders=61439;
2598 heads=15;
2599 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2600 }
2601 // then go through the large bitshift process
2602 case ATA_TRANSLATION_LARGE:
2603 while(cylinders > 1024) {
2604 cylinders >>= 1;
2605 heads <<= 1;
2606
2607 // If we max out the head count
2608 if (heads > 127) break;
2609 }
2610 break;
2611 }
2612 // clip to 1024 cylinders in lchs
2613 if (cylinders > 1024) cylinders=1024;
2614 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2615
2616 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2617 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2618 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2619#endif /* VBOX */
2620
2621 // fill hdidmap
2622 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2623 hdcount++;
2624 }
2625
2626 // Now we send a IDENTIFY command to ATAPI device
2627 if(type == ATA_TYPE_ATAPI) {
2628
2629 Bit8u type, removable, mode;
2630 Bit16u blksize;
2631
2632 //Temporary values to do the transfer
2633 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2634 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2635
2636 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2637 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2638
2639 type = read_byte(get_SS(),buffer+1) & 0x1f;
2640 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2641 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2642 blksize = 2048;
2643
2644 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2645 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2646 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2647 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2648
2649 // fill cdidmap
2650 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2651 cdcount++;
2652 }
2653
2654 {
2655 Bit32u sizeinmb;
2656 Bit16u ataversion;
2657 Bit8u c, i, version, model[41];
2658
2659 switch (type) {
2660 case ATA_TYPE_ATA:
2661 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2662 sizeinmb >>= 11;
2663 case ATA_TYPE_ATAPI:
2664 // Read ATA/ATAPI version
2665 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2666 for(version=15;version>0;version--) {
2667 if((ataversion&(1<<version))!=0)
2668 break;
2669 }
2670
2671 // Read model name
2672 for(i=0;i<20;i++){
2673 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2674 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2675 }
2676
2677 // Reformat
2678 write_byte(get_SS(),model+40,0x00);
2679 for(i=39;i>0;i--){
2680 if(read_byte(get_SS(),model+i)==0x20)
2681 write_byte(get_SS(),model+i,0x00);
2682 else break;
2683 }
2684 break;
2685 }
2686
2687#ifdef VBOX
2688 // we don't want any noisy output for now
2689#else /* !VBOX */
2690 switch (type) {
2691 case ATA_TYPE_ATA:
2692 printf("ata%d %s: ",channel,slave?" slave":"master");
2693 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2694 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2695 break;
2696 case ATA_TYPE_ATAPI:
2697 printf("ata%d %s: ",channel,slave?" slave":"master");
2698 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2699 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2700 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2701 else
2702 printf(" ATAPI-%d Device\n",version);
2703 break;
2704 case ATA_TYPE_UNKNOWN:
2705 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2706 break;
2707 }
2708#endif /* !VBOX */
2709 }
2710 }
2711
2712 // Store the devices counts
2713 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2714 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2715 write_byte(0x40,0x75, hdcount);
2716
2717#ifdef VBOX
2718 // we don't want any noisy output for now
2719#else /* !VBOX */
2720 printf("\n");
2721#endif /* !VBOX */
2722
2723 // FIXME : should use bios=cmos|auto|disable bits
2724 // FIXME : should know about translation bits
2725 // FIXME : move hard_drive_post here
2726
2727}
2728
2729// ---------------------------------------------------------------------------
2730// ATA/ATAPI driver : software reset
2731// ---------------------------------------------------------------------------
2732// ATA-3
2733// 8.2.1 Software reset - Device 0
2734
2735void ata_reset(device)
2736Bit16u device;
2737{
2738 Bit16u ebda_seg=read_word(0x0040,0x000E);
2739 Bit16u iobase1, iobase2;
2740 Bit8u channel, slave, sn, sc;
2741 Bit16u max;
2742#ifdef VBOX
2743 Bit16u pdelay;
2744#endif /* VBOX */
2745
2746 channel = device / 2;
2747 slave = device % 2;
2748
2749 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2750 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2751
2752 // Reset
2753
2754// 8.2.1 (a) -- set SRST in DC
2755 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2756
2757// 8.2.1 (b) -- wait for BSY
2758 max=0xff;
2759 while(--max>0) {
2760 Bit8u status = inb(iobase1+ATA_CB_STAT);
2761 if ((status & ATA_CB_STAT_BSY) != 0) break;
2762 }
2763
2764// 8.2.1 (f) -- clear SRST
2765 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2766
2767 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2768
2769// 8.2.1 (g) -- check for sc==sn==0x01
2770 // select device
2771 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2772 sc = inb(iobase1+ATA_CB_SC);
2773 sn = inb(iobase1+ATA_CB_SN);
2774
2775 if ( (sc==0x01) && (sn==0x01) ) {
2776
2777// 8.2.1 (h) -- wait for not BSY
2778#ifdef VBOX
2779 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2780#else /* !VBOX */
2781 max=0xff;
2782#endif /* !VBOX */
2783 while(--max>0) {
2784 Bit8u status = inb(iobase1+ATA_CB_STAT);
2785 if ((status & ATA_CB_STAT_BSY) == 0) break;
2786#ifdef VBOX
2787 pdelay=0xffff;
2788 while (--pdelay>0) {
2789 /* nothing */
2790 }
2791#endif /* VBOX */
2792 }
2793 }
2794 }
2795
2796// 8.2.1 (i) -- wait for DRDY
2797#ifdef VBOX
2798 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2799#else /* !VBOX */
2800 max=0xfff;
2801#endif /* !VBOX */
2802 while(--max>0) {
2803 Bit8u status = inb(iobase1+ATA_CB_STAT);
2804 if ((status & ATA_CB_STAT_RDY) != 0) break;
2805 }
2806
2807 // Enable interrupts
2808 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2809}
2810
2811// ---------------------------------------------------------------------------
2812// ATA/ATAPI driver : execute a non data command
2813// ---------------------------------------------------------------------------
2814
2815Bit16u ata_cmd_non_data()
2816{return 0;}
2817
2818// ---------------------------------------------------------------------------
2819// ATA/ATAPI driver : execute a data-in command
2820// ---------------------------------------------------------------------------
2821 // returns
2822 // 0 : no error
2823 // 1 : BUSY bit set
2824 // 2 : read error
2825 // 3 : expected DRQ=1
2826 // 4 : no sectors left to read/verify
2827 // 5 : more sectors to read/verify
2828 // 6 : no sectors left to write
2829 // 7 : more sectors to write
2830Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2831Bit16u device, command, count, cylinder, head, sector, segment, offset;
2832Bit32u lba;
2833{
2834 Bit16u ebda_seg=read_word(0x0040,0x000E);
2835 Bit16u iobase1, iobase2, blksize;
2836 Bit8u channel, slave;
2837 Bit8u status, current, mode;
2838
2839 channel = device / 2;
2840 slave = device % 2;
2841
2842 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2843 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2844 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2845 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2846 if (mode == ATA_MODE_PIO32) blksize>>=2;
2847 else blksize>>=1;
2848
2849#ifdef VBOX
2850 status = inb(iobase1 + ATA_CB_STAT);
2851 if (status & ATA_CB_STAT_BSY)
2852 {
2853 // Enable interrupts
2854 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2855 return 1;
2856 }
2857#endif /* VBOX */
2858
2859 // sector will be 0 only on lba access. Convert to lba-chs
2860 if (sector == 0) {
2861#ifdef VBOX
2862 if (count >= 256 || lba + count >= 268435456)
2863 {
2864 sector = (lba & 0xff000000L) >> 24;
2865 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2866 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2867 outb(iobase1 + ATA_CB_SN, sector);
2868 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2869 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2870 /* Leave the bottom 24 bits as is, they are treated correctly by the
2871 * LBA28 code path. */
2872 lba &= 0xffffff;
2873 }
2874#endif /* VBOX */
2875 sector = (Bit16u) (lba & 0x000000ffL);
2876 lba >>= 8;
2877 cylinder = (Bit16u) (lba & 0x0000ffffL);
2878 lba >>= 16;
2879 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2880 }
2881
2882 // Reset count of transferred data
2883 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2884 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2885 current = 0;
2886
2887#ifndef VBOX
2888 status = inb(iobase1 + ATA_CB_STAT);
2889 if (status & ATA_CB_STAT_BSY) return 1;
2890#endif /* !VBOX */
2891
2892 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2893 outb(iobase1 + ATA_CB_FR, 0x00);
2894 outb(iobase1 + ATA_CB_SC, count);
2895 outb(iobase1 + ATA_CB_SN, sector);
2896 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2897 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2898 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2899 outb(iobase1 + ATA_CB_CMD, command);
2900
2901 while (1) {
2902 status = inb(iobase1 + ATA_CB_STAT);
2903 if ( !(status & ATA_CB_STAT_BSY) ) break;
2904 }
2905
2906 if (status & ATA_CB_STAT_ERR) {
2907 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2908#ifdef VBOX
2909 // Enable interrupts
2910 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2911#endif /* VBOX */
2912 return 2;
2913 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2914 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2915#ifdef VBOX
2916 // Enable interrupts
2917 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2918#endif /* VBOX */
2919 return 3;
2920 }
2921
2922 // FIXME : move seg/off translation here
2923
2924ASM_START
2925 sti ;; enable higher priority interrupts
2926ASM_END
2927
2928 while (1) {
2929
2930ASM_START
2931 push bp
2932 mov bp, sp
2933 mov di, _ata_cmd_data_in.offset + 2[bp]
2934 mov ax, _ata_cmd_data_in.segment + 2[bp]
2935 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2936
2937 ;; adjust if there will be an overrun. 2K max sector size
2938 cmp di, #0xf800 ;;
2939 jbe ata_in_no_adjust
2940
2941ata_in_adjust:
2942 sub di, #0x0800 ;; sub 2 kbytes from offset
2943 add ax, #0x0080 ;; add 2 Kbytes to segment
2944
2945ata_in_no_adjust:
2946 mov es, ax ;; segment in es
2947
2948 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2949
2950 mov ah, _ata_cmd_data_in.mode + 2[bp]
2951 cmp ah, #ATA_MODE_PIO32
2952 je ata_in_32
2953
2954ata_in_16:
2955 rep
2956 insw ;; CX words transfered from port(DX) to ES:[DI]
2957 jmp ata_in_done
2958
2959ata_in_32:
2960 rep
2961 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2962
2963ata_in_done:
2964 mov _ata_cmd_data_in.offset + 2[bp], di
2965 mov _ata_cmd_data_in.segment + 2[bp], es
2966 pop bp
2967ASM_END
2968
2969 current++;
2970 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2971 count--;
2972#ifdef VBOX
2973 while (1) {
2974 status = inb(iobase1 + ATA_CB_STAT);
2975 if ( !(status & ATA_CB_STAT_BSY) ) break;
2976 }
2977#else /* !VBOX */
2978 status = inb(iobase1 + ATA_CB_STAT);
2979#endif /* !VBOX */
2980 if (count == 0) {
2981 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2982 != ATA_CB_STAT_RDY ) {
2983 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2984#ifdef VBOX
2985 // Enable interrupts
2986 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2987#endif /* VBOX */
2988 return 4;
2989 }
2990 break;
2991 }
2992 else {
2993 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2994 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2995 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2996#ifdef VBOX
2997 // Enable interrupts
2998 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2999#endif /* VBOX */
3000 return 5;
3001 }
3002 continue;
3003 }
3004 }
3005 // Enable interrupts
3006 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3007 return 0;
3008}
3009
3010// ---------------------------------------------------------------------------
3011// ATA/ATAPI driver : execute a data-out command
3012// ---------------------------------------------------------------------------
3013 // returns
3014 // 0 : no error
3015 // 1 : BUSY bit set
3016 // 2 : read error
3017 // 3 : expected DRQ=1
3018 // 4 : no sectors left to read/verify
3019 // 5 : more sectors to read/verify
3020 // 6 : no sectors left to write
3021 // 7 : more sectors to write
3022Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3023Bit16u device, command, count, cylinder, head, sector, segment, offset;
3024Bit32u lba;
3025{
3026 Bit16u ebda_seg=read_word(0x0040,0x000E);
3027 Bit16u iobase1, iobase2, blksize;
3028 Bit8u channel, slave;
3029 Bit8u status, current, mode;
3030
3031 channel = device / 2;
3032 slave = device % 2;
3033
3034 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3035 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3036 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3037 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3038 if (mode == ATA_MODE_PIO32) blksize>>=2;
3039 else blksize>>=1;
3040
3041#ifdef VBOX
3042 status = inb(iobase1 + ATA_CB_STAT);
3043 if (status & ATA_CB_STAT_BSY)
3044 {
3045 // Enable interrupts
3046 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3047 return 1;
3048 }
3049#endif /* VBOX */
3050
3051 // sector will be 0 only on lba access. Convert to lba-chs
3052 if (sector == 0) {
3053#ifdef VBOX
3054 if (count >= 256 || lba + count >= 268435456)
3055 {
3056 sector = (lba & 0xff000000L) >> 24;
3057 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3058 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3059 outb(iobase1 + ATA_CB_SN, sector);
3060 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3061 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3062 /* Leave the bottom 24 bits as is, they are treated correctly by the
3063 * LBA28 code path. */
3064 lba &= 0xffffff;
3065 }
3066#endif /* VBOX */
3067 sector = (Bit16u) (lba & 0x000000ffL);
3068 lba >>= 8;
3069 cylinder = (Bit16u) (lba & 0x0000ffffL);
3070 lba >>= 16;
3071 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3072 }
3073
3074 // Reset count of transferred data
3075 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3076 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3077 current = 0;
3078
3079#ifndef VBOX
3080 status = inb(iobase1 + ATA_CB_STAT);
3081 if (status & ATA_CB_STAT_BSY) return 1;
3082#endif /* !VBOX */
3083
3084 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3085 outb(iobase1 + ATA_CB_FR, 0x00);
3086 outb(iobase1 + ATA_CB_SC, count);
3087 outb(iobase1 + ATA_CB_SN, sector);
3088 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3089 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3090 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3091 outb(iobase1 + ATA_CB_CMD, command);
3092
3093 while (1) {
3094 status = inb(iobase1 + ATA_CB_STAT);
3095 if ( !(status & ATA_CB_STAT_BSY) ) break;
3096 }
3097
3098 if (status & ATA_CB_STAT_ERR) {
3099 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3100#ifdef VBOX
3101 // Enable interrupts
3102 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3103#endif /* VBOX */
3104 return 2;
3105 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3106 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3107#ifdef VBOX
3108 // Enable interrupts
3109 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3110#endif /* VBOX */
3111 return 3;
3112 }
3113
3114 // FIXME : move seg/off translation here
3115
3116ASM_START
3117 sti ;; enable higher priority interrupts
3118ASM_END
3119
3120 while (1) {
3121
3122ASM_START
3123 push bp
3124 mov bp, sp
3125 mov si, _ata_cmd_data_out.offset + 2[bp]
3126 mov ax, _ata_cmd_data_out.segment + 2[bp]
3127 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3128
3129 ;; adjust if there will be an overrun. 2K max sector size
3130 cmp si, #0xf800 ;;
3131 jbe ata_out_no_adjust
3132
3133ata_out_adjust:
3134 sub si, #0x0800 ;; sub 2 kbytes from offset
3135 add ax, #0x0080 ;; add 2 Kbytes to segment
3136
3137ata_out_no_adjust:
3138 mov es, ax ;; segment in es
3139
3140 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3141
3142 mov ah, _ata_cmd_data_out.mode + 2[bp]
3143 cmp ah, #ATA_MODE_PIO32
3144 je ata_out_32
3145
3146ata_out_16:
3147 seg ES
3148 rep
3149 outsw ;; CX words transfered from port(DX) to ES:[SI]
3150 jmp ata_out_done
3151
3152ata_out_32:
3153 seg ES
3154 rep
3155 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3156
3157ata_out_done:
3158 mov _ata_cmd_data_out.offset + 2[bp], si
3159 mov _ata_cmd_data_out.segment + 2[bp], es
3160 pop bp
3161ASM_END
3162
3163 current++;
3164 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3165 count--;
3166#ifdef VBOX
3167 while (1) {
3168 status = inb(iobase1 + ATA_CB_STAT);
3169 if ( !(status & ATA_CB_STAT_BSY) ) break;
3170 }
3171#else /* !VBOX */
3172 status = inb(iobase1 + ATA_CB_STAT);
3173#endif /* VBOX */
3174 if (count == 0) {
3175 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3176 != ATA_CB_STAT_RDY ) {
3177 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3178#ifdef VBOX
3179 // Enable interrupts
3180 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3181#endif /* VBOX */
3182 return 6;
3183 }
3184 break;
3185 }
3186 else {
3187 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3188 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3189 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3190#ifdef VBOX
3191 // Enable interrupts
3192 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3193#endif /* VBOX */
3194 return 7;
3195 }
3196 continue;
3197 }
3198 }
3199 // Enable interrupts
3200 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3201 return 0;
3202}
3203
3204// ---------------------------------------------------------------------------
3205// ATA/ATAPI driver : execute a packet command
3206// ---------------------------------------------------------------------------
3207 // returns
3208 // 0 : no error
3209 // 1 : error in parameters
3210 // 2 : BUSY bit set
3211 // 3 : error
3212 // 4 : not ready
3213Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3214Bit8u cmdlen,inout;
3215Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3216Bit16u header;
3217Bit32u length;
3218{
3219 Bit16u ebda_seg=read_word(0x0040,0x000E);
3220 Bit16u iobase1, iobase2;
3221 Bit16u lcount, lbefore, lafter, count;
3222 Bit8u channel, slave;
3223 Bit8u status, mode, lmode;
3224 Bit32u total, transfer;
3225
3226 channel = device / 2;
3227 slave = device % 2;
3228
3229 // Data out is not supported yet
3230 if (inout == ATA_DATA_OUT) {
3231 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3232 return 1;
3233 }
3234
3235 // The header length must be even
3236 if (header & 1) {
3237 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3238 return 1;
3239 }
3240
3241 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3242 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3243 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3244 transfer= 0L;
3245
3246 if (cmdlen < 12) cmdlen=12;
3247 if (cmdlen > 12) cmdlen=16;
3248 cmdlen>>=1;
3249
3250 // Reset count of transferred data
3251 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3252 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3253
3254 status = inb(iobase1 + ATA_CB_STAT);
3255 if (status & ATA_CB_STAT_BSY) return 2;
3256
3257 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3258 // outb(iobase1 + ATA_CB_FR, 0x00);
3259 // outb(iobase1 + ATA_CB_SC, 0x00);
3260 // outb(iobase1 + ATA_CB_SN, 0x00);
3261 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3262 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3263 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3264 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3265
3266 // Device should ok to receive command
3267 while (1) {
3268 status = inb(iobase1 + ATA_CB_STAT);
3269 if ( !(status & ATA_CB_STAT_BSY) ) break;
3270 }
3271
3272 if (status & ATA_CB_STAT_ERR) {
3273 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3274#ifdef VBOX
3275 // Enable interrupts
3276 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3277#endif /* VBOX */
3278 return 3;
3279 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3280 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3281#ifdef VBOX
3282 // Enable interrupts
3283 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3284#endif /* VBOX */
3285 return 4;
3286 }
3287
3288 // Normalize address
3289 cmdseg += (cmdoff / 16);
3290 cmdoff %= 16;
3291
3292 // Send command to device
3293ASM_START
3294 sti ;; enable higher priority interrupts
3295
3296 push bp
3297 mov bp, sp
3298
3299 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3300 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3301 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3302 mov es, ax ;; segment in es
3303
3304 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3305
3306 seg ES
3307 rep
3308 outsw ;; CX words transfered from port(DX) to ES:[SI]
3309
3310 pop bp
3311ASM_END
3312
3313 if (inout == ATA_DATA_NO) {
3314 status = inb(iobase1 + ATA_CB_STAT);
3315 }
3316 else {
3317 while (1) {
3318
3319#ifdef VBOX
3320 while (1) {
3321 status = inb(iobase1 + ATA_CB_STAT);
3322 if ( !(status & ATA_CB_STAT_BSY) ) break;
3323 }
3324#else /* VBOX */
3325 status = inb(iobase1 + ATA_CB_STAT);
3326#endif /* VBOX */
3327
3328 // Check if command completed
3329 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3330
3331 if (status & ATA_CB_STAT_ERR) {
3332 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3333#ifdef VBOX
3334 // Enable interrupts
3335 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3336#endif /* VBOX */
3337 return 3;
3338 }
3339
3340 // Device must be ready to send data
3341 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3342 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3343 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3344#ifdef VBOX
3345 // Enable interrupts
3346 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3347#endif /* VBOX */
3348 return 4;
3349 }
3350
3351 // Normalize address
3352 bufseg += (bufoff / 16);
3353 bufoff %= 16;
3354
3355 // Get the byte count
3356 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3357
3358 // adjust to read what we want
3359 if(header>lcount) {
3360 lbefore=lcount;
3361 header-=lcount;
3362 lcount=0;
3363 }
3364 else {
3365 lbefore=header;
3366 header=0;
3367 lcount-=lbefore;
3368 }
3369
3370 if(lcount>length) {
3371 lafter=lcount-length;
3372 lcount=length;
3373 length=0;
3374 }
3375 else {
3376 lafter=0;
3377 length-=lcount;
3378 }
3379
3380 // Save byte count
3381 count = lcount;
3382
3383 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3384 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3385
3386 // If counts not dividable by 4, use 16bits mode
3387 lmode = mode;
3388 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3389 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3390 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3391
3392 // adds an extra byte if count are odd. before is always even
3393 if (lcount & 0x01) {
3394 lcount+=1;
3395 if ((lafter > 0) && (lafter & 0x01)) {
3396 lafter-=1;
3397 }
3398 }
3399
3400 if (lmode == ATA_MODE_PIO32) {
3401 lcount>>=2; lbefore>>=2; lafter>>=2;
3402 }
3403 else {
3404 lcount>>=1; lbefore>>=1; lafter>>=1;
3405 }
3406
3407 ; // FIXME bcc bug
3408
3409ASM_START
3410 push bp
3411 mov bp, sp
3412
3413 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3414
3415 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3416 jcxz ata_packet_no_before
3417
3418 mov ah, _ata_cmd_packet.lmode + 2[bp]
3419 cmp ah, #ATA_MODE_PIO32
3420 je ata_packet_in_before_32
3421
3422ata_packet_in_before_16:
3423 in ax, dx
3424 loop ata_packet_in_before_16
3425 jmp ata_packet_no_before
3426
3427ata_packet_in_before_32:
3428 push eax
3429ata_packet_in_before_32_loop:
3430 in eax, dx
3431 loop ata_packet_in_before_32_loop
3432 pop eax
3433
3434ata_packet_no_before:
3435 mov cx, _ata_cmd_packet.lcount + 2[bp]
3436 jcxz ata_packet_after
3437
3438 mov di, _ata_cmd_packet.bufoff + 2[bp]
3439 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3440 mov es, ax
3441
3442 mov ah, _ata_cmd_packet.lmode + 2[bp]
3443 cmp ah, #ATA_MODE_PIO32
3444 je ata_packet_in_32
3445
3446ata_packet_in_16:
3447 rep
3448 insw ;; CX words transfered tp port(DX) to ES:[DI]
3449 jmp ata_packet_after
3450
3451ata_packet_in_32:
3452 rep
3453 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3454
3455ata_packet_after:
3456 mov cx, _ata_cmd_packet.lafter + 2[bp]
3457 jcxz ata_packet_done
3458
3459 mov ah, _ata_cmd_packet.lmode + 2[bp]
3460 cmp ah, #ATA_MODE_PIO32
3461 je ata_packet_in_after_32
3462
3463ata_packet_in_after_16:
3464 in ax, dx
3465 loop ata_packet_in_after_16
3466 jmp ata_packet_done
3467
3468ata_packet_in_after_32:
3469 push eax
3470ata_packet_in_after_32_loop:
3471 in eax, dx
3472 loop ata_packet_in_after_32_loop
3473 pop eax
3474
3475ata_packet_done:
3476 pop bp
3477ASM_END
3478
3479 // Compute new buffer address
3480 bufoff += count;
3481
3482 // Save transferred bytes count
3483 transfer += count;
3484 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3485 }
3486 }
3487
3488 // Final check, device must be ready
3489 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3490 != ATA_CB_STAT_RDY ) {
3491 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3492#ifdef VBOX
3493 // Enable interrupts
3494 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3495#endif /* VBOX */
3496 return 4;
3497 }
3498
3499 // Enable interrupts
3500 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3501 return 0;
3502}
3503
3504// ---------------------------------------------------------------------------
3505// End of ATA/ATAPI Driver
3506// ---------------------------------------------------------------------------
3507
3508// ---------------------------------------------------------------------------
3509// Start of ATA/ATAPI generic functions
3510// ---------------------------------------------------------------------------
3511
3512 Bit16u
3513atapi_get_sense(device)
3514 Bit16u device;
3515{
3516 Bit8u atacmd[12];
3517 Bit8u buffer[16];
3518 Bit8u i;
3519
3520 memsetb(get_SS(),atacmd,0,12);
3521
3522 // Request SENSE
3523 atacmd[0]=0x03;
3524 atacmd[4]=0x20;
3525 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3526 return 0x0002;
3527
3528 if ((buffer[0] & 0x7e) == 0x70) {
3529 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3530 }
3531
3532 return 0;
3533}
3534
3535 Bit16u
3536atapi_is_ready(device)
3537 Bit16u device;
3538{
3539 Bit8u atacmd[12];
3540 Bit8u buffer[];
3541
3542 memsetb(get_SS(),atacmd,0,12);
3543
3544 // Test Unit Ready
3545 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3546 return 0x000f;
3547
3548 if (atapi_get_sense(device) !=0 ) {
3549 memsetb(get_SS(),atacmd,0,12);
3550
3551 // try to send Test Unit Ready again
3552 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3553 return 0x000f;
3554
3555 return atapi_get_sense(device);
3556 }
3557 return 0;
3558}
3559
3560 Bit16u
3561atapi_is_cdrom(device)
3562 Bit8u device;
3563{
3564 Bit16u ebda_seg=read_word(0x0040,0x000E);
3565
3566 if (device >= BX_MAX_ATA_DEVICES)
3567 return 0;
3568
3569 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3570 return 0;
3571
3572 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3573 return 0;
3574
3575 return 1;
3576}
3577
3578// ---------------------------------------------------------------------------
3579// End of ATA/ATAPI generic functions
3580// ---------------------------------------------------------------------------
3581
3582#endif // BX_USE_ATADRV
3583
3584#if BX_ELTORITO_BOOT
3585
3586// ---------------------------------------------------------------------------
3587// Start of El-Torito boot functions
3588// ---------------------------------------------------------------------------
3589
3590 void
3591cdemu_init()
3592{
3593 Bit16u ebda_seg=read_word(0x0040,0x000E);
3594
3595 // the only important data is this one for now
3596 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3597}
3598
3599 Bit8u
3600cdemu_isactive()
3601{
3602 Bit16u ebda_seg=read_word(0x0040,0x000E);
3603
3604 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3605}
3606
3607 Bit8u
3608cdemu_emulated_drive()
3609{
3610 Bit16u ebda_seg=read_word(0x0040,0x000E);
3611
3612 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3613}
3614
3615static char isotag[6]="CD001";
3616static char eltorito[24]="EL TORITO SPECIFICATION";
3617//
3618// Returns ah: emulated drive, al: error code
3619//
3620 Bit16u
3621cdrom_boot()
3622{
3623 Bit16u ebda_seg=read_word(0x0040,0x000E);
3624 Bit8u atacmd[12], buffer[2048];
3625 Bit32u lba;
3626 Bit16u boot_segment, nbsectors, i, error;
3627 Bit8u device;
3628#ifdef VBOX
3629 Bit8u read_try;
3630#endif /* VBOX */
3631
3632 // Find out the first cdrom
3633 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3634 if (atapi_is_cdrom(device)) break;
3635 }
3636
3637 // if not found
3638 if(device >= BX_MAX_ATA_DEVICES) return 2;
3639
3640 // Read the Boot Record Volume Descriptor
3641 memsetb(get_SS(),atacmd,0,12);
3642 atacmd[0]=0x28; // READ command
3643 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3644 atacmd[8]=(0x01 & 0x00ff); // Sectors
3645 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3646 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3647 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3648 atacmd[5]=(0x11 & 0x000000ff);
3649#ifdef VBOX
3650 for (read_try = 0; read_try <= 4; read_try++)
3651 {
3652 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3653 if (!error)
3654 break;
3655 }
3656 if (error)
3657 return 3;
3658#else /* !VBOX */
3659 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3660 return 3;
3661#endif /* !VBOX */
3662
3663 // Validity checks
3664 if(buffer[0]!=0)return 4;
3665 for(i=0;i<5;i++){
3666 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3667 }
3668 for(i=0;i<23;i++)
3669 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3670
3671 // ok, now we calculate the Boot catalog address
3672 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3673
3674 // And we read the Boot Catalog
3675 memsetb(get_SS(),atacmd,0,12);
3676 atacmd[0]=0x28; // READ command
3677 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3678 atacmd[8]=(0x01 & 0x00ff); // Sectors
3679 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3680 atacmd[3]=(lba & 0x00ff0000) >> 16;
3681 atacmd[4]=(lba & 0x0000ff00) >> 8;
3682 atacmd[5]=(lba & 0x000000ff);
3683 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3684 return 7;
3685
3686 // Validation entry
3687 if(buffer[0x00]!=0x01)return 8; // Header
3688 if(buffer[0x01]!=0x00)return 9; // Platform
3689 if(buffer[0x1E]!=0x55)return 10; // key 1
3690 if(buffer[0x1F]!=0xAA)return 10; // key 2
3691
3692 // Initial/Default Entry
3693 if(buffer[0x20]!=0x88)return 11; // Bootable
3694
3695 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3696 if(buffer[0x21]==0){
3697 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3698 // Win2000 cd boot needs to know it booted from cd
3699 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3700 }
3701 else if(buffer[0x21]<4)
3702 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3703 else
3704 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3705
3706 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3707 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3708
3709 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3710 if(boot_segment==0x0000)boot_segment=0x07C0;
3711
3712 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3713 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3714
3715 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3716 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3717
3718 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3719 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3720
3721 // And we read the image in memory
3722 memsetb(get_SS(),atacmd,0,12);
3723 atacmd[0]=0x28; // READ command
3724 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3725 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3726 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3727 atacmd[3]=(lba & 0x00ff0000) >> 16;
3728 atacmd[4]=(lba & 0x0000ff00) >> 8;
3729 atacmd[5]=(lba & 0x000000ff);
3730 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3731 return 12;
3732
3733 // Remember the media type
3734 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3735 case 0x01: // 1.2M floppy
3736 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3737 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3738 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3739 break;
3740 case 0x02: // 1.44M floppy
3741 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3742 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3743 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3744 break;
3745 case 0x03: // 2.88M floppy
3746 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3747 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3748 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3749 break;
3750 case 0x04: // Harddrive
3751 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3752 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3753 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3754 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3755 break;
3756 }
3757
3758 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3759 // Increase bios installed hardware number of devices
3760 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3761 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3762 else
3763 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3764 }
3765
3766
3767 // everything is ok, so from now on, the emulation is active
3768 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3769 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3770
3771 // return the boot drive + no error
3772 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3773}
3774
3775// ---------------------------------------------------------------------------
3776// End of El-Torito boot functions
3777// ---------------------------------------------------------------------------
3778#endif // BX_ELTORITO_BOOT
3779
3780 void
3781int14_function(regs, ds, iret_addr)
3782 pusha_regs_t regs; // regs pushed from PUSHA instruction
3783 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3784 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3785{
3786 Bit16u addr,timer,val16;
3787 Bit8u timeout;
3788
3789 ASM_START
3790 sti
3791 ASM_END
3792
3793 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3794 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3795 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3796 switch (regs.u.r8.ah) {
3797 case 0:
3798 outb(addr+3, inb(addr+3) | 0x80);
3799 if (regs.u.r8.al & 0xE0 == 0) {
3800 outb(addr, 0x17);
3801 outb(addr+1, 0x04);
3802 } else {
3803 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3804 outb(addr, val16 & 0xFF);
3805 outb(addr+1, val16 >> 8);
3806 }
3807 outb(addr+3, regs.u.r8.al & 0x1F);
3808 regs.u.r8.ah = inb(addr+5);
3809 regs.u.r8.al = inb(addr+6);
3810 ClearCF(iret_addr.flags);
3811 break;
3812 case 1:
3813 timer = read_word(0x0040, 0x006C);
3814 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3815 val16 = read_word(0x0040, 0x006C);
3816 if (val16 != timer) {
3817 timer = val16;
3818 timeout--;
3819 }
3820 }
3821 if (timeout) outb(addr, regs.u.r8.al);
3822 regs.u.r8.ah = inb(addr+5);
3823 if (!timeout) regs.u.r8.ah |= 0x80;
3824 ClearCF(iret_addr.flags);
3825 break;
3826 case 2:
3827 timer = read_word(0x0040, 0x006C);
3828 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3829 val16 = read_word(0x0040, 0x006C);
3830 if (val16 != timer) {
3831 timer = val16;
3832 timeout--;
3833 }
3834 }
3835 if (timeout) {
3836 regs.u.r8.ah = 0;
3837 regs.u.r8.al = inb(addr);
3838 } else {
3839 regs.u.r8.ah = inb(addr+5);
3840 }
3841 ClearCF(iret_addr.flags);
3842 break;
3843 case 3:
3844 regs.u.r8.ah = inb(addr+5);
3845 regs.u.r8.al = inb(addr+6);
3846 ClearCF(iret_addr.flags);
3847 break;
3848 default:
3849 SetCF(iret_addr.flags); // Unsupported
3850 }
3851 } else {
3852 SetCF(iret_addr.flags); // Unsupported
3853 }
3854}
3855
3856 void
3857int15_function(regs, ES, DS, FLAGS)
3858 pusha_regs_t regs; // REGS pushed via pusha
3859 Bit16u ES, DS, FLAGS;
3860{
3861 Bit16u ebda_seg=read_word(0x0040,0x000E);
3862 bx_bool prev_a20_enable;
3863 Bit16u base15_00;
3864 Bit8u base23_16;
3865 Bit16u ss;
3866 Bit16u BX,CX,DX;
3867
3868 Bit16u bRegister;
3869 Bit8u irqDisable;
3870
3871BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3872
3873 switch (regs.u.r8.ah) {
3874#ifdef VBOX
3875 case 0x00: /* assorted functions */
3876 if (regs.u.r8.al != 0xc0)
3877 goto undecoded;
3878 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3879 * which we don't support, but logging that event is annoying. In fact
3880 * it is likely that they just misread some specs, because there is a
3881 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3882 * wants to achieve. */
3883 SET_CF();
3884 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3885 break;
3886#endif
3887 case 0x24: /* A20 Control */
3888 switch (regs.u.r8.al) {
3889 case 0x00:
3890 set_enable_a20(0);
3891 CLEAR_CF();
3892 regs.u.r8.ah = 0;
3893 break;
3894 case 0x01:
3895 set_enable_a20(1);
3896 CLEAR_CF();
3897 regs.u.r8.ah = 0;
3898 break;
3899 case 0x02:
3900 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3901 CLEAR_CF();
3902 regs.u.r8.ah = 0;
3903 break;
3904 case 0x03:
3905 CLEAR_CF();
3906 regs.u.r8.ah = 0;
3907 regs.u.r16.bx = 3;
3908 break;
3909 default:
3910 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3911 SET_CF();
3912 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3913 }
3914 break;
3915
3916 case 0x41:
3917 SET_CF();
3918 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3919 break;
3920
3921 case 0x4f:
3922 /* keyboard intercept */
3923#if BX_CPU < 2
3924 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3925#else
3926 // nop
3927#endif
3928 SET_CF();
3929 break;
3930
3931 case 0x52: // removable media eject
3932 CLEAR_CF();
3933 regs.u.r8.ah = 0; // "ok ejection may proceed"
3934 break;
3935
3936 case 0x83: {
3937 if( regs.u.r8.al == 0 ) {
3938 // Set Interval requested.
3939 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3940 // Interval not already set.
3941 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3942 write_word( 0x40, 0x98, ES ); // Byte location, segment
3943 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3944 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3945 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3946 CLEAR_CF( );
3947 irqDisable = inb( 0xA1 );
3948 outb( 0xA1, irqDisable & 0xFE );
3949 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3950 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3951 } else {
3952 // Interval already set.
3953 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3954 SET_CF();
3955 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3956 }
3957 } else if( regs.u.r8.al == 1 ) {
3958 // Clear Interval requested
3959 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3960 CLEAR_CF( );
3961 bRegister = inb_cmos( 0xB );
3962 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3963 } else {
3964 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3965 SET_CF();
3966 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3967 regs.u.r8.al--;
3968 }
3969
3970 break;
3971 }
3972
3973 case 0x87:
3974#if BX_CPU < 3
3975# error "Int15 function 87h not supported on < 80386"
3976#endif
3977 // +++ should probably have descriptor checks
3978 // +++ should have exception handlers
3979
3980 // turn off interrupts
3981ASM_START
3982 cli
3983ASM_END
3984
3985 prev_a20_enable = set_enable_a20(1); // enable A20 line
3986
3987 // 128K max of transfer on 386+ ???
3988 // source == destination ???
3989
3990 // ES:SI points to descriptor table
3991 // offset use initially comments
3992 // ==============================================
3993 // 00..07 Unused zeros Null descriptor
3994 // 08..0f GDT zeros filled in by BIOS
3995 // 10..17 source ssssssss source of data
3996 // 18..1f dest dddddddd destination of data
3997 // 20..27 CS zeros filled in by BIOS
3998 // 28..2f SS zeros filled in by BIOS
3999
4000 //es:si
4001 //eeee0
4002 //0ssss
4003 //-----
4004
4005// check for access rights of source & dest here
4006
4007 // Initialize GDT descriptor
4008 base15_00 = (ES << 4) + regs.u.r16.si;
4009 base23_16 = ES >> 12;
4010 if (base15_00 < (ES<<4))
4011 base23_16++;
4012 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4013 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4014 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4015 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4016 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4017
4018 // Initialize CS descriptor
4019 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4020 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4021 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4022 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4023 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4024
4025 // Initialize SS descriptor
4026 ss = get_SS();
4027 base15_00 = ss << 4;
4028 base23_16 = ss >> 12;
4029 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4030 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4031 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4032 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4033 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4034
4035 CX = regs.u.r16.cx;
4036ASM_START
4037 // Compile generates locals offset info relative to SP.
4038 // Get CX (word count) from stack.
4039 mov bx, sp
4040 SEG SS
4041 mov cx, _int15_function.CX [bx]
4042
4043 // since we need to set SS:SP, save them to the BDA
4044 // for future restore
4045 push eax
4046 xor eax, eax
4047 mov ds, ax
4048 mov 0x0469, ss
4049 mov 0x0467, sp
4050
4051 SEG ES
4052 lgdt [si + 0x08]
4053 SEG CS
4054 lidt [pmode_IDT_info]
4055 ;; perhaps do something with IDT here
4056
4057 ;; set PE bit in CR0
4058 mov eax, cr0
4059 or al, #0x01
4060 mov cr0, eax
4061 ;; far jump to flush CPU queue after transition to protected mode
4062 JMP_AP(0x0020, protected_mode)
4063
4064protected_mode:
4065 ;; GDT points to valid descriptor table, now load SS, DS, ES
4066 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4067 mov ss, ax
4068 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4069 mov ds, ax
4070 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4071 mov es, ax
4072 xor si, si
4073 xor di, di
4074 cld
4075 rep
4076 movsw ;; move CX words from DS:SI to ES:DI
4077
4078 ;; make sure DS and ES limits are 64KB
4079 mov ax, #0x28
4080 mov ds, ax
4081 mov es, ax
4082
4083 ;; reset PG bit in CR0 ???
4084 mov eax, cr0
4085 and al, #0xFE
4086 mov cr0, eax
4087
4088 ;; far jump to flush CPU queue after transition to real mode
4089 JMP_AP(0xf000, real_mode)
4090
4091real_mode:
4092 ;; restore IDT to normal real-mode defaults
4093 SEG CS
4094 lidt [rmode_IDT_info]
4095
4096 // restore SS:SP from the BDA
4097 xor ax, ax
4098 mov ds, ax
4099 mov ss, 0x0469
4100 mov sp, 0x0467
4101 pop eax
4102ASM_END
4103
4104 set_enable_a20(prev_a20_enable);
4105
4106 // turn back on interrupts
4107ASM_START
4108 sti
4109ASM_END
4110
4111 regs.u.r8.ah = 0;
4112 CLEAR_CF();
4113 break;
4114
4115
4116 case 0x88:
4117 // Get the amount of extended memory (above 1M)
4118#if BX_CPU < 2
4119 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4120 SET_CF();
4121#else
4122 regs.u.r8.al = inb_cmos(0x30);
4123 regs.u.r8.ah = inb_cmos(0x31);
4124
4125 // According to Ralf Brown's interrupt the limit should be 15M,
4126 // but real machines mostly return max. 63M.
4127 if(regs.u.r16.ax > 0xffc0)
4128 regs.u.r16.ax = 0xffc0;
4129
4130 CLEAR_CF();
4131#endif
4132 break;
4133
4134#ifdef VBOX
4135 case 0x89:
4136 // Switch to Protected Mode.
4137 // ES:DI points to user-supplied GDT
4138 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4139 // This subfunction does not return!
4140
4141// turn off interrupts
4142ASM_START
4143 cli
4144ASM_END
4145
4146 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4147
4148 // Initialize CS descriptor for BIOS
4149 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4150 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4151 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4152 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4153 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4154
4155 BX = regs.u.r16.bx;
4156ASM_START
4157 // Compiler generates locals offset info relative to SP.
4158 // Get BX (PIC offsets) from stack.
4159 mov bx, sp
4160 SEG SS
4161 mov bx, _int15_function.BX [bx]
4162
4163 // Program PICs
4164 mov al, #0x11 ; send initialisation commands
4165 out 0x20, al
4166 out 0xa0, al
4167 mov al, bh
4168 out 0x21, al
4169 mov al, bl
4170 out 0xa1, al
4171 mov al, #0x04
4172 out 0x21, al
4173 mov al, #0x02
4174 out 0xa1, al
4175 mov al, #0x01
4176 out 0x21, al
4177 out 0xa1, al
4178 mov al, #0xff ; mask all IRQs, user must re-enable
4179 out 0x21, al
4180 out 0xa1, al
4181
4182 // Load GDT and IDT from supplied data
4183 SEG ES
4184 lgdt [si + 0x08]
4185 SEG ES
4186 lidt [si + 0x10]
4187
4188 // set PE bit in CR0
4189 mov eax, cr0
4190 or al, #0x01
4191 mov cr0, eax
4192 // far jump to flush CPU queue after transition to protected mode
4193 JMP_AP(0x0038, protmode_switch)
4194
4195protmode_switch:
4196 ;; GDT points to valid descriptor table, now load SS, DS, ES
4197 mov ax, #0x28
4198 mov ss, ax
4199 mov ax, #0x18
4200 mov ds, ax
4201 mov ax, #0x20
4202 mov es, ax
4203
4204 // unwind the stack - this will break if calling sequence changes!
4205 mov sp,bp
4206 add sp,#4 ; skip return address
4207 popa ; restore regs
4208 pop ax ; skip saved es
4209 pop ax ; skip saved ds
4210 pop ax ; skip saved flags
4211
4212 // return to caller - note that we do not use IRET because
4213 // we cannot enable interrupts
4214 pop cx ; get return offset
4215 pop ax ; skip return segment
4216 pop ax ; skip flags
4217 mov ax, #0x30 ; ah must be 0 on successful exit
4218 push ax
4219 push cx ; re-create modified ret address on stack
4220 retf
4221
4222ASM_END
4223
4224 break;
4225#endif
4226
4227 case 0x90:
4228 /* Device busy interrupt. Called by Int 16h when no key available */
4229 break;
4230
4231 case 0x91:
4232 /* Interrupt complete. Called by Int 16h when key becomes available */
4233 break;
4234
4235 case 0xbf:
4236 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4237 SET_CF();
4238 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4239 break;
4240
4241 case 0xC0:
4242#if 0
4243 SET_CF();
4244 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4245 break;
4246#endif
4247 CLEAR_CF();
4248 regs.u.r8.ah = 0;
4249 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4250 ES = 0xF000;
4251 break;
4252
4253 case 0xc1:
4254 ES = ebda_seg;
4255 CLEAR_CF();
4256 break;
4257
4258 case 0xd8:
4259 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4260 SET_CF();
4261 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4262 break;
4263
4264#ifdef VBOX
4265 /* Make the BIOS warning for pretty much every Linux kernel start
4266 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4267 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4268 SET_CF();
4269 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4270 break;
4271undecoded:
4272#endif /* VBOX */
4273 default:
4274 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4275 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4276 SET_CF();
4277 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4278 break;
4279 }
4280}
4281
4282#if BX_USE_PS2_MOUSE
4283 void
4284int15_function_mouse(regs, ES, DS, FLAGS)
4285 pusha_regs_t regs; // REGS pushed via pusha
4286 Bit16u ES, DS, FLAGS;
4287{
4288 Bit16u ebda_seg=read_word(0x0040,0x000E);
4289 Bit8u mouse_flags_1, mouse_flags_2;
4290 Bit16u mouse_driver_seg;
4291 Bit16u mouse_driver_offset;
4292 Bit8u mouse_cmd;
4293 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4294
4295BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4296
4297 switch (regs.u.r8.ah) {
4298 case 0xC2:
4299 // Return Codes status in AH
4300 // =========================
4301 // 00: success
4302 // 01: invalid subfunction (AL > 7)
4303 // 02: invalid input value (out of allowable range)
4304 // 03: interface error
4305 // 04: resend command received from mouse controller,
4306 // device driver should attempt command again
4307 // 05: cannot enable mouse, since no far call has been installed
4308 // 80/86: mouse service not implemented
4309
4310 if (regs.u.r8.al > 7) {
4311BX_DEBUG_INT15("unsupported subfn\n");
4312 // invalid function
4313 SET_CF();
4314 regs.u.r8.ah = 1;
4315 break;
4316 }
4317
4318 // Valid subfn; disable AUX input and IRQ12, assume no error
4319 set_kbd_command_byte(0x65);
4320 CLEAR_CF();
4321 regs.u.r8.ah = 0;
4322
4323 switch (regs.u.r8.al) {
4324 case 0: // Disable/Enable Mouse
4325BX_DEBUG_INT15("case 0: ");
4326 if (regs.u.r8.bh > 1) {
4327 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4328 // invalid subfunction
4329 SET_CF();
4330 regs.u.r8.ah = 1;
4331 break;
4332 }
4333 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4334 if ( (mouse_flags_2 & 0x80) == 0 ) {
4335 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4336 SET_CF();
4337 regs.u.r8.ah = 5; // no far call installed
4338 break;
4339 }
4340 if (regs.u.r8.bh == 0) {
4341BX_DEBUG_INT15("Disable Mouse\n");
4342 mouse_cmd = 0xF5; // disable mouse command
4343 } else {
4344BX_DEBUG_INT15("Enable Mouse\n");
4345 mouse_cmd = 0xF4; // enable mouse command
4346 }
4347
4348 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4349 if (ret == 0) {
4350 ret = get_mouse_data(&mouse_data1);
4351 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4352 // success
4353 break;
4354 }
4355 }
4356
4357 // interface error
4358 SET_CF();
4359 regs.u.r8.ah = 3;
4360 break;
4361
4362 case 5: // Initialize Mouse
4363 // Valid package sizes are 1 to 8
4364 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4365 SET_CF();
4366 regs.u.r8.ah = 2; // invalid input
4367 break;
4368 }
4369 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4370 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4371 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4372 // fall through!
4373
4374 case 1: // Reset Mouse
4375BX_DEBUG_INT15("case 1 or 5:\n");
4376 // clear current package byte index
4377 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4378 mouse_flags_1 = mouse_flags_1 & 0xf8;
4379 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4380 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4381 if (ret == 0) {
4382 ret = get_mouse_data(&mouse_data3);
4383 // if no mouse attached, it will return RESEND
4384 if (mouse_data3 == 0xfe) {
4385 SET_CF();
4386 regs.u.r8.ah = 4; // resend
4387 break;
4388 }
4389 if (mouse_data3 != 0xfa)
4390 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4391 if ( ret == 0 ) {
4392 ret = get_mouse_data(&mouse_data1);
4393 if ( ret == 0 ) {
4394 ret = get_mouse_data(&mouse_data2);
4395 if ( ret == 0 ) {
4396 // success
4397 regs.u.r8.bl = mouse_data1;
4398 regs.u.r8.bh = mouse_data2;
4399 break;
4400 }
4401 }
4402 }
4403 }
4404
4405 // interface error
4406 SET_CF();
4407 regs.u.r8.ah = 3;
4408 break;
4409
4410 case 2: // Set Sample Rate
4411BX_DEBUG_INT15("case 2:\n");
4412 switch (regs.u.r8.bh) {
4413 case 0: mouse_data1 = 10; break; // 10 reports/sec
4414 case 1: mouse_data1 = 20; break; // 20 reports/sec
4415 case 2: mouse_data1 = 40; break; // 40 reports/sec
4416 case 3: mouse_data1 = 60; break; // 60 reports/sec
4417 case 4: mouse_data1 = 80; break; // 80 reports/sec
4418 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4419 case 6: mouse_data1 = 200; break; // 200 reports/sec
4420 default: mouse_data1 = 0;
4421 }
4422 if (mouse_data1 > 0) {
4423 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4424 if (ret == 0) {
4425 ret = get_mouse_data(&mouse_data2);
4426 ret = send_to_mouse_ctrl(mouse_data1);
4427 ret = get_mouse_data(&mouse_data2);
4428 // success
4429 } else {
4430 // interface error
4431 SET_CF();
4432 regs.u.r8.ah = 3;
4433 }
4434 } else {
4435 // invalid input
4436 SET_CF();
4437 regs.u.r8.ah = 2;
4438 }
4439 break;
4440
4441 case 3: // Set Resolution
4442BX_DEBUG_INT15("case 3:\n");
4443 // BX:
4444 // 0 = 25 dpi, 1 count per millimeter
4445 // 1 = 50 dpi, 2 counts per millimeter
4446 // 2 = 100 dpi, 4 counts per millimeter
4447 // 3 = 200 dpi, 8 counts per millimeter
4448 if (regs.u.r8.bh < 4) {
4449 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4450 if (ret == 0) {
4451 ret = get_mouse_data(&mouse_data1);
4452 if (mouse_data1 != 0xfa)
4453 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4454 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4455 ret = get_mouse_data(&mouse_data1);
4456 if (mouse_data1 != 0xfa)
4457 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4458 // success
4459 } else {
4460 // interface error
4461 SET_CF();
4462 regs.u.r8.ah = 3;
4463 }
4464 } else {
4465 // invalid input
4466 SET_CF();
4467 regs.u.r8.ah = 2;
4468 }
4469 break;
4470
4471 case 4: // Get Device ID
4472BX_DEBUG_INT15("case 4:\n");
4473 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4474 if (ret == 0) {
4475 ret = get_mouse_data(&mouse_data1);
4476 ret = get_mouse_data(&mouse_data2);
4477 regs.u.r8.bh = mouse_data2;
4478 // success
4479 } else {
4480 // interface error
4481 SET_CF();
4482 regs.u.r8.ah = 3;
4483 }
4484 break;
4485
4486 case 6: // Return Status & Set Scaling Factor...
4487BX_DEBUG_INT15("case 6:\n");
4488 switch (regs.u.r8.bh) {
4489 case 0: // Return Status
4490 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4491 if (ret == 0) {
4492 ret = get_mouse_data(&mouse_data1);
4493 if (mouse_data1 != 0xfa)
4494 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4495 if (ret == 0) {
4496 ret = get_mouse_data(&mouse_data1);
4497 if ( ret == 0 ) {
4498 ret = get_mouse_data(&mouse_data2);
4499 if ( ret == 0 ) {
4500 ret = get_mouse_data(&mouse_data3);
4501 if ( ret == 0 ) {
4502 regs.u.r8.bl = mouse_data1;
4503 regs.u.r8.cl = mouse_data2;
4504 regs.u.r8.dl = mouse_data3;
4505 // success
4506 break;
4507 }
4508 }
4509 }
4510 }
4511 }
4512
4513 // interface error
4514 SET_CF();
4515 regs.u.r8.ah = 3;
4516 break;
4517
4518 case 1: // Set Scaling Factor to 1:1
4519 case 2: // Set Scaling Factor to 2:1
4520 if (regs.u.r8.bh == 1) {
4521 ret = send_to_mouse_ctrl(0xE6);
4522 } else {
4523 ret = send_to_mouse_ctrl(0xE7);
4524 }
4525 if (ret == 0) {
4526 get_mouse_data(&mouse_data1);
4527 ret = (mouse_data1 != 0xFA);
4528 }
4529 if (ret != 0) {
4530 // interface error
4531 SET_CF();
4532 regs.u.r8.ah = 3;
4533 }
4534 break;
4535
4536 default:
4537 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4538 // invalid subfunction
4539 SET_CF();
4540 regs.u.r8.ah = 1;
4541 }
4542 break;
4543
4544 case 7: // Set Mouse Handler Address
4545BX_DEBUG_INT15("case 7:\n");
4546 mouse_driver_seg = ES;
4547 mouse_driver_offset = regs.u.r16.bx;
4548 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4549 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4550 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4551 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4552 /* remove handler */
4553 if ( (mouse_flags_2 & 0x80) != 0 ) {
4554 mouse_flags_2 &= ~0x80;
4555 }
4556 }
4557 else {
4558 /* install handler */
4559 mouse_flags_2 |= 0x80;
4560 }
4561 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4562 break;
4563
4564 default:
4565 BX_PANIC("INT 15h C2 default case entered\n");
4566 // invalid subfunction
4567 SET_CF();
4568 regs.u.r8.ah = 1;
4569 }
4570BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4571 // Re-enable AUX input and IRQ12
4572 set_kbd_command_byte(0x47);
4573 break;
4574
4575 default:
4576 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4577 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4578 SET_CF();
4579 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4580 break;
4581 }
4582}
4583#endif
4584
4585
4586void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4587 Bit16u ES;
4588 Bit16u DI;
4589 Bit32u start;
4590 Bit32u end;
4591 Bit8u extra_start;
4592 Bit8u extra_end;
4593 Bit16u type;
4594{
4595 write_word(ES, DI, start);
4596 write_word(ES, DI+2, start >> 16);
4597 write_word(ES, DI+4, 0x00); /** @todo r=bird: why write it twice? */
4598 write_word(ES, DI+4, extra_start);
4599 write_word(ES, DI+6, 0x00);
4600
4601 end -= start;
4602 extra_end -= extra_start;
4603 write_word(ES, DI+8, end);
4604 write_word(ES, DI+10, end >> 16);
4605#ifdef VBOX
4606 if (end == 0)
4607 write_word(ES, DI+12, 0x0001);
4608 else
4609 /** @todo XXX: nike - is it really correct? see QEMU BIOS patch */
4610 write_word(ES, DI+12, extra_end);
4611#else /* !VBOX */
4612 write_word(ES, DI+12, 0x0000);
4613#endif /* !VBOX */
4614 write_word(ES, DI+14, 0x0000);
4615
4616 write_word(ES, DI+16, type);
4617 write_word(ES, DI+18, 0x0);
4618}
4619
4620 void
4621int15_function32(regs, ES, DS, FLAGS)
4622 pushad_regs_t regs; // REGS pushed via pushad
4623 Bit16u ES, DS, FLAGS;
4624{
4625 Bit32u extended_memory_size=0; // 64bits long
4626#ifdef VBOX_WITH_MORE_THAN_4GB
4627 Bit32u extra_lowbits_memory_size=0;
4628#endif
4629 Bit16u CX,DX;
4630#ifdef VBOX_WITH_MORE_THAN_4GB
4631 Bit8u extra_highbits_memory_size=0;
4632#endif
4633
4634BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4635
4636 switch (regs.u.r8.ah) {
4637 case 0x86:
4638 // Wait for CX:DX microseconds. currently using the
4639 // refresh request port 0x61 bit4, toggling every 15usec
4640
4641 CX = regs.u.r16.cx;
4642 DX = regs.u.r16.dx;
4643
4644ASM_START
4645 sti
4646
4647 ;; Get the count in eax
4648 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4649 mov bx, sp
4650 SEG SS
4651 mov ax, _int15_function32.CX [bx]
4652 shl eax, #16
4653 SEG SS
4654 mov ax, _int15_function32.DX [bx]
4655
4656 ;; convert to numbers of 15usec ticks
4657 mov ebx, #15
4658 xor edx, edx
4659 div eax, ebx
4660 mov ecx, eax
4661
4662 ;; wait for ecx number of refresh requests
4663 in al, #0x61
4664 and al,#0x10
4665 mov ah, al
4666
4667 or ecx, ecx
4668 je int1586_tick_end
4669int1586_tick:
4670 in al, #0x61
4671 and al,#0x10
4672 cmp al, ah
4673 je int1586_tick
4674 mov ah, al
4675 dec ecx
4676 jnz int1586_tick
4677int1586_tick_end:
4678ASM_END
4679
4680 break;
4681
4682 case 0xe8:
4683 switch(regs.u.r8.al)
4684 {
4685 case 0x20: // coded by osmaker aka K.J.
4686 if(regs.u.r32.edx == 0x534D4150)
4687 {
4688 extended_memory_size = inb_cmos(0x35);
4689 extended_memory_size <<= 8;
4690 extended_memory_size |= inb_cmos(0x34);
4691 extended_memory_size *= 64;
4692 // greater than EFF00000???
4693 if(extended_memory_size > 0x3bc000) {
4694 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4695 }
4696 extended_memory_size *= 1024;
4697 extended_memory_size += (16L * 1024 * 1024);
4698
4699 if(extended_memory_size <= (16L * 1024 * 1024)) {
4700 extended_memory_size = inb_cmos(0x31);
4701 extended_memory_size <<= 8;
4702 extended_memory_size |= inb_cmos(0x30);
4703 extended_memory_size *= 1024;
4704 }
4705
4706#ifdef VBOX_WITH_MORE_THAN_4GB /* bird: later (btw. this ain't making sense complixity wise, unless its a AMI/AWARD/PHOENIX interface) */
4707 extra_lowbits_memory_size = inb_cmos(0x61);
4708 extra_lowbits_memory_size <<= 8;
4709 extra_lowbits_memory_size |= inb_cmos(0x62);
4710 extra_lowbits_memory_size *= 64;
4711 extra_lowbits_memory_size *= 1024;
4712 extra_highbits_memory_size = inb_cmos(0x63);
4713#endif
4714
4715 switch(regs.u.r16.bx)
4716 {
4717 case 0:
4718 set_e820_range(ES, regs.u.r16.di,
4719 0x0000000L, 0x0009fc00L, 0, 0, 1);
4720 regs.u.r32.ebx = 1;
4721 regs.u.r32.eax = 0x534D4150;
4722 regs.u.r32.ecx = 0x14;
4723 CLEAR_CF();
4724 return;
4725 break;
4726 case 1:
4727 set_e820_range(ES, regs.u.r16.di,
4728 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4729 regs.u.r32.ebx = 2;
4730 regs.u.r32.eax = 0x534D4150;
4731 regs.u.r32.ecx = 0x14;
4732 CLEAR_CF();
4733 return;
4734 break;
4735 case 2:
4736#ifdef VBOX
4737 /* Mark the BIOS as reserved. VBox doesn't currently
4738 * use the 0xe0000-0xeffff area. It does use the
4739 * 0xd0000-0xdffff area for the BIOS logo, but it's
4740 * not worth marking it as reserved. Note that various
4741 * Windows versions don't accept (read: in debug builds
4742 * they trigger the "Too many similar traps" assertion)
4743 * a single reserved range from 0xd0000 to 0xffffff.
4744 * A 128K area starting from 0xd0000 works. */
4745 set_e820_range(ES, regs.u.r16.di,
4746 0x000f0000L, 0x00100000L, 0, 0, 2);
4747#else /* !VBOX */
4748 set_e820_range(ES, regs.u.r16.di,
4749 0x000e8000L, 0x00100000L, 0, 0, 2);
4750#endif /* !VBOX */
4751 regs.u.r32.ebx = 3;
4752 regs.u.r32.eax = 0x534D4150;
4753 regs.u.r32.ecx = 0x14;
4754 CLEAR_CF();
4755 return;
4756 break;
4757 case 3:
4758 set_e820_range(ES, regs.u.r16.di,
4759 0x00100000L,
4760 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4761 regs.u.r32.ebx = 4;
4762 regs.u.r32.eax = 0x534D4150;
4763 regs.u.r32.ecx = 0x14;
4764 CLEAR_CF();
4765 return;
4766 break;
4767 case 4:
4768 set_e820_range(ES, regs.u.r16.di,
4769 extended_memory_size - ACPI_DATA_SIZE,
4770 extended_memory_size, 0, 0, 3); // ACPI RAM
4771 regs.u.r32.ebx = 5;
4772 regs.u.r32.eax = 0x534D4150;
4773 regs.u.r32.ecx = 0x14;
4774 CLEAR_CF();
4775 return;
4776 break;
4777 case 5:
4778 /* 256KB BIOS area at the end of 4 GB */
4779 set_e820_range(ES, regs.u.r16.di,
4780 0xfffc0000L, 0x00000000L, 0, 0, 2);
4781#ifdef VBOX_WITH_MORE_THAN_4GB
4782 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4783 regs.u.r32.ebx = 6;
4784 else
4785#endif
4786 regs.u.r32.ebx = 0;
4787 regs.u.r32.eax = 0x534D4150;
4788 regs.u.r32.ecx = 0x14;
4789 CLEAR_CF();
4790 return;
4791#ifdef VBOX_WITH_MORE_THAN_4GB
4792 case 6:
4793 /* Mapping of memory above 4 GB */
4794 set_e820_range(ES, regs.u.r16.di,
4795 0x00000000L, extra_lowbits_memory_size,
4796 1, extra_highbits_memory_size + 1, 1);
4797 regs.u.r32.ebx = 0;
4798 regs.u.r32.eax = 0x534D4150;
4799 regs.u.r32.ecx = 0x14;
4800 CLEAR_CF();
4801 return;
4802#endif
4803 default: /* AX=E820, DX=534D4150, BX unrecognized */
4804 goto int15_unimplemented;
4805 break;
4806 }
4807 } else {
4808 // if DX != 0x534D4150)
4809 goto int15_unimplemented;
4810 }
4811 break;
4812
4813 case 0x01:
4814 // do we have any reason to fail here ?
4815 CLEAR_CF();
4816
4817 // my real system sets ax and bx to 0
4818 // this is confirmed by Ralph Brown list
4819 // but syslinux v1.48 is known to behave
4820 // strangely if ax is set to 0
4821 // regs.u.r16.ax = 0;
4822 // regs.u.r16.bx = 0;
4823
4824 // Get the amount of extended memory (above 1M)
4825 regs.u.r8.cl = inb_cmos(0x30);
4826 regs.u.r8.ch = inb_cmos(0x31);
4827
4828 // limit to 15M
4829 if(regs.u.r16.cx > 0x3c00)
4830 {
4831 regs.u.r16.cx = 0x3c00;
4832 }
4833
4834 // Get the amount of extended memory above 16M in 64k blocs
4835 regs.u.r8.dl = inb_cmos(0x34);
4836 regs.u.r8.dh = inb_cmos(0x35);
4837
4838 // Set configured memory equal to extended memory
4839 regs.u.r16.ax = regs.u.r16.cx;
4840 regs.u.r16.bx = regs.u.r16.dx;
4841 break;
4842 default: /* AH=0xE8?? but not implemented */
4843 goto int15_unimplemented;
4844 }
4845 break;
4846 int15_unimplemented:
4847 // fall into the default
4848 default:
4849 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4850 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4851 SET_CF();
4852 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4853 break;
4854 }
4855}
4856
4857 void
4858int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4859 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4860{
4861 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4862 Bit16u kbd_code, max;
4863
4864 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4865
4866 shift_flags = read_byte(0x0040, 0x17);
4867 led_flags = read_byte(0x0040, 0x97);
4868 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4869ASM_START
4870 cli
4871ASM_END
4872 outb(0x60, 0xed);
4873 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4874 if ((inb(0x60) == 0xfa)) {
4875 led_flags &= 0xf8;
4876 led_flags |= ((shift_flags >> 4) & 0x07);
4877 outb(0x60, led_flags & 0x07);
4878 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4879 inb(0x60);
4880 write_byte(0x0040, 0x97, led_flags);
4881 }
4882ASM_START
4883 sti
4884ASM_END
4885 }
4886
4887 switch (GET_AH()) {
4888 case 0x00: /* read keyboard input */
4889
4890 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4891 BX_PANIC("KBD: int16h: out of keyboard input\n");
4892 }
4893 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4894 else if (ascii_code == 0xE0) ascii_code = 0;
4895 AX = (scan_code << 8) | ascii_code;
4896 break;
4897
4898 case 0x01: /* check keyboard status */
4899 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4900 SET_ZF();
4901 return;
4902 }
4903 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4904 else if (ascii_code == 0xE0) ascii_code = 0;
4905 AX = (scan_code << 8) | ascii_code;
4906 CLEAR_ZF();
4907 break;
4908
4909 case 0x02: /* get shift flag status */
4910 shift_flags = read_byte(0x0040, 0x17);
4911 SET_AL(shift_flags);
4912 break;
4913
4914 case 0x05: /* store key-stroke into buffer */
4915 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4916 SET_AL(1);
4917 }
4918 else {
4919 SET_AL(0);
4920 }
4921 break;
4922
4923 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4924 // bit Bochs Description
4925 // 7 0 reserved
4926 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4927 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4928 // 4 1 INT 16/AH=0Ah supported
4929 // 3 0 INT 16/AX=0306h supported
4930 // 2 0 INT 16/AX=0305h supported
4931 // 1 0 INT 16/AX=0304h supported
4932 // 0 0 INT 16/AX=0300h supported
4933 //
4934 SET_AL(0x30);
4935 break;
4936
4937 case 0x0A: /* GET KEYBOARD ID */
4938 count = 2;
4939 kbd_code = 0x0;
4940 outb(0x60, 0xf2);
4941 /* Wait for data */
4942 max=0xffff;
4943 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4944 if (max>0x0) {
4945 if ((inb(0x60) == 0xfa)) {
4946 do {
4947 max=0xffff;
4948 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4949 if (max>0x0) {
4950 kbd_code >>= 8;
4951 kbd_code |= (inb(0x60) << 8);
4952 }
4953 } while (--count>0);
4954 }
4955 }
4956 BX=kbd_code;
4957 break;
4958
4959 case 0x10: /* read MF-II keyboard input */
4960
4961 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4962 BX_PANIC("KBD: int16h: out of keyboard input\n");
4963 }
4964 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4965 AX = (scan_code << 8) | ascii_code;
4966 break;
4967
4968 case 0x11: /* check MF-II keyboard status */
4969 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4970 SET_ZF();
4971 return;
4972 }
4973 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4974 AX = (scan_code << 8) | ascii_code;
4975 CLEAR_ZF();
4976 break;
4977
4978 case 0x12: /* get extended keyboard status */
4979 shift_flags = read_byte(0x0040, 0x17);
4980 SET_AL(shift_flags);
4981 shift_flags = read_byte(0x0040, 0x18) & 0x73;
4982 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
4983 SET_AH(shift_flags);
4984 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4985 break;
4986
4987 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4988 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4989 break;
4990
4991 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4992 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4993 break;
4994
4995 case 0x6F:
4996 if (GET_AL() == 0x08)
4997 SET_AH(0x02); // unsupported, aka normal keyboard
4998
4999 default:
5000 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5001 }
5002}
5003
5004 unsigned int
5005dequeue_key(scan_code, ascii_code, incr)
5006 Bit8u *scan_code;
5007 Bit8u *ascii_code;
5008 unsigned int incr;
5009{
5010 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5011 Bit16u ss;
5012 Bit8u acode, scode;
5013
5014#if BX_CPU < 2
5015 buffer_start = 0x001E;
5016 buffer_end = 0x003E;
5017#else
5018 buffer_start = read_word(0x0040, 0x0080);
5019 buffer_end = read_word(0x0040, 0x0082);
5020#endif
5021
5022 buffer_head = read_word(0x0040, 0x001a);
5023 buffer_tail = read_word(0x0040, 0x001c);
5024
5025 if (buffer_head != buffer_tail) {
5026 ss = get_SS();
5027 acode = read_byte(0x0040, buffer_head);
5028 scode = read_byte(0x0040, buffer_head+1);
5029 write_byte(ss, ascii_code, acode);
5030 write_byte(ss, scan_code, scode);
5031
5032 if (incr) {
5033 buffer_head += 2;
5034 if (buffer_head >= buffer_end)
5035 buffer_head = buffer_start;
5036 write_word(0x0040, 0x001a, buffer_head);
5037 }
5038 return(1);
5039 }
5040 else {
5041 return(0);
5042 }
5043}
5044
5045static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5046
5047 Bit8u
5048send_to_mouse_ctrl(sendbyte)
5049 Bit8u sendbyte;
5050{
5051 Bit8u response;
5052
5053 // wait for chance to write to ctrl
5054 if ( inb(0x64) & 0x02 )
5055 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5056 outb(0x64, 0xD4);
5057 outb(0x60, sendbyte);
5058 return(0);
5059}
5060
5061
5062 Bit8u
5063get_mouse_data(data)
5064 Bit8u *data;
5065{
5066 Bit8u response;
5067 Bit16u ss;
5068
5069 while ( (inb(0x64) & 0x21) != 0x21 ) {
5070 }
5071
5072 response = inb(0x60);
5073
5074 ss = get_SS();
5075 write_byte(ss, data, response);
5076 return(0);
5077}
5078
5079 void
5080set_kbd_command_byte(command_byte)
5081 Bit8u command_byte;
5082{
5083 if ( inb(0x64) & 0x02 )
5084 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5085
5086 outb(0x64, 0x60); // write command byte
5087 outb(0x60, command_byte);
5088}
5089
5090 void
5091int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5092 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5093{
5094 Bit8u scancode, asciicode, shift_flags;
5095 Bit8u mf2_flags, mf2_state;
5096
5097 //
5098 // DS has been set to F000 before call
5099 //
5100
5101
5102 scancode = GET_AL();
5103
5104 if (scancode == 0) {
5105 BX_INFO("KBD: int09 handler: AL=0\n");
5106 return;
5107 }
5108
5109
5110 shift_flags = read_byte(0x0040, 0x17);
5111 mf2_flags = read_byte(0x0040, 0x18);
5112 mf2_state = read_byte(0x0040, 0x96);
5113 asciicode = 0;
5114
5115 switch (scancode) {
5116 case 0x3a: /* Caps Lock press */
5117 shift_flags ^= 0x40;
5118 write_byte(0x0040, 0x17, shift_flags);
5119 mf2_flags |= 0x40;
5120 write_byte(0x0040, 0x18, mf2_flags);
5121 break;
5122 case 0xba: /* Caps Lock release */
5123 mf2_flags &= ~0x40;
5124 write_byte(0x0040, 0x18, mf2_flags);
5125 break;
5126
5127 case 0x2a: /* L Shift press */
5128 shift_flags |= 0x02;
5129 write_byte(0x0040, 0x17, shift_flags);
5130 break;
5131 case 0xaa: /* L Shift release */
5132 shift_flags &= ~0x02;
5133 write_byte(0x0040, 0x17, shift_flags);
5134 break;
5135
5136 case 0x36: /* R Shift press */
5137 shift_flags |= 0x01;
5138 write_byte(0x0040, 0x17, shift_flags);
5139 break;
5140 case 0xb6: /* R Shift release */
5141 shift_flags &= ~0x01;
5142 write_byte(0x0040, 0x17, shift_flags);
5143 break;
5144
5145 case 0x1d: /* Ctrl press */
5146 if ((mf2_state & 0x01) == 0) {
5147 shift_flags |= 0x04;
5148 write_byte(0x0040, 0x17, shift_flags);
5149 if (mf2_state & 0x02) {
5150 mf2_state |= 0x04;
5151 write_byte(0x0040, 0x96, mf2_state);
5152 } else {
5153 mf2_flags |= 0x01;
5154 write_byte(0x0040, 0x18, mf2_flags);
5155 }
5156 }
5157 break;
5158 case 0x9d: /* Ctrl release */
5159 if ((mf2_state & 0x01) == 0) {
5160 shift_flags &= ~0x04;
5161 write_byte(0x0040, 0x17, shift_flags);
5162 if (mf2_state & 0x02) {
5163 mf2_state &= ~0x04;
5164 write_byte(0x0040, 0x96, mf2_state);
5165 } else {
5166 mf2_flags &= ~0x01;
5167 write_byte(0x0040, 0x18, mf2_flags);
5168 }
5169 }
5170 break;
5171
5172 case 0x38: /* Alt press */
5173 shift_flags |= 0x08;
5174 write_byte(0x0040, 0x17, shift_flags);
5175 if (mf2_state & 0x02) {
5176 mf2_state |= 0x08;
5177 write_byte(0x0040, 0x96, mf2_state);
5178 } else {
5179 mf2_flags |= 0x02;
5180 write_byte(0x0040, 0x18, mf2_flags);
5181 }
5182 break;
5183 case 0xb8: /* Alt release */
5184 shift_flags &= ~0x08;
5185 write_byte(0x0040, 0x17, shift_flags);
5186 if (mf2_state & 0x02) {
5187 mf2_state &= ~0x08;
5188 write_byte(0x0040, 0x96, mf2_state);
5189 } else {
5190 mf2_flags &= ~0x02;
5191 write_byte(0x0040, 0x18, mf2_flags);
5192 }
5193 break;
5194
5195 case 0x45: /* Num Lock press */
5196 if ((mf2_state & 0x03) == 0) {
5197 mf2_flags |= 0x20;
5198 write_byte(0x0040, 0x18, mf2_flags);
5199 shift_flags ^= 0x20;
5200 write_byte(0x0040, 0x17, shift_flags);
5201 }
5202 break;
5203 case 0xc5: /* Num Lock release */
5204 if ((mf2_state & 0x03) == 0) {
5205 mf2_flags &= ~0x20;
5206 write_byte(0x0040, 0x18, mf2_flags);
5207 }
5208 break;
5209
5210 case 0x46: /* Scroll Lock press */
5211 mf2_flags |= 0x10;
5212 write_byte(0x0040, 0x18, mf2_flags);
5213 shift_flags ^= 0x10;
5214 write_byte(0x0040, 0x17, shift_flags);
5215 break;
5216
5217 case 0xc6: /* Scroll Lock release */
5218 mf2_flags &= ~0x10;
5219 write_byte(0x0040, 0x18, mf2_flags);
5220 break;
5221
5222 default:
5223 if (scancode & 0x80) {
5224 break; /* toss key releases ... */
5225 }
5226 if (scancode > MAX_SCAN_CODE) {
5227 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5228 return;
5229 }
5230 if (shift_flags & 0x08) { /* ALT */
5231 asciicode = scan_to_scanascii[scancode].alt;
5232 scancode = scan_to_scanascii[scancode].alt >> 8;
5233 } else if (shift_flags & 0x04) { /* CONTROL */
5234 asciicode = scan_to_scanascii[scancode].control;
5235 scancode = scan_to_scanascii[scancode].control >> 8;
5236 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5237 /* extended keys handling */
5238 asciicode = 0xe0;
5239 scancode = scan_to_scanascii[scancode].normal >> 8;
5240 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5241 /* check if lock state should be ignored
5242 * because a SHIFT key are pressed */
5243
5244 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5245 asciicode = scan_to_scanascii[scancode].normal;
5246 scancode = scan_to_scanascii[scancode].normal >> 8;
5247 } else {
5248 asciicode = scan_to_scanascii[scancode].shift;
5249 scancode = scan_to_scanascii[scancode].shift >> 8;
5250 }
5251 } else {
5252 /* check if lock is on */
5253 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5254 asciicode = scan_to_scanascii[scancode].shift;
5255 scancode = scan_to_scanascii[scancode].shift >> 8;
5256 } else {
5257 asciicode = scan_to_scanascii[scancode].normal;
5258 scancode = scan_to_scanascii[scancode].normal >> 8;
5259 }
5260 }
5261 if (scancode==0 && asciicode==0) {
5262 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5263 }
5264 enqueue_key(scancode, asciicode);
5265 break;
5266 }
5267 if ((scancode & 0x7f) != 0x1d) {
5268 mf2_state &= ~0x01;
5269 }
5270 mf2_state &= ~0x02;
5271 write_byte(0x0040, 0x96, mf2_state);
5272}
5273
5274 unsigned int
5275enqueue_key(scan_code, ascii_code)
5276 Bit8u scan_code, ascii_code;
5277{
5278 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5279
5280#if BX_CPU < 2
5281 buffer_start = 0x001E;
5282 buffer_end = 0x003E;
5283#else
5284 buffer_start = read_word(0x0040, 0x0080);
5285 buffer_end = read_word(0x0040, 0x0082);
5286#endif
5287
5288 buffer_head = read_word(0x0040, 0x001A);
5289 buffer_tail = read_word(0x0040, 0x001C);
5290
5291 temp_tail = buffer_tail;
5292 buffer_tail += 2;
5293 if (buffer_tail >= buffer_end)
5294 buffer_tail = buffer_start;
5295
5296 if (buffer_tail == buffer_head) {
5297 return(0);
5298 }
5299
5300 write_byte(0x0040, temp_tail, ascii_code);
5301 write_byte(0x0040, temp_tail+1, scan_code);
5302 write_word(0x0040, 0x001C, buffer_tail);
5303 return(1);
5304}
5305
5306
5307 void
5308int74_function(make_farcall, Z, Y, X, status)
5309 Bit16u make_farcall, Z, Y, X, status;
5310{
5311 Bit16u ebda_seg=read_word(0x0040,0x000E);
5312 Bit8u in_byte, index, package_count;
5313 Bit8u mouse_flags_1, mouse_flags_2;
5314
5315BX_DEBUG_INT74("entering int74_function\n");
5316 make_farcall = 0;
5317
5318 in_byte = inb(0x64);
5319 if ( (in_byte & 0x21) != 0x21 ) {
5320 return;
5321 }
5322 in_byte = inb(0x60);
5323BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5324
5325 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5326 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5327
5328 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5329 return;
5330 }
5331
5332 package_count = mouse_flags_2 & 0x07;
5333 index = mouse_flags_1 & 0x07;
5334 write_byte(ebda_seg, 0x28 + index, in_byte);
5335
5336 if ( index >= package_count ) {
5337BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5338 status = read_byte(ebda_seg, 0x0028 + 0);
5339 X = read_byte(ebda_seg, 0x0028 + 1);
5340 Y = read_byte(ebda_seg, 0x0028 + 2);
5341 Z = 0;
5342 mouse_flags_1 = 0;
5343 // check if far call handler installed
5344 if (mouse_flags_2 & 0x80)
5345 make_farcall = 1;
5346 }
5347 else {
5348 mouse_flags_1++;
5349 }
5350 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5351}
5352
5353#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5354
5355#if BX_USE_ATADRV
5356
5357 void
5358int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5359 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5360{
5361 Bit32u lba;
5362 Bit16u ebda_seg=read_word(0x0040,0x000E);
5363 Bit16u cylinder, head, sector;
5364 Bit16u segment, offset;
5365 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5366 Bit16u size, count;
5367 Bit8u device, status;
5368
5369 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5370
5371 write_byte(0x0040, 0x008e, 0); // clear completion flag
5372
5373 // basic check : device has to be defined
5374 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5375 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5376 goto int13_fail;
5377 }
5378
5379 // Get the ata channel
5380 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5381
5382 // basic check : device has to be valid
5383 if (device >= BX_MAX_ATA_DEVICES) {
5384 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5385 goto int13_fail;
5386 }
5387
5388 switch (GET_AH()) {
5389
5390 case 0x00: /* disk controller reset */
5391 ata_reset (device);
5392 goto int13_success;
5393 break;
5394
5395 case 0x01: /* read disk status */
5396 status = read_byte(0x0040, 0x0074);
5397 SET_AH(status);
5398 SET_DISK_RET_STATUS(0);
5399 /* set CF if error status read */
5400 if (status) goto int13_fail_nostatus;
5401 else goto int13_success_noah;
5402 break;
5403
5404 case 0x02: // read disk sectors
5405 case 0x03: // write disk sectors
5406 case 0x04: // verify disk sectors
5407
5408 count = GET_AL();
5409 cylinder = GET_CH();
5410 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5411 sector = (GET_CL() & 0x3f);
5412 head = GET_DH();
5413
5414 segment = ES;
5415 offset = BX;
5416
5417 if ( (count > 128) || (count == 0) ) {
5418 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5419 goto int13_fail;
5420 }
5421
5422 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5423 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5424 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5425
5426 // sanity check on cyl heads, sec
5427 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5428 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5429 goto int13_fail;
5430 }
5431
5432 // FIXME verify
5433 if ( GET_AH() == 0x04 ) goto int13_success;
5434
5435 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5436 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5437
5438 // if needed, translate lchs to lba, and execute command
5439 if ( (nph != nlh) || (npspt != nlspt)) {
5440 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5441 sector = 0; // this forces the command to be lba
5442 }
5443
5444 if ( GET_AH() == 0x02 )
5445 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5446 else
5447 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5448
5449 // Set nb of sector transferred
5450 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5451
5452 if (status != 0) {
5453 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5454 SET_AH(0x0c);
5455 goto int13_fail_noah;
5456 }
5457
5458 goto int13_success;
5459 break;
5460
5461 case 0x05: /* format disk track */
5462 BX_INFO("format disk track called\n");
5463 goto int13_success;
5464 return;
5465 break;
5466
5467 case 0x08: /* read disk drive parameters */
5468
5469 // Get logical geometry from table
5470 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5471 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5472 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5473 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5474
5475#ifndef VBOX
5476 nlc = nlc - 2; /* 0 based , last sector not used */
5477#else /* VBOX */
5478 /* Maximum cylinder number is just one less than the number of cylinders. */
5479 nlc = nlc - 1; /* 0 based , last sector not used */
5480#endif /* VBOX */
5481 SET_AL(0);
5482 SET_CH(nlc & 0xff);
5483 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5484 SET_DH(nlh - 1);
5485 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5486
5487 // FIXME should set ES & DI
5488
5489 goto int13_success;
5490 break;
5491
5492 case 0x10: /* check drive ready */
5493 // should look at 40:8E also???
5494
5495 // Read the status from controller
5496 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5497 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5498 goto int13_success;
5499 }
5500 else {
5501 SET_AH(0xAA);
5502 goto int13_fail_noah;
5503 }
5504 break;
5505
5506 case 0x15: /* read disk drive size */
5507
5508 // Get physical geometry from table
5509 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5510 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5511 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5512
5513 // Compute sector count seen by int13
5514#ifndef VBOX
5515 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5516#else /* VBOX */
5517 /* Is it so hard to multiply a couple of counts (without introducing
5518 * arbitrary off by one errors)? */
5519 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5520#endif /* VBOX */
5521 CX = lba >> 16;
5522 DX = lba & 0xffff;
5523
5524 SET_AH(3); // hard disk accessible
5525 goto int13_success_noah;
5526 break;
5527
5528 case 0x41: // IBM/MS installation check
5529 BX=0xaa55; // install check
5530 SET_AH(0x30); // EDD 3.0
5531 CX=0x0007; // ext disk access and edd, removable supported
5532 goto int13_success_noah;
5533 break;
5534
5535 case 0x42: // IBM/MS extended read
5536 case 0x43: // IBM/MS extended write
5537 case 0x44: // IBM/MS verify
5538 case 0x47: // IBM/MS extended seek
5539
5540 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5541 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5542 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5543
5544 // Can't use 64 bits lba
5545 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5546 if (lba != 0L) {
5547 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5548 goto int13_fail;
5549 }
5550
5551 // Get 32 bits lba and check
5552 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5553 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5554 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5555 goto int13_fail;
5556 }
5557
5558 // If verify or seek
5559 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5560 goto int13_success;
5561
5562 // Execute the command
5563 if ( GET_AH() == 0x42 )
5564#ifdef VBOX
5565 {
5566 if (count >= 256 || lba + count >= 268435456)
5567 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5568 else
5569 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5570 }
5571#else /* !VBOX */
5572 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5573#endif /* VBOX */
5574 else
5575#ifdef VBOX
5576 {
5577 if (count >= 256 || lba + count >= 268435456)
5578 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5579 else
5580 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5581 }
5582#else /* !VBOX */
5583 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5584#endif /* VBOX */
5585
5586 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5587 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5588
5589 if (status != 0) {
5590 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5591 SET_AH(0x0c);
5592 goto int13_fail_noah;
5593 }
5594
5595 goto int13_success;
5596 break;
5597
5598 case 0x45: // IBM/MS lock/unlock drive
5599 case 0x49: // IBM/MS extended media change
5600 goto int13_success; // Always success for HD
5601 break;
5602
5603 case 0x46: // IBM/MS eject media
5604 SET_AH(0xb2); // Volume Not Removable
5605 goto int13_fail_noah; // Always fail for HD
5606 break;
5607
5608 case 0x48: // IBM/MS get drive parameters
5609 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5610
5611 // Buffer is too small
5612 if(size < 0x1a)
5613 goto int13_fail;
5614
5615 // EDD 1.x
5616 if(size >= 0x1a) {
5617 Bit16u blksize;
5618
5619 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5620 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5621 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5622 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5623 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5624
5625 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5626 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5627 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5628 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5629 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5630 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5631 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5632 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5633 }
5634
5635 // EDD 2.x
5636 if(size >= 0x1e) {
5637 Bit8u channel, dev, irq, mode, checksum, i, translation;
5638 Bit16u iobase1, iobase2, options;
5639
5640 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5641
5642 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5643 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5644
5645 // Fill in dpte
5646 channel = device / 2;
5647 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5648 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5649 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5650 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5651 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5652
5653 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5654 options |= (1<<4); // lba translation
5655 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5656 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5657 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5658
5659 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5660 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5661 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5662 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5663 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5664 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5665 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5666 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5667 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5668 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5669 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5670
5671 checksum=0;
5672 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5673 checksum = ~checksum;
5674 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5675 }
5676
5677 // EDD 3.x
5678 if(size >= 0x42) {
5679 Bit8u channel, iface, checksum, i;
5680 Bit16u iobase1;
5681
5682 channel = device / 2;
5683 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5684 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5685
5686 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5687 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5688 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5689 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5690 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5691
5692 if (iface==ATA_IFACE_ISA) {
5693 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5694 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5695 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5696 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5697 }
5698 else {
5699 // FIXME PCI
5700 }
5701 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5702 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5703 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5704 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5705
5706 if (iface==ATA_IFACE_ISA) {
5707 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5708 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5709 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5710 }
5711 else {
5712 // FIXME PCI
5713 }
5714 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5715 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5716 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5717 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5718
5719 checksum=0;
5720 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5721 checksum = ~checksum;
5722 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5723 }
5724
5725 goto int13_success;
5726 break;
5727
5728 case 0x4e: // // IBM/MS set hardware configuration
5729 // DMA, prefetch, PIO maximum not supported
5730 switch (GET_AL()) {
5731 case 0x01:
5732 case 0x03:
5733 case 0x04:
5734 case 0x06:
5735 goto int13_success;
5736 break;
5737 default :
5738 goto int13_fail;
5739 }
5740 break;
5741
5742 case 0x09: /* initialize drive parameters */
5743 case 0x0c: /* seek to specified cylinder */
5744 case 0x0d: /* alternate disk reset */
5745 case 0x11: /* recalibrate */
5746 case 0x14: /* controller internal diagnostic */
5747 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5748 goto int13_success;
5749 break;
5750
5751 case 0x0a: /* read disk sectors with ECC */
5752 case 0x0b: /* write disk sectors with ECC */
5753 case 0x18: // set media type for format
5754 case 0x50: // IBM/MS send packet command
5755 default:
5756 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5757 goto int13_fail;
5758 break;
5759 }
5760
5761int13_fail:
5762 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5763int13_fail_noah:
5764 SET_DISK_RET_STATUS(GET_AH());
5765int13_fail_nostatus:
5766 SET_CF(); // error occurred
5767 return;
5768
5769int13_success:
5770 SET_AH(0x00); // no error
5771int13_success_noah:
5772 SET_DISK_RET_STATUS(0x00);
5773 CLEAR_CF(); // no error
5774 return;
5775}
5776
5777// ---------------------------------------------------------------------------
5778// Start of int13 for cdrom
5779// ---------------------------------------------------------------------------
5780
5781 void
5782int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5783 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5784{
5785 Bit16u ebda_seg=read_word(0x0040,0x000E);
5786 Bit8u device, status, locks;
5787 Bit8u atacmd[12];
5788 Bit32u lba;
5789 Bit16u count, segment, offset, i, size;
5790
5791 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5792
5793 SET_DISK_RET_STATUS(0x00);
5794
5795 /* basic check : device should be 0xE0+ */
5796 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5797 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5798 goto int13_fail;
5799 }
5800
5801 // Get the ata channel
5802 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5803
5804 /* basic check : device has to be valid */
5805 if (device >= BX_MAX_ATA_DEVICES) {
5806 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5807 goto int13_fail;
5808 }
5809
5810 switch (GET_AH()) {
5811
5812 // all those functions return SUCCESS
5813 case 0x00: /* disk controller reset */
5814 case 0x09: /* initialize drive parameters */
5815 case 0x0c: /* seek to specified cylinder */
5816 case 0x0d: /* alternate disk reset */
5817 case 0x10: /* check drive ready */
5818 case 0x11: /* recalibrate */
5819 case 0x14: /* controller internal diagnostic */
5820 case 0x16: /* detect disk change */
5821 goto int13_success;
5822 break;
5823
5824 // all those functions return disk write-protected
5825 case 0x03: /* write disk sectors */
5826 case 0x05: /* format disk track */
5827 case 0x43: // IBM/MS extended write
5828 SET_AH(0x03);
5829 goto int13_fail_noah;
5830 break;
5831
5832 case 0x01: /* read disk status */
5833 status = read_byte(0x0040, 0x0074);
5834 SET_AH(status);
5835 SET_DISK_RET_STATUS(0);
5836
5837 /* set CF if error status read */
5838 if (status) goto int13_fail_nostatus;
5839 else goto int13_success_noah;
5840 break;
5841
5842 case 0x15: /* read disk drive size */
5843 SET_AH(0x02);
5844 goto int13_fail_noah;
5845 break;
5846
5847 case 0x41: // IBM/MS installation check
5848 BX=0xaa55; // install check
5849 SET_AH(0x30); // EDD 2.1
5850 CX=0x0007; // ext disk access, removable and edd
5851 goto int13_success_noah;
5852 break;
5853
5854 case 0x42: // IBM/MS extended read
5855 case 0x44: // IBM/MS verify sectors
5856 case 0x47: // IBM/MS extended seek
5857
5858 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5859 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5860 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5861
5862 // Can't use 64 bits lba
5863 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5864 if (lba != 0L) {
5865 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5866 goto int13_fail;
5867 }
5868
5869 // Get 32 bits lba
5870 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5871
5872 // If verify or seek
5873 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5874 goto int13_success;
5875
5876 memsetb(get_SS(),atacmd,0,12);
5877 atacmd[0]=0x28; // READ command
5878 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5879 atacmd[8]=(count & 0x00ff); // Sectors
5880 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5881 atacmd[3]=(lba & 0x00ff0000) >> 16;
5882 atacmd[4]=(lba & 0x0000ff00) >> 8;
5883 atacmd[5]=(lba & 0x000000ff);
5884 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5885
5886 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5887 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5888
5889 if (status != 0) {
5890 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5891 SET_AH(0x0c);
5892 goto int13_fail_noah;
5893 }
5894
5895 goto int13_success;
5896 break;
5897
5898 case 0x45: // IBM/MS lock/unlock drive
5899 if (GET_AL() > 2) goto int13_fail;
5900
5901 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5902
5903 switch (GET_AL()) {
5904 case 0 : // lock
5905 if (locks == 0xff) {
5906 SET_AH(0xb4);
5907 SET_AL(1);
5908 goto int13_fail_noah;
5909 }
5910 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5911 SET_AL(1);
5912 break;
5913 case 1 : // unlock
5914 if (locks == 0x00) {
5915 SET_AH(0xb0);
5916 SET_AL(0);
5917 goto int13_fail_noah;
5918 }
5919 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5920 SET_AL(locks==0?0:1);
5921 break;
5922 case 2 : // status
5923 SET_AL(locks==0?0:1);
5924 break;
5925 }
5926 goto int13_success;
5927 break;
5928
5929 case 0x46: // IBM/MS eject media
5930 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5931
5932 if (locks != 0) {
5933 SET_AH(0xb1); // media locked
5934 goto int13_fail_noah;
5935 }
5936 // FIXME should handle 0x31 no media in device
5937 // FIXME should handle 0xb5 valid request failed
5938
5939 // Call removable media eject
5940 ASM_START
5941 push bp
5942 mov bp, sp
5943
5944 mov ah, #0x52
5945 int 15
5946 mov _int13_cdrom.status + 2[bp], ah
5947 jnc int13_cdrom_rme_end
5948 mov _int13_cdrom.status, #1
5949int13_cdrom_rme_end:
5950 pop bp
5951 ASM_END
5952
5953 if (status != 0) {
5954 SET_AH(0xb1); // media locked
5955 goto int13_fail_noah;
5956 }
5957
5958 goto int13_success;
5959 break;
5960
5961 case 0x48: // IBM/MS get drive parameters
5962 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5963
5964 // Buffer is too small
5965 if(size < 0x1a)
5966 goto int13_fail;
5967
5968 // EDD 1.x
5969 if(size >= 0x1a) {
5970 Bit16u cylinders, heads, spt, blksize;
5971
5972 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5973
5974 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5975 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5976 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5977 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5978 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5979 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5980 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5981 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5982 }
5983
5984 // EDD 2.x
5985 if(size >= 0x1e) {
5986 Bit8u channel, dev, irq, mode, checksum, i;
5987 Bit16u iobase1, iobase2, options;
5988
5989 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5990
5991 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5992 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5993
5994 // Fill in dpte
5995 channel = device / 2;
5996 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5997 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5998 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5999 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6000
6001 // FIXME atapi device
6002 options = (1<<4); // lba translation
6003 options |= (1<<5); // removable device
6004 options |= (1<<6); // atapi device
6005 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6006
6007 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6008 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6009 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6010 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6011 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6012 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6013 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6014 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6015 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6016 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6017 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6018
6019 checksum=0;
6020 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6021 checksum = ~checksum;
6022 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6023 }
6024
6025 // EDD 3.x
6026 if(size >= 0x42) {
6027 Bit8u channel, iface, checksum, i;
6028 Bit16u iobase1;
6029
6030 channel = device / 2;
6031 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6032 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6033
6034 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6035 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6036 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6037 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6038 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6039
6040 if (iface==ATA_IFACE_ISA) {
6041 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6042 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6043 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6044 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6045 }
6046 else {
6047 // FIXME PCI
6048 }
6049 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6050 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6051 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6052 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6053
6054 if (iface==ATA_IFACE_ISA) {
6055 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6056 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6057 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6058 }
6059 else {
6060 // FIXME PCI
6061 }
6062 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6063 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6064 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6065 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6066
6067 checksum=0;
6068 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6069 checksum = ~checksum;
6070 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6071 }
6072
6073 goto int13_success;
6074 break;
6075
6076 case 0x49: // IBM/MS extended media change
6077 // always send changed ??
6078 SET_AH(06);
6079 goto int13_fail_nostatus;
6080 break;
6081
6082 case 0x4e: // // IBM/MS set hardware configuration
6083 // DMA, prefetch, PIO maximum not supported
6084 switch (GET_AL()) {
6085 case 0x01:
6086 case 0x03:
6087 case 0x04:
6088 case 0x06:
6089 goto int13_success;
6090 break;
6091 default :
6092 goto int13_fail;
6093 }
6094 break;
6095
6096 // all those functions return unimplemented
6097 case 0x02: /* read sectors */
6098 case 0x04: /* verify sectors */
6099 case 0x08: /* read disk drive parameters */
6100 case 0x0a: /* read disk sectors with ECC */
6101 case 0x0b: /* write disk sectors with ECC */
6102 case 0x18: /* set media type for format */
6103 case 0x50: // ? - send packet command
6104 default:
6105 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6106 goto int13_fail;
6107 break;
6108 }
6109
6110int13_fail:
6111 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6112int13_fail_noah:
6113 SET_DISK_RET_STATUS(GET_AH());
6114int13_fail_nostatus:
6115 SET_CF(); // error occurred
6116 return;
6117
6118int13_success:
6119 SET_AH(0x00); // no error
6120int13_success_noah:
6121 SET_DISK_RET_STATUS(0x00);
6122 CLEAR_CF(); // no error
6123 return;
6124}
6125
6126// ---------------------------------------------------------------------------
6127// End of int13 for cdrom
6128// ---------------------------------------------------------------------------
6129
6130#if BX_ELTORITO_BOOT
6131// ---------------------------------------------------------------------------
6132// Start of int13 for eltorito functions
6133// ---------------------------------------------------------------------------
6134
6135 void
6136int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6137 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6138{
6139 Bit16u ebda_seg=read_word(0x0040,0x000E);
6140
6141 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6142 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6143
6144 switch (GET_AH()) {
6145
6146 // FIXME ElTorito Various. Should be implemented
6147 case 0x4a: // ElTorito - Initiate disk emu
6148 case 0x4c: // ElTorito - Initiate disk emu and boot
6149 case 0x4d: // ElTorito - Return Boot catalog
6150 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6151 goto int13_fail;
6152 break;
6153
6154 case 0x4b: // ElTorito - Terminate disk emu
6155 // FIXME ElTorito Hardcoded
6156 write_byte(DS,SI+0x00,0x13);
6157 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6158 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6159 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6160 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6161 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6162 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6163 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6164 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6165 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6166 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6167 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6168
6169 // If we have to terminate emulation
6170 if(GET_AL() == 0x00) {
6171 // FIXME ElTorito Various. Should be handled accordingly to spec
6172 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6173 }
6174
6175 goto int13_success;
6176 break;
6177
6178 default:
6179 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6180 goto int13_fail;
6181 break;
6182 }
6183
6184int13_fail:
6185 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6186 SET_DISK_RET_STATUS(GET_AH());
6187 SET_CF(); // error occurred
6188 return;
6189
6190int13_success:
6191 SET_AH(0x00); // no error
6192 SET_DISK_RET_STATUS(0x00);
6193 CLEAR_CF(); // no error
6194 return;
6195}
6196
6197// ---------------------------------------------------------------------------
6198// End of int13 for eltorito functions
6199// ---------------------------------------------------------------------------
6200
6201// ---------------------------------------------------------------------------
6202// Start of int13 when emulating a device from the cd
6203// ---------------------------------------------------------------------------
6204
6205 void
6206int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6207 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6208{
6209 Bit16u ebda_seg=read_word(0x0040,0x000E);
6210 Bit8u device, status;
6211 Bit16u vheads, vspt, vcylinders;
6212 Bit16u head, sector, cylinder, nbsectors;
6213 Bit32u vlba, ilba, slba, elba;
6214 Bit16u before, segment, offset;
6215 Bit8u atacmd[12];
6216
6217 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6218
6219 /* at this point, we are emulating a floppy/harddisk */
6220
6221 // Recompute the device number
6222 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6223 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6224
6225 SET_DISK_RET_STATUS(0x00);
6226
6227 /* basic checks : emulation should be active, dl should equal the emulated drive */
6228 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6229 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6230 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6231 goto int13_fail;
6232 }
6233
6234 switch (GET_AH()) {
6235
6236 // all those functions return SUCCESS
6237 case 0x00: /* disk controller reset */
6238 case 0x09: /* initialize drive parameters */
6239 case 0x0c: /* seek to specified cylinder */
6240 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6241 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6242 case 0x11: /* recalibrate */
6243 case 0x14: /* controller internal diagnostic */
6244 case 0x16: /* detect disk change */
6245 goto int13_success;
6246 break;
6247
6248 // all those functions return disk write-protected
6249 case 0x03: /* write disk sectors */
6250 case 0x05: /* format disk track */
6251 SET_AH(0x03);
6252 goto int13_fail_noah;
6253 break;
6254
6255 case 0x01: /* read disk status */
6256 status=read_byte(0x0040, 0x0074);
6257 SET_AH(status);
6258 SET_DISK_RET_STATUS(0);
6259
6260 /* set CF if error status read */
6261 if (status) goto int13_fail_nostatus;
6262 else goto int13_success_noah;
6263 break;
6264
6265 case 0x02: // read disk sectors
6266 case 0x04: // verify disk sectors
6267 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6268 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6269 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6270
6271 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6272
6273 sector = GET_CL() & 0x003f;
6274 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6275 head = GET_DH();
6276 nbsectors = GET_AL();
6277 segment = ES;
6278 offset = BX;
6279
6280 // no sector to read ?
6281 if(nbsectors==0) goto int13_success;
6282
6283 // sanity checks sco openserver needs this!
6284 if ((sector > vspt)
6285 || (cylinder >= vcylinders)
6286 || (head >= vheads)) {
6287 goto int13_fail;
6288 }
6289
6290 // After controls, verify do nothing
6291 if (GET_AH() == 0x04) goto int13_success;
6292
6293 segment = ES+(BX / 16);
6294 offset = BX % 16;
6295
6296 // calculate the virtual lba inside the image
6297 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6298
6299 // In advance so we don't loose the count
6300 SET_AL(nbsectors);
6301
6302 // start lba on cd
6303 slba = (Bit32u)vlba/4;
6304 before= (Bit16u)vlba%4;
6305
6306 // end lba on cd
6307 elba = (Bit32u)(vlba+nbsectors-1)/4;
6308
6309 memsetb(get_SS(),atacmd,0,12);
6310 atacmd[0]=0x28; // READ command
6311 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6312 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6313 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6314 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6315 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6316 atacmd[5]=(ilba+slba & 0x000000ff);
6317 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6318 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6319 SET_AH(0x02);
6320 SET_AL(0);
6321 goto int13_fail_noah;
6322 }
6323
6324 goto int13_success;
6325 break;
6326
6327 case 0x08: /* read disk drive parameters */
6328 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6329 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6330 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6331
6332 SET_AL( 0x00 );
6333 SET_BL( 0x00 );
6334 SET_CH( vcylinders & 0xff );
6335 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6336 SET_DH( vheads );
6337 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6338 // FIXME ElTorito Harddisk. should send the HD count
6339
6340 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6341 case 0x01: SET_BL( 0x02 ); break;
6342 case 0x02: SET_BL( 0x04 ); break;
6343 case 0x03: SET_BL( 0x06 ); break;
6344 }
6345
6346ASM_START
6347 push bp
6348 mov bp, sp
6349 mov ax, #diskette_param_table2
6350 mov _int13_cdemu.DI+2[bp], ax
6351 mov _int13_cdemu.ES+2[bp], cs
6352 pop bp
6353ASM_END
6354 goto int13_success;
6355 break;
6356
6357 case 0x15: /* read disk drive size */
6358 // FIXME ElTorito Harddisk. What geometry to send ?
6359 SET_AH(0x03);
6360 goto int13_success_noah;
6361 break;
6362
6363 // all those functions return unimplemented
6364 case 0x0a: /* read disk sectors with ECC */
6365 case 0x0b: /* write disk sectors with ECC */
6366 case 0x18: /* set media type for format */
6367 case 0x41: // IBM/MS installation check
6368 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6369 case 0x42: // IBM/MS extended read
6370 case 0x43: // IBM/MS extended write
6371 case 0x44: // IBM/MS verify sectors
6372 case 0x45: // IBM/MS lock/unlock drive
6373 case 0x46: // IBM/MS eject media
6374 case 0x47: // IBM/MS extended seek
6375 case 0x48: // IBM/MS get drive parameters
6376 case 0x49: // IBM/MS extended media change
6377 case 0x4e: // ? - set hardware configuration
6378 case 0x50: // ? - send packet command
6379 default:
6380 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6381 goto int13_fail;
6382 break;
6383 }
6384
6385int13_fail:
6386 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6387int13_fail_noah:
6388 SET_DISK_RET_STATUS(GET_AH());
6389int13_fail_nostatus:
6390 SET_CF(); // error occurred
6391 return;
6392
6393int13_success:
6394 SET_AH(0x00); // no error
6395int13_success_noah:
6396 SET_DISK_RET_STATUS(0x00);
6397 CLEAR_CF(); // no error
6398 return;
6399}
6400
6401// ---------------------------------------------------------------------------
6402// End of int13 when emulating a device from the cd
6403// ---------------------------------------------------------------------------
6404
6405#endif // BX_ELTORITO_BOOT
6406
6407#else //BX_USE_ATADRV
6408
6409 void
6410outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6411 Bit16u cylinder;
6412 Bit16u hd_heads;
6413 Bit16u head;
6414 Bit16u hd_sectors;
6415 Bit16u sector;
6416 Bit16u dl;
6417{
6418ASM_START
6419 push bp
6420 mov bp, sp
6421 push eax
6422 push ebx
6423 push edx
6424 xor eax,eax
6425 mov ax,4[bp] // cylinder
6426 xor ebx,ebx
6427 mov bl,6[bp] // hd_heads
6428 imul ebx
6429
6430 mov bl,8[bp] // head
6431 add eax,ebx
6432 mov bl,10[bp] // hd_sectors
6433 imul ebx
6434 mov bl,12[bp] // sector
6435 add eax,ebx
6436
6437 dec eax
6438 mov dx,#0x1f3
6439 out dx,al
6440 mov dx,#0x1f4
6441 mov al,ah
6442 out dx,al
6443 shr eax,#16
6444 mov dx,#0x1f5
6445 out dx,al
6446 and ah,#0xf
6447 mov bl,14[bp] // dl
6448 and bl,#1
6449 shl bl,#4
6450 or ah,bl
6451 or ah,#0xe0
6452 mov al,ah
6453 mov dx,#0x01f6
6454 out dx,al
6455 pop edx
6456 pop ebx
6457 pop eax
6458 pop bp
6459ASM_END
6460}
6461
6462 void
6463int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6464 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6465{
6466 Bit8u drive, num_sectors, sector, head, status, mod;
6467 Bit8u drive_map;
6468 Bit8u n_drives;
6469 Bit16u cyl_mod, ax;
6470 Bit16u max_cylinder, cylinder, total_sectors;
6471 Bit16u hd_cylinders;
6472 Bit8u hd_heads, hd_sectors;
6473 Bit16u val16;
6474 Bit8u sector_count;
6475 unsigned int i;
6476 Bit16u tempbx;
6477 Bit16u dpsize;
6478
6479 Bit16u count, segment, offset;
6480 Bit32u lba;
6481 Bit16u error;
6482
6483 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6484
6485 write_byte(0x0040, 0x008e, 0); // clear completion flag
6486
6487 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6488 handler code */
6489 /* check how many disks first (cmos reg 0x12), return an error if
6490 drive not present */
6491 drive_map = inb_cmos(0x12);
6492 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6493 (((drive_map & 0x0f)==0) ? 0 : 2);
6494 n_drives = (drive_map==0) ? 0 :
6495 ((drive_map==3) ? 2 : 1);
6496
6497 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6498 SET_AH(0x01);
6499 SET_DISK_RET_STATUS(0x01);
6500 SET_CF(); /* error occurred */
6501 return;
6502 }
6503
6504 switch (GET_AH()) {
6505
6506 case 0x00: /* disk controller reset */
6507BX_DEBUG_INT13_HD("int13_f00\n");
6508
6509 SET_AH(0);
6510 SET_DISK_RET_STATUS(0);
6511 set_diskette_ret_status(0);
6512 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6513 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6514 CLEAR_CF(); /* successful */
6515 return;
6516 break;
6517
6518 case 0x01: /* read disk status */
6519BX_DEBUG_INT13_HD("int13_f01\n");
6520 status = read_byte(0x0040, 0x0074);
6521 SET_AH(status);
6522 SET_DISK_RET_STATUS(0);
6523 /* set CF if error status read */
6524 if (status) SET_CF();
6525 else CLEAR_CF();
6526 return;
6527 break;
6528
6529 case 0x04: // verify disk sectors
6530 case 0x02: // read disk sectors
6531 drive = GET_ELDL();
6532 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6533
6534 num_sectors = GET_AL();
6535 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6536 sector = (GET_CL() & 0x3f);
6537 head = GET_DH();
6538
6539
6540 if (hd_cylinders > 1024) {
6541 if (hd_cylinders <= 2048) {
6542 cylinder <<= 1;
6543 }
6544 else if (hd_cylinders <= 4096) {
6545 cylinder <<= 2;
6546 }
6547 else if (hd_cylinders <= 8192) {
6548 cylinder <<= 3;
6549 }
6550 else { // hd_cylinders <= 16384
6551 cylinder <<= 4;
6552 }
6553
6554 ax = head / hd_heads;
6555 cyl_mod = ax & 0xff;
6556 head = ax >> 8;
6557 cylinder |= cyl_mod;
6558 }
6559
6560 if ( (cylinder >= hd_cylinders) ||
6561 (sector > hd_sectors) ||
6562 (head >= hd_heads) ) {
6563 SET_AH(1);
6564 SET_DISK_RET_STATUS(1);
6565 SET_CF(); /* error occurred */
6566 return;
6567 }
6568
6569 if ( (num_sectors > 128) || (num_sectors == 0) )
6570 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6571
6572 if (head > 15)
6573 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6574
6575 if ( GET_AH() == 0x04 ) {
6576 SET_AH(0);
6577 SET_DISK_RET_STATUS(0);
6578 CLEAR_CF();
6579 return;
6580 }
6581
6582 status = inb(0x1f7);
6583 if (status & 0x80) {
6584 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6585 }
6586 outb(0x01f2, num_sectors);
6587 /* activate LBA? (tomv) */
6588 if (hd_heads > 16) {
6589BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6590 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6591 }
6592 else {
6593 outb(0x01f3, sector);
6594 outb(0x01f4, cylinder & 0x00ff);
6595 outb(0x01f5, cylinder >> 8);
6596 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6597 }
6598 outb(0x01f7, 0x20);
6599
6600 while (1) {
6601 status = inb(0x1f7);
6602 if ( !(status & 0x80) ) break;
6603 }
6604
6605 if (status & 0x01) {
6606 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6607 } else if ( !(status & 0x08) ) {
6608 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6609 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6610 }
6611
6612 sector_count = 0;
6613 tempbx = BX;
6614
6615ASM_START
6616 sti ;; enable higher priority interrupts
6617ASM_END
6618
6619 while (1) {
6620ASM_START
6621 ;; store temp bx in real DI register
6622 push bp
6623 mov bp, sp
6624 mov di, _int13_harddisk.tempbx + 2 [bp]
6625 pop bp
6626
6627 ;; adjust if there will be an overrun
6628 cmp di, #0xfe00
6629 jbe i13_f02_no_adjust
6630i13_f02_adjust:
6631 sub di, #0x0200 ; sub 512 bytes from offset
6632 mov ax, es
6633 add ax, #0x0020 ; add 512 to segment
6634 mov es, ax
6635
6636i13_f02_no_adjust:
6637 mov cx, #0x0100 ;; counter (256 words = 512b)
6638 mov dx, #0x01f0 ;; AT data read port
6639
6640 rep
6641 insw ;; CX words transfered from port(DX) to ES:[DI]
6642
6643i13_f02_done:
6644 ;; store real DI register back to temp bx
6645 push bp
6646 mov bp, sp
6647 mov _int13_harddisk.tempbx + 2 [bp], di
6648 pop bp
6649ASM_END
6650
6651 sector_count++;
6652 num_sectors--;
6653 if (num_sectors == 0) {
6654 status = inb(0x1f7);
6655 if ( (status & 0xc9) != 0x40 )
6656 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6657 break;
6658 }
6659 else {
6660 status = inb(0x1f7);
6661 if ( (status & 0xc9) != 0x48 )
6662 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6663 continue;
6664 }
6665 }
6666
6667 SET_AH(0);
6668 SET_DISK_RET_STATUS(0);
6669 SET_AL(sector_count);
6670 CLEAR_CF(); /* successful */
6671 return;
6672 break;
6673
6674
6675 case 0x03: /* write disk sectors */
6676BX_DEBUG_INT13_HD("int13_f03\n");
6677 drive = GET_ELDL ();
6678 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6679
6680 num_sectors = GET_AL();
6681 cylinder = GET_CH();
6682 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6683 sector = (GET_CL() & 0x3f);
6684 head = GET_DH();
6685
6686 if (hd_cylinders > 1024) {
6687 if (hd_cylinders <= 2048) {
6688 cylinder <<= 1;
6689 }
6690 else if (hd_cylinders <= 4096) {
6691 cylinder <<= 2;
6692 }
6693 else if (hd_cylinders <= 8192) {
6694 cylinder <<= 3;
6695 }
6696 else { // hd_cylinders <= 16384
6697 cylinder <<= 4;
6698 }
6699
6700 ax = head / hd_heads;
6701 cyl_mod = ax & 0xff;
6702 head = ax >> 8;
6703 cylinder |= cyl_mod;
6704 }
6705
6706 if ( (cylinder >= hd_cylinders) ||
6707 (sector > hd_sectors) ||
6708 (head >= hd_heads) ) {
6709 SET_AH( 1);
6710 SET_DISK_RET_STATUS(1);
6711 SET_CF(); /* error occurred */
6712 return;
6713 }
6714
6715 if ( (num_sectors > 128) || (num_sectors == 0) )
6716 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6717
6718 if (head > 15)
6719 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6720
6721 status = inb(0x1f7);
6722 if (status & 0x80) {
6723 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6724 }
6725// should check for Drive Ready Bit also in status reg
6726 outb(0x01f2, num_sectors);
6727
6728 /* activate LBA? (tomv) */
6729 if (hd_heads > 16) {
6730BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6731 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6732 }
6733 else {
6734 outb(0x01f3, sector);
6735 outb(0x01f4, cylinder & 0x00ff);
6736 outb(0x01f5, cylinder >> 8);
6737 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6738 }
6739 outb(0x01f7, 0x30);
6740
6741 // wait for busy bit to turn off after seeking
6742 while (1) {
6743 status = inb(0x1f7);
6744 if ( !(status & 0x80) ) break;
6745 }
6746
6747 if ( !(status & 0x08) ) {
6748 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6749 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6750 }
6751
6752 sector_count = 0;
6753 tempbx = BX;
6754
6755ASM_START
6756 sti ;; enable higher priority interrupts
6757ASM_END
6758
6759 while (1) {
6760ASM_START
6761 ;; store temp bx in real SI register
6762 push bp
6763 mov bp, sp
6764 mov si, _int13_harddisk.tempbx + 2 [bp]
6765 pop bp
6766
6767 ;; adjust if there will be an overrun
6768 cmp si, #0xfe00
6769 jbe i13_f03_no_adjust
6770i13_f03_adjust:
6771 sub si, #0x0200 ; sub 512 bytes from offset
6772 mov ax, es
6773 add ax, #0x0020 ; add 512 to segment
6774 mov es, ax
6775
6776i13_f03_no_adjust:
6777 mov cx, #0x0100 ;; counter (256 words = 512b)
6778 mov dx, #0x01f0 ;; AT data read port
6779
6780 seg ES
6781 rep
6782 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6783
6784 ;; store real SI register back to temp bx
6785 push bp
6786 mov bp, sp
6787 mov _int13_harddisk.tempbx + 2 [bp], si
6788 pop bp
6789ASM_END
6790
6791 sector_count++;
6792 num_sectors--;
6793 if (num_sectors == 0) {
6794 status = inb(0x1f7);
6795 if ( (status & 0xe9) != 0x40 )
6796 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6797 break;
6798 }
6799 else {
6800 status = inb(0x1f7);
6801 if ( (status & 0xc9) != 0x48 )
6802 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6803 continue;
6804 }
6805 }
6806
6807 SET_AH(0);
6808 SET_DISK_RET_STATUS(0);
6809 SET_AL(sector_count);
6810 CLEAR_CF(); /* successful */
6811 return;
6812 break;
6813
6814 case 0x05: /* format disk track */
6815BX_DEBUG_INT13_HD("int13_f05\n");
6816 BX_PANIC("format disk track called\n");
6817 /* nop */
6818 SET_AH(0);
6819 SET_DISK_RET_STATUS(0);
6820 CLEAR_CF(); /* successful */
6821 return;
6822 break;
6823
6824 case 0x08: /* read disk drive parameters */
6825BX_DEBUG_INT13_HD("int13_f08\n");
6826
6827 drive = GET_ELDL ();
6828 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6829
6830 // translate CHS
6831 //
6832 if (hd_cylinders <= 1024) {
6833 // hd_cylinders >>= 0;
6834 // hd_heads <<= 0;
6835 }
6836 else if (hd_cylinders <= 2048) {
6837 hd_cylinders >>= 1;
6838 hd_heads <<= 1;
6839 }
6840 else if (hd_cylinders <= 4096) {
6841 hd_cylinders >>= 2;
6842 hd_heads <<= 2;
6843 }
6844 else if (hd_cylinders <= 8192) {
6845 hd_cylinders >>= 3;
6846 hd_heads <<= 3;
6847 }
6848 else { // hd_cylinders <= 16384
6849 hd_cylinders >>= 4;
6850 hd_heads <<= 4;
6851 }
6852
6853 max_cylinder = hd_cylinders - 2; /* 0 based */
6854 SET_AL(0);
6855 SET_CH(max_cylinder & 0xff);
6856 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6857 SET_DH(hd_heads - 1);
6858 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6859 SET_AH(0);
6860 SET_DISK_RET_STATUS(0);
6861 CLEAR_CF(); /* successful */
6862
6863 return;
6864 break;
6865
6866 case 0x09: /* initialize drive parameters */
6867BX_DEBUG_INT13_HD("int13_f09\n");
6868 SET_AH(0);
6869 SET_DISK_RET_STATUS(0);
6870 CLEAR_CF(); /* successful */
6871 return;
6872 break;
6873
6874 case 0x0a: /* read disk sectors with ECC */
6875BX_DEBUG_INT13_HD("int13_f0a\n");
6876 case 0x0b: /* write disk sectors with ECC */
6877BX_DEBUG_INT13_HD("int13_f0b\n");
6878 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6879 return;
6880 break;
6881
6882 case 0x0c: /* seek to specified cylinder */
6883BX_DEBUG_INT13_HD("int13_f0c\n");
6884 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6885 SET_AH(0);
6886 SET_DISK_RET_STATUS(0);
6887 CLEAR_CF(); /* successful */
6888 return;
6889 break;
6890
6891 case 0x0d: /* alternate disk reset */
6892BX_DEBUG_INT13_HD("int13_f0d\n");
6893 SET_AH(0);
6894 SET_DISK_RET_STATUS(0);
6895 CLEAR_CF(); /* successful */
6896 return;
6897 break;
6898
6899 case 0x10: /* check drive ready */
6900BX_DEBUG_INT13_HD("int13_f10\n");
6901 //SET_AH(0);
6902 //SET_DISK_RET_STATUS(0);
6903 //CLEAR_CF(); /* successful */
6904 //return;
6905 //break;
6906
6907 // should look at 40:8E also???
6908 status = inb(0x01f7);
6909 if ( (status & 0xc0) == 0x40 ) {
6910 SET_AH(0);
6911 SET_DISK_RET_STATUS(0);
6912 CLEAR_CF(); // drive ready
6913 return;
6914 }
6915 else {
6916 SET_AH(0xAA);
6917 SET_DISK_RET_STATUS(0xAA);
6918 SET_CF(); // not ready
6919 return;
6920 }
6921 break;
6922
6923 case 0x11: /* recalibrate */
6924BX_DEBUG_INT13_HD("int13_f11\n");
6925 SET_AH(0);
6926 SET_DISK_RET_STATUS(0);
6927 CLEAR_CF(); /* successful */
6928 return;
6929 break;
6930
6931 case 0x14: /* controller internal diagnostic */
6932BX_DEBUG_INT13_HD("int13_f14\n");
6933 SET_AH(0);
6934 SET_DISK_RET_STATUS(0);
6935 CLEAR_CF(); /* successful */
6936 SET_AL(0);
6937 return;
6938 break;
6939
6940 case 0x15: /* read disk drive size */
6941 drive = GET_ELDL();
6942 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6943ASM_START
6944 push bp
6945 mov bp, sp
6946 mov al, _int13_harddisk.hd_heads + 2 [bp]
6947 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6948 mul al, ah ;; ax = heads * sectors
6949 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6950 dec bx ;; use (cylinders - 1) ???
6951 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6952 ;; now we need to move the 32bit result dx:ax to what the
6953 ;; BIOS wants which is cx:dx.
6954 ;; and then into CX:DX on the stack
6955 mov _int13_harddisk.CX + 2 [bp], dx
6956 mov _int13_harddisk.DX + 2 [bp], ax
6957 pop bp
6958ASM_END
6959 SET_AH(3); // hard disk accessible
6960 SET_DISK_RET_STATUS(0); // ??? should this be 0
6961 CLEAR_CF(); // successful
6962 return;
6963 break;
6964
6965 case 0x18: // set media type for format
6966 case 0x41: // IBM/MS
6967 case 0x42: // IBM/MS
6968 case 0x43: // IBM/MS
6969 case 0x44: // IBM/MS
6970 case 0x45: // IBM/MS lock/unlock drive
6971 case 0x46: // IBM/MS eject media
6972 case 0x47: // IBM/MS extended seek
6973 case 0x49: // IBM/MS extended media change
6974 case 0x50: // IBM/MS send packet command
6975 default:
6976 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6977
6978 SET_AH(1); // code=invalid function in AH or invalid parameter
6979 SET_DISK_RET_STATUS(1);
6980 SET_CF(); /* unsuccessful */
6981 return;
6982 break;
6983 }
6984}
6985
6986static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6987static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6988
6989 void
6990get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6991 Bit8u drive;
6992 Bit16u *hd_cylinders;
6993 Bit8u *hd_heads;
6994 Bit8u *hd_sectors;
6995{
6996 Bit8u hd_type;
6997 Bit16u ss;
6998 Bit16u cylinders;
6999 Bit8u iobase;
7000
7001 ss = get_SS();
7002 if (drive == 0x80) {
7003 hd_type = inb_cmos(0x12) & 0xf0;
7004 if (hd_type != 0xf0)
7005 BX_INFO(panic_msg_reg12h,0);
7006 hd_type = inb_cmos(0x19); // HD0: extended type
7007 if (hd_type != 47)
7008 BX_INFO(panic_msg_reg19h,0,0x19);
7009 iobase = 0x1b;
7010 } else {
7011 hd_type = inb_cmos(0x12) & 0x0f;
7012 if (hd_type != 0x0f)
7013 BX_INFO(panic_msg_reg12h,1);
7014 hd_type = inb_cmos(0x1a); // HD0: extended type
7015 if (hd_type != 47)
7016 BX_INFO(panic_msg_reg19h,0,0x1a);
7017 iobase = 0x24;
7018 }
7019
7020 // cylinders
7021 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7022 write_word(ss, hd_cylinders, cylinders);
7023
7024 // heads
7025 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7026
7027 // sectors per track
7028 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7029}
7030
7031#endif //else BX_USE_ATADRV
7032
7033
7034//////////////////////
7035// FLOPPY functions //
7036//////////////////////
7037
7038void floppy_reset_controller()
7039{
7040 Bit8u val8;
7041
7042 // Reset controller
7043 val8 = inb(0x03f2);
7044 outb(0x03f2, val8 & ~0x04);
7045 outb(0x03f2, val8 | 0x04);
7046
7047 // Wait for controller to come out of reset
7048 do {
7049 val8 = inb(0x3f4);
7050 } while ( (val8 & 0xc0) != 0x80 );
7051}
7052
7053void floppy_prepare_controller(drive)
7054 Bit16u drive;
7055{
7056 Bit8u val8, dor, prev_reset;
7057
7058 // set 40:3e bit 7 to 0
7059 val8 = read_byte(0x0040, 0x003e);
7060 val8 &= 0x7f;
7061 write_byte(0x0040, 0x003e, val8);
7062
7063 // turn on motor of selected drive, DMA & int enabled, normal operation
7064 prev_reset = inb(0x03f2) & 0x04;
7065 if (drive)
7066 dor = 0x20;
7067 else
7068 dor = 0x10;
7069 dor |= 0x0c;
7070 dor |= drive;
7071 outb(0x03f2, dor);
7072
7073 // reset the disk motor timeout value of INT 08
7074 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7075
7076#ifdef VBOX
7077 // program data rate
7078 val8 = read_byte(0x0040, 0x008b);
7079 val8 >>= 6;
7080 outb(0x03f7, val8);
7081#endif
7082
7083 // wait for drive readiness
7084 do {
7085 val8 = inb(0x3f4);
7086 } while ( (val8 & 0xc0) != 0x80 );
7087
7088 if (prev_reset == 0) {
7089 // turn on interrupts
7090ASM_START
7091 sti
7092ASM_END
7093 // wait on 40:3e bit 7 to become 1
7094 do {
7095 val8 = read_byte(0x0040, 0x003e);
7096 } while ( (val8 & 0x80) == 0 );
7097 val8 &= 0x7f;
7098ASM_START
7099 cli
7100ASM_END
7101 write_byte(0x0040, 0x003e, val8);
7102 }
7103}
7104
7105 bx_bool
7106floppy_media_known(drive)
7107 Bit16u drive;
7108{
7109 Bit8u val8;
7110 Bit16u media_state_offset;
7111
7112 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7113 if (drive)
7114 val8 >>= 1;
7115 val8 &= 0x01;
7116 if (val8 == 0)
7117 return(0);
7118
7119 media_state_offset = 0x0090;
7120 if (drive)
7121 media_state_offset += 1;
7122
7123 val8 = read_byte(0x0040, media_state_offset);
7124 val8 = (val8 >> 4) & 0x01;
7125 if (val8 == 0)
7126 return(0);
7127
7128 // check pass, return KNOWN
7129 return(1);
7130}
7131
7132 bx_bool
7133floppy_media_sense(drive)
7134 Bit16u drive;
7135{
7136 bx_bool retval;
7137 Bit16u media_state_offset;
7138 Bit8u drive_type, config_data, media_state;
7139
7140 if (floppy_drive_recal(drive) == 0) {
7141 return(0);
7142 }
7143
7144 // for now cheat and get drive type from CMOS,
7145 // assume media is same as drive type
7146
7147 // ** config_data **
7148 // Bitfields for diskette media control:
7149 // Bit(s) Description (Table M0028)
7150 // 7-6 last data rate set by controller
7151 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7152 // 5-4 last diskette drive step rate selected
7153 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7154 // 3-2 {data rate at start of operation}
7155 // 1-0 reserved
7156
7157 // ** media_state **
7158 // Bitfields for diskette drive media state:
7159 // Bit(s) Description (Table M0030)
7160 // 7-6 data rate
7161 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7162 // 5 double stepping required (e.g. 360kB in 1.2MB)
7163 // 4 media type established
7164 // 3 drive capable of supporting 4MB media
7165 // 2-0 on exit from BIOS, contains
7166 // 000 trying 360kB in 360kB
7167 // 001 trying 360kB in 1.2MB
7168 // 010 trying 1.2MB in 1.2MB
7169 // 011 360kB in 360kB established
7170 // 100 360kB in 1.2MB established
7171 // 101 1.2MB in 1.2MB established
7172 // 110 reserved
7173 // 111 all other formats/drives
7174
7175 drive_type = inb_cmos(0x10);
7176 if (drive == 0)
7177 drive_type >>= 4;
7178 else
7179 drive_type &= 0x0f;
7180 if ( drive_type == 1 ) {
7181 // 360K 5.25" drive
7182 config_data = 0x00; // 0000 0000
7183 media_state = 0x25; // 0010 0101
7184 retval = 1;
7185 }
7186 else if ( drive_type == 2 ) {
7187 // 1.2 MB 5.25" drive
7188 config_data = 0x00; // 0000 0000
7189 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7190 retval = 1;
7191 }
7192 else if ( drive_type == 3 ) {
7193 // 720K 3.5" drive
7194 config_data = 0x00; // 0000 0000 ???
7195 media_state = 0x17; // 0001 0111
7196 retval = 1;
7197 }
7198 else if ( drive_type == 4 ) {
7199 // 1.44 MB 3.5" drive
7200 config_data = 0x00; // 0000 0000
7201 media_state = 0x17; // 0001 0111
7202 retval = 1;
7203 }
7204 else if ( drive_type == 5 ) {
7205 // 2.88 MB 3.5" drive
7206 config_data = 0xCC; // 1100 1100
7207 media_state = 0xD7; // 1101 0111
7208 retval = 1;
7209 }
7210 //
7211 // Extended floppy size uses special cmos setting
7212 else if ( drive_type == 6 ) {
7213 // 160k 5.25" drive
7214 config_data = 0x00; // 0000 0000
7215 media_state = 0x27; // 0010 0111
7216 retval = 1;
7217 }
7218 else if ( drive_type == 7 ) {
7219 // 180k 5.25" drive
7220 config_data = 0x00; // 0000 0000
7221 media_state = 0x27; // 0010 0111
7222 retval = 1;
7223 }
7224 else if ( drive_type == 8 ) {
7225 // 320k 5.25" drive
7226 config_data = 0x00; // 0000 0000
7227 media_state = 0x27; // 0010 0111
7228 retval = 1;
7229 }
7230
7231 else {
7232 // not recognized
7233 config_data = 0x00; // 0000 0000
7234 media_state = 0x00; // 0000 0000
7235 retval = 0;
7236 }
7237
7238 if (drive == 0)
7239 media_state_offset = 0x90;
7240 else
7241 media_state_offset = 0x91;
7242 write_byte(0x0040, 0x008B, config_data);
7243 write_byte(0x0040, media_state_offset, media_state);
7244
7245 return(retval);
7246}
7247
7248 bx_bool
7249floppy_drive_recal(drive)
7250 Bit16u drive;
7251{
7252 Bit8u val8;
7253 Bit16u curr_cyl_offset;
7254
7255 floppy_prepare_controller(drive);
7256
7257 // send Recalibrate command (2 bytes) to controller
7258 outb(0x03f5, 0x07); // 07: Recalibrate
7259 outb(0x03f5, drive); // 0=drive0, 1=drive1
7260
7261 // turn on interrupts
7262ASM_START
7263 sti
7264ASM_END
7265
7266 // wait on 40:3e bit 7 to become 1
7267 do {
7268 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7269 } while ( val8 == 0 );
7270
7271 val8 = 0; // separate asm from while() loop
7272 // turn off interrupts
7273ASM_START
7274 cli
7275ASM_END
7276
7277 // set 40:3e bit 7 to 0, and calibrated bit
7278 val8 = read_byte(0x0040, 0x003e);
7279 val8 &= 0x7f;
7280 if (drive) {
7281 val8 |= 0x02; // Drive 1 calibrated
7282 curr_cyl_offset = 0x0095;
7283 } else {
7284 val8 |= 0x01; // Drive 0 calibrated
7285 curr_cyl_offset = 0x0094;
7286 }
7287 write_byte(0x0040, 0x003e, val8);
7288 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7289
7290 return(1);
7291}
7292
7293
7294
7295 bx_bool
7296floppy_drive_exists(drive)
7297 Bit16u drive;
7298{
7299 Bit8u drive_type;
7300
7301 // check CMOS to see if drive exists
7302 drive_type = inb_cmos(0x10);
7303 if (drive == 0)
7304 drive_type >>= 4;
7305 else
7306 drive_type &= 0x0f;
7307 if ( drive_type == 0 )
7308 return(0);
7309 else
7310 return(1);
7311}
7312
7313#if BX_SUPPORT_FLOPPY
7314 void
7315int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7316 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7317{
7318 Bit8u drive, num_sectors, track, sector, head, status;
7319 Bit16u base_address, base_count, base_es;
7320 Bit8u page, mode_register, val8, dor;
7321 Bit8u return_status[7];
7322 Bit8u drive_type, num_floppies, ah;
7323 Bit16u es, last_addr;
7324
7325 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7326
7327 ah = GET_AH();
7328
7329 switch ( ah ) {
7330 case 0x00: // diskette controller reset
7331BX_DEBUG_INT13_FL("floppy f00\n");
7332 drive = GET_ELDL();
7333 if (drive > 1) {
7334 SET_AH(1); // invalid param
7335 set_diskette_ret_status(1);
7336 SET_CF();
7337 return;
7338 }
7339 drive_type = inb_cmos(0x10);
7340
7341 if (drive == 0)
7342 drive_type >>= 4;
7343 else
7344 drive_type &= 0x0f;
7345 if (drive_type == 0) {
7346 SET_AH(0x80); // drive not responding
7347 set_diskette_ret_status(0x80);
7348 SET_CF();
7349 return;
7350 }
7351 SET_AH(0);
7352 set_diskette_ret_status(0);
7353 CLEAR_CF(); // successful
7354 set_diskette_current_cyl(drive, 0); // current cylinder
7355 return;
7356
7357 case 0x01: // Read Diskette Status
7358 CLEAR_CF();
7359 val8 = read_byte(0x0000, 0x0441);
7360 SET_AH(val8);
7361 if (val8) {
7362 SET_CF();
7363 }
7364 return;
7365
7366 case 0x02: // Read Diskette Sectors
7367 case 0x03: // Write Diskette Sectors
7368 case 0x04: // Verify Diskette Sectors
7369 num_sectors = GET_AL();
7370 track = GET_CH();
7371 sector = GET_CL();
7372 head = GET_DH();
7373 drive = GET_ELDL();
7374
7375 if ( (drive > 1) || (head > 1) ||
7376 (num_sectors == 0) || (num_sectors > 72) ) {
7377BX_INFO("floppy: drive>1 || head>1 ...\n");
7378 SET_AH(1);
7379 set_diskette_ret_status(1);
7380 SET_AL(0); // no sectors read
7381 SET_CF(); // error occurred
7382 return;
7383 }
7384
7385 // see if drive exists
7386 if (floppy_drive_exists(drive) == 0) {
7387 SET_AH(0x80); // not responding
7388 set_diskette_ret_status(0x80);
7389 SET_AL(0); // no sectors read
7390 SET_CF(); // error occurred
7391 return;
7392 }
7393
7394 // see if media in drive, and type is known
7395 if (floppy_media_known(drive) == 0) {
7396 if (floppy_media_sense(drive) == 0) {
7397 SET_AH(0x0C); // Media type not found
7398 set_diskette_ret_status(0x0C);
7399 SET_AL(0); // no sectors read
7400 SET_CF(); // error occurred
7401 return;
7402 }
7403 }
7404
7405 if (ah == 0x02) {
7406 // Read Diskette Sectors
7407
7408 //-----------------------------------
7409 // set up DMA controller for transfer
7410 //-----------------------------------
7411
7412 // es:bx = pointer to where to place information from diskette
7413 // port 04: DMA-1 base and current address, channel 2
7414 // port 05: DMA-1 base and current count, channel 2
7415 page = (ES >> 12); // upper 4 bits
7416 base_es = (ES << 4); // lower 16bits contributed by ES
7417 base_address = base_es + BX; // lower 16 bits of address
7418 // contributed by ES:BX
7419 if ( base_address < base_es ) {
7420 // in case of carry, adjust page by 1
7421 page++;
7422 }
7423 base_count = (num_sectors * 512) - 1;
7424
7425 // check for 64K boundary overrun
7426 last_addr = base_address + base_count;
7427 if (last_addr < base_address) {
7428 SET_AH(0x09);
7429 set_diskette_ret_status(0x09);
7430 SET_AL(0); // no sectors read
7431 SET_CF(); // error occurred
7432 return;
7433 }
7434
7435 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7436 outb(0x000a, 0x06);
7437
7438 BX_DEBUG_INT13_FL("clear flip-flop\n");
7439 outb(0x000c, 0x00); // clear flip-flop
7440 outb(0x0004, base_address);
7441 outb(0x0004, base_address>>8);
7442 BX_DEBUG_INT13_FL("clear flip-flop\n");
7443 outb(0x000c, 0x00); // clear flip-flop
7444 outb(0x0005, base_count);
7445 outb(0x0005, base_count>>8);
7446
7447 // port 0b: DMA-1 Mode Register
7448 mode_register = 0x46; // single mode, increment, autoinit disable,
7449 // transfer type=write, channel 2
7450 BX_DEBUG_INT13_FL("setting mode register\n");
7451 outb(0x000b, mode_register);
7452
7453 BX_DEBUG_INT13_FL("setting page register\n");
7454 // port 81: DMA-1 Page Register, channel 2
7455 outb(0x0081, page);
7456
7457 BX_DEBUG_INT13_FL("unmask chan 2\n");
7458 outb(0x000a, 0x02); // unmask channel 2
7459
7460 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7461 outb(0x000a, 0x02);
7462
7463 //--------------------------------------
7464 // set up floppy controller for transfer
7465 //--------------------------------------
7466 floppy_prepare_controller(drive);
7467
7468 // send read-normal-data command (9 bytes) to controller
7469 outb(0x03f5, 0xe6); // e6: read normal data
7470 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7471 outb(0x03f5, track);
7472 outb(0x03f5, head);
7473 outb(0x03f5, sector);
7474 outb(0x03f5, 2); // 512 byte sector size
7475 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7476 outb(0x03f5, 0); // Gap length
7477 outb(0x03f5, 0xff); // Gap length
7478
7479 // turn on interrupts
7480 ASM_START
7481 sti
7482 ASM_END
7483
7484 // wait on 40:3e bit 7 to become 1
7485 do {
7486 val8 = read_byte(0x0040, 0x0040);
7487 if (val8 == 0) {
7488 floppy_reset_controller();
7489 SET_AH(0x80); // drive not ready (timeout)
7490 set_diskette_ret_status(0x80);
7491 SET_AL(0); // no sectors read
7492 SET_CF(); // error occurred
7493 return;
7494 }
7495 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7496 } while ( val8 == 0 );
7497
7498 val8 = 0; // separate asm from while() loop
7499 // turn off interrupts
7500 ASM_START
7501 cli
7502 ASM_END
7503
7504 // set 40:3e bit 7 to 0
7505 val8 = read_byte(0x0040, 0x003e);
7506 val8 &= 0x7f;
7507 write_byte(0x0040, 0x003e, val8);
7508
7509 // check port 3f4 for accessibility to status bytes
7510 val8 = inb(0x3f4);
7511 if ( (val8 & 0xc0) != 0xc0 )
7512 BX_PANIC("int13_diskette: ctrl not ready\n");
7513
7514 // read 7 return status bytes from controller
7515 // using loop index broken, have to unroll...
7516 return_status[0] = inb(0x3f5);
7517 return_status[1] = inb(0x3f5);
7518 return_status[2] = inb(0x3f5);
7519 return_status[3] = inb(0x3f5);
7520 return_status[4] = inb(0x3f5);
7521 return_status[5] = inb(0x3f5);
7522 return_status[6] = inb(0x3f5);
7523 // record in BIOS Data Area
7524 write_byte(0x0040, 0x0042, return_status[0]);
7525 write_byte(0x0040, 0x0043, return_status[1]);
7526 write_byte(0x0040, 0x0044, return_status[2]);
7527 write_byte(0x0040, 0x0045, return_status[3]);
7528 write_byte(0x0040, 0x0046, return_status[4]);
7529 write_byte(0x0040, 0x0047, return_status[5]);
7530 write_byte(0x0040, 0x0048, return_status[6]);
7531
7532 if ( (return_status[0] & 0xc0) != 0 ) {
7533 SET_AH(0x20);
7534 set_diskette_ret_status(0x20);
7535 SET_AL(0); // no sectors read
7536 SET_CF(); // error occurred
7537 return;
7538 }
7539
7540 // ??? should track be new val from return_status[3] ?
7541 set_diskette_current_cyl(drive, track);
7542 // AL = number of sectors read (same value as passed)
7543 SET_AH(0x00); // success
7544 CLEAR_CF(); // success
7545 return;
7546 } else if (ah == 0x03) {
7547 // Write Diskette Sectors
7548
7549 //-----------------------------------
7550 // set up DMA controller for transfer
7551 //-----------------------------------
7552
7553 // es:bx = pointer to where to place information from diskette
7554 // port 04: DMA-1 base and current address, channel 2
7555 // port 05: DMA-1 base and current count, channel 2
7556 page = (ES >> 12); // upper 4 bits
7557 base_es = (ES << 4); // lower 16bits contributed by ES
7558 base_address = base_es + BX; // lower 16 bits of address
7559 // contributed by ES:BX
7560 if ( base_address < base_es ) {
7561 // in case of carry, adjust page by 1
7562 page++;
7563 }
7564 base_count = (num_sectors * 512) - 1;
7565
7566 // check for 64K boundary overrun
7567 last_addr = base_address + base_count;
7568 if (last_addr < base_address) {
7569 SET_AH(0x09);
7570 set_diskette_ret_status(0x09);
7571 SET_AL(0); // no sectors read
7572 SET_CF(); // error occurred
7573 return;
7574 }
7575
7576 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7577 outb(0x000a, 0x06);
7578
7579 outb(0x000c, 0x00); // clear flip-flop
7580 outb(0x0004, base_address);
7581 outb(0x0004, base_address>>8);
7582 outb(0x000c, 0x00); // clear flip-flop
7583 outb(0x0005, base_count);
7584 outb(0x0005, base_count>>8);
7585
7586 // port 0b: DMA-1 Mode Register
7587 mode_register = 0x4a; // single mode, increment, autoinit disable,
7588 // transfer type=read, channel 2
7589 outb(0x000b, mode_register);
7590
7591 // port 81: DMA-1 Page Register, channel 2
7592 outb(0x0081, page);
7593
7594 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7595 outb(0x000a, 0x02);
7596
7597 //--------------------------------------
7598 // set up floppy controller for transfer
7599 //--------------------------------------
7600 floppy_prepare_controller(drive);
7601
7602 // send write-normal-data command (9 bytes) to controller
7603 outb(0x03f5, 0xc5); // c5: write normal data
7604 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7605 outb(0x03f5, track);
7606 outb(0x03f5, head);
7607 outb(0x03f5, sector);
7608 outb(0x03f5, 2); // 512 byte sector size
7609 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7610 outb(0x03f5, 0); // Gap length
7611 outb(0x03f5, 0xff); // Gap length
7612
7613 // turn on interrupts
7614 ASM_START
7615 sti
7616 ASM_END
7617
7618 // wait on 40:3e bit 7 to become 1
7619 do {
7620 val8 = read_byte(0x0040, 0x0040);
7621 if (val8 == 0) {
7622 floppy_reset_controller();
7623 SET_AH(0x80); // drive not ready (timeout)
7624 set_diskette_ret_status(0x80);
7625 SET_AL(0); // no sectors written
7626 SET_CF(); // error occurred
7627 return;
7628 }
7629 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7630 } while ( val8 == 0 );
7631
7632 val8 = 0; // separate asm from while() loop
7633 // turn off interrupts
7634 ASM_START
7635 cli
7636 ASM_END
7637
7638 // set 40:3e bit 7 to 0
7639 val8 = read_byte(0x0040, 0x003e);
7640 val8 &= 0x7f;
7641 write_byte(0x0040, 0x003e, val8);
7642
7643 // check port 3f4 for accessibility to status bytes
7644 val8 = inb(0x3f4);
7645 if ( (val8 & 0xc0) != 0xc0 )
7646 BX_PANIC("int13_diskette: ctrl not ready\n");
7647
7648 // read 7 return status bytes from controller
7649 // using loop index broken, have to unroll...
7650 return_status[0] = inb(0x3f5);
7651 return_status[1] = inb(0x3f5);
7652 return_status[2] = inb(0x3f5);
7653 return_status[3] = inb(0x3f5);
7654 return_status[4] = inb(0x3f5);
7655 return_status[5] = inb(0x3f5);
7656 return_status[6] = inb(0x3f5);
7657 // record in BIOS Data Area
7658 write_byte(0x0040, 0x0042, return_status[0]);
7659 write_byte(0x0040, 0x0043, return_status[1]);
7660 write_byte(0x0040, 0x0044, return_status[2]);
7661 write_byte(0x0040, 0x0045, return_status[3]);
7662 write_byte(0x0040, 0x0046, return_status[4]);
7663 write_byte(0x0040, 0x0047, return_status[5]);
7664 write_byte(0x0040, 0x0048, return_status[6]);
7665
7666 if ( (return_status[0] & 0xc0) != 0 ) {
7667 if ( (return_status[1] & 0x02) != 0 ) {
7668 // diskette not writable.
7669 // AH=status code=0x03 (tried to write on write-protected disk)
7670 // AL=number of sectors written=0
7671 AX = 0x0300;
7672 SET_CF();
7673 return;
7674 } else {
7675 BX_PANIC("int13_diskette_function: read error\n");
7676 }
7677 }
7678
7679 // ??? should track be new val from return_status[3] ?
7680 set_diskette_current_cyl(drive, track);
7681 // AL = number of sectors read (same value as passed)
7682 SET_AH(0x00); // success
7683 CLEAR_CF(); // success
7684 return;
7685 } else { // if (ah == 0x04)
7686 // Verify Diskette Sectors
7687
7688 // ??? should track be new val from return_status[3] ?
7689 set_diskette_current_cyl(drive, track);
7690 // AL = number of sectors verified (same value as passed)
7691 CLEAR_CF(); // success
7692 SET_AH(0x00); // success
7693 return;
7694 }
7695 break;
7696
7697 case 0x05: // format diskette track
7698BX_DEBUG_INT13_FL("floppy f05\n");
7699
7700 num_sectors = GET_AL();
7701 track = GET_CH();
7702 head = GET_DH();
7703 drive = GET_ELDL();
7704
7705 if ((drive > 1) || (head > 1) || (track > 79) ||
7706 (num_sectors == 0) || (num_sectors > 18)) {
7707 SET_AH(1);
7708 set_diskette_ret_status(1);
7709 SET_CF(); // error occurred
7710 }
7711
7712 // see if drive exists
7713 if (floppy_drive_exists(drive) == 0) {
7714 SET_AH(0x80); // drive not responding
7715 set_diskette_ret_status(0x80);
7716 SET_CF(); // error occurred
7717 return;
7718 }
7719
7720 // see if media in drive, and type is known
7721 if (floppy_media_known(drive) == 0) {
7722 if (floppy_media_sense(drive) == 0) {
7723 SET_AH(0x0C); // Media type not found
7724 set_diskette_ret_status(0x0C);
7725 SET_AL(0); // no sectors read
7726 SET_CF(); // error occurred
7727 return;
7728 }
7729 }
7730
7731 // set up DMA controller for transfer
7732 page = (ES >> 12); // upper 4 bits
7733 base_es = (ES << 4); // lower 16bits contributed by ES
7734 base_address = base_es + BX; // lower 16 bits of address
7735 // contributed by ES:BX
7736 if ( base_address < base_es ) {
7737 // in case of carry, adjust page by 1
7738 page++;
7739 }
7740 base_count = (num_sectors * 4) - 1;
7741
7742 // check for 64K boundary overrun
7743 last_addr = base_address + base_count;
7744 if (last_addr < base_address) {
7745 SET_AH(0x09);
7746 set_diskette_ret_status(0x09);
7747 SET_AL(0); // no sectors read
7748 SET_CF(); // error occurred
7749 return;
7750 }
7751
7752 outb(0x000a, 0x06);
7753 outb(0x000c, 0x00); // clear flip-flop
7754 outb(0x0004, base_address);
7755 outb(0x0004, base_address>>8);
7756 outb(0x000c, 0x00); // clear flip-flop
7757 outb(0x0005, base_count);
7758 outb(0x0005, base_count>>8);
7759 mode_register = 0x4a; // single mode, increment, autoinit disable,
7760 // transfer type=read, channel 2
7761 outb(0x000b, mode_register);
7762 // port 81: DMA-1 Page Register, channel 2
7763 outb(0x0081, page);
7764 outb(0x000a, 0x02);
7765
7766 // set up floppy controller for transfer
7767 floppy_prepare_controller(drive);
7768
7769 // send format-track command (6 bytes) to controller
7770 outb(0x03f5, 0x4d); // 4d: format track
7771 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7772 outb(0x03f5, 2); // 512 byte sector size
7773 outb(0x03f5, num_sectors); // number of sectors per track
7774 outb(0x03f5, 0); // Gap length
7775 outb(0x03f5, 0xf6); // Fill byte
7776 // turn on interrupts
7777 ASM_START
7778 sti
7779 ASM_END
7780
7781 // wait on 40:3e bit 7 to become 1
7782 do {
7783 val8 = read_byte(0x0040, 0x0040);
7784 if (val8 == 0) {
7785 floppy_reset_controller();
7786 SET_AH(0x80); // drive not ready (timeout)
7787 set_diskette_ret_status(0x80);
7788 SET_CF(); // error occurred
7789 return;
7790 }
7791 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7792 } while ( val8 == 0 );
7793
7794 val8 = 0; // separate asm from while() loop
7795 // turn off interrupts
7796 ASM_START
7797 cli
7798 ASM_END
7799 // set 40:3e bit 7 to 0
7800 val8 = read_byte(0x0040, 0x003e);
7801 val8 &= 0x7f;
7802 write_byte(0x0040, 0x003e, val8);
7803 // check port 3f4 for accessibility to status bytes
7804 val8 = inb(0x3f4);
7805 if ( (val8 & 0xc0) != 0xc0 )
7806 BX_PANIC("int13_diskette: ctrl not ready\n");
7807
7808 // read 7 return status bytes from controller
7809 // using loop index broken, have to unroll...
7810 return_status[0] = inb(0x3f5);
7811 return_status[1] = inb(0x3f5);
7812 return_status[2] = inb(0x3f5);
7813 return_status[3] = inb(0x3f5);
7814 return_status[4] = inb(0x3f5);
7815 return_status[5] = inb(0x3f5);
7816 return_status[6] = inb(0x3f5);
7817 // record in BIOS Data Area
7818 write_byte(0x0040, 0x0042, return_status[0]);
7819 write_byte(0x0040, 0x0043, return_status[1]);
7820 write_byte(0x0040, 0x0044, return_status[2]);
7821 write_byte(0x0040, 0x0045, return_status[3]);
7822 write_byte(0x0040, 0x0046, return_status[4]);
7823 write_byte(0x0040, 0x0047, return_status[5]);
7824 write_byte(0x0040, 0x0048, return_status[6]);
7825
7826 if ( (return_status[0] & 0xc0) != 0 ) {
7827 if ( (return_status[1] & 0x02) != 0 ) {
7828 // diskette not writable.
7829 // AH=status code=0x03 (tried to write on write-protected disk)
7830 // AL=number of sectors written=0
7831 AX = 0x0300;
7832 SET_CF();
7833 return;
7834 } else {
7835 BX_PANIC("int13_diskette_function: write error\n");
7836 }
7837 }
7838
7839 SET_AH(0);
7840 set_diskette_ret_status(0);
7841 set_diskette_current_cyl(drive, 0);
7842 CLEAR_CF(); // successful
7843 return;
7844
7845
7846 case 0x08: // read diskette drive parameters
7847BX_DEBUG_INT13_FL("floppy f08\n");
7848 drive = GET_ELDL();
7849
7850 if (drive > 1) {
7851 AX = 0;
7852 BX = 0;
7853 CX = 0;
7854 DX = 0;
7855 ES = 0;
7856 DI = 0;
7857 SET_DL(num_floppies);
7858 SET_CF();
7859 return;
7860 }
7861
7862 drive_type = inb_cmos(0x10);
7863 num_floppies = 0;
7864 if (drive_type & 0xf0)
7865 num_floppies++;
7866 if (drive_type & 0x0f)
7867 num_floppies++;
7868
7869 if (drive == 0)
7870 drive_type >>= 4;
7871 else
7872 drive_type &= 0x0f;
7873
7874 SET_BH(0);
7875 SET_BL(drive_type);
7876 SET_AH(0);
7877 SET_AL(0);
7878 SET_DL(num_floppies);
7879
7880 switch (drive_type) {
7881 case 0: // none
7882 CX = 0;
7883 SET_DH(0); // max head #
7884 break;
7885
7886 case 1: // 360KB, 5.25"
7887 CX = 0x2709; // 40 tracks, 9 sectors
7888 SET_DH(1); // max head #
7889 break;
7890
7891 case 2: // 1.2MB, 5.25"
7892 CX = 0x4f0f; // 80 tracks, 15 sectors
7893 SET_DH(1); // max head #
7894 break;
7895
7896 case 3: // 720KB, 3.5"
7897 CX = 0x4f09; // 80 tracks, 9 sectors
7898 SET_DH(1); // max head #
7899 break;
7900
7901 case 4: // 1.44MB, 3.5"
7902 CX = 0x4f12; // 80 tracks, 18 sectors
7903 SET_DH(1); // max head #
7904 break;
7905
7906 case 5: // 2.88MB, 3.5"
7907 CX = 0x4f24; // 80 tracks, 36 sectors
7908 SET_DH(1); // max head #
7909 break;
7910
7911 case 6: // 160k, 5.25"
7912 CX = 0x2708; // 40 tracks, 8 sectors
7913 SET_DH(0); // max head #
7914 break;
7915
7916 case 7: // 180k, 5.25"
7917 CX = 0x2709; // 40 tracks, 9 sectors
7918 SET_DH(0); // max head #
7919 break;
7920
7921 case 8: // 320k, 5.25"
7922 CX = 0x2708; // 40 tracks, 8 sectors
7923 SET_DH(1); // max head #
7924 break;
7925
7926 default: // ?
7927 BX_PANIC("floppy: int13: bad floppy type\n");
7928 }
7929
7930 /* set es & di to point to 11 byte diskette param table in ROM */
7931ASM_START
7932 push bp
7933 mov bp, sp
7934 mov ax, #diskette_param_table2
7935 mov _int13_diskette_function.DI+2[bp], ax
7936 mov _int13_diskette_function.ES+2[bp], cs
7937 pop bp
7938ASM_END
7939 CLEAR_CF(); // success
7940 /* disk status not changed upon success */
7941 return;
7942
7943
7944 case 0x15: // read diskette drive type
7945BX_DEBUG_INT13_FL("floppy f15\n");
7946 drive = GET_ELDL();
7947 if (drive > 1) {
7948 SET_AH(0); // only 2 drives supported
7949 // set_diskette_ret_status here ???
7950 SET_CF();
7951 return;
7952 }
7953 drive_type = inb_cmos(0x10);
7954
7955 if (drive == 0)
7956 drive_type >>= 4;
7957 else
7958 drive_type &= 0x0f;
7959 CLEAR_CF(); // successful, not present
7960 if (drive_type==0) {
7961 SET_AH(0); // drive not present
7962 }
7963 else {
7964 SET_AH(1); // drive present, does not support change line
7965 }
7966
7967 return;
7968
7969 case 0x16: // get diskette change line status
7970BX_DEBUG_INT13_FL("floppy f16\n");
7971 drive = GET_ELDL();
7972 if (drive > 1) {
7973 SET_AH(0x01); // invalid drive
7974 set_diskette_ret_status(0x01);
7975 SET_CF();
7976 return;
7977 }
7978
7979 SET_AH(0x06); // change line not supported
7980 set_diskette_ret_status(0x06);
7981 SET_CF();
7982 return;
7983
7984 case 0x17: // set diskette type for format(old)
7985BX_DEBUG_INT13_FL("floppy f17\n");
7986 /* not used for 1.44M floppies */
7987 SET_AH(0x01); // not supported
7988 set_diskette_ret_status(1); /* not supported */
7989 SET_CF();
7990 return;
7991
7992 case 0x18: // set diskette type for format(new)
7993BX_DEBUG_INT13_FL("floppy f18\n");
7994 SET_AH(0x01); // do later
7995 set_diskette_ret_status(1);
7996 SET_CF();
7997 return;
7998
7999 default:
8000 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8001
8002 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8003 SET_AH(0x01); // ???
8004 set_diskette_ret_status(1);
8005 SET_CF();
8006 return;
8007 // }
8008 }
8009}
8010#else // #if BX_SUPPORT_FLOPPY
8011 void
8012int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8013 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8014{
8015 Bit8u val8;
8016
8017 switch ( GET_AH() ) {
8018
8019 case 0x01: // Read Diskette Status
8020 CLEAR_CF();
8021 val8 = read_byte(0x0000, 0x0441);
8022 SET_AH(val8);
8023 if (val8) {
8024 SET_CF();
8025 }
8026 return;
8027
8028 default:
8029 SET_CF();
8030 write_byte(0x0000, 0x0441, 0x01);
8031 SET_AH(0x01);
8032 }
8033}
8034#endif // #if BX_SUPPORT_FLOPPY
8035
8036 void
8037set_diskette_ret_status(value)
8038 Bit8u value;
8039{
8040 write_byte(0x0040, 0x0041, value);
8041}
8042
8043 void
8044set_diskette_current_cyl(drive, cyl)
8045 Bit8u drive;
8046 Bit8u cyl;
8047{
8048 if (drive > 1)
8049 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8050 write_byte(0x0040, 0x0094+drive, cyl);
8051}
8052
8053 void
8054determine_floppy_media(drive)
8055 Bit16u drive;
8056{
8057#if 0
8058 Bit8u val8, DOR, ctrl_info;
8059
8060 ctrl_info = read_byte(0x0040, 0x008F);
8061 if (drive==1)
8062 ctrl_info >>= 4;
8063 else
8064 ctrl_info &= 0x0f;
8065
8066#if 0
8067 if (drive == 0) {
8068 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8069 }
8070 else {
8071 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8072 }
8073#endif
8074
8075 if ( (ctrl_info & 0x04) != 0x04 ) {
8076 // Drive not determined means no drive exists, done.
8077 return;
8078 }
8079
8080#if 0
8081 // check Main Status Register for readiness
8082 val8 = inb(0x03f4) & 0x80; // Main Status Register
8083 if (val8 != 0x80)
8084 BX_PANIC("d_f_m: MRQ bit not set\n");
8085
8086 // change line
8087
8088 // existing BDA values
8089
8090 // turn on drive motor
8091 outb(0x03f2, DOR); // Digital Output Register
8092 //
8093#endif
8094 BX_PANIC("d_f_m: OK so far\n");
8095#endif
8096}
8097
8098 void
8099int17_function(regs, ds, iret_addr)
8100 pusha_regs_t regs; // regs pushed from PUSHA instruction
8101 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8102 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8103{
8104 Bit16u addr,timeout;
8105 Bit8u val8;
8106
8107 ASM_START
8108 sti
8109 ASM_END
8110
8111 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8112 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8113 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8114 if (regs.u.r8.ah == 0) {
8115 outb(addr, regs.u.r8.al);
8116 val8 = inb(addr+2);
8117 outb(addr+2, val8 | 0x01); // send strobe
8118 ASM_START
8119 nop
8120 ASM_END
8121 outb(addr+2, val8 & ~0x01);
8122 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8123 timeout--;
8124 }
8125 }
8126 if (regs.u.r8.ah == 1) {
8127 val8 = inb(addr+2);
8128 outb(addr+2, val8 & ~0x04); // send init
8129 ASM_START
8130 nop
8131 ASM_END
8132 outb(addr+2, val8 | 0x04);
8133 }
8134 val8 = inb(addr+1);
8135 regs.u.r8.ah = (val8 ^ 0x48);
8136 if (!timeout) regs.u.r8.ah |= 0x01;
8137 ClearCF(iret_addr.flags);
8138 } else {
8139 SetCF(iret_addr.flags); // Unsupported
8140 }
8141}
8142
8143// returns bootsegment in ax, drive in bl
8144 Bit32u
8145int19_function(bseqnr)
8146Bit8u bseqnr;
8147{
8148 Bit16u ebda_seg=read_word(0x0040,0x000E);
8149 Bit16u bootseq;
8150 Bit8u bootdrv;
8151 Bit8u bootcd;
8152#ifdef VBOX
8153 Bit8u bootlan;
8154#endif /* VBOX */
8155 Bit8u bootchk;
8156 Bit16u bootseg;
8157 Bit16u status;
8158 Bit8u lastdrive=0;
8159
8160 // if BX_ELTORITO_BOOT is not defined, old behavior
8161 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8162 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8163 // 0: system boot sequence, first drive C: then A:
8164 // 1: system boot sequence, first drive A: then C:
8165 // else BX_ELTORITO_BOOT is defined
8166 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8167 // CMOS reg 0x3D & 0x0f : 1st boot device
8168 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8169 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8170#ifdef VBOX
8171 // CMOS reg 0x3C & 0x0f : 4th boot device
8172#endif /* VBOX */
8173 // boot device codes:
8174 // 0x00 : not defined
8175 // 0x01 : first floppy
8176 // 0x02 : first harddrive
8177 // 0x03 : first cdrom
8178#ifdef VBOX
8179 // 0x04 : local area network
8180#endif /* VBOX */
8181 // else : boot failure
8182
8183 // Get the boot sequence
8184#if BX_ELTORITO_BOOT
8185 bootseq=inb_cmos(0x3d);
8186 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8187#ifdef VBOX
8188 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8189 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8190 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8191 /* Boot delay hack. */
8192 if (bseqnr == 1)
8193 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8194#endif /* VBOX */
8195
8196 if (bseqnr==2) bootseq >>= 4;
8197 if (bseqnr==3) bootseq >>= 8;
8198#ifdef VBOX
8199 if (bseqnr==4) bootseq >>= 12;
8200#endif /* VBOX */
8201 if (bootseq<0x10) lastdrive = 1;
8202 bootdrv=0x00; bootcd=0;
8203#ifdef VBOX
8204 bootlan=0;
8205#endif /* VBOX */
8206 switch(bootseq & 0x0f) {
8207 case 0x01:
8208 bootdrv=0x00;
8209 bootcd=0;
8210 break;
8211 case 0x02:
8212 {
8213 // Get the Boot drive.
8214 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8215
8216 bootdrv = boot_drive + 0x80;
8217 bootcd=0;
8218 break;
8219 }
8220 case 0x03:
8221 bootdrv=0x00;
8222 bootcd=1;
8223 break;
8224#ifdef VBOX
8225 case 0x04: bootlan=1; break;
8226#endif /* VBOX */
8227 default: return 0x00000000;
8228 }
8229#else
8230 bootseq=inb_cmos(0x2d);
8231
8232 if (bseqnr==2) {
8233 bootseq ^= 0x20;
8234 lastdrive = 1;
8235 }
8236 bootdrv=0x00; bootcd=0;
8237 if((bootseq&0x20)==0) bootdrv=0x80;
8238#endif // BX_ELTORITO_BOOT
8239
8240#if BX_ELTORITO_BOOT
8241 // We have to boot from cd
8242 if (bootcd != 0) {
8243 status = cdrom_boot();
8244
8245 // If failure
8246 if ( (status & 0x00ff) !=0 ) {
8247 print_cdromboot_failure(status);
8248#ifdef VBOX
8249 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8250#else /* !VBOX */
8251 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8252#endif /* !VBOX */
8253 return 0x00000000;
8254 }
8255
8256 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8257 bootdrv = (Bit8u)(status>>8);
8258 }
8259
8260#endif // BX_ELTORITO_BOOT
8261
8262#ifdef VBOX
8263 // Check for boot from LAN first
8264 if (bootlan == 1) {
8265 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8266 Bit16u pnpoff;
8267 Bit32u manuf;
8268 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8269 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8270 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8271 // Found PnP signature
8272 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8273 if (manuf == 0x65687445) {
8274 // Found Etherboot ROM
8275 print_boot_device(bootcd, bootlan, bootdrv);
8276ASM_START
8277 push ds
8278 push es
8279 pusha
8280 calli 0x0006,VBOX_LANBOOT_SEG
8281 popa
8282 pop es
8283 pop ds
8284ASM_END
8285 } else if (manuf == 0x65746E49) {
8286 // Found Intel PXE ROM
8287 print_boot_device(bootcd, bootlan, bootdrv);
8288ASM_START
8289 push ds
8290 push es
8291 pusha
8292 sti ; Why are interrupts disabled now? Because we were called through an INT!
8293 push #VBOX_LANBOOT_SEG
8294 pop ds
8295 mov bx,#0x1a ; PnP header offset
8296 mov bx,[bx]
8297 add bx,#0x1a ; BEV offset in PnP header
8298 mov ax,[bx]
8299 test ax,ax
8300 jz no_rom
8301bev_jump:
8302 push cs
8303 push #no_rom
8304 push #VBOX_LANBOOT_SEG
8305 push ax
8306 retf ; call Boot Entry Vector
8307no_rom:
8308 popa
8309 pop es
8310 pop ds
8311ASM_END
8312 }
8313 }
8314 }
8315
8316 // boot from LAN will not return if successful.
8317 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8318 return 0x00000000;
8319 }
8320#endif /* VBOX */
8321 // We have to boot from harddisk or floppy
8322#ifdef VBOX
8323 if (bootcd == 0 && bootlan == 0) {
8324#else /* !VBOX */
8325 if (bootcd == 0) {
8326#endif /* !VBOX */
8327 bootseg=0x07c0;
8328
8329ASM_START
8330 push bp
8331 mov bp, sp
8332
8333 xor ax, ax
8334 mov _int19_function.status + 2[bp], ax
8335 mov dl, _int19_function.bootdrv + 2[bp]
8336 mov ax, _int19_function.bootseg + 2[bp]
8337 mov es, ax ;; segment
8338 xor bx, bx ;; offset
8339 mov ah, #0x02 ;; function 2, read diskette sector
8340 mov al, #0x01 ;; read 1 sector
8341 mov ch, #0x00 ;; track 0
8342 mov cl, #0x01 ;; sector 1
8343 mov dh, #0x00 ;; head 0
8344 int #0x13 ;; read sector
8345 jnc int19_load_done
8346 mov ax, #0x0001
8347 mov _int19_function.status + 2[bp], ax
8348
8349int19_load_done:
8350 pop bp
8351ASM_END
8352
8353 if (status != 0) {
8354#ifdef VBOX
8355 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8356#else /* !VBOX */
8357 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8358#endif /* !VBOX */
8359 return 0x00000000;
8360 }
8361 }
8362
8363#ifdef VBOX
8364 // Don't check boot sectors on floppies and don't read CMOS - byte
8365 // 0x38 in CMOS always has the low bit clear.
8366 // There is *no* requirement whatsoever for a valid boot sector to
8367 // have a 55AAh signature. UNIX boot floppies typically have no such
8368 // signature. In general, it is impossible to tell a valid bootsector
8369 // from an invalid one.
8370 // NB: It is somewhat common for failed OS installs to have the
8371 // 0x55AA signature and a valid partition table but zeros in the
8372 // rest of the boot sector. We do a quick check by comparing the first
8373 // two words of boot sector; if identical, the boot sector is
8374 // extremely unlikely to be valid.
8375#endif
8376 // check signature if instructed by cmos reg 0x38, only for floppy
8377 // bootchk = 1 : signature check disabled
8378 // bootchk = 0 : signature check enabled
8379 if (bootdrv != 0) bootchk = 0;
8380#ifdef VBOX
8381 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8382#else
8383 else bootchk = inb_cmos(0x38) & 0x01;
8384#endif
8385
8386#if BX_ELTORITO_BOOT
8387 // if boot from cd, no signature check
8388 if (bootcd != 0)
8389 bootchk = 1;
8390#endif // BX_ELTORITO_BOOT
8391
8392 if (bootchk == 0) {
8393 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8394 read_word(bootseg,0) == read_word(bootseg,2)) {
8395#ifdef VBOX
8396 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8397#else /* !VBOX */
8398 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8399#endif /* VBOX */
8400 return 0x00000000;
8401 }
8402 }
8403
8404#if BX_ELTORITO_BOOT
8405 // Print out the boot string
8406#ifdef VBOX
8407 print_boot_device(bootcd, bootlan, bootdrv);
8408#else /* !VBOX */
8409 print_boot_device(bootcd, bootdrv);
8410#endif /* !VBOX */
8411#else // BX_ELTORITO_BOOT
8412#ifdef VBOX
8413 print_boot_device(0, bootlan, bootdrv);
8414#else /* !VBOX */
8415 print_boot_device(0, bootdrv);
8416#endif /* !VBOX */
8417#endif // BX_ELTORITO_BOOT
8418
8419 // return the boot segment
8420 return (((Bit32u)bootdrv) << 16) + bootseg;
8421}
8422
8423 void
8424int1a_function(regs, ds, iret_addr)
8425 pusha_regs_t regs; // regs pushed from PUSHA instruction
8426 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8427 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8428{
8429 Bit8u val8;
8430
8431 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);
8432
8433 ASM_START
8434 sti
8435 ASM_END
8436
8437 switch (regs.u.r8.ah) {
8438 case 0: // get current clock count
8439 ASM_START
8440 cli
8441 ASM_END
8442 regs.u.r16.cx = BiosData->ticks_high;
8443 regs.u.r16.dx = BiosData->ticks_low;
8444 regs.u.r8.al = BiosData->midnight_flag;
8445 BiosData->midnight_flag = 0; // reset flag
8446 ASM_START
8447 sti
8448 ASM_END
8449 // AH already 0
8450 ClearCF(iret_addr.flags); // OK
8451 break;
8452
8453 case 1: // Set Current Clock Count
8454 ASM_START
8455 cli
8456 ASM_END
8457 BiosData->ticks_high = regs.u.r16.cx;
8458 BiosData->ticks_low = regs.u.r16.dx;
8459 BiosData->midnight_flag = 0; // reset flag
8460 ASM_START
8461 sti
8462 ASM_END
8463 regs.u.r8.ah = 0;
8464 ClearCF(iret_addr.flags); // OK
8465 break;
8466
8467
8468 case 2: // Read CMOS Time
8469 if (rtc_updating()) {
8470 SetCF(iret_addr.flags);
8471 break;
8472 }
8473
8474 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8475 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8476 regs.u.r8.ch = inb_cmos(0x04); // Hours
8477 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8478 regs.u.r8.ah = 0;
8479 regs.u.r8.al = regs.u.r8.ch;
8480 ClearCF(iret_addr.flags); // OK
8481 break;
8482
8483 case 3: // Set CMOS Time
8484 // Using a debugger, I notice the following masking/setting
8485 // of bits in Status Register B, by setting Reg B to
8486 // a few values and getting its value after INT 1A was called.
8487 //
8488 // try#1 try#2 try#3
8489 // before 1111 1101 0111 1101 0000 0000
8490 // after 0110 0010 0110 0010 0000 0010
8491 //
8492 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8493 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8494 if (rtc_updating()) {
8495 init_rtc();
8496 // fall through as if an update were not in progress
8497 }
8498 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8499 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8500 outb_cmos(0x04, regs.u.r8.ch); // Hours
8501 // Set Daylight Savings time enabled bit to requested value
8502 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8503 // (reg B already selected)
8504 outb_cmos(0x0b, val8);
8505 regs.u.r8.ah = 0;
8506 regs.u.r8.al = val8; // val last written to Reg B
8507 ClearCF(iret_addr.flags); // OK
8508 break;
8509
8510 case 4: // Read CMOS Date
8511 regs.u.r8.ah = 0;
8512 if (rtc_updating()) {
8513 SetCF(iret_addr.flags);
8514 break;
8515 }
8516 regs.u.r8.cl = inb_cmos(0x09); // Year
8517 regs.u.r8.dh = inb_cmos(0x08); // Month
8518 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8519 regs.u.r8.ch = inb_cmos(0x32); // Century
8520 regs.u.r8.al = regs.u.r8.ch;
8521 ClearCF(iret_addr.flags); // OK
8522 break;
8523
8524 case 5: // Set CMOS Date
8525 // Using a debugger, I notice the following masking/setting
8526 // of bits in Status Register B, by setting Reg B to
8527 // a few values and getting its value after INT 1A was called.
8528 //
8529 // try#1 try#2 try#3 try#4
8530 // before 1111 1101 0111 1101 0000 0010 0000 0000
8531 // after 0110 1101 0111 1101 0000 0010 0000 0000
8532 //
8533 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8534 // My assumption: RegB = (RegB & 01111111b)
8535 if (rtc_updating()) {
8536 init_rtc();
8537 SetCF(iret_addr.flags);
8538 break;
8539 }
8540 outb_cmos(0x09, regs.u.r8.cl); // Year
8541 outb_cmos(0x08, regs.u.r8.dh); // Month
8542 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8543 outb_cmos(0x32, regs.u.r8.ch); // Century
8544 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8545 outb_cmos(0x0b, val8);
8546 regs.u.r8.ah = 0;
8547 regs.u.r8.al = val8; // AL = val last written to Reg B
8548 ClearCF(iret_addr.flags); // OK
8549 break;
8550
8551 case 6: // Set Alarm Time in CMOS
8552 // Using a debugger, I notice the following masking/setting
8553 // of bits in Status Register B, by setting Reg B to
8554 // a few values and getting its value after INT 1A was called.
8555 //
8556 // try#1 try#2 try#3
8557 // before 1101 1111 0101 1111 0000 0000
8558 // after 0110 1111 0111 1111 0010 0000
8559 //
8560 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8561 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8562 val8 = inb_cmos(0x0b); // Get Status Reg B
8563 regs.u.r16.ax = 0;
8564 if (val8 & 0x20) {
8565 // Alarm interrupt enabled already
8566 SetCF(iret_addr.flags); // Error: alarm in use
8567 break;
8568 }
8569 if (rtc_updating()) {
8570 init_rtc();
8571 // fall through as if an update were not in progress
8572 }
8573 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8574 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8575 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8576 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8577 // enable Status Reg B alarm bit, clear halt clock bit
8578 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8579 ClearCF(iret_addr.flags); // OK
8580 break;
8581
8582 case 7: // Turn off Alarm
8583 // Using a debugger, I notice the following masking/setting
8584 // of bits in Status Register B, by setting Reg B to
8585 // a few values and getting its value after INT 1A was called.
8586 //
8587 // try#1 try#2 try#3 try#4
8588 // before 1111 1101 0111 1101 0010 0000 0010 0010
8589 // after 0100 0101 0101 0101 0000 0000 0000 0010
8590 //
8591 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8592 // My assumption: RegB = (RegB & 01010111b)
8593 val8 = inb_cmos(0x0b); // Get Status Reg B
8594 // clear clock-halt bit, disable alarm bit
8595 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8596 regs.u.r8.ah = 0;
8597 regs.u.r8.al = val8; // val last written to Reg B
8598 ClearCF(iret_addr.flags); // OK
8599 break;
8600#if BX_PCIBIOS
8601 case 0xb1:
8602 // real mode PCI BIOS functions now handled in assembler code
8603 // this C code handles the error code for information only
8604 if (regs.u.r8.bl == 0xff) {
8605 BX_INFO("PCI BIOS: PCI not present\n");
8606 } else if (regs.u.r8.bl == 0x81) {
8607 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8608 } else if (regs.u.r8.bl == 0x83) {
8609 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8610 } else if (regs.u.r8.bl == 0x86) {
8611 if (regs.u.r8.al == 0x02) {
8612 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8613 } else {
8614 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);
8615 }
8616 }
8617 regs.u.r8.ah = regs.u.r8.bl;
8618 SetCF(iret_addr.flags);
8619 break;
8620#endif
8621
8622 default:
8623 SetCF(iret_addr.flags); // Unsupported
8624 }
8625}
8626
8627 void
8628int70_function(regs, ds, iret_addr)
8629 pusha_regs_t regs; // regs pushed from PUSHA instruction
8630 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8631 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8632{
8633 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8634 Bit8u registerB = 0, registerC = 0;
8635
8636 // Check which modes are enabled and have occurred.
8637 registerB = inb_cmos( 0xB );
8638 registerC = inb_cmos( 0xC );
8639
8640 if( ( registerB & 0x60 ) != 0 ) {
8641 if( ( registerC & 0x20 ) != 0 ) {
8642 // Handle Alarm Interrupt.
8643ASM_START
8644 sti
8645 int #0x4a
8646 cli
8647ASM_END
8648 }
8649 if( ( registerC & 0x40 ) != 0 ) {
8650 // Handle Periodic Interrupt.
8651
8652 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8653 // Wait Interval (Int 15, AH=83) active.
8654 Bit32u time, toggle;
8655
8656 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8657 if( time < 0x3D1 ) {
8658 // Done waiting.
8659 Bit16u segment, offset;
8660
8661 segment = read_word( 0x40, 0x98 );
8662 offset = read_word( 0x40, 0x9A );
8663 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8664 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8665 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8666 } else {
8667 // Continue waiting.
8668 time -= 0x3D1;
8669 write_dword( 0x40, 0x9C, time );
8670 }
8671 }
8672 }
8673 }
8674
8675ASM_START
8676 call eoi_both_pics
8677ASM_END
8678}
8679
8680 void
8681dummy_isr_function(regs, ds, iret_addr)
8682 pusha_regs_t regs; // regs pushed from PUSHA instruction
8683 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8684 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8685{
8686 // Interrupt handler for unexpected hardware interrupts. We have to clear
8687 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8688 // and all hell will break loose! This routine also masks the unexpected
8689 // interrupt so it will generally be called only once for each unexpected
8690 // interrupt level.
8691 Bit8u isrA, isrB, imr, last_int = 0xFF;
8692
8693 outb( 0x20, 0x0B );
8694 isrA = inb( 0x20 );
8695 if (isrA) {
8696 outb( 0xA0, 0x0B );
8697 isrB = inb( 0xA0 );
8698 if (isrB) {
8699 imr = inb( 0xA1 );
8700 outb( 0xA1, imr | isrB ); // Mask this interrupt
8701 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8702 } else {
8703 imr = inb( 0x21 );
8704 isrA &= 0xFB; // Never mask the cascade interrupt
8705 outb( 0x21, imr | isrA); // Mask this interrupt
8706 }
8707 outb( 0x20, 0x20 ); // Send EOI on master PIC
8708 last_int = isrA;
8709 }
8710 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8711}
8712
8713ASM_START
8714;------------------------------------------
8715;- INT74h : PS/2 mouse hardware interrupt -
8716;------------------------------------------
8717int74_handler:
8718 sti
8719 pusha
8720 push ds ;; save DS
8721 push #0x00 ;; placeholder for status
8722 push #0x00 ;; placeholder for X
8723 push #0x00 ;; placeholder for Y
8724 push #0x00 ;; placeholder for Z
8725 push #0x00 ;; placeholder for make_far_call boolean
8726 call _int74_function
8727 pop cx ;; remove make_far_call from stack
8728 jcxz int74_done
8729
8730 ;; make far call to EBDA:0022
8731 push #0x00
8732 pop ds
8733 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8734 pop ds
8735 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8736 call far ptr[0x22]
8737int74_done:
8738 cli
8739 call eoi_both_pics
8740 add sp, #8 ;; pop status, x, y, z
8741
8742 pop ds ;; restore DS
8743 popa
8744 iret
8745
8746
8747;; This will perform an IRET, but will retain value of current CF
8748;; by altering flags on stack. Better than RETF #02.
8749iret_modify_cf:
8750 jc carry_set
8751 push bp
8752 mov bp, sp
8753 and BYTE [bp + 0x06], #0xfe
8754 pop bp
8755 iret
8756carry_set:
8757 push bp
8758 mov bp, sp
8759 or BYTE [bp + 0x06], #0x01
8760 pop bp
8761 iret
8762
8763
8764;----------------------
8765;- INT13h (relocated) -
8766;----------------------
8767;
8768; int13_relocated is a little bit messed up since I played with it
8769; I have to rewrite it:
8770; - call a function that detect which function to call
8771; - make all called C function get the same parameters list
8772;
8773int13_relocated:
8774
8775#if BX_ELTORITO_BOOT
8776 ;; check for an eltorito function
8777 cmp ah,#0x4a
8778 jb int13_not_eltorito
8779 cmp ah,#0x4d
8780 ja int13_not_eltorito
8781
8782 pusha
8783 push es
8784 push ds
8785 push ss
8786 pop ds
8787
8788 push #int13_out
8789 jmp _int13_eltorito ;; ELDX not used
8790
8791int13_not_eltorito:
8792 push ax
8793 push bx
8794 push cx
8795 push dx
8796
8797 ;; check if emulation active
8798 call _cdemu_isactive
8799 cmp al,#0x00
8800 je int13_cdemu_inactive
8801
8802 ;; check if access to the emulated drive
8803 call _cdemu_emulated_drive
8804 pop dx
8805 push dx
8806 cmp al,dl ;; int13 on emulated drive
8807 jne int13_nocdemu
8808
8809 pop dx
8810 pop cx
8811 pop bx
8812 pop ax
8813
8814 pusha
8815 push es
8816 push ds
8817 push ss
8818 pop ds
8819
8820 push #int13_out
8821 jmp _int13_cdemu ;; ELDX not used
8822
8823int13_nocdemu:
8824 and dl,#0xE0 ;; mask to get device class, including cdroms
8825 cmp al,dl ;; al is 0x00 or 0x80
8826 jne int13_cdemu_inactive ;; inactive for device class
8827
8828 pop dx
8829 pop cx
8830 pop bx
8831 pop ax
8832
8833 push ax
8834 push cx
8835 push dx
8836 push bx
8837
8838 dec dl ;; real drive is dl - 1
8839 jmp int13_legacy
8840
8841int13_cdemu_inactive:
8842 pop dx
8843 pop cx
8844 pop bx
8845 pop ax
8846
8847#endif // BX_ELTORITO_BOOT
8848
8849int13_noeltorito:
8850
8851 push ax
8852 push cx
8853 push dx
8854 push bx
8855
8856int13_legacy:
8857
8858 push dx ;; push eltorito value of dx instead of sp
8859
8860 push bp
8861 push si
8862 push di
8863
8864 push es
8865 push ds
8866 push ss
8867 pop ds
8868
8869 ;; now the 16-bit registers can be restored with:
8870 ;; pop ds; pop es; popa; iret
8871 ;; arguments passed to functions should be
8872 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8873
8874 test dl, #0x80
8875 jnz int13_notfloppy
8876
8877 push #int13_out
8878 jmp _int13_diskette_function
8879
8880int13_notfloppy:
8881
8882#if BX_USE_ATADRV
8883
8884 cmp dl, #0xE0
8885 jb int13_notcdrom
8886
8887 // ebx is modified: BSD 5.2.1 boot loader problem
8888 // someone should figure out which 32 bit register that actually are used
8889
8890 shr ebx, #16
8891 push bx
8892
8893 call _int13_cdrom
8894
8895 pop bx
8896 shl ebx, #16
8897
8898 jmp int13_out
8899
8900int13_notcdrom:
8901
8902#endif
8903
8904int13_disk:
8905 ;; int13_harddisk modifies high word of EAX
8906 shr eax, #16
8907 push ax
8908 call _int13_harddisk
8909 pop ax
8910 shl eax, #16
8911
8912int13_out:
8913 pop ds
8914 pop es
8915 popa
8916 iret
8917
8918
8919;----------
8920;- INT18h -
8921;----------
8922int18_handler: ;; Boot Failure routing
8923 call _int18_panic_msg
8924 hlt
8925 iret
8926
8927;----------
8928;- INT19h -
8929;----------
8930int19_relocated: ;; Boot function, relocated
8931
8932#ifdef VBOX
8933 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
8934 // just to try booting from the configured drives. All BIOS variables and
8935 // interrupt vectors need to be reset, otherwise strange things may happen.
8936 // The approach used is faking a warm reboot (which just skips showing the
8937 // logo), which is a bit more than what we need, but hey, it's fast.
8938 mov bp, sp
8939 mov ax, 2[bp]
8940 cmp ax, #0xf000
8941 jz bios_initiated_boot
8942 xor ax, ax
8943 mov ds, ax
8944 mov ax, #0x1234
8945 mov 0x472, ax
8946 jmp post
8947bios_initiated_boot:
8948#endif /* VBOX */
8949
8950 ;; int19 was beginning to be really complex, so now it
8951 ;; just calls an C function, that does the work
8952 ;; it returns in BL the boot drive, and in AX the boot segment
8953 ;; the boot segment will be 0x0000 if something has failed
8954
8955 push bp
8956 mov bp, sp
8957
8958 ;; drop ds
8959 xor ax, ax
8960 mov ds, ax
8961
8962 ;; 1st boot device
8963 mov ax, #0x0001
8964 push ax
8965 call _int19_function
8966 inc sp
8967 inc sp
8968 ;; bl contains the boot drive
8969 ;; ax contains the boot segment or 0 if failure
8970
8971 test ax, ax ;; if ax is 0 try next boot device
8972 jnz boot_setup
8973
8974 ;; 2nd boot device
8975 mov ax, #0x0002
8976 push ax
8977 call _int19_function
8978 inc sp
8979 inc sp
8980 test ax, ax ;; if ax is 0 try next boot device
8981 jnz boot_setup
8982
8983 ;; 3rd boot device
8984 mov ax, #0x0003
8985 push ax
8986 call _int19_function
8987 inc sp
8988 inc sp
8989#ifdef VBOX
8990 test ax, ax ;; if ax is 0 try next boot device
8991 jnz boot_setup
8992
8993 ;; 4th boot device
8994 mov ax, #0x0004
8995 push ax
8996 call _int19_function
8997 inc sp
8998 inc sp
8999#endif /* VBOX */
9000 test ax, ax ;; if ax is 0 call int18
9001 jz int18_handler
9002
9003boot_setup:
9004 mov dl, bl ;; set drive so guest os find it
9005 shl eax, #0x04 ;; convert seg to ip
9006 mov 2[bp], ax ;; set ip
9007
9008 shr eax, #0x04 ;; get cs back
9009 and ax, #0xF000 ;; remove what went in ip
9010 mov 4[bp], ax ;; set cs
9011 xor ax, ax
9012 mov es, ax ;; set es to zero fixes [ 549815 ]
9013 mov [bp], ax ;; set bp to zero
9014 mov ax, #0xaa55 ;; set ok flag
9015
9016 pop bp
9017 iret ;; Beam me up Scotty
9018
9019;----------
9020;- INT1Ch -
9021;----------
9022int1c_handler: ;; User Timer Tick
9023 iret
9024
9025
9026;----------------------
9027;- POST: Floppy Drive -
9028;----------------------
9029floppy_drive_post:
9030 xor ax, ax
9031 mov ds, ax
9032
9033 mov al, #0x00
9034 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9035
9036 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9037
9038 mov 0x0440, al ;; diskette motor timeout counter: not active
9039 mov 0x0441, al ;; diskette controller status return code
9040
9041 mov 0x0442, al ;; disk & diskette controller status register 0
9042 mov 0x0443, al ;; diskette controller status register 1
9043 mov 0x0444, al ;; diskette controller status register 2
9044 mov 0x0445, al ;; diskette controller cylinder number
9045 mov 0x0446, al ;; diskette controller head number
9046 mov 0x0447, al ;; diskette controller sector number
9047 mov 0x0448, al ;; diskette controller bytes written
9048
9049 mov 0x048b, al ;; diskette configuration data
9050
9051 ;; -----------------------------------------------------------------
9052 ;; (048F) diskette controller information
9053 ;;
9054 mov al, #0x10 ;; get CMOS diskette drive type
9055 out 0x70, AL
9056 in AL, 0x71
9057 mov ah, al ;; save byte to AH
9058
9059look_drive0:
9060 shr al, #4 ;; look at top 4 bits for drive 0
9061 jz f0_missing ;; jump if no drive0
9062 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9063 jmp look_drive1
9064f0_missing:
9065 mov bl, #0x00 ;; no drive0
9066
9067look_drive1:
9068 mov al, ah ;; restore from AH
9069 and al, #0x0f ;; look at bottom 4 bits for drive 1
9070 jz f1_missing ;; jump if no drive1
9071 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9072f1_missing:
9073 ;; leave high bits in BL zerod
9074 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9075 ;; -----------------------------------------------------------------
9076
9077 mov al, #0x00
9078 mov 0x0490, al ;; diskette 0 media state
9079 mov 0x0491, al ;; diskette 1 media state
9080
9081 ;; diskette 0,1 operational starting state
9082 ;; drive type has not been determined,
9083 ;; has no changed detection line
9084 mov 0x0492, al
9085 mov 0x0493, al
9086
9087 mov 0x0494, al ;; diskette 0 current cylinder
9088 mov 0x0495, al ;; diskette 1 current cylinder
9089
9090 mov al, #0x02
9091 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9092
9093 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9094 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9095 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9096
9097 ret
9098
9099
9100;--------------------
9101;- POST: HARD DRIVE -
9102;--------------------
9103; relocated here because the primary POST area isnt big enough.
9104hard_drive_post:
9105 // IRQ 14 = INT 76h
9106 // INT 76h calls INT 15h function ax=9100
9107
9108 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9109 mov dx, #0x03f6
9110 out dx, al
9111
9112 xor ax, ax
9113 mov ds, ax
9114 mov 0x0474, al /* hard disk status of last operation */
9115 mov 0x0477, al /* hard disk port offset (XT only ???) */
9116 mov 0x048c, al /* hard disk status register */
9117 mov 0x048d, al /* hard disk error register */
9118 mov 0x048e, al /* hard disk task complete flag */
9119 mov al, #0x01
9120 mov 0x0475, al /* hard disk number attached */
9121 mov al, #0xc0
9122 mov 0x0476, al /* hard disk control byte */
9123 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9124 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9125 ;; INT 41h: hard disk 0 configuration pointer
9126 ;; INT 46h: hard disk 1 configuration pointer
9127 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9128 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9129
9130#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9131 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9132 mov al, #0x12
9133 out #0x70, al
9134 in al, #0x71
9135 and al, #0xf0
9136 cmp al, #0xf0
9137 je post_d0_extended
9138 jmp check_for_hd1
9139post_d0_extended:
9140 mov al, #0x19
9141 out #0x70, al
9142 in al, #0x71
9143 cmp al, #47 ;; decimal 47 - user definable
9144 je post_d0_type47
9145 HALT(__LINE__)
9146post_d0_type47:
9147 ;; CMOS purpose param table offset
9148 ;; 1b cylinders low 0
9149 ;; 1c cylinders high 1
9150 ;; 1d heads 2
9151 ;; 1e write pre-comp low 5
9152 ;; 1f write pre-comp high 6
9153 ;; 20 retries/bad map/heads>8 8
9154 ;; 21 landing zone low C
9155 ;; 22 landing zone high D
9156 ;; 23 sectors/track E
9157
9158 mov ax, #EBDA_SEG
9159 mov ds, ax
9160
9161 ;;; Filling EBDA table for hard disk 0.
9162 mov al, #0x1f
9163 out #0x70, al
9164 in al, #0x71
9165 mov ah, al
9166 mov al, #0x1e
9167 out #0x70, al
9168 in al, #0x71
9169 mov (0x003d + 0x05), ax ;; write precomp word
9170
9171 mov al, #0x20
9172 out #0x70, al
9173 in al, #0x71
9174 mov (0x003d + 0x08), al ;; drive control byte
9175
9176 mov al, #0x22
9177 out #0x70, al
9178 in al, #0x71
9179 mov ah, al
9180 mov al, #0x21
9181 out #0x70, al
9182 in al, #0x71
9183 mov (0x003d + 0x0C), ax ;; landing zone word
9184
9185 mov al, #0x1c ;; get cylinders word in AX
9186 out #0x70, al
9187 in al, #0x71 ;; high byte
9188 mov ah, al
9189 mov al, #0x1b
9190 out #0x70, al
9191 in al, #0x71 ;; low byte
9192 mov bx, ax ;; BX = cylinders
9193
9194 mov al, #0x1d
9195 out #0x70, al
9196 in al, #0x71
9197 mov cl, al ;; CL = heads
9198
9199 mov al, #0x23
9200 out #0x70, al
9201 in al, #0x71
9202 mov dl, al ;; DL = sectors
9203
9204 cmp bx, #1024
9205 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9206
9207hd0_post_physical_chs:
9208 ;; no logical CHS mapping used, just physical CHS
9209 ;; use Standard Fixed Disk Parameter Table (FDPT)
9210 mov (0x003d + 0x00), bx ;; number of physical cylinders
9211 mov (0x003d + 0x02), cl ;; number of physical heads
9212 mov (0x003d + 0x0E), dl ;; number of physical sectors
9213 jmp check_for_hd1
9214
9215hd0_post_logical_chs:
9216 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9217 mov (0x003d + 0x09), bx ;; number of physical cylinders
9218 mov (0x003d + 0x0b), cl ;; number of physical heads
9219 mov (0x003d + 0x04), dl ;; number of physical sectors
9220 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9221 mov al, #0xa0
9222 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9223
9224 cmp bx, #2048
9225 jnbe hd0_post_above_2048
9226 ;; 1024 < c <= 2048 cylinders
9227 shr bx, #0x01
9228 shl cl, #0x01
9229 jmp hd0_post_store_logical
9230
9231hd0_post_above_2048:
9232 cmp bx, #4096
9233 jnbe hd0_post_above_4096
9234 ;; 2048 < c <= 4096 cylinders
9235 shr bx, #0x02
9236 shl cl, #0x02
9237 jmp hd0_post_store_logical
9238
9239hd0_post_above_4096:
9240 cmp bx, #8192
9241 jnbe hd0_post_above_8192
9242 ;; 4096 < c <= 8192 cylinders
9243 shr bx, #0x03
9244 shl cl, #0x03
9245 jmp hd0_post_store_logical
9246
9247hd0_post_above_8192:
9248 ;; 8192 < c <= 16384 cylinders
9249 shr bx, #0x04
9250 shl cl, #0x04
9251
9252hd0_post_store_logical:
9253 mov (0x003d + 0x00), bx ;; number of physical cylinders
9254 mov (0x003d + 0x02), cl ;; number of physical heads
9255 ;; checksum
9256 mov cl, #0x0f ;; repeat count
9257 mov si, #0x003d ;; offset to disk0 FDPT
9258 mov al, #0x00 ;; sum
9259hd0_post_checksum_loop:
9260 add al, [si]
9261 inc si
9262 dec cl
9263 jnz hd0_post_checksum_loop
9264 not al ;; now take 2s complement
9265 inc al
9266 mov [si], al
9267;;; Done filling EBDA table for hard disk 0.
9268
9269
9270check_for_hd1:
9271 ;; is there really a second hard disk? if not, return now
9272 mov al, #0x12
9273 out #0x70, al
9274 in al, #0x71
9275 and al, #0x0f
9276 jnz post_d1_exists
9277 ret
9278post_d1_exists:
9279 ;; check that the hd type is really 0x0f.
9280 cmp al, #0x0f
9281 jz post_d1_extended
9282 HALT(__LINE__)
9283post_d1_extended:
9284 ;; check that the extended type is 47 - user definable
9285 mov al, #0x1a
9286 out #0x70, al
9287 in al, #0x71
9288 cmp al, #47 ;; decimal 47 - user definable
9289 je post_d1_type47
9290 HALT(__LINE__)
9291post_d1_type47:
9292 ;; Table for disk1.
9293 ;; CMOS purpose param table offset
9294 ;; 0x24 cylinders low 0
9295 ;; 0x25 cylinders high 1
9296 ;; 0x26 heads 2
9297 ;; 0x27 write pre-comp low 5
9298 ;; 0x28 write pre-comp high 6
9299 ;; 0x29 heads>8 8
9300 ;; 0x2a landing zone low C
9301 ;; 0x2b landing zone high D
9302 ;; 0x2c sectors/track E
9303;;; Fill EBDA table for hard disk 1.
9304 mov ax, #EBDA_SEG
9305 mov ds, ax
9306 mov al, #0x28
9307 out #0x70, al
9308 in al, #0x71
9309 mov ah, al
9310 mov al, #0x27
9311 out #0x70, al
9312 in al, #0x71
9313 mov (0x004d + 0x05), ax ;; write precomp word
9314
9315 mov al, #0x29
9316 out #0x70, al
9317 in al, #0x71
9318 mov (0x004d + 0x08), al ;; drive control byte
9319
9320 mov al, #0x2b
9321 out #0x70, al
9322 in al, #0x71
9323 mov ah, al
9324 mov al, #0x2a
9325 out #0x70, al
9326 in al, #0x71
9327 mov (0x004d + 0x0C), ax ;; landing zone word
9328
9329 mov al, #0x25 ;; get cylinders word in AX
9330 out #0x70, al
9331 in al, #0x71 ;; high byte
9332 mov ah, al
9333 mov al, #0x24
9334 out #0x70, al
9335 in al, #0x71 ;; low byte
9336 mov bx, ax ;; BX = cylinders
9337
9338 mov al, #0x26
9339 out #0x70, al
9340 in al, #0x71
9341 mov cl, al ;; CL = heads
9342
9343 mov al, #0x2c
9344 out #0x70, al
9345 in al, #0x71
9346 mov dl, al ;; DL = sectors
9347
9348 cmp bx, #1024
9349 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9350
9351hd1_post_physical_chs:
9352 ;; no logical CHS mapping used, just physical CHS
9353 ;; use Standard Fixed Disk Parameter Table (FDPT)
9354 mov (0x004d + 0x00), bx ;; number of physical cylinders
9355 mov (0x004d + 0x02), cl ;; number of physical heads
9356 mov (0x004d + 0x0E), dl ;; number of physical sectors
9357 ret
9358
9359hd1_post_logical_chs:
9360 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9361 mov (0x004d + 0x09), bx ;; number of physical cylinders
9362 mov (0x004d + 0x0b), cl ;; number of physical heads
9363 mov (0x004d + 0x04), dl ;; number of physical sectors
9364 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9365 mov al, #0xa0
9366 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9367
9368 cmp bx, #2048
9369 jnbe hd1_post_above_2048
9370 ;; 1024 < c <= 2048 cylinders
9371 shr bx, #0x01
9372 shl cl, #0x01
9373 jmp hd1_post_store_logical
9374
9375hd1_post_above_2048:
9376 cmp bx, #4096
9377 jnbe hd1_post_above_4096
9378 ;; 2048 < c <= 4096 cylinders
9379 shr bx, #0x02
9380 shl cl, #0x02
9381 jmp hd1_post_store_logical
9382
9383hd1_post_above_4096:
9384 cmp bx, #8192
9385 jnbe hd1_post_above_8192
9386 ;; 4096 < c <= 8192 cylinders
9387 shr bx, #0x03
9388 shl cl, #0x03
9389 jmp hd1_post_store_logical
9390
9391hd1_post_above_8192:
9392 ;; 8192 < c <= 16384 cylinders
9393 shr bx, #0x04
9394 shl cl, #0x04
9395
9396hd1_post_store_logical:
9397 mov (0x004d + 0x00), bx ;; number of physical cylinders
9398 mov (0x004d + 0x02), cl ;; number of physical heads
9399 ;; checksum
9400 mov cl, #0x0f ;; repeat count
9401 mov si, #0x004d ;; offset to disk0 FDPT
9402 mov al, #0x00 ;; sum
9403hd1_post_checksum_loop:
9404 add al, [si]
9405 inc si
9406 dec cl
9407 jnz hd1_post_checksum_loop
9408 not al ;; now take 2s complement
9409 inc al
9410 mov [si], al
9411;;; Done filling EBDA table for hard disk 1.
9412#endif /* !VBOX */
9413
9414 ret
9415
9416;--------------------
9417;- POST: EBDA segment
9418;--------------------
9419; relocated here because the primary POST area isnt big enough.
9420; the SET_INT_VECTORs have nothing to do with EBDA but do not
9421; fit into the primary POST area either
9422ebda_post:
9423 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9424 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9425 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9426 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9427
9428#if BX_USE_EBDA
9429 mov ax, #EBDA_SEG
9430 mov ds, ax
9431 mov byte ptr [0x0], #EBDA_SIZE
9432#endif
9433 xor ax, ax ; mov EBDA seg into 40E
9434 mov ds, ax
9435 mov word ptr [0x40E], #EBDA_SEG
9436 ret;;
9437
9438;--------------------
9439;- POST: EOI + jmp via [0x40:67)
9440;--------------------
9441; relocated here because the primary POST area isnt big enough.
9442eoi_jmp_post:
9443 call eoi_both_pics
9444
9445 xor ax, ax
9446 mov ds, ax
9447
9448 jmp far ptr [0x467]
9449
9450
9451;--------------------
9452eoi_both_pics:
9453 mov al, #0x20
9454 out #0xA0, al ;; slave PIC EOI
9455eoi_master_pic:
9456 mov al, #0x20
9457 out #0x20, al ;; master PIC EOI
9458 ret
9459
9460;--------------------
9461BcdToBin:
9462 ;; in: AL in BCD format
9463 ;; out: AL in binary format, AH will always be 0
9464 ;; trashes BX
9465 mov bl, al
9466 and bl, #0x0f ;; bl has low digit
9467 shr al, #4 ;; al has high digit
9468 mov bh, #10
9469 mul al, bh ;; multiply high digit by 10 (result in AX)
9470 add al, bl ;; then add low digit
9471 ret
9472
9473;--------------------
9474timer_tick_post:
9475 ;; Setup the Timer Ticks Count (0x46C:dword) and
9476 ;; Timer Ticks Roller Flag (0x470:byte)
9477 ;; The Timer Ticks Count needs to be set according to
9478 ;; the current CMOS time, as if ticks have been occurring
9479 ;; at 18.2hz since midnight up to this point. Calculating
9480 ;; this is a little complicated. Here are the factors I gather
9481 ;; regarding this. 14,318,180 hz was the original clock speed,
9482 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9483 ;; at the time, or 4 to drive the CGA video adapter. The div3
9484 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9485 ;; the timer. With a maximum 16bit timer count, this is again
9486 ;; divided down by 65536 to 18.2hz.
9487 ;;
9488 ;; 14,318,180 Hz clock
9489 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9490 ;; /4 = 1,193,181 Hz fed to timer
9491 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9492 ;; 1 second = 18.20650736 ticks
9493 ;; 1 minute = 1092.390442 ticks
9494 ;; 1 hour = 65543.42651 ticks
9495 ;;
9496 ;; Given the values in the CMOS clock, one could calculate
9497 ;; the number of ticks by the following:
9498 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9499 ;; (BcdToBin(minutes) * 1092.3904)
9500 ;; (BcdToBin(hours) * 65543.427)
9501 ;; To get a little more accuracy, since Im using integer
9502 ;; arithmatic, I use:
9503 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9504 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9505 ;; (BcdToBin(hours) * 65543427) / 1000
9506
9507 ;; assuming DS=0000
9508
9509 ;; get CMOS seconds
9510 xor eax, eax ;; clear EAX
9511 mov al, #0x00
9512 out #0x70, al
9513 in al, #0x71 ;; AL has CMOS seconds in BCD
9514 call BcdToBin ;; EAX now has seconds in binary
9515 mov edx, #18206507
9516 mul eax, edx
9517 mov ebx, #1000000
9518 xor edx, edx
9519 div eax, ebx
9520 mov ecx, eax ;; ECX will accumulate total ticks
9521
9522 ;; get CMOS minutes
9523 xor eax, eax ;; clear EAX
9524 mov al, #0x02
9525 out #0x70, al
9526 in al, #0x71 ;; AL has CMOS minutes in BCD
9527 call BcdToBin ;; EAX now has minutes in binary
9528 mov edx, #10923904
9529 mul eax, edx
9530 mov ebx, #10000
9531 xor edx, edx
9532 div eax, ebx
9533 add ecx, eax ;; add to total ticks
9534
9535 ;; get CMOS hours
9536 xor eax, eax ;; clear EAX
9537 mov al, #0x04
9538 out #0x70, al
9539 in al, #0x71 ;; AL has CMOS hours in BCD
9540 call BcdToBin ;; EAX now has hours in binary
9541 mov edx, #65543427
9542 mul eax, edx
9543 mov ebx, #1000
9544 xor edx, edx
9545 div eax, ebx
9546 add ecx, eax ;; add to total ticks
9547
9548 mov 0x46C, ecx ;; Timer Ticks Count
9549 xor al, al
9550 mov 0x470, al ;; Timer Ticks Rollover Flag
9551 ret
9552
9553;--------------------
9554int76_handler:
9555 ;; record completion in BIOS task complete flag
9556 push ax
9557 push ds
9558 mov ax, #0x0040
9559 mov ds, ax
9560 mov 0x008E, #0xff
9561 call eoi_both_pics
9562 pop ds
9563 pop ax
9564 iret
9565
9566;--------------------
9567#ifdef VBOX
9568init_pic:
9569 ;; init PIC
9570 mov al, #0x11 ; send initialisation commands
9571 out 0x20, al
9572 out 0xa0, al
9573 mov al, #0x08
9574 out 0x21, al
9575 mov al, #0x70
9576 out 0xa1, al
9577 mov al, #0x04
9578 out 0x21, al
9579 mov al, #0x02
9580 out 0xa1, al
9581 mov al, #0x01
9582 out 0x21, al
9583 out 0xa1, al
9584 mov al, #0xb8
9585 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9586#if BX_USE_PS2_MOUSE
9587 mov al, #0x8f
9588#else
9589 mov al, #0x9f
9590#endif
9591 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9592 ret
9593#endif /* VBOX */
9594
9595;--------------------
9596#if BX_APM
9597
9598use32 386
9599#define APM_PROT32
9600#include "apmbios.S"
9601
9602use16 386
9603#define APM_PROT16
9604#include "apmbios.S"
9605
9606#define APM_REAL
9607#include "apmbios.S"
9608
9609#endif
9610
9611;--------------------
9612#if BX_PCIBIOS
9613use32 386
9614.align 16
9615bios32_structure:
9616 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9617 dw bios32_entry_point, 0xf ;; 32 bit physical address
9618 db 0 ;; revision level
9619 ;; length in paragraphs and checksum stored in a word to prevent errors
9620 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9621 & 0xff) << 8) + 0x01
9622 db 0,0,0,0,0 ;; reserved
9623
9624.align 16
9625bios32_entry_point:
9626 pushfd
9627 cmp eax, #0x49435024 ;; "$PCI"
9628 jne unknown_service
9629 mov eax, #0x80000000
9630 mov dx, #0x0cf8
9631 out dx, eax
9632 mov dx, #0x0cfc
9633 in eax, dx
9634#ifdef PCI_FIXED_HOST_BRIDGE
9635 cmp eax, #PCI_FIXED_HOST_BRIDGE
9636 jne unknown_service
9637#else
9638 ;; say ok if a device is present
9639 cmp eax, #0xffffffff
9640 je unknown_service
9641#endif
9642 mov ebx, #0x000f0000
9643 mov ecx, #0
9644 mov edx, #pcibios_protected
9645 xor al, al
9646 jmp bios32_end
9647unknown_service:
9648 mov al, #0x80
9649bios32_end:
9650#ifdef BX_QEMU
9651 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9652#endif
9653 popfd
9654 retf
9655
9656.align 16
9657pcibios_protected:
9658 pushfd
9659 cli
9660 push esi
9661 push edi
9662 cmp al, #0x01 ;; installation check
9663 jne pci_pro_f02
9664 mov bx, #0x0210
9665 mov cx, #0
9666 mov edx, #0x20494350 ;; "PCI "
9667 mov al, #0x01
9668 jmp pci_pro_ok
9669pci_pro_f02: ;; find pci device
9670 cmp al, #0x02
9671 jne pci_pro_f03
9672 shl ecx, #16
9673 mov cx, dx
9674 xor bx, bx
9675 mov di, #0x00
9676pci_pro_devloop:
9677 call pci_pro_select_reg
9678 mov dx, #0x0cfc
9679 in eax, dx
9680 cmp eax, ecx
9681 jne pci_pro_nextdev
9682 cmp si, #0
9683 je pci_pro_ok
9684 dec si
9685pci_pro_nextdev:
9686 inc bx
9687 cmp bx, #0x0100
9688 jne pci_pro_devloop
9689 mov ah, #0x86
9690 jmp pci_pro_fail
9691pci_pro_f03: ;; find class code
9692 cmp al, #0x03
9693 jne pci_pro_f08
9694 xor bx, bx
9695 mov di, #0x08
9696pci_pro_devloop2:
9697 call pci_pro_select_reg
9698 mov dx, #0x0cfc
9699 in eax, dx
9700 shr eax, #8
9701 cmp eax, ecx
9702 jne pci_pro_nextdev2
9703 cmp si, #0
9704 je pci_pro_ok
9705 dec si
9706pci_pro_nextdev2:
9707 inc bx
9708 cmp bx, #0x0100
9709 jne pci_pro_devloop2
9710 mov ah, #0x86
9711 jmp pci_pro_fail
9712pci_pro_f08: ;; read configuration byte
9713 cmp al, #0x08
9714 jne pci_pro_f09
9715 call pci_pro_select_reg
9716 push edx
9717 mov dx, di
9718 and dx, #0x03
9719 add dx, #0x0cfc
9720 in al, dx
9721 pop edx
9722 mov cl, al
9723 jmp pci_pro_ok
9724pci_pro_f09: ;; read configuration word
9725 cmp al, #0x09
9726 jne pci_pro_f0a
9727 call pci_pro_select_reg
9728 push edx
9729 mov dx, di
9730 and dx, #0x02
9731 add dx, #0x0cfc
9732 in ax, dx
9733 pop edx
9734 mov cx, ax
9735 jmp pci_pro_ok
9736pci_pro_f0a: ;; read configuration dword
9737 cmp al, #0x0a
9738 jne pci_pro_f0b
9739 call pci_pro_select_reg
9740 push edx
9741 mov dx, #0x0cfc
9742 in eax, dx
9743 pop edx
9744 mov ecx, eax
9745 jmp pci_pro_ok
9746pci_pro_f0b: ;; write configuration byte
9747 cmp al, #0x0b
9748 jne pci_pro_f0c
9749 call pci_pro_select_reg
9750 push edx
9751 mov dx, di
9752 and dx, #0x03
9753 add dx, #0x0cfc
9754 mov al, cl
9755 out dx, al
9756 pop edx
9757 jmp pci_pro_ok
9758pci_pro_f0c: ;; write configuration word
9759 cmp al, #0x0c
9760 jne pci_pro_f0d
9761 call pci_pro_select_reg
9762 push edx
9763 mov dx, di
9764 and dx, #0x02
9765 add dx, #0x0cfc
9766 mov ax, cx
9767 out dx, ax
9768 pop edx
9769 jmp pci_pro_ok
9770pci_pro_f0d: ;; write configuration dword
9771 cmp al, #0x0d
9772 jne pci_pro_unknown
9773 call pci_pro_select_reg
9774 push edx
9775 mov dx, #0x0cfc
9776 mov eax, ecx
9777 out dx, eax
9778 pop edx
9779 jmp pci_pro_ok
9780pci_pro_unknown:
9781 mov ah, #0x81
9782pci_pro_fail:
9783 pop edi
9784 pop esi
9785#ifdef BX_QEMU
9786 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9787#endif
9788 popfd
9789 stc
9790 retf
9791pci_pro_ok:
9792 xor ah, ah
9793 pop edi
9794 pop esi
9795#ifdef BX_QEMU
9796 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9797#endif
9798 popfd
9799 clc
9800 retf
9801
9802pci_pro_select_reg:
9803 push edx
9804 mov eax, #0x800000
9805 mov ax, bx
9806 shl eax, #8
9807 and di, #0xff
9808 or ax, di
9809 and al, #0xfc
9810 mov dx, #0x0cf8
9811 out dx, eax
9812 pop edx
9813 ret
9814
9815use16 386
9816
9817pcibios_real:
9818 push eax
9819 push dx
9820 mov eax, #0x80000000
9821 mov dx, #0x0cf8
9822 out dx, eax
9823 mov dx, #0x0cfc
9824 in eax, dx
9825#ifdef PCI_FIXED_HOST_BRIDGE
9826 cmp eax, #PCI_FIXED_HOST_BRIDGE
9827 je pci_present
9828#else
9829 ;; say ok if a device is present
9830 cmp eax, #0xffffffff
9831 jne pci_present
9832#endif
9833 pop dx
9834 pop eax
9835 mov ah, #0xff
9836 stc
9837 ret
9838pci_present:
9839 pop dx
9840 pop eax
9841 cmp al, #0x01 ;; installation check
9842 jne pci_real_f02
9843 mov ax, #0x0001
9844 mov bx, #0x0210
9845 mov cx, #0
9846 mov edx, #0x20494350 ;; "PCI "
9847 mov edi, #0xf0000
9848 mov di, #pcibios_protected
9849 clc
9850 ret
9851pci_real_f02: ;; find pci device
9852 push esi
9853 push edi
9854 cmp al, #0x02
9855 jne pci_real_f03
9856 shl ecx, #16
9857 mov cx, dx
9858 xor bx, bx
9859 mov di, #0x00
9860pci_real_devloop:
9861 call pci_real_select_reg
9862 mov dx, #0x0cfc
9863 in eax, dx
9864 cmp eax, ecx
9865 jne pci_real_nextdev
9866 cmp si, #0
9867 je pci_real_ok
9868 dec si
9869pci_real_nextdev:
9870 inc bx
9871 cmp bx, #0x0100
9872 jne pci_real_devloop
9873 mov dx, cx
9874 shr ecx, #16
9875 mov ax, #0x8602
9876 jmp pci_real_fail
9877pci_real_f03: ;; find class code
9878 cmp al, #0x03
9879 jne pci_real_f08
9880 xor bx, bx
9881 mov di, #0x08
9882pci_real_devloop2:
9883 call pci_real_select_reg
9884 mov dx, #0x0cfc
9885 in eax, dx
9886 shr eax, #8
9887 cmp eax, ecx
9888 jne pci_real_nextdev2
9889 cmp si, #0
9890 je pci_real_ok
9891 dec si
9892pci_real_nextdev2:
9893 inc bx
9894 cmp bx, #0x0100
9895 jne pci_real_devloop2
9896 mov dx, cx
9897 shr ecx, #16
9898 mov ax, #0x8603
9899 jmp pci_real_fail
9900pci_real_f08: ;; read configuration byte
9901 cmp al, #0x08
9902 jne pci_real_f09
9903 call pci_real_select_reg
9904 push dx
9905 mov dx, di
9906 and dx, #0x03
9907 add dx, #0x0cfc
9908 in al, dx
9909 pop dx
9910 mov cl, al
9911 jmp pci_real_ok
9912pci_real_f09: ;; read configuration word
9913 cmp al, #0x09
9914 jne pci_real_f0a
9915 call pci_real_select_reg
9916 push dx
9917 mov dx, di
9918 and dx, #0x02
9919 add dx, #0x0cfc
9920 in ax, dx
9921 pop dx
9922 mov cx, ax
9923 jmp pci_real_ok
9924pci_real_f0a: ;; read configuration dword
9925 cmp al, #0x0a
9926 jne pci_real_f0b
9927 call pci_real_select_reg
9928 push dx
9929 mov dx, #0x0cfc
9930 in eax, dx
9931 pop dx
9932 mov ecx, eax
9933 jmp pci_real_ok
9934pci_real_f0b: ;; write configuration byte
9935 cmp al, #0x0b
9936 jne pci_real_f0c
9937 call pci_real_select_reg
9938 push dx
9939 mov dx, di
9940 and dx, #0x03
9941 add dx, #0x0cfc
9942 mov al, cl
9943 out dx, al
9944 pop dx
9945 jmp pci_real_ok
9946pci_real_f0c: ;; write configuration word
9947 cmp al, #0x0c
9948 jne pci_real_f0d
9949 call pci_real_select_reg
9950 push dx
9951 mov dx, di
9952 and dx, #0x02
9953 add dx, #0x0cfc
9954 mov ax, cx
9955 out dx, ax
9956 pop dx
9957 jmp pci_real_ok
9958pci_real_f0d: ;; write configuration dword
9959 cmp al, #0x0d
9960 jne pci_real_f0e
9961 call pci_real_select_reg
9962 push dx
9963 mov dx, #0x0cfc
9964 mov eax, ecx
9965 out dx, eax
9966 pop dx
9967 jmp pci_real_ok
9968pci_real_f0e: ;; get irq routing options
9969 cmp al, #0x0e
9970 jne pci_real_unknown
9971 SEG ES
9972 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9973 jb pci_real_too_small
9974 SEG ES
9975 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9976 pushf
9977 push ds
9978 push es
9979 push cx
9980 push si
9981 push di
9982 cld
9983 mov si, #pci_routing_table_structure_start
9984 push cs
9985 pop ds
9986 SEG ES
9987 mov cx, [di+2]
9988 SEG ES
9989 mov es, [di+4]
9990 mov di, cx
9991 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
9992 rep
9993 movsb
9994 pop di
9995 pop si
9996 pop cx
9997 pop es
9998 pop ds
9999 popf
10000 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10001 jmp pci_real_ok
10002pci_real_too_small:
10003 SEG ES
10004 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10005 mov ah, #0x89
10006 jmp pci_real_fail
10007
10008pci_real_unknown:
10009 mov ah, #0x81
10010pci_real_fail:
10011 pop edi
10012 pop esi
10013 stc
10014 ret
10015pci_real_ok:
10016 xor ah, ah
10017 pop edi
10018 pop esi
10019 clc
10020 ret
10021
10022pci_real_select_reg:
10023 push dx
10024 mov eax, #0x800000
10025 mov ax, bx
10026 shl eax, #8
10027 and di, #0xff
10028 or ax, di
10029 and al, #0xfc
10030 mov dx, #0x0cf8
10031 out dx, eax
10032 pop dx
10033 ret
10034
10035.align 16
10036pci_routing_table_structure:
10037 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10038 db 0, 1 ;; version
10039#ifdef VBOX
10040 dw 32 + (10 * 16) ;; table size
10041#else /* !VBOX */
10042 dw 32 + (6 * 16) ;; table size
10043#endif /* !VBOX */
10044 db 0 ;; PCI interrupt router bus
10045 db 0x08 ;; PCI interrupt router DevFunc
10046 dw 0x0000 ;; PCI exclusive IRQs
10047 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10048 dw 0x7000 ;; compatible PCI interrupt router device ID
10049 dw 0,0 ;; Miniport data
10050 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10051#ifdef VBOX
10052 db 0x21 ;; checksum
10053#else /* !VBOX */
10054 db 0x07 ;; checksum
10055#endif /* !VBOX */
10056pci_routing_table_structure_start:
10057 ;; first slot entry PCI-to-ISA (embedded)
10058 db 0 ;; pci bus number
10059 db 0x08 ;; pci device number (bit 7-3)
10060 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10061 dw 0xdef8 ;; IRQ bitmap INTA#
10062 db 0x61 ;; link value INTB#
10063 dw 0xdef8 ;; IRQ bitmap INTB#
10064 db 0x62 ;; link value INTC#
10065 dw 0xdef8 ;; IRQ bitmap INTC#
10066 db 0x63 ;; link value INTD#
10067 dw 0xdef8 ;; IRQ bitmap INTD#
10068 db 0 ;; physical slot (0 = embedded)
10069 db 0 ;; reserved
10070 ;; second slot entry: 1st PCI slot
10071 db 0 ;; pci bus number
10072 db 0x10 ;; pci device number (bit 7-3)
10073 db 0x61 ;; link value INTA#
10074 dw 0xdef8 ;; IRQ bitmap INTA#
10075 db 0x62 ;; link value INTB#
10076 dw 0xdef8 ;; IRQ bitmap INTB#
10077 db 0x63 ;; link value INTC#
10078 dw 0xdef8 ;; IRQ bitmap INTC#
10079 db 0x60 ;; link value INTD#
10080 dw 0xdef8 ;; IRQ bitmap INTD#
10081 db 1 ;; physical slot (0 = embedded)
10082 db 0 ;; reserved
10083 ;; third slot entry: 2nd PCI slot
10084 db 0 ;; pci bus number
10085 db 0x18 ;; pci device number (bit 7-3)
10086 db 0x62 ;; link value INTA#
10087 dw 0xdef8 ;; IRQ bitmap INTA#
10088 db 0x63 ;; link value INTB#
10089 dw 0xdef8 ;; IRQ bitmap INTB#
10090 db 0x60 ;; link value INTC#
10091 dw 0xdef8 ;; IRQ bitmap INTC#
10092 db 0x61 ;; link value INTD#
10093 dw 0xdef8 ;; IRQ bitmap INTD#
10094 db 2 ;; physical slot (0 = embedded)
10095 db 0 ;; reserved
10096 ;; 4th slot entry: 3rd PCI slot
10097 db 0 ;; pci bus number
10098 db 0x20 ;; pci device number (bit 7-3)
10099 db 0x63 ;; link value INTA#
10100 dw 0xdef8 ;; IRQ bitmap INTA#
10101 db 0x60 ;; link value INTB#
10102 dw 0xdef8 ;; IRQ bitmap INTB#
10103 db 0x61 ;; link value INTC#
10104 dw 0xdef8 ;; IRQ bitmap INTC#
10105 db 0x62 ;; link value INTD#
10106 dw 0xdef8 ;; IRQ bitmap INTD#
10107 db 3 ;; physical slot (0 = embedded)
10108 db 0 ;; reserved
10109 ;; 5th slot entry: 4rd PCI slot
10110 db 0 ;; pci bus number
10111 db 0x28 ;; pci device number (bit 7-3)
10112 db 0x60 ;; link value INTA#
10113 dw 0xdef8 ;; IRQ bitmap INTA#
10114 db 0x61 ;; link value INTB#
10115 dw 0xdef8 ;; IRQ bitmap INTB#
10116 db 0x62 ;; link value INTC#
10117 dw 0xdef8 ;; IRQ bitmap INTC#
10118 db 0x63 ;; link value INTD#
10119 dw 0xdef8 ;; IRQ bitmap INTD#
10120 db 4 ;; physical slot (0 = embedded)
10121 db 0 ;; reserved
10122 ;; 6th slot entry: 5rd PCI slot
10123 db 0 ;; pci bus number
10124 db 0x30 ;; pci device number (bit 7-3)
10125 db 0x61 ;; link value INTA#
10126 dw 0xdef8 ;; IRQ bitmap INTA#
10127 db 0x62 ;; link value INTB#
10128 dw 0xdef8 ;; IRQ bitmap INTB#
10129 db 0x63 ;; link value INTC#
10130 dw 0xdef8 ;; IRQ bitmap INTC#
10131 db 0x60 ;; link value INTD#
10132 dw 0xdef8 ;; IRQ bitmap INTD#
10133 db 5 ;; physical slot (0 = embedded)
10134 db 0 ;; reserved
10135#ifdef VBOX
10136 ;; 7th slot entry: 6th PCI slot
10137 db 0 ;; pci bus number
10138 db 0x38 ;; pci device number (bit 7-3)
10139 db 0x62 ;; link value INTA#
10140 dw 0xdef8 ;; IRQ bitmap INTA#
10141 db 0x63 ;; link value INTB#
10142 dw 0xdef8 ;; IRQ bitmap INTB#
10143 db 0x60 ;; link value INTC#
10144 dw 0xdef8 ;; IRQ bitmap INTC#
10145 db 0x61 ;; link value INTD#
10146 dw 0xdef8 ;; IRQ bitmap INTD#
10147 db 6 ;; physical slot (0 = embedded)
10148 db 0 ;; reserved
10149 ;; 8th slot entry: 7th PCI slot
10150 db 0 ;; pci bus number
10151 db 0x40 ;; pci device number (bit 7-3)
10152 db 0x63 ;; link value INTA#
10153 dw 0xdef8 ;; IRQ bitmap INTA#
10154 db 0x60 ;; link value INTB#
10155 dw 0xdef8 ;; IRQ bitmap INTB#
10156 db 0x61 ;; link value INTC#
10157 dw 0xdef8 ;; IRQ bitmap INTC#
10158 db 0x62 ;; link value INTD#
10159 dw 0xdef8 ;; IRQ bitmap INTD#
10160 db 7 ;; physical slot (0 = embedded)
10161 db 0 ;; reserved
10162 ;; 9th slot entry: 8th PCI slot
10163 db 0 ;; pci bus number
10164 db 0x48 ;; pci device number (bit 7-3)
10165 db 0x60 ;; link value INTA#
10166 dw 0xdef8 ;; IRQ bitmap INTA#
10167 db 0x61 ;; link value INTB#
10168 dw 0xdef8 ;; IRQ bitmap INTB#
10169 db 0x62 ;; link value INTC#
10170 dw 0xdef8 ;; IRQ bitmap INTC#
10171 db 0x63 ;; link value INTD#
10172 dw 0xdef8 ;; IRQ bitmap INTD#
10173 db 8 ;; physical slot (0 = embedded)
10174 db 0 ;; reserved
10175 ;; 10th slot entry: 9th PCI slot
10176 db 0 ;; pci bus number
10177 db 0x50 ;; pci device number (bit 7-3)
10178 db 0x61 ;; link value INTA#
10179 dw 0xdef8 ;; IRQ bitmap INTA#
10180 db 0x62 ;; link value INTB#
10181 dw 0xdef8 ;; IRQ bitmap INTB#
10182 db 0x63 ;; link value INTC#
10183 dw 0xdef8 ;; IRQ bitmap INTC#
10184 db 0x60 ;; link value INTD#
10185 dw 0xdef8 ;; IRQ bitmap INTD#
10186 db 9 ;; physical slot (0 = embedded)
10187 db 0 ;; reserved
10188 ;; 11th slot entry: 10th PCI slot
10189 db 0 ;; pci bus number
10190 db 0x58 ;; pci device number (bit 7-3)
10191 db 0x61 ;; link value INTA#
10192 dw 0xdef8 ;; IRQ bitmap INTA#
10193 db 0x62 ;; link value INTB#
10194 dw 0xdef8 ;; IRQ bitmap INTB#
10195 db 0x63 ;; link value INTC#
10196 dw 0xdef8 ;; IRQ bitmap INTC#
10197 db 0x60 ;; link value INTD#
10198 dw 0xdef8 ;; IRQ bitmap INTD#
10199 db 10 ;; physical slot (0 = embedded)
10200 db 0 ;; reserved
10201 ;; 12th slot entry: 11th PCI slot
10202 db 0 ;; pci bus number
10203 db 0x60 ;; pci device number (bit 7-3)
10204 db 0x61 ;; link value INTA#
10205 dw 0xdef8 ;; IRQ bitmap INTA#
10206 db 0x62 ;; link value INTB#
10207 dw 0xdef8 ;; IRQ bitmap INTB#
10208 db 0x63 ;; link value INTC#
10209 dw 0xdef8 ;; IRQ bitmap INTC#
10210 db 0x60 ;; link value INTD#
10211 dw 0xdef8 ;; IRQ bitmap INTD#
10212 db 11 ;; physical slot (0 = embedded)
10213 db 0 ;; reserved
10214 ;; 13th slot entry: 12th PCI slot
10215 db 0 ;; pci bus number
10216 db 0x68 ;; pci device number (bit 7-3)
10217 db 0x61 ;; link value INTA#
10218 dw 0xdef8 ;; IRQ bitmap INTA#
10219 db 0x62 ;; link value INTB#
10220 dw 0xdef8 ;; IRQ bitmap INTB#
10221 db 0x63 ;; link value INTC#
10222 dw 0xdef8 ;; IRQ bitmap INTC#
10223 db 0x60 ;; link value INTD#
10224 dw 0xdef8 ;; IRQ bitmap INTD#
10225 db 12 ;; physical slot (0 = embedded)
10226 db 0 ;; reserved
10227 ;; 14th slot entry: 13th PCI slot
10228 db 0 ;; pci bus number
10229 db 0x70 ;; pci device number (bit 7-3)
10230 db 0x61 ;; link value INTA#
10231 dw 0xdef8 ;; IRQ bitmap INTA#
10232 db 0x62 ;; link value INTB#
10233 dw 0xdef8 ;; IRQ bitmap INTB#
10234 db 0x63 ;; link value INTC#
10235 dw 0xdef8 ;; IRQ bitmap INTC#
10236 db 0x60 ;; link value INTD#
10237 dw 0xdef8 ;; IRQ bitmap INTD#
10238 db 13 ;; physical slot (0 = embedded)
10239 db 0 ;; reserved
10240 ;; 15th slot entry: 14th PCI slot
10241 db 0 ;; pci bus number
10242 db 0x78 ;; pci device number (bit 7-3)
10243 db 0x61 ;; link value INTA#
10244 dw 0xdef8 ;; IRQ bitmap INTA#
10245 db 0x62 ;; link value INTB#
10246 dw 0xdef8 ;; IRQ bitmap INTB#
10247 db 0x63 ;; link value INTC#
10248 dw 0xdef8 ;; IRQ bitmap INTC#
10249 db 0x60 ;; link value INTD#
10250 dw 0xdef8 ;; IRQ bitmap INTD#
10251 db 14 ;; physical slot (0 = embedded)
10252 db 0 ;; reserved
10253#endif /* VBOX */
10254pci_routing_table_structure_end:
10255
10256#if !BX_ROMBIOS32
10257pci_irq_list:
10258 db 11, 10, 9, 5;
10259
10260pcibios_init_sel_reg:
10261 push eax
10262 mov eax, #0x800000
10263 mov ax, bx
10264 shl eax, #8
10265 and dl, #0xfc
10266 or al, dl
10267 mov dx, #0x0cf8
10268 out dx, eax
10269 pop eax
10270 ret
10271
10272pcibios_init_iomem_bases:
10273 push bp
10274 mov bp, sp
10275 mov eax, #0xe0000000 ;; base for memory init
10276 push eax
10277 mov ax, #0xc000 ;; base for i/o init
10278 push ax
10279 mov ax, #0x0010 ;; start at base address #0
10280 push ax
10281 mov bx, #0x0008
10282pci_init_io_loop1:
10283 mov dl, #0x00
10284 call pcibios_init_sel_reg
10285 mov dx, #0x0cfc
10286 in ax, dx
10287 cmp ax, #0xffff
10288 jz next_pci_dev
10289#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10290 mov dl, #0x04 ;; disable i/o and memory space access
10291 call pcibios_init_sel_reg
10292 mov dx, #0x0cfc
10293 in al, dx
10294 and al, #0xfc
10295 out dx, al
10296pci_init_io_loop2:
10297 mov dl, [bp-8]
10298 call pcibios_init_sel_reg
10299 mov dx, #0x0cfc
10300 in eax, dx
10301 test al, #0x01
10302 jnz init_io_base
10303 mov ecx, eax
10304 mov eax, #0xffffffff
10305 out dx, eax
10306 in eax, dx
10307 cmp eax, ecx
10308 je next_pci_base
10309 xor eax, #0xffffffff
10310 mov ecx, eax
10311 mov eax, [bp-4]
10312 out dx, eax
10313 add eax, ecx ;; calculate next free mem base
10314 add eax, #0x01000000
10315 and eax, #0xff000000
10316 mov [bp-4], eax
10317 jmp next_pci_base
10318init_io_base:
10319 mov cx, ax
10320 mov ax, #0xffff
10321 out dx, ax
10322 in ax, dx
10323 cmp ax, cx
10324 je next_pci_base
10325 xor ax, #0xfffe
10326 mov cx, ax
10327 mov ax, [bp-6]
10328 out dx, ax
10329 add ax, cx ;; calculate next free i/o base
10330 add ax, #0x0100
10331 and ax, #0xff00
10332 mov [bp-6], ax
10333next_pci_base:
10334 mov al, [bp-8]
10335 add al, #0x04
10336 cmp al, #0x28
10337 je enable_iomem_space
10338 mov byte ptr[bp-8], al
10339 jmp pci_init_io_loop2
10340#endif /* !VBOX */
10341enable_iomem_space:
10342 mov dl, #0x04 ;; enable i/o and memory space access if available
10343 call pcibios_init_sel_reg
10344 mov dx, #0x0cfc
10345 in al, dx
10346 or al, #0x07
10347 out dx, al
10348#ifdef VBOX
10349 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10350 call pcibios_init_sel_reg
10351 mov dx, #0x0cfc
10352 in eax, dx
10353 cmp eax, #0x20001022
10354 jne next_pci_dev
10355 mov dl, #0x10 ;; get I/O address
10356 call pcibios_init_sel_reg
10357 mov dx, #0x0cfc
10358 in ax, dx
10359 and ax, #0xfffc
10360 mov cx, ax
10361 mov dx, cx
10362 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10363 in ax, dx ;; reset is performed by reading the reset register
10364 mov dx, cx
10365 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10366 in eax, dx ;; reset is performed by reading the reset register
10367#endif /* VBOX */
10368next_pci_dev:
10369 mov byte ptr[bp-8], #0x10
10370 inc bx
10371 cmp bx, #0x0100
10372 jne pci_init_io_loop1
10373 mov sp, bp
10374 pop bp
10375 ret
10376
10377pcibios_init_set_elcr:
10378 push ax
10379 push cx
10380 mov dx, #0x04d0
10381 test al, #0x08
10382 jz is_master_pic
10383 inc dx
10384 and al, #0x07
10385is_master_pic:
10386 mov cl, al
10387 mov bl, #0x01
10388 shl bl, cl
10389 in al, dx
10390 or al, bl
10391 out dx, al
10392 pop cx
10393 pop ax
10394 ret
10395
10396pcibios_init_irqs:
10397 push ds
10398 push bp
10399 mov ax, #0xf000
10400 mov ds, ax
10401 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10402 mov al, #0x00
10403 out dx, al
10404 inc dx
10405 out dx, al
10406 mov si, #pci_routing_table_structure
10407 mov bh, [si+8]
10408 mov bl, [si+9]
10409 mov dl, #0x00
10410 call pcibios_init_sel_reg
10411 mov dx, #0x0cfc
10412 in eax, dx
10413 cmp eax, [si+12] ;; check irq router
10414 jne pci_init_end
10415 mov dl, [si+34]
10416 call pcibios_init_sel_reg
10417 push bx ;; save irq router bus + devfunc
10418 mov dx, #0x0cfc
10419 mov ax, #0x8080
10420 out dx, ax ;; reset PIRQ route control
10421 inc dx
10422 inc dx
10423 out dx, ax
10424 mov ax, [si+6]
10425 sub ax, #0x20
10426 shr ax, #4
10427 mov cx, ax
10428 add si, #0x20 ;; set pointer to 1st entry
10429 mov bp, sp
10430 mov ax, #pci_irq_list
10431 push ax
10432 xor ax, ax
10433 push ax
10434pci_init_irq_loop1:
10435 mov bh, [si]
10436 mov bl, [si+1]
10437pci_init_irq_loop2:
10438 mov dl, #0x00
10439 call pcibios_init_sel_reg
10440 mov dx, #0x0cfc
10441 in ax, dx
10442 cmp ax, #0xffff
10443 jnz pci_test_int_pin
10444 test bl, #0x07
10445 jz next_pir_entry
10446 jmp next_pci_func
10447pci_test_int_pin:
10448 mov dl, #0x3c
10449 call pcibios_init_sel_reg
10450 mov dx, #0x0cfd
10451 in al, dx
10452 and al, #0x07
10453 jz next_pci_func
10454 dec al ;; determine pirq reg
10455 mov dl, #0x03
10456 mul al, dl
10457 add al, #0x02
10458 xor ah, ah
10459 mov bx, ax
10460 mov al, [si+bx]
10461 mov dl, al
10462 mov bx, [bp]
10463 call pcibios_init_sel_reg
10464 mov dx, #0x0cfc
10465 and al, #0x03
10466 add dl, al
10467 in al, dx
10468 cmp al, #0x80
10469 jb pirq_found
10470 mov bx, [bp-2] ;; pci irq list pointer
10471 mov al, [bx]
10472 out dx, al
10473 inc bx
10474 mov [bp-2], bx
10475 call pcibios_init_set_elcr
10476pirq_found:
10477 mov bh, [si]
10478 mov bl, [si+1]
10479 add bl, [bp-3] ;; pci function number
10480 mov dl, #0x3c
10481 call pcibios_init_sel_reg
10482 mov dx, #0x0cfc
10483 out dx, al
10484next_pci_func:
10485 inc byte ptr[bp-3]
10486 inc bl
10487 test bl, #0x07
10488 jnz pci_init_irq_loop2
10489next_pir_entry:
10490 add si, #0x10
10491 mov byte ptr[bp-3], #0x00
10492 loop pci_init_irq_loop1
10493 mov sp, bp
10494 pop bx
10495pci_init_end:
10496 pop bp
10497 pop ds
10498 ret
10499#endif // BX_ROMBIOS32
10500#endif // BX_PCIBIOS
10501
10502#if BX_ROMBIOS32
10503rombios32_init:
10504 ;; save a20 and enable it
10505 in al, 0x92
10506 push ax
10507 or al, #0x02
10508 out 0x92, al
10509
10510 ;; save SS:SP to the BDA
10511 xor ax, ax
10512 mov ds, ax
10513 mov 0x0469, ss
10514 mov 0x0467, sp
10515
10516 SEG CS
10517 lidt [pmode_IDT_info]
10518 SEG CS
10519 lgdt [rombios32_gdt_48]
10520 ;; set PE bit in CR0
10521 mov eax, cr0
10522 or al, #0x01
10523 mov cr0, eax
10524 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10525 db 0x66, 0xea
10526 dw rombios32_05
10527 dw 0x000f ;; high 16 bit address
10528 dw 0x0010
10529
10530use32 386
10531rombios32_05:
10532 ;; init data segments
10533 mov eax, #0x18
10534 mov ds, ax
10535 mov es, ax
10536 mov ss, ax
10537 xor eax, eax
10538 mov fs, ax
10539 mov gs, ax
10540 cld
10541
10542 ;; copy rombios32 code to ram (ram offset = 1MB)
10543 mov esi, #0xfffe0000
10544 mov edi, #0x00040000
10545 mov ecx, #0x10000 / 4
10546 rep
10547 movsd
10548
10549 ;; init the stack pointer
10550 mov esp, #0x00080000
10551
10552 ;; call rombios32 code
10553 mov eax, #0x00040000
10554 call eax
10555
10556 ;; return to 16 bit protected mode first
10557 db 0xea
10558 dd rombios32_10
10559 dw 0x20
10560
10561use16 386
10562rombios32_10:
10563 ;; restore data segment limits to 0xffff
10564 mov ax, #0x28
10565 mov ds, ax
10566 mov es, ax
10567 mov ss, ax
10568 mov fs, ax
10569 mov gs, ax
10570
10571 ;; reset PE bit in CR0
10572 mov eax, cr0
10573 and al, #0xFE
10574 mov cr0, eax
10575
10576 ;; far jump to flush CPU queue after transition to real mode
10577 JMP_AP(0xf000, rombios32_real_mode)
10578
10579rombios32_real_mode:
10580 ;; restore IDT to normal real-mode defaults
10581 SEG CS
10582 lidt [rmode_IDT_info]
10583
10584 xor ax, ax
10585 mov ds, ax
10586 mov es, ax
10587 mov fs, ax
10588 mov gs, ax
10589
10590 ;; restore SS:SP from the BDA
10591 mov ss, 0x0469
10592 xor esp, esp
10593 mov sp, 0x0467
10594 ;; restore a20
10595 pop ax
10596 out 0x92, al
10597 ret
10598
10599rombios32_gdt_48:
10600 dw 0x30
10601 dw rombios32_gdt
10602 dw 0x000f
10603
10604rombios32_gdt:
10605 dw 0, 0, 0, 0
10606 dw 0, 0, 0, 0
10607 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
10608 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
10609 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
10610 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
10611#endif
10612
10613
10614; parallel port detection: base address in DX, index in BX, timeout in CL
10615detect_parport:
10616 push dx
10617 add dx, #2
10618 in al, dx
10619 and al, #0xdf ; clear input mode
10620 out dx, al
10621 pop dx
10622 mov al, #0xaa
10623 out dx, al
10624 in al, dx
10625 cmp al, #0xaa
10626 jne no_parport
10627 push bx
10628 shl bx, #1
10629 mov [bx+0x408], dx ; Parallel I/O address
10630 pop bx
10631 mov [bx+0x478], cl ; Parallel printer timeout
10632 inc bx
10633no_parport:
10634 ret
10635
10636; serial port detection: base address in DX, index in BX, timeout in CL
10637detect_serial:
10638 push dx
10639 inc dx
10640 mov al, #0x02
10641 out dx, al
10642 in al, dx
10643 cmp al, #0x02
10644 jne no_serial
10645 inc dx
10646 in al, dx
10647 cmp al, #0x02
10648 jne no_serial
10649 dec dx
10650 xor al, al
10651 out dx, al
10652 pop dx
10653 push bx
10654 shl bx, #1
10655 mov [bx+0x400], dx ; Serial I/O address
10656 pop bx
10657 mov [bx+0x47c], cl ; Serial timeout
10658 inc bx
10659 ret
10660no_serial:
10661 pop dx
10662 ret
10663
10664rom_checksum:
10665 push ax
10666 push bx
10667 push cx
10668 xor ax, ax
10669 xor bx, bx
10670 xor cx, cx
10671 mov ch, [2]
10672 shl cx, #1
10673checksum_loop:
10674 add al, [bx]
10675 inc bx
10676 loop checksum_loop
10677 and al, #0xff
10678 pop cx
10679 pop bx
10680 pop ax
10681 ret
10682
10683rom_scan:
10684 ;; Scan for existence of valid expansion ROMS.
10685 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
10686 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
10687 ;; System ROM: only 0xE0000
10688 ;;
10689 ;; Header:
10690 ;; Offset Value
10691 ;; 0 0x55
10692 ;; 1 0xAA
10693 ;; 2 ROM length in 512-byte blocks
10694 ;; 3 ROM initialization entry point (FAR CALL)
10695
10696 mov cx, #0xc000
10697rom_scan_loop:
10698 mov ds, cx
10699 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
10700 cmp [0], #0xAA55 ;; look for signature
10701 jne rom_scan_increment
10702 call rom_checksum
10703 jnz rom_scan_increment
10704 mov al, [2] ;; change increment to ROM length in 512-byte blocks
10705
10706 ;; We want our increment in 512-byte quantities, rounded to
10707 ;; the nearest 2k quantity, since we only scan at 2k intervals.
10708 test al, #0x03
10709 jz block_count_rounded
10710 and al, #0xfc ;; needs rounding up
10711 add al, #0x04
10712block_count_rounded:
10713
10714 xor bx, bx ;; Restore DS back to 0000:
10715 mov ds, bx
10716 push ax ;; Save AX
10717 ;; Push addr of ROM entry point
10718 push cx ;; Push seg
10719 push #0x0003 ;; Push offset
10720 mov bp, sp ;; Call ROM init routine using seg:off on stack
10721 db 0xff ;; call_far ss:[bp+0]
10722 db 0x5e
10723 db 0
10724 cli ;; In case expansion ROM BIOS turns IF on
10725 add sp, #2 ;; Pop offset value
10726 pop cx ;; Pop seg value (restore CX)
10727 pop ax ;; Restore AX
10728rom_scan_increment:
10729 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
10730 ;; because the segment selector is shifted left 4 bits.
10731 add cx, ax
10732 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
10733 jbe rom_scan_loop
10734
10735 xor ax, ax ;; Restore DS back to 0000:
10736 mov ds, ax
10737 ret
10738
10739;; for 'C' strings and other data, insert them here with
10740;; a the following hack:
10741;; DATA_SEG_DEFS_HERE
10742
10743
10744;; the following area can be used to write dynamically generated tables
10745 .align 16
10746bios_table_area_start:
10747 dd 0xaafb4442
10748 dd bios_table_area_end - bios_table_area_start - 8;
10749
10750;--------
10751;- POST -
10752;--------
10753.org 0xe05b ; POST Entry Point
10754bios_table_area_end:
10755post:
10756
10757 xor ax, ax
10758
10759 ;; first reset the DMA controllers
10760 out 0x0d,al
10761 out 0xda,al
10762
10763 ;; then initialize the DMA controllers
10764 mov al, #0xC0
10765 out 0xD6, al ; cascade mode of channel 4 enabled
10766 mov al, #0x00
10767 out 0xD4, al ; unmask channel 4
10768
10769 ;; Examine CMOS shutdown status.
10770 mov AL, #0x0f
10771 out 0x70, AL
10772 in AL, 0x71
10773
10774 ;; backup status
10775 mov bl, al
10776
10777 ;; Reset CMOS shutdown status.
10778 mov AL, #0x0f
10779 out 0x70, AL ; select CMOS register Fh
10780 mov AL, #0x00
10781 out 0x71, AL ; set shutdown action to normal
10782
10783 ;; Examine CMOS shutdown status.
10784 mov al, bl
10785
10786 ;; 0x00, 0x09, 0x0D+ = normal startup
10787 cmp AL, #0x00
10788 jz normal_post
10789 cmp AL, #0x0d
10790 jae normal_post
10791 cmp AL, #0x09
10792 je normal_post
10793
10794 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
10795 cmp al, #0x05
10796 je eoi_jmp_post
10797
10798 ;; Examine CMOS shutdown status.
10799 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
10800 push bx
10801 call _shutdown_status_panic
10802
10803#if 0
10804 HALT(__LINE__)
10805 ;
10806 ;#if 0
10807 ; 0xb0, 0x20, /* mov al, #0x20 */
10808 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10809 ;#endif
10810 ;
10811 pop es
10812 pop ds
10813 popa
10814 iret
10815#endif
10816
10817normal_post:
10818 ; case 0: normal startup
10819
10820 cli
10821 mov ax, #0xfffe
10822 mov sp, ax
10823 xor ax, ax
10824 mov ds, ax
10825 mov ss, ax
10826
10827#ifndef VBOX
10828 ;; zero out BIOS data area (40:00..40:ff)
10829 mov es, ax
10830 mov cx, #0x0080 ;; 128 words
10831 mov di, #0x0400
10832 cld
10833 rep
10834 stosw
10835#else /* VBOX */
10836 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
10837 mov es, ax
10838 xor di, di
10839 cld
10840 mov cx, #0x0239 ;; 569 words
10841 rep
10842 stosw
10843 inc di
10844 inc di
10845 mov cx, #0x7dc6 ;; 32198 words
10846 rep
10847 stosw
10848 ;; zero out remaining base memory except the last 16 bytes of the EBDA
10849 ;; because we store the MP table there
10850 xor eax, eax
10851 xor bx, bx
10852memory_zero_loop:
10853 add bx, #0x1000
10854 cmp bx, #0x9000
10855 jae memory_cleared
10856 mov es, bx
10857 xor di, di
10858 mov cx, #0x4000
10859 rep
10860 stosd
10861 jmp memory_zero_loop
10862memory_cleared:
10863 mov es, bx
10864 xor di, di
10865 mov cx, #0x3f00
10866 rep
10867 stosd
10868 xor bx, bx
10869#endif
10870
10871 call _log_bios_start
10872
10873 ;; set all interrupts to default handler
10874 xor bx, bx ;; offset index
10875 mov cx, #0x0100 ;; counter (256 interrupts)
10876 mov ax, #dummy_iret_handler
10877 mov dx, #0xF000
10878
10879post_default_ints:
10880 mov [bx], ax
10881 inc bx
10882 inc bx
10883 mov [bx], dx
10884 inc bx
10885 inc bx
10886 loop post_default_ints
10887
10888 ;; set vector 0x79 to zero
10889 ;; this is used by 'gardian angel' protection system
10890 SET_INT_VECTOR(0x79, #0, #0)
10891
10892 ;; base memory in K 40:13 (word)
10893 mov ax, #BASE_MEM_IN_K
10894 mov 0x0413, ax
10895
10896
10897 ;; Manufacturing Test 40:12
10898 ;; zerod out above
10899
10900#ifndef VBOX
10901 ;; Warm Boot Flag 0040:0072
10902 ;; value of 1234h = skip memory checks
10903 ;; zerod out above
10904#endif /* !VBOX */
10905
10906
10907 ;; Printer Services vector
10908 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10909
10910 ;; Bootstrap failure vector
10911 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10912
10913 ;; Bootstrap Loader vector
10914 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10915
10916 ;; User Timer Tick vector
10917 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10918
10919 ;; Memory Size Check vector
10920 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10921
10922 ;; Equipment Configuration Check vector
10923 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10924
10925 ;; System Services
10926 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10927
10928 ;; EBDA setup
10929 call ebda_post
10930
10931 ;; PIT setup
10932 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10933 ;; int 1C already points at dummy_iret_handler (above)
10934 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
10935 out 0x43, al
10936 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
10937 out 0x40, al
10938 out 0x40, al
10939
10940 ;; Keyboard
10941 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10942 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10943
10944 xor ax, ax
10945 mov ds, ax
10946 mov 0x0417, al /* keyboard shift flags, set 1 */
10947 mov 0x0418, al /* keyboard shift flags, set 2 */
10948 mov 0x0419, al /* keyboard alt-numpad work area */
10949 mov 0x0471, al /* keyboard ctrl-break flag */
10950 mov 0x0497, al /* keyboard status flags 4 */
10951 mov al, #0x10
10952 mov 0x0496, al /* keyboard status flags 3 */
10953
10954
10955 /* keyboard head of buffer pointer */
10956 mov bx, #0x001E
10957 mov 0x041A, bx
10958
10959 /* keyboard end of buffer pointer */
10960 mov 0x041C, bx
10961
10962 /* keyboard pointer to start of buffer */
10963 mov bx, #0x001E
10964 mov 0x0480, bx
10965
10966 /* keyboard pointer to end of buffer */
10967 mov bx, #0x003E
10968 mov 0x0482, bx
10969
10970 /* init the keyboard */
10971 call _keyboard_init
10972
10973 ;; mov CMOS Equipment Byte to BDA Equipment Word
10974 mov ax, 0x0410
10975 mov al, #0x14
10976 out 0x70, al
10977 in al, 0x71
10978 mov 0x0410, ax
10979
10980
10981 ;; Parallel setup
10982 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10983 xor ax, ax
10984 mov ds, ax
10985 xor bx, bx
10986 mov cl, #0x14 ; timeout value
10987 mov dx, #0x378 ; Parallel I/O address, port 1
10988 call detect_parport
10989 mov dx, #0x278 ; Parallel I/O address, port 2
10990 call detect_parport
10991 shl bx, #0x0e
10992 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
10993 and ax, #0x3fff
10994 or ax, bx ; set number of parallel ports
10995 mov 0x410, ax
10996
10997 ;; Serial setup
10998 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10999 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11000 xor bx, bx
11001 mov cl, #0x0a ; timeout value
11002 mov dx, #0x03f8 ; Serial I/O address, port 1
11003 call detect_serial
11004 mov dx, #0x02f8 ; Serial I/O address, port 2
11005 call detect_serial
11006 mov dx, #0x03e8 ; Serial I/O address, port 3
11007 call detect_serial
11008 mov dx, #0x02e8 ; Serial I/O address, port 4
11009 call detect_serial
11010 shl bx, #0x09
11011 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11012 and ax, #0xf1ff
11013 or ax, bx ; set number of serial port
11014 mov 0x410, ax
11015
11016 ;; CMOS RTC
11017 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11018 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11019 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11020 ;; BIOS DATA AREA 0x4CE ???
11021 call timer_tick_post
11022
11023 ;; PS/2 mouse setup
11024 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11025
11026 ;; IRQ13 (FPU exception) setup
11027 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11028
11029 ;; Video setup
11030 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11031
11032#ifdef VBOX
11033 ;; moved the PIC initialization to another place as we need
11034 ;; some space for additions init calls. Otherwise this code
11035 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11036 call init_pic
11037#else /* !VBOX */
11038 ;; PIC
11039 mov al, #0x11 ; send initialisation commands
11040 out 0x20, al
11041 out 0xa0, al
11042 mov al, #0x08
11043 out 0x21, al
11044 mov al, #0x70
11045 out 0xa1, al
11046 mov al, #0x04
11047 out 0x21, al
11048 mov al, #0x02
11049 out 0xa1, al
11050 mov al, #0x01
11051 out 0x21, al
11052 out 0xa1, al
11053 mov al, #0xb8
11054 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11055#if BX_USE_PS2_MOUSE
11056 mov al, #0x8f
11057#else
11058 mov al, #0x9f
11059#endif
11060 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11061#endif /* !VBOX */
11062
11063#if BX_ROMBIOS32
11064 call rombios32_init
11065#else
11066 call pcibios_init_iomem_bases
11067 call pcibios_init_irqs
11068#endif
11069 call rom_scan
11070
11071#if BX_USE_ATADRV
11072 ;;
11073 ;; ATA/ATAPI driver setup
11074 ;;
11075 call _ata_init
11076 call _ata_detect
11077 ;;
11078#endif
11079
11080#if defined(VBOX) && (defined(VBOX_WITH_BUSLOGIC) || defined(VBX_WITH_LSILOGIC))
11081 ;;
11082 ;; SCSI driver setup
11083 ;;
11084 call _scsi_init
11085 ;;
11086#endif
11087
11088 call _print_bios_banner
11089
11090 ;;
11091 ;; Floppy setup
11092 ;;
11093 call floppy_drive_post
11094
11095 ;;
11096 ;; Hard Drive setup
11097 ;;
11098 call hard_drive_post
11099
11100#if BX_ELTORITO_BOOT
11101 ;;
11102 ;; eltorito floppy/harddisk emulation from cd
11103 ;;
11104 call _cdemu_init
11105 ;;
11106#endif // BX_ELTORITO_BOOT
11107
11108 sti ;; enable interrupts
11109 int #0x19
11110
11111
11112.org 0xe2c3 ; NMI Handler Entry Point
11113nmi:
11114 ;; FIXME the NMI handler should not panic
11115 ;; but iret when called from int75 (fpu exception)
11116 call _nmi_handler_msg
11117 iret
11118
11119int75_handler:
11120 out 0xf0, al // clear irq13
11121 call eoi_both_pics // clear interrupt
11122 int 2 // legacy nmi call
11123 iret
11124
11125;-------------------------------------------
11126;- INT 13h Fixed Disk Services Entry Point -
11127;-------------------------------------------
11128.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11129int13_handler:
11130 //JMPL(int13_relocated)
11131 jmp int13_relocated
11132
11133.org 0xe401 ; Fixed Disk Parameter Table
11134
11135;----------
11136;- INT19h -
11137;----------
11138.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11139int19_handler:
11140
11141 jmp int19_relocated
11142;-------------------------------------------
11143;- System BIOS Configuration Data Table
11144;-------------------------------------------
11145.org BIOS_CONFIG_TABLE
11146db 0x08 ; Table size (bytes) -Lo
11147db 0x00 ; Table size (bytes) -Hi
11148db SYS_MODEL_ID
11149db SYS_SUBMODEL_ID
11150db BIOS_REVISION
11151; Feature byte 1
11152; b7: 1=DMA channel 3 used by hard disk
11153; b6: 1=2 interrupt controllers present
11154; b5: 1=RTC present
11155; b4: 1=BIOS calls int 15h/4Fh every key
11156; b3: 1=wait for extern event supported (Int 15h/41h)
11157; b2: 1=extended BIOS data area used
11158; b1: 0=AT or ESDI bus, 1=MicroChannel
11159; b0: 1=Dual bus (MicroChannel + ISA)
11160db (0 << 7) | \
11161 (1 << 6) | \
11162 (1 << 5) | \
11163 (BX_CALL_INT15_4F << 4) | \
11164 (0 << 3) | \
11165 (BX_USE_EBDA << 2) | \
11166 (0 << 1) | \
11167 (0 << 0)
11168; Feature byte 2
11169; b7: 1=32-bit DMA supported
11170; b6: 1=int16h, function 9 supported
11171; b5: 1=int15h/C6h (get POS data) supported
11172; b4: 1=int15h/C7h (get mem map info) supported
11173; b3: 1=int15h/C8h (en/dis CPU) supported
11174; b2: 1=non-8042 kb controller
11175; b1: 1=data streaming supported
11176; b0: reserved
11177db (0 << 7) | \
11178 (1 << 6) | \
11179 (0 << 5) | \
11180 (0 << 4) | \
11181 (0 << 3) | \
11182 (0 << 2) | \
11183 (0 << 1) | \
11184 (0 << 0)
11185; Feature byte 3
11186; b7: not used
11187; b6: reserved
11188; b5: reserved
11189; b4: POST supports ROM-to-RAM enable/disable
11190; b3: SCSI on system board
11191; b2: info panel installed
11192; b1: Initial Machine Load (IML) system - BIOS on disk
11193; b0: SCSI supported in IML
11194db 0x00
11195; Feature byte 4
11196; b7: IBM private
11197; b6: EEPROM present
11198; b5-3: ABIOS presence (011 = not supported)
11199; b2: private
11200; b1: memory split above 16Mb supported
11201; b0: POSTEXT directly supported by POST
11202db 0x00
11203; Feature byte 5 (IBM)
11204; b1: enhanced mouse
11205; b0: flash EPROM
11206db 0x00
11207
11208
11209
11210.org 0xe729 ; Baud Rate Generator Table
11211
11212;----------
11213;- INT14h -
11214;----------
11215.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11216int14_handler:
11217 push ds
11218 pusha
11219 xor ax, ax
11220 mov ds, ax
11221 call _int14_function
11222 popa
11223 pop ds
11224 iret
11225
11226
11227;----------------------------------------
11228;- INT 16h Keyboard Service Entry Point -
11229;----------------------------------------
11230.org 0xe82e
11231int16_handler:
11232
11233 sti
11234 push ds
11235 pushf
11236 pusha
11237
11238 cmp ah, #0x00
11239 je int16_F00
11240 cmp ah, #0x10
11241 je int16_F00
11242
11243 mov bx, #0xf000
11244 mov ds, bx
11245 call _int16_function
11246 popa
11247 popf
11248 pop ds
11249 jz int16_zero_set
11250
11251int16_zero_clear:
11252 push bp
11253 mov bp, sp
11254 //SEG SS
11255 and BYTE [bp + 0x06], #0xbf
11256 pop bp
11257 iret
11258
11259int16_zero_set:
11260 push bp
11261 mov bp, sp
11262 //SEG SS
11263 or BYTE [bp + 0x06], #0x40
11264 pop bp
11265 iret
11266
11267int16_F00:
11268 mov bx, #0x0040
11269 mov ds, bx
11270
11271int16_wait_for_key:
11272 cli
11273 mov bx, 0x001a
11274 cmp bx, 0x001c
11275 jne int16_key_found
11276 sti
11277 nop
11278#if 0
11279 /* no key yet, call int 15h, function AX=9002 */
11280 0x50, /* push AX */
11281 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11282 0xcd, 0x15, /* int 15h */
11283 0x58, /* pop AX */
11284 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11285#endif
11286 jmp int16_wait_for_key
11287
11288int16_key_found:
11289 mov bx, #0xf000
11290 mov ds, bx
11291 call _int16_function
11292 popa
11293 popf
11294 pop ds
11295#if 0
11296 /* notify int16 complete w/ int 15h, function AX=9102 */
11297 0x50, /* push AX */
11298 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11299 0xcd, 0x15, /* int 15h */
11300 0x58, /* pop AX */
11301#endif
11302 iret
11303
11304
11305
11306;-------------------------------------------------
11307;- INT09h : Keyboard Hardware Service Entry Point -
11308;-------------------------------------------------
11309.org 0xe987
11310int09_handler:
11311 cli
11312 push ax
11313
11314 mov al, #0xAD ;;disable keyboard
11315 out #0x64, al
11316
11317 mov al, #0x0B
11318 out #0x20, al
11319 in al, #0x20
11320 and al, #0x02
11321 jz int09_finish
11322
11323 in al, #0x60 ;;read key from keyboard controller
11324 sti
11325 push ds
11326 pusha
11327#ifdef BX_CALL_INT15_4F
11328 mov ah, #0x4f ;; allow for keyboard intercept
11329 stc
11330 int #0x15
11331 jnc int09_done
11332#endif
11333
11334 ;; check for extended key
11335 cmp al, #0xe0
11336 jne int09_check_pause
11337 xor ax, ax
11338 mov ds, ax
11339 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11340 or al, #0x02
11341 mov BYTE [0x496], al
11342 jmp int09_done
11343
11344int09_check_pause: ;; check for pause key
11345 cmp al, #0xe1
11346 jne int09_process_key
11347 xor ax, ax
11348 mov ds, ax
11349 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11350 or al, #0x01
11351 mov BYTE [0x496], al
11352 jmp int09_done
11353
11354int09_process_key:
11355 mov bx, #0xf000
11356 mov ds, bx
11357 call _int09_function
11358
11359int09_done:
11360 popa
11361 pop ds
11362 cli
11363 call eoi_master_pic
11364
11365int09_finish:
11366 mov al, #0xAE ;;enable keyboard
11367 out #0x64, al
11368 pop ax
11369 iret
11370
11371
11372;----------------------------------------
11373;- INT 13h Diskette Service Entry Point -
11374;----------------------------------------
11375.org 0xec59
11376int13_diskette:
11377 jmp int13_noeltorito
11378
11379;---------------------------------------------
11380;- INT 0Eh Diskette Hardware ISR Entry Point -
11381;---------------------------------------------
11382.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11383int0e_handler:
11384 push ax
11385 push dx
11386 mov dx, #0x03f4
11387 in al, dx
11388 and al, #0xc0
11389 cmp al, #0xc0
11390 je int0e_normal
11391 mov dx, #0x03f5
11392 mov al, #0x08 ; sense interrupt status
11393 out dx, al
11394int0e_loop1:
11395 mov dx, #0x03f4
11396 in al, dx
11397 and al, #0xc0
11398 cmp al, #0xc0
11399 jne int0e_loop1
11400int0e_loop2:
11401 mov dx, #0x03f5
11402 in al, dx
11403 mov dx, #0x03f4
11404 in al, dx
11405 and al, #0xc0
11406 cmp al, #0xc0
11407 je int0e_loop2
11408int0e_normal:
11409 push ds
11410 xor ax, ax ;; segment 0000
11411 mov ds, ax
11412 call eoi_master_pic
11413 mov al, 0x043e
11414 or al, #0x80 ;; diskette interrupt has occurred
11415 mov 0x043e, al
11416 pop ds
11417 pop dx
11418 pop ax
11419 iret
11420
11421
11422.org 0xefc7 ; Diskette Controller Parameter Table
11423diskette_param_table:
11424;; Since no provisions are made for multiple drive types, most
11425;; values in this table are ignored. I set parameters for 1.44M
11426;; floppy here
11427db 0xAF
11428db 0x02 ;; head load time 0000001, DMA used
11429db 0x25
11430db 0x02
11431db 18
11432db 0x1B
11433db 0xFF
11434db 0x6C
11435db 0xF6
11436db 0x0F
11437db 0x08
11438
11439
11440;----------------------------------------
11441;- INT17h : Printer Service Entry Point -
11442;----------------------------------------
11443.org 0xefd2
11444int17_handler:
11445 push ds
11446 pusha
11447 xor ax, ax
11448 mov ds, ax
11449 call _int17_function
11450 popa
11451 pop ds
11452 iret
11453
11454diskette_param_table2:
11455;; New diskette parameter table adding 3 parameters from IBM
11456;; Since no provisions are made for multiple drive types, most
11457;; values in this table are ignored. I set parameters for 1.44M
11458;; floppy here
11459db 0xAF
11460db 0x02 ;; head load time 0000001, DMA used
11461db 0x25
11462db 0x02
11463db 18
11464db 0x1B
11465db 0xFF
11466db 0x6C
11467db 0xF6
11468db 0x0F
11469db 0x08
11470db 79 ;; maximum track
11471db 0 ;; data transfer rate
11472db 4 ;; drive type in cmos
11473
11474.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11475 HALT(__LINE__)
11476 iret
11477
11478;----------
11479;- INT10h -
11480;----------
11481.org 0xf065 ; INT 10h Video Support Service Entry Point
11482int10_handler:
11483 ;; dont do anything, since the VGA BIOS handles int10h requests
11484 iret
11485
11486.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11487
11488;----------
11489;- INT12h -
11490;----------
11491.org 0xf841 ; INT 12h Memory Size Service Entry Point
11492; ??? different for Pentium (machine check)?
11493int12_handler:
11494 push ds
11495 mov ax, #0x0040
11496 mov ds, ax
11497 mov ax, 0x0013
11498 pop ds
11499 iret
11500
11501;----------
11502;- INT11h -
11503;----------
11504.org 0xf84d ; INT 11h Equipment List Service Entry Point
11505int11_handler:
11506 push ds
11507 mov ax, #0x0040
11508 mov ds, ax
11509 mov ax, 0x0010
11510 pop ds
11511 iret
11512
11513;----------
11514;- INT15h -
11515;----------
11516.org 0xf859 ; INT 15h System Services Entry Point
11517int15_handler:
11518 pushf
11519#if BX_APM
11520 cmp ah, #0x53
11521 je apm_call
11522#endif
11523 push ds
11524 push es
11525 cmp ah, #0x86
11526 je int15_handler32
11527 cmp ah, #0xE8
11528 je int15_handler32
11529 pusha
11530#if BX_USE_PS2_MOUSE
11531 cmp ah, #0xC2
11532 je int15_handler_mouse
11533#endif
11534 call _int15_function
11535int15_handler_mouse_ret:
11536 popa
11537int15_handler32_ret:
11538 pop es
11539 pop ds
11540 popf
11541 jmp iret_modify_cf
11542#if BX_APM
11543apm_call:
11544 jmp _apmreal_entry
11545#endif
11546
11547#if BX_USE_PS2_MOUSE
11548int15_handler_mouse:
11549 call _int15_function_mouse
11550 jmp int15_handler_mouse_ret
11551#endif
11552
11553int15_handler32:
11554 pushad
11555 call _int15_function32
11556 popad
11557 jmp int15_handler32_ret
11558
11559;; Protected mode IDT descriptor
11560;;
11561;; I just make the limit 0, so the machine will shutdown
11562;; if an exception occurs during protected mode memory
11563;; transfers.
11564;;
11565;; Set base to f0000 to correspond to beginning of BIOS,
11566;; in case I actually define an IDT later
11567;; Set limit to 0
11568
11569pmode_IDT_info:
11570dw 0x0000 ;; limit 15:00
11571dw 0x0000 ;; base 15:00
11572db 0x0f ;; base 23:16
11573
11574;; Real mode IDT descriptor
11575;;
11576;; Set to typical real-mode values.
11577;; base = 000000
11578;; limit = 03ff
11579
11580rmode_IDT_info:
11581dw 0x03ff ;; limit 15:00
11582dw 0x0000 ;; base 15:00
11583db 0x00 ;; base 23:16
11584
11585;;
11586;; Handler for unexpected hardware interrupts
11587;;
11588dummy_isr:
11589 push ds
11590 pushad
11591 xor ax, ax
11592 mov ds, ax
11593 call _dummy_isr_function
11594 popad
11595 pop ds
11596 iret
11597
11598;----------
11599;- INT1Ah -
11600;----------
11601.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
11602int1a_handler:
11603#if BX_PCIBIOS
11604 cmp ah, #0xb1
11605 jne int1a_normal
11606 call pcibios_real
11607 jc pcibios_error
11608 retf 2
11609pcibios_error:
11610 mov bl, ah
11611 mov ah, #0xb1
11612 push ds
11613 pusha
11614 mov ax, ss ; set readable descriptor to ds, for calling pcibios
11615 mov ds, ax ; on 16bit protected mode.
11616 jmp int1a_callfunction
11617int1a_normal:
11618#endif
11619 push ds
11620 pusha
11621 xor ax, ax
11622 mov ds, ax
11623int1a_callfunction:
11624 call _int1a_function
11625 popa
11626 pop ds
11627 iret
11628
11629;;
11630;; int70h: IRQ8 - CMOS RTC
11631;;
11632int70_handler:
11633 push ds
11634 pushad
11635 xor ax, ax
11636 mov ds, ax
11637 call _int70_function
11638 popad
11639 pop ds
11640 iret
11641
11642;---------
11643;- INT08 -
11644;---------
11645.org 0xfea5 ; INT 08h System Timer ISR Entry Point
11646int08_handler:
11647 sti
11648 push eax
11649 push ds
11650 xor ax, ax
11651 mov ds, ax
11652
11653 ;; time to turn off drive(s)?
11654 mov al,0x0440
11655 or al,al
11656 jz int08_floppy_off
11657 dec al
11658 mov 0x0440,al
11659 jnz int08_floppy_off
11660 ;; turn motor(s) off
11661 push dx
11662 mov dx,#0x03f2
11663 in al,dx
11664 and al,#0xcf
11665 out dx,al
11666 pop dx
11667int08_floppy_off:
11668
11669 mov eax, 0x046c ;; get ticks dword
11670 inc eax
11671
11672 ;; compare eax to one days worth of timer ticks at 18.2 hz
11673 cmp eax, #0x001800B0
11674 jb int08_store_ticks
11675 ;; there has been a midnight rollover at this point
11676 xor eax, eax ;; zero out counter
11677 inc BYTE 0x0470 ;; increment rollover flag
11678
11679int08_store_ticks:
11680 mov 0x046c, eax ;; store new ticks dword
11681 ;; chain to user timer tick INT #0x1c
11682 //pushf
11683 //;; call_ep [ds:loc]
11684 //CALL_EP( 0x1c << 2 )
11685 int #0x1c
11686 cli
11687 call eoi_master_pic
11688 pop ds
11689 pop eax
11690 iret
11691
11692.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
11693
11694
11695.org 0xff00
11696.ascii BIOS_COPYRIGHT_STRING
11697
11698#ifdef VBOX
11699// The SMBIOS header
11700.org 0xff30
11701.align 16
11702 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
11703 ; calculate Entry Point Structure checksum - note that we already
11704 ; know the checksum for the DMI header paragraph is zero
11705 db ( - ( 0x5f + 0x53 + 0x4d + 0x5f \
11706 + 0x1f \
11707 + ((VBOX_SMBIOS_MAJOR_VER ) & 0xff) + ((VBOX_SMBIOS_MINOR_VER ) & 0xff) \
11708 + ((VBOX_SMBIOS_MAXSS ) & 0xff) + ((VBOX_SMBIOS_MAXSS >> 8) & 0xff) \
11709 )) & 0xff
11710 db 0x1f ; EPS length - defined by standard
11711 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
11712 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
11713 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
11714 db 0x00 ; Entry point revision
11715 db 0x00, 0x00, 0x00, 0x00, 0x00
11716
11717// The DMI header
11718 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
11719 ; calculate the DMI header checksum
11720 db ( - ( 0x5f + 0x44 + 0x4d + 0x49 + 0x5f \
11721 + ((VBOX_DMI_TABLE_BASE ) & 0xff) + ((VBOX_DMI_TABLE_BASE >> 8) & 0xff) \
11722 + ((VBOX_DMI_TABLE_BASE >> 16) & 0xff) + ((VBOX_DMI_TABLE_BASE >> 24) & 0xff) \
11723 + ((VBOX_DMI_TABLE_SIZE ) & 0xff) + ((VBOX_DMI_TABLE_SIZE >> 8) & 0xff) \
11724 + ((VBOX_DMI_TABLE_ENTR ) & 0xff) + ((VBOX_DMI_TABLE_ENTR >> 8) & 0xff) \
11725 + VBOX_DMI_TABLE_VER \
11726 )) & 0xff
11727 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
11728 dd VBOX_DMI_TABLE_BASE ; DMI tables base
11729 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
11730 db VBOX_DMI_TABLE_VER ; DMI version
11731 db 0x00 ; Just for alignment
11732#endif
11733
11734;------------------------------------------------
11735;- IRET Instruction for Dummy Interrupt Handler -
11736;------------------------------------------------
11737.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
11738dummy_iret_handler:
11739 iret
11740
11741.org 0xff54 ; INT 05h Print Screen Service Entry Point
11742 HALT(__LINE__)
11743 iret
11744
11745.org 0xfff0 ; Power-up Entry Point
11746 jmp 0xf000:post
11747
11748.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
11749.ascii BIOS_BUILD_DATE
11750
11751.org 0xfffe ; System Model ID
11752db SYS_MODEL_ID
11753db 0x00 ; filler
11754
11755.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
11756ASM_END
11757/*
11758 * This font comes from the fntcol16.zip package (c) by Joseph Gil
11759 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
11760 * This font is public domain
11761 */
11762static Bit8u vgafont8[128*8]=
11763{
11764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11765 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
11766 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
11767 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11768 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11769 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
11770 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
11771 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
11772 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
11773 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
11774 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
11775 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
11776 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
11777 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
11778 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
11779 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
11780 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
11781 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
11782 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
11783 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
11784 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
11785 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
11786 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11787 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11788 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11789 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11790 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11791 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11792 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11793 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11794 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11795 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11797 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11798 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11799 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11800 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11801 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11802 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11803 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11804 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11805 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11806 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11807 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11808 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11809 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11810 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11811 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11812 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11813 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11814 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11815 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11816 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11817 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11818 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11819 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11820 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11821 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11822 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11823 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11824 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11825 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11826 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11827 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11828 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11829 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11830 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11831 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11832 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11833 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11834 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11835 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11836 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11837 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11838 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11839 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11840 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11841 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11842 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11843 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11844 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11845 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11846 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11847 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11848 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11849 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11850 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11851 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11852 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11853 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11854 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11855 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11856 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11857 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11858 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11859 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11860 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11861 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11862 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11863 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11864 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11865 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11866 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11867 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11868 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11869 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11870 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11871 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11872 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11873 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11874 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11875 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11876 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11877 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11878 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11879 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11880 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11881 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11882 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11883 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11884 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11885 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11886 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11887 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11888 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11889 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11890 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11891 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11892};
11893
11894ASM_START
11895.org 0xcc00
11896// bcc-generated data will be placed here
11897ASM_END
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette