VirtualBox

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

Last change on this file since 21206 was 21206, checked in by vboxsync, 15 years ago

proper #ifdef VBOX for r49510

  • Property svn:eol-style set to native
File size: 332.4 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#ifdef VBOX_WITH_SCSI
222/* Enough for now */
223# define BX_MAX_SCSI_DEVICES 4
224
225/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
226# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
227# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
228#endif
229
230#ifndef VBOX
231#define PANIC_PORT 0x400
232#define PANIC_PORT2 0x401
233#define INFO_PORT 0x402
234#define DEBUG_PORT 0x403
235#else /* VBOX */
236/* Redirect INFO output to backdoor logging port. */
237#define PANIC_PORT 0x400
238#define PANIC_PORT2 0x401
239#define INFO_PORT 0x504
240#define DEBUG_PORT 0x403
241#endif /* VBOX */
242
243// define this if you want to make PCIBIOS working on a specific bridge only
244// undef enables PCIBIOS when at least one PCI device is found
245// i440FX is emulated by Bochs and QEMU
246#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
247
248// #20 is dec 20
249// #$20 is hex 20 = 32
250// #0x20 is hex 20 = 32
251// LDA #$20
252// JSR $E820
253// LDD .i,S
254// JSR $C682
255// mov al, #$20
256
257// all hex literals should be prefixed with '0x'
258// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
259// no mov SEG-REG, #value, must mov register into seg-reg
260// grep -i "mov[ ]*.s" rombios.c
261
262// This is for compiling with gcc2 and gcc3
263#define ASM_START #asm
264#define ASM_END #endasm
265
266ASM_START
267.rom
268
269.org 0x0000
270
271#if BX_CPU >= 3
272use16 386
273#else
274use16 286
275#endif
276
277MACRO HALT
278 ;; the HALT macro is called with the line number of the HALT call.
279 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
280 ;; to print a BX_PANIC message. This will normally halt the simulation
281 ;; with a message such as "BIOS panic at rombios.c, line 4091".
282 ;; However, users can choose to make panics non-fatal and continue.
283#if BX_VIRTUAL_PORTS
284 mov dx,#PANIC_PORT
285 mov ax,#?1
286 out dx,ax
287#else
288 mov dx,#0x80
289 mov ax,#?1
290 out dx,al
291#endif
292MEND
293
294MACRO JMP_AP
295 db 0xea
296 dw ?2
297 dw ?1
298MEND
299
300MACRO SET_INT_VECTOR
301 mov ax, ?3
302 mov ?1*4, ax
303 mov ax, ?2
304 mov ?1*4+2, ax
305MEND
306
307ASM_END
308
309typedef unsigned char Bit8u;
310typedef unsigned short Bit16u;
311typedef unsigned short bx_bool;
312typedef unsigned long Bit32u;
313
314#if BX_USE_ATADRV
315
316 void memsetb(seg,offset,value,count);
317 void memcpyb(dseg,doffset,sseg,soffset,count);
318 void memcpyd(dseg,doffset,sseg,soffset,count);
319
320 // memset of count bytes
321 void
322 memsetb(seg,offset,value,count)
323 Bit16u seg;
324 Bit16u offset;
325 Bit16u value;
326 Bit16u count;
327 {
328 ASM_START
329 push bp
330 mov bp, sp
331
332 push ax
333 push cx
334 push es
335 push di
336
337 mov cx, 10[bp] ; count
338 test cx, cx
339 je memsetb_end
340 mov ax, 4[bp] ; segment
341 mov es, ax
342 mov ax, 6[bp] ; offset
343 mov di, ax
344 mov al, 8[bp] ; value
345 cld
346 rep
347 stosb
348
349 memsetb_end:
350 pop di
351 pop es
352 pop cx
353 pop ax
354
355 pop bp
356 ASM_END
357 }
358
359#if 0
360 // memcpy of count bytes
361 void
362 memcpyb(dseg,doffset,sseg,soffset,count)
363 Bit16u dseg;
364 Bit16u doffset;
365 Bit16u sseg;
366 Bit16u soffset;
367 Bit16u count;
368 {
369 ASM_START
370 push bp
371 mov bp, sp
372
373 push ax
374 push cx
375 push es
376 push di
377 push ds
378 push si
379
380 mov cx, 12[bp] ; count
381 cmp cx, #0x0000
382 je memcpyb_end
383 mov ax, 4[bp] ; dsegment
384 mov es, ax
385 mov ax, 6[bp] ; doffset
386 mov di, ax
387 mov ax, 8[bp] ; ssegment
388 mov ds, ax
389 mov ax, 10[bp] ; soffset
390 mov si, ax
391 cld
392 rep
393 movsb
394
395 memcpyb_end:
396 pop si
397 pop ds
398 pop di
399 pop es
400 pop cx
401 pop ax
402
403 pop bp
404 ASM_END
405 }
406
407 // memcpy of count dword
408 void
409 memcpyd(dseg,doffset,sseg,soffset,count)
410 Bit16u dseg;
411 Bit16u doffset;
412 Bit16u sseg;
413 Bit16u soffset;
414 Bit16u count;
415 {
416 ASM_START
417 push bp
418 mov bp, sp
419
420 push ax
421 push cx
422 push es
423 push di
424 push ds
425 push si
426
427 mov cx, 12[bp] ; count
428 test cx, cx
429 je memcpyd_end
430 mov ax, 4[bp] ; dsegment
431 mov es, ax
432 mov ax, 6[bp] ; doffset
433 mov di, ax
434 mov ax, 8[bp] ; ssegment
435 mov ds, ax
436 mov ax, 10[bp] ; soffset
437 mov si, ax
438 cld
439 rep
440 movsd
441
442 memcpyd_end:
443 pop si
444 pop ds
445 pop di
446 pop es
447 pop cx
448 pop ax
449
450 pop bp
451 ASM_END
452 }
453#endif
454#endif //BX_USE_ATADRV
455
456 // read_dword and write_dword functions
457 static Bit32u read_dword();
458 static void write_dword();
459
460 Bit32u
461 read_dword(seg, offset)
462 Bit16u seg;
463 Bit16u offset;
464 {
465 ASM_START
466 push bp
467 mov bp, sp
468
469 push bx
470 push ds
471 mov ax, 4[bp] ; segment
472 mov ds, ax
473 mov bx, 6[bp] ; offset
474 mov ax, [bx]
475 add bx, #2
476 mov dx, [bx]
477 ;; ax = return value (word)
478 ;; dx = return value (word)
479 pop ds
480 pop bx
481
482 pop bp
483 ASM_END
484 }
485
486 void
487 write_dword(seg, offset, data)
488 Bit16u seg;
489 Bit16u offset;
490 Bit32u data;
491 {
492 ASM_START
493 push bp
494 mov bp, sp
495
496 push ax
497 push bx
498 push ds
499 mov ax, 4[bp] ; segment
500 mov ds, ax
501 mov bx, 6[bp] ; offset
502 mov ax, 8[bp] ; data word
503 mov [bx], ax ; write data word
504 add bx, #2
505 mov ax, 10[bp] ; data word
506 mov [bx], ax ; write data word
507 pop ds
508 pop bx
509 pop ax
510
511 pop bp
512 ASM_END
513 }
514
515 // Bit32u (unsigned long) and long helper functions
516 ASM_START
517
518 ;; and function
519 landl:
520 landul:
521 SEG SS
522 and ax,[di]
523 SEG SS
524 and bx,2[di]
525 ret
526
527 ;; add function
528 laddl:
529 laddul:
530 SEG SS
531 add ax,[di]
532 SEG SS
533 adc bx,2[di]
534 ret
535
536 ;; cmp function
537 lcmpl:
538 lcmpul:
539 and eax, #0x0000FFFF
540 shl ebx, #16
541 or eax, ebx
542 shr ebx, #16
543 SEG SS
544 cmp eax, dword ptr [di]
545 ret
546
547 ;; sub function
548 lsubl:
549 lsubul:
550 SEG SS
551 sub ax,[di]
552 SEG SS
553 sbb bx,2[di]
554 ret
555
556 ;; mul function
557 lmull:
558 lmulul:
559 and eax, #0x0000FFFF
560 shl ebx, #16
561 or eax, ebx
562 SEG SS
563 mul eax, dword ptr [di]
564 mov ebx, eax
565 shr ebx, #16
566 ret
567
568 ;; dec function
569 ldecl:
570 ldecul:
571 SEG SS
572 dec dword ptr [bx]
573 ret
574
575 ;; or function
576 lorl:
577 lorul:
578 SEG SS
579 or ax,[di]
580 SEG SS
581 or bx,2[di]
582 ret
583
584 ;; inc function
585 lincl:
586 lincul:
587 SEG SS
588 inc dword ptr [bx]
589 ret
590
591 ;; tst function
592 ltstl:
593 ltstul:
594 and eax, #0x0000FFFF
595 shl ebx, #16
596 or eax, ebx
597 shr ebx, #16
598 test eax, eax
599 ret
600
601 ;; sr function
602 lsrul:
603 mov cx,di
604 jcxz lsr_exit
605 and eax, #0x0000FFFF
606 shl ebx, #16
607 or eax, ebx
608 lsr_loop:
609 shr eax, #1
610 loop lsr_loop
611 mov ebx, eax
612 shr ebx, #16
613 lsr_exit:
614 ret
615
616 ;; sl function
617 lsll:
618 lslul:
619 mov cx,di
620 jcxz lsl_exit
621 and eax, #0x0000FFFF
622 shl ebx, #16
623 or eax, ebx
624 lsl_loop:
625 shl eax, #1
626 loop lsl_loop
627 mov ebx, eax
628 shr ebx, #16
629 lsl_exit:
630 ret
631
632 idiv_:
633 cwd
634 idiv bx
635 ret
636
637 idiv_u:
638 xor dx,dx
639 div bx
640 ret
641
642 ldivul:
643 and eax, #0x0000FFFF
644 shl ebx, #16
645 or eax, ebx
646 xor edx, edx
647 SEG SS
648 mov bx, 2[di]
649 shl ebx, #16
650 SEG SS
651 mov bx, [di]
652 div ebx
653 mov ebx, eax
654 shr ebx, #16
655 ret
656
657 ASM_END
658
659// for access to RAM area which is used by interrupt vectors
660// and BIOS Data Area
661
662typedef struct {
663 unsigned char filler1[0x400];
664 unsigned char filler2[0x6c];
665 Bit16u ticks_low;
666 Bit16u ticks_high;
667 Bit8u midnight_flag;
668 } bios_data_t;
669
670#define BiosData ((bios_data_t *) 0)
671
672#if BX_USE_ATADRV
673 typedef struct {
674 Bit16u heads; // # heads
675 Bit16u cylinders; // # cylinders
676 Bit16u spt; // # sectors / track
677 } chs_t;
678
679 // DPTE definition
680 typedef struct {
681 Bit16u iobase1;
682 Bit16u iobase2;
683 Bit8u prefix;
684 Bit8u unused;
685 Bit8u irq;
686 Bit8u blkcount;
687 Bit8u dma;
688 Bit8u pio;
689 Bit16u options;
690 Bit16u reserved;
691 Bit8u revision;
692 Bit8u checksum;
693 } dpte_t;
694
695 typedef struct {
696 Bit8u iface; // ISA or PCI
697 Bit16u iobase1; // IO Base 1
698 Bit16u iobase2; // IO Base 2
699 Bit8u irq; // IRQ
700 } ata_channel_t;
701
702 typedef struct {
703 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
704 Bit8u device; // Detected type of attached devices (hd/cd/none)
705 Bit8u removable; // Removable device flag
706 Bit8u lock; // Locks for removable devices
707 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
708 Bit16u blksize; // block size
709
710 Bit8u translation; // type of translation
711 chs_t lchs; // Logical CHS
712 chs_t pchs; // Physical CHS
713
714 Bit32u sectors; // Total sectors count
715 } ata_device_t;
716
717 typedef struct {
718 // ATA channels info
719 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
720
721 // ATA devices info
722 ata_device_t devices[BX_MAX_ATA_DEVICES];
723 //
724 // map between (bios hd id - 0x80) and ata channels and scsi disks.
725#ifdef VBOX_WITH_SCSI
726 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
727#else
728 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
729#endif
730
731 // map between (bios cd id - 0xE0) and ata channels
732 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
733
734 // Buffer for DPTE table
735 dpte_t dpte;
736
737 // Count of transferred sectors and bytes
738 Bit16u trsfsectors;
739 Bit32u trsfbytes;
740
741 } ata_t;
742
743#if BX_ELTORITO_BOOT
744 // ElTorito Device Emulation data
745 typedef struct {
746 Bit8u active;
747 Bit8u media;
748 Bit8u emulated_drive;
749 Bit8u controller_index;
750 Bit16u device_spec;
751 Bit32u ilba;
752 Bit16u buffer_segment;
753 Bit16u load_segment;
754 Bit16u sector_count;
755
756 // Virtual device
757 chs_t vdevice;
758 } cdemu_t;
759#endif // BX_ELTORITO_BOOT
760
761#ifdef VBOX_WITH_SCSI
762 typedef struct {
763 // I/O port this device is attached to.
764 Bit16u io_base;
765 // Target Id.
766 Bit8u target_id;
767 // SCSI devices info
768 ata_device_t device_info;
769 } scsi_device_t;
770
771 typedef struct {
772 // SCSi device info
773 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
774 // Number of scsi disks.
775 Bit8u hdcount;
776 } scsi_t;
777#endif
778
779 // for access to EBDA area
780 // The EBDA structure should conform to
781 // http://www.frontiernet.net/~fys/rombios.htm document
782 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
783 typedef struct {
784 unsigned char filler1[0x3D];
785
786 // FDPT - Can be splitted in data members if needed
787 unsigned char fdpt0[0x10];
788 unsigned char fdpt1[0x10];
789
790 unsigned char filler2[0xC4];
791
792 // ATA Driver data
793 ata_t ata;
794
795#if BX_ELTORITO_BOOT
796 // El Torito Emulation data
797 cdemu_t cdemu;
798#endif // BX_ELTORITO_BOOT
799
800#ifdef VBOX
801
802#ifdef VBOX_WITH_SCSI
803 // SCSI Driver data
804 scsi_t scsi;
805# endif
806
807 unsigned char uForceBootDrive;
808 unsigned char uForceBootDevice;
809#endif /* VBOX */
810
811 } ebda_data_t;
812
813#ifdef VBOX
814 // the last 16 bytes of the EBDA segment are used for the MPS floating
815 // pointer structure (only if an IOAPIC is present)
816#endif
817
818 #define EbdaData ((ebda_data_t *) 0)
819
820 // for access to the int13ext structure
821 typedef struct {
822 Bit8u size;
823 Bit8u reserved;
824 Bit16u count;
825 Bit16u offset;
826 Bit16u segment;
827 Bit32u lba1;
828 Bit32u lba2;
829 } int13ext_t;
830
831 #define Int13Ext ((int13ext_t *) 0)
832
833 // Disk Physical Table definition
834 typedef struct {
835 Bit16u size;
836 Bit16u infos;
837 Bit32u cylinders;
838 Bit32u heads;
839 Bit32u spt;
840 Bit32u sector_count1;
841 Bit32u sector_count2;
842 Bit16u blksize;
843 Bit16u dpte_offset;
844 Bit16u dpte_segment;
845 Bit16u key;
846 Bit8u dpi_length;
847 Bit8u reserved1;
848 Bit16u reserved2;
849 Bit8u host_bus[4];
850 Bit8u iface_type[8];
851 Bit8u iface_path[8];
852 Bit8u device_path[8];
853 Bit8u reserved3;
854 Bit8u checksum;
855 } dpt_t;
856
857 #define Int13DPT ((dpt_t *) 0)
858
859#endif // BX_USE_ATADRV
860
861typedef struct {
862 union {
863 struct {
864 Bit16u di, si, bp, sp;
865 Bit16u bx, dx, cx, ax;
866 } r16;
867 struct {
868 Bit16u filler[4];
869 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
870 } r8;
871 } u;
872 } pusha_regs_t;
873
874typedef struct {
875 union {
876 struct {
877 Bit32u edi, esi, ebp, esp;
878 Bit32u ebx, edx, ecx, eax;
879 } r32;
880 struct {
881 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
882 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
883 } r16;
884 struct {
885 Bit32u filler[4];
886 Bit8u bl, bh;
887 Bit16u filler1;
888 Bit8u dl, dh;
889 Bit16u filler2;
890 Bit8u cl, ch;
891 Bit16u filler3;
892 Bit8u al, ah;
893 Bit16u filler4;
894 } r8;
895 } u;
896} pushad_regs_t;
897
898typedef struct {
899 union {
900 struct {
901 Bit16u flags;
902 } r16;
903 struct {
904 Bit8u flagsl;
905 Bit8u flagsh;
906 } r8;
907 } u;
908 } flags_t;
909
910#define SetCF(x) x.u.r8.flagsl |= 0x01
911#define SetZF(x) x.u.r8.flagsl |= 0x40
912#define ClearCF(x) x.u.r8.flagsl &= 0xfe
913#define ClearZF(x) x.u.r8.flagsl &= 0xbf
914#define GetCF(x) (x.u.r8.flagsl & 0x01)
915
916typedef struct {
917 Bit16u ip;
918 Bit16u cs;
919 flags_t flags;
920 } iret_addr_t;
921
922
923
924static Bit8u inb();
925static Bit8u inb_cmos();
926static void outb();
927static void outb_cmos();
928static Bit16u inw();
929static void outw();
930static void init_rtc();
931static bx_bool rtc_updating();
932
933static Bit8u read_byte();
934static Bit16u read_word();
935static void write_byte();
936static void write_word();
937static void bios_printf();
938
939static Bit8u send_to_mouse_ctrl();
940static Bit8u get_mouse_data();
941static void set_kbd_command_byte();
942
943static void int09_function();
944static void int13_harddisk();
945static void int13_cdrom();
946static void int13_cdemu();
947static void int13_eltorito();
948static void int13_diskette_function();
949static void int14_function();
950static void int15_function();
951static void int16_function();
952static void int17_function();
953static Bit32u int19_function();
954static void int1a_function();
955static void int70_function();
956static void int74_function();
957static void dummy_isr_function();
958static Bit16u get_CS();
959static Bit16u get_SS();
960static unsigned int enqueue_key();
961static unsigned int dequeue_key();
962static void get_hd_geometry();
963static void set_diskette_ret_status();
964static void set_diskette_current_cyl();
965static void determine_floppy_media();
966static bx_bool floppy_drive_exists();
967static bx_bool floppy_drive_recal();
968static bx_bool floppy_media_known();
969static bx_bool floppy_media_sense();
970static bx_bool set_enable_a20();
971static void debugger_on();
972static void debugger_off();
973static void keyboard_init();
974static void keyboard_panic();
975static void shutdown_status_panic();
976static void nmi_handler_msg();
977
978static void print_bios_banner();
979static void print_boot_device();
980static void print_boot_failure();
981static void print_cdromboot_failure();
982
983# if BX_USE_ATADRV
984
985// ATA / ATAPI driver
986void ata_init();
987void ata_detect();
988void ata_reset();
989
990Bit16u ata_cmd_non_data();
991Bit16u ata_cmd_data_in();
992Bit16u ata_cmd_data_out();
993Bit16u ata_cmd_packet();
994
995Bit16u atapi_get_sense();
996Bit16u atapi_is_ready();
997Bit16u atapi_is_cdrom();
998
999#endif // BX_USE_ATADRV
1000
1001#if BX_ELTORITO_BOOT
1002
1003void cdemu_init();
1004Bit8u cdemu_isactive();
1005Bit8u cdemu_emulated_drive();
1006
1007Bit16u cdrom_boot();
1008
1009#endif // BX_ELTORITO_BOOT
1010
1011#ifdef VBOX
1012static char bios_prefix_string[] = "BIOS: ";
1013/* Do not use build timestamps in this string. Otherwise even rebuilding the
1014 * very same code will lead to compare errors when restoring saved state. */
1015static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1016#define BIOS_COPYRIGHT_STRING "Sun VirtualBox BIOS"
1017#else /* !VBOX */
1018static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1019
1020#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1021#endif /* !VBOX */
1022
1023#define BIOS_PRINTF_HALT 1
1024#define BIOS_PRINTF_SCREEN 2
1025#define BIOS_PRINTF_INFO 4
1026#define BIOS_PRINTF_DEBUG 8
1027#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1028#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1029
1030#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1031
1032// Defines the output macros.
1033// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1034// per-device basis. Debug info are sent only in debug mode
1035#if DEBUG_ROMBIOS
1036# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1037#else
1038# define BX_DEBUG(format, p...)
1039#endif
1040#ifdef VBOX
1041#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, get_CS(), bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
1042#else /* !VBOX */
1043#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1044#endif /* !VBOX */
1045#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1046
1047#if DEBUG_ATA
1048# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1049#else
1050# define BX_DEBUG_ATA(a...)
1051#endif
1052#if DEBUG_INT13_HD
1053# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1054#else
1055# define BX_DEBUG_INT13_HD(a...)
1056#endif
1057#if DEBUG_INT13_CD
1058# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1059#else
1060# define BX_DEBUG_INT13_CD(a...)
1061#endif
1062#if DEBUG_INT13_ET
1063# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1064#else
1065# define BX_DEBUG_INT13_ET(a...)
1066#endif
1067#if DEBUG_INT13_FL
1068# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1069#else
1070# define BX_DEBUG_INT13_FL(a...)
1071#endif
1072#if DEBUG_INT15
1073# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1074#else
1075# define BX_DEBUG_INT15(a...)
1076#endif
1077#if DEBUG_INT16
1078# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1079#else
1080# define BX_DEBUG_INT16(a...)
1081#endif
1082#if DEBUG_INT1A
1083# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1084#else
1085# define BX_DEBUG_INT1A(a...)
1086#endif
1087#if DEBUG_INT74
1088# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1089#else
1090# define BX_DEBUG_INT74(a...)
1091#endif
1092
1093#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1094#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1095#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1096#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1097#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1098#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1099#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1100#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1101
1102#define GET_AL() ( AX & 0x00ff )
1103#define GET_BL() ( BX & 0x00ff )
1104#define GET_CL() ( CX & 0x00ff )
1105#define GET_DL() ( DX & 0x00ff )
1106#define GET_AH() ( AX >> 8 )
1107#define GET_BH() ( BX >> 8 )
1108#define GET_CH() ( CX >> 8 )
1109#define GET_DH() ( DX >> 8 )
1110
1111#define GET_ELDL() ( ELDX & 0x00ff )
1112#define GET_ELDH() ( ELDX >> 8 )
1113
1114#define SET_CF() FLAGS |= 0x0001
1115#define CLEAR_CF() FLAGS &= 0xfffe
1116#define GET_CF() (FLAGS & 0x0001)
1117
1118#define SET_ZF() FLAGS |= 0x0040
1119#define CLEAR_ZF() FLAGS &= 0xffbf
1120#define GET_ZF() (FLAGS & 0x0040)
1121
1122#define UNSUPPORTED_FUNCTION 0x86
1123
1124#define none 0
1125#define MAX_SCAN_CODE 0x58
1126
1127static struct {
1128 Bit16u normal;
1129 Bit16u shift;
1130 Bit16u control;
1131 Bit16u alt;
1132 Bit8u lock_flags;
1133 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1134 { none, none, none, none, none },
1135 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1136 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1137 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1138 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1139 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1140 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1141 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1142 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1143 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1144 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1145 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1146 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1147 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1148 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1149 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1150 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1151 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1152 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1153 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1154 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1155 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1156 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1157 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1158 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1159 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1160 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1161 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1162 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1163 { none, none, none, none, none }, /* L Ctrl */
1164 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1165 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1166 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1167 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1168 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1169 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1170 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1171 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1172 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1173 { 0x273b, 0x273a, none, none, none }, /* ;: */
1174 { 0x2827, 0x2822, none, none, none }, /* '" */
1175 { 0x2960, 0x297e, none, none, none }, /* `~ */
1176 { none, none, none, none, none }, /* L shift */
1177 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1178 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1179 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1180 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1181 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1182 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1183 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1184 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1185 { 0x332c, 0x333c, none, none, none }, /* ,< */
1186 { 0x342e, 0x343e, none, none, none }, /* .> */
1187 { 0x352f, 0x353f, none, none, none }, /* /? */
1188 { none, none, none, none, none }, /* R Shift */
1189 { 0x372a, 0x372a, none, none, none }, /* * */
1190 { none, none, none, none, none }, /* L Alt */
1191 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1192 { none, none, none, none, none }, /* caps lock */
1193 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1194 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1195 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1196 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1197 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1198 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1199 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1200 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1201 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1202 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1203 { none, none, none, none, none }, /* Num Lock */
1204 { none, none, none, none, none }, /* Scroll Lock */
1205 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1206 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1207 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1208 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1209 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1210 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1211 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1212 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1213 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1214 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1215 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1216 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1217 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1218 { none, none, none, none, none },
1219 { none, none, none, none, none },
1220 { 0x565c, 0x567c, none, none, none }, /* \| */
1221#ifndef VBOX
1222 { 0x5700, 0x5700, none, none, none }, /* F11 */
1223 { 0x5800, 0x5800, none, none, none } /* F12 */
1224#else
1225 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1226 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1227#endif
1228 };
1229
1230 Bit8u
1231inb(port)
1232 Bit16u port;
1233{
1234ASM_START
1235 push bp
1236 mov bp, sp
1237
1238 push dx
1239 mov dx, 4[bp]
1240 in al, dx
1241 pop dx
1242
1243 pop bp
1244ASM_END
1245}
1246
1247#if BX_USE_ATADRV
1248 Bit16u
1249inw(port)
1250 Bit16u port;
1251{
1252ASM_START
1253 push bp
1254 mov bp, sp
1255
1256 push dx
1257 mov dx, 4[bp]
1258 in ax, dx
1259 pop dx
1260
1261 pop bp
1262ASM_END
1263}
1264#endif
1265
1266 void
1267outb(port, val)
1268 Bit16u port;
1269 Bit8u val;
1270{
1271ASM_START
1272 push bp
1273 mov bp, sp
1274
1275 push ax
1276 push dx
1277 mov dx, 4[bp]
1278 mov al, 6[bp]
1279 out dx, al
1280 pop dx
1281 pop ax
1282
1283 pop bp
1284ASM_END
1285}
1286
1287#if BX_USE_ATADRV
1288 void
1289outw(port, val)
1290 Bit16u port;
1291 Bit16u val;
1292{
1293ASM_START
1294 push bp
1295 mov bp, sp
1296
1297 push ax
1298 push dx
1299 mov dx, 4[bp]
1300 mov ax, 6[bp]
1301 out dx, ax
1302 pop dx
1303 pop ax
1304
1305 pop bp
1306ASM_END
1307}
1308#endif
1309
1310 void
1311outb_cmos(cmos_reg, val)
1312 Bit8u cmos_reg;
1313 Bit8u val;
1314{
1315ASM_START
1316 push bp
1317 mov bp, sp
1318
1319 mov al, 4[bp] ;; cmos_reg
1320 out 0x70, al
1321 mov al, 6[bp] ;; val
1322 out 0x71, al
1323
1324 pop bp
1325ASM_END
1326}
1327
1328 Bit8u
1329inb_cmos(cmos_reg)
1330 Bit8u cmos_reg;
1331{
1332ASM_START
1333 push bp
1334 mov bp, sp
1335
1336 mov al, 4[bp] ;; cmos_reg
1337 out 0x70, al
1338 in al, 0x71
1339
1340 pop bp
1341ASM_END
1342}
1343
1344 void
1345init_rtc()
1346{
1347 outb_cmos(0x0a, 0x26);
1348 outb_cmos(0x0b, 0x02);
1349 inb_cmos(0x0c);
1350 inb_cmos(0x0d);
1351}
1352
1353 bx_bool
1354rtc_updating()
1355{
1356 // This function checks to see if the update-in-progress bit
1357 // is set in CMOS Status Register A. If not, it returns 0.
1358 // If it is set, it tries to wait until there is a transition
1359 // to 0, and will return 0 if such a transition occurs. A 1
1360 // is returned only after timing out. The maximum period
1361 // that this bit should be set is constrained to 244useconds.
1362 // The count I use below guarantees coverage or more than
1363 // this time, with any reasonable IPS setting.
1364
1365 Bit16u count;
1366
1367 count = 25000;
1368 while (--count != 0) {
1369 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1370 return(0);
1371 }
1372 return(1); // update-in-progress never transitioned to 0
1373}
1374
1375
1376 Bit8u
1377read_byte(seg, offset)
1378 Bit16u seg;
1379 Bit16u offset;
1380{
1381ASM_START
1382 push bp
1383 mov bp, sp
1384
1385 push bx
1386 push ds
1387 mov ax, 4[bp] ; segment
1388 mov ds, ax
1389 mov bx, 6[bp] ; offset
1390 mov al, [bx]
1391 ;; al = return value (byte)
1392 pop ds
1393 pop bx
1394
1395 pop bp
1396ASM_END
1397}
1398
1399 Bit16u
1400read_word(seg, offset)
1401 Bit16u seg;
1402 Bit16u offset;
1403{
1404ASM_START
1405 push bp
1406 mov bp, sp
1407
1408 push bx
1409 push ds
1410 mov ax, 4[bp] ; segment
1411 mov ds, ax
1412 mov bx, 6[bp] ; offset
1413 mov ax, [bx]
1414 ;; ax = return value (word)
1415 pop ds
1416 pop bx
1417
1418 pop bp
1419ASM_END
1420}
1421
1422 void
1423write_byte(seg, offset, data)
1424 Bit16u seg;
1425 Bit16u offset;
1426 Bit8u data;
1427{
1428ASM_START
1429 push bp
1430 mov bp, sp
1431
1432 push ax
1433 push bx
1434 push ds
1435 mov ax, 4[bp] ; segment
1436 mov ds, ax
1437 mov bx, 6[bp] ; offset
1438 mov al, 8[bp] ; data byte
1439 mov [bx], al ; write data byte
1440 pop ds
1441 pop bx
1442 pop ax
1443
1444 pop bp
1445ASM_END
1446}
1447
1448 void
1449write_word(seg, offset, data)
1450 Bit16u seg;
1451 Bit16u offset;
1452 Bit16u data;
1453{
1454ASM_START
1455 push bp
1456 mov bp, sp
1457
1458 push ax
1459 push bx
1460 push ds
1461 mov ax, 4[bp] ; segment
1462 mov ds, ax
1463 mov bx, 6[bp] ; offset
1464 mov ax, 8[bp] ; data word
1465 mov [bx], ax ; write data word
1466 pop ds
1467 pop bx
1468 pop ax
1469
1470 pop bp
1471ASM_END
1472}
1473
1474 Bit16u
1475get_CS()
1476{
1477ASM_START
1478 mov ax, cs
1479ASM_END
1480}
1481
1482 Bit16u
1483get_SS()
1484{
1485ASM_START
1486 mov ax, ss
1487ASM_END
1488}
1489
1490#if BX_DEBUG_SERIAL
1491/* serial debug port*/
1492#define BX_DEBUG_PORT 0x03f8
1493
1494/* data */
1495#define UART_RBR 0x00
1496#define UART_THR 0x00
1497
1498/* control */
1499#define UART_IER 0x01
1500#define UART_IIR 0x02
1501#define UART_FCR 0x02
1502#define UART_LCR 0x03
1503#define UART_MCR 0x04
1504#define UART_DLL 0x00
1505#define UART_DLM 0x01
1506
1507/* status */
1508#define UART_LSR 0x05
1509#define UART_MSR 0x06
1510#define UART_SCR 0x07
1511
1512int uart_can_tx_byte(base_port)
1513 Bit16u base_port;
1514{
1515 return inb(base_port + UART_LSR) & 0x20;
1516}
1517
1518void uart_wait_to_tx_byte(base_port)
1519 Bit16u base_port;
1520{
1521 while (!uart_can_tx_byte(base_port));
1522}
1523
1524void uart_wait_until_sent(base_port)
1525 Bit16u base_port;
1526{
1527 while (!(inb(base_port + UART_LSR) & 0x40));
1528}
1529
1530void uart_tx_byte(base_port, data)
1531 Bit16u base_port;
1532 Bit8u data;
1533{
1534 uart_wait_to_tx_byte(base_port);
1535 outb(base_port + UART_THR, data);
1536 uart_wait_until_sent(base_port);
1537}
1538#endif
1539
1540 void
1541wrch(c)
1542 Bit8u c;
1543{
1544 ASM_START
1545 push bp
1546 mov bp, sp
1547
1548 push bx
1549 mov ah, #0x0e
1550 mov al, 4[bp]
1551 xor bx,bx
1552 int #0x10
1553 pop bx
1554
1555 pop bp
1556 ASM_END
1557}
1558
1559 void
1560send(action, c)
1561 Bit16u action;
1562 Bit8u c;
1563{
1564#if BX_DEBUG_SERIAL
1565 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1566 uart_tx_byte(BX_DEBUG_PORT, c);
1567#endif
1568#if BX_VIRTUAL_PORTS
1569 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1570 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1571#endif
1572 if (action & BIOS_PRINTF_SCREEN) {
1573 if (c == '\n') wrch('\r');
1574 wrch(c);
1575 }
1576}
1577
1578 void
1579put_int(action, val, width, neg)
1580 Bit16u action;
1581 short val, width;
1582 bx_bool neg;
1583{
1584 short nval = val / 10;
1585 if (nval)
1586 put_int(action, nval, width - 1, neg);
1587 else {
1588 while (--width > 0) send(action, ' ');
1589 if (neg) send(action, '-');
1590 }
1591 send(action, val - (nval * 10) + '0');
1592}
1593
1594 void
1595put_uint(action, val, width, neg)
1596 Bit16u action;
1597 unsigned short val;
1598 short width;
1599 bx_bool neg;
1600{
1601 unsigned short nval = val / 10;
1602 if (nval)
1603 put_uint(action, nval, width - 1, neg);
1604 else {
1605 while (--width > 0) send(action, ' ');
1606 if (neg) send(action, '-');
1607 }
1608 send(action, val - (nval * 10) + '0');
1609}
1610
1611 void
1612put_luint(action, val, width, neg)
1613 Bit16u action;
1614 unsigned long val;
1615 short width;
1616 bx_bool neg;
1617{
1618 unsigned long nval = val / 10;
1619 if (nval)
1620 put_luint(action, nval, width - 1, neg);
1621 else {
1622 while (--width > 0) send(action, ' ');
1623 if (neg) send(action, '-');
1624 }
1625 send(action, val - (nval * 10) + '0');
1626}
1627
1628void put_str(action, segment, offset)
1629 Bit16u action;
1630 Bit16u segment;
1631 Bit16u offset;
1632{
1633 Bit8u c;
1634
1635 while (c = read_byte(segment, offset)) {
1636 send(action, c);
1637 offset++;
1638 }
1639}
1640
1641
1642//--------------------------------------------------------------------------
1643// bios_printf()
1644// A compact variable argument printf function.
1645//
1646// Supports %[format_width][length]format
1647// where format can be x,X,u,d,s,S,c
1648// and the optional length modifier is l (ell)
1649//--------------------------------------------------------------------------
1650 void
1651bios_printf(action, s)
1652 Bit16u action;
1653 Bit8u *s;
1654{
1655 Bit8u c, format_char;
1656 bx_bool in_format;
1657 short i;
1658 Bit16u *arg_ptr;
1659 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1660
1661 arg_ptr = &s;
1662 arg_seg = get_SS();
1663
1664 in_format = 0;
1665 format_width = 0;
1666
1667 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1668#if BX_VIRTUAL_PORTS
1669 outb(PANIC_PORT2, 0x00);
1670#endif
1671 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1672 }
1673
1674 while (c = read_byte(get_CS(), s)) {
1675 if ( c == '%' ) {
1676 in_format = 1;
1677 format_width = 0;
1678 }
1679 else if (in_format) {
1680 if ( (c>='0') && (c<='9') ) {
1681 format_width = (format_width * 10) + (c - '0');
1682 }
1683 else {
1684 arg_ptr++; // increment to next arg
1685 arg = read_word(arg_seg, arg_ptr);
1686 if (c == 'x' || c == 'X') {
1687 if (format_width == 0)
1688 format_width = 4;
1689 if (c == 'x')
1690 hexadd = 'a';
1691 else
1692 hexadd = 'A';
1693 for (i=format_width-1; i>=0; i--) {
1694 nibble = (arg >> (4 * i)) & 0x000f;
1695 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1696 }
1697 }
1698 else if (c == 'u') {
1699 put_uint(action, arg, format_width, 0);
1700 }
1701 else if (c == 'l') {
1702 s++;
1703 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1704 arg_ptr++; /* increment to next arg */
1705 hibyte = read_word(arg_seg, arg_ptr);
1706 if (c == 'd') {
1707 if (hibyte & 0x8000)
1708 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1709 else
1710 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1711 }
1712 else if (c == 'u') {
1713 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1714 }
1715 else if (c == 'x' || c == 'X')
1716 {
1717 if (format_width == 0)
1718 format_width = 8;
1719 if (c == 'x')
1720 hexadd = 'a';
1721 else
1722 hexadd = 'A';
1723 for (i=format_width-1; i>=0; i--) {
1724 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1725 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1726 }
1727 }
1728 }
1729 else if (c == 'd') {
1730 if (arg & 0x8000)
1731 put_int(action, -arg, format_width - 1, 1);
1732 else
1733 put_int(action, arg, format_width, 0);
1734 }
1735 else if (c == 's') {
1736 put_str(action, get_CS(), arg);
1737 }
1738 else if (c == 'S') {
1739 hibyte = arg;
1740 arg_ptr++;
1741 arg = read_word(arg_seg, arg_ptr);
1742 put_str(action, hibyte, arg);
1743 }
1744 else if (c == 'c') {
1745 send(action, arg);
1746 }
1747 else
1748 BX_PANIC("bios_printf: unknown format\n");
1749 in_format = 0;
1750 }
1751 }
1752 else {
1753 send(action, c);
1754 }
1755 s ++;
1756 }
1757
1758 if (action & BIOS_PRINTF_HALT) {
1759 // freeze in a busy loop.
1760ASM_START
1761 cli
1762 halt2_loop:
1763 hlt
1764 jmp halt2_loop
1765ASM_END
1766 }
1767}
1768
1769//--------------------------------------------------------------------------
1770// keyboard_init
1771//--------------------------------------------------------------------------
1772// this file is based on LinuxBIOS implementation of keyboard.c
1773// could convert to #asm to gain space
1774 void
1775keyboard_init()
1776{
1777 Bit16u max;
1778
1779 /* ------------------- Flush buffers ------------------------*/
1780 /* Wait until buffer is empty */
1781 max=0xffff;
1782 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1783
1784 /* flush incoming keys */
1785 max=0x2000;
1786 while (--max > 0) {
1787 outb(0x80, 0x00);
1788 if (inb(0x64) & 0x01) {
1789 inb(0x60);
1790 max = 0x2000;
1791 }
1792 }
1793
1794 // Due to timer issues, and if the IPS setting is > 15000000,
1795 // the incoming keys might not be flushed here. That will
1796 // cause a panic a few lines below. See sourceforge bug report :
1797 // [ 642031 ] FATAL: Keyboard RESET error:993
1798
1799 /* ------------------- controller side ----------------------*/
1800 /* send cmd = 0xAA, self test 8042 */
1801 outb(0x64, 0xaa);
1802
1803 /* Wait until buffer is empty */
1804 max=0xffff;
1805 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1806 if (max==0x0) keyboard_panic(00);
1807
1808 /* Wait for data */
1809 max=0xffff;
1810 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1811 if (max==0x0) keyboard_panic(01);
1812
1813 /* read self-test result, 0x55 should be returned from 0x60 */
1814 if ((inb(0x60) != 0x55)){
1815 keyboard_panic(991);
1816 }
1817
1818 /* send cmd = 0xAB, keyboard interface test */
1819 outb(0x64,0xab);
1820
1821 /* Wait until buffer is empty */
1822 max=0xffff;
1823 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1824 if (max==0x0) keyboard_panic(10);
1825
1826 /* Wait for data */
1827 max=0xffff;
1828 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1829 if (max==0x0) keyboard_panic(11);
1830
1831 /* read keyboard interface test result, */
1832 /* 0x00 should be returned form 0x60 */
1833 if ((inb(0x60) != 0x00)) {
1834 keyboard_panic(992);
1835 }
1836
1837 /* Enable Keyboard clock */
1838 outb(0x64,0xae);
1839 outb(0x64,0xa8);
1840
1841 /* ------------------- keyboard side ------------------------*/
1842 /* reset kerboard and self test (keyboard side) */
1843 outb(0x60, 0xff);
1844
1845 /* Wait until buffer is empty */
1846 max=0xffff;
1847 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1848 if (max==0x0) keyboard_panic(20);
1849
1850 /* Wait for data */
1851 max=0xffff;
1852 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1853 if (max==0x0) keyboard_panic(21);
1854
1855 /* keyboard should return ACK */
1856 if ((inb(0x60) != 0xfa)) {
1857 keyboard_panic(993);
1858 }
1859
1860 /* Wait for data */
1861 max=0xffff;
1862 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1863 if (max==0x0) keyboard_panic(31);
1864
1865 if ((inb(0x60) != 0xaa)) {
1866 keyboard_panic(994);
1867 }
1868
1869 /* Disable keyboard */
1870 outb(0x60, 0xf5);
1871
1872 /* Wait until buffer is empty */
1873 max=0xffff;
1874 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1875 if (max==0x0) keyboard_panic(40);
1876
1877 /* Wait for data */
1878 max=0xffff;
1879 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1880 if (max==0x0) keyboard_panic(41);
1881
1882 /* keyboard should return ACK */
1883 if ((inb(0x60) != 0xfa)) {
1884 keyboard_panic(995);
1885 }
1886
1887 /* Write Keyboard Mode */
1888 outb(0x64, 0x60);
1889
1890 /* Wait until buffer is empty */
1891 max=0xffff;
1892 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1893 if (max==0x0) keyboard_panic(50);
1894
1895 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1896 outb(0x60, 0x65);
1897
1898 /* Wait until buffer is empty */
1899 max=0xffff;
1900 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1901 if (max==0x0) keyboard_panic(60);
1902
1903 /* Enable keyboard */
1904 outb(0x60, 0xf4);
1905
1906 /* Wait until buffer is empty */
1907 max=0xffff;
1908 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1909 if (max==0x0) keyboard_panic(70);
1910
1911 /* Wait for data */
1912 max=0xffff;
1913 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1914 if (max==0x0) keyboard_panic(70);
1915
1916 /* keyboard should return ACK */
1917 if ((inb(0x60) != 0xfa)) {
1918 keyboard_panic(996);
1919 }
1920
1921 outb(0x80, 0x77);
1922}
1923
1924//--------------------------------------------------------------------------
1925// keyboard_panic
1926//--------------------------------------------------------------------------
1927 void
1928keyboard_panic(status)
1929 Bit16u status;
1930{
1931 // If you're getting a 993 keyboard panic here,
1932 // please see the comment in keyboard_init
1933
1934 BX_PANIC("Keyboard error:%u\n",status);
1935}
1936
1937//--------------------------------------------------------------------------
1938// shutdown_status_panic
1939// called when the shutdown statsu is not implemented, displays the status
1940//--------------------------------------------------------------------------
1941 void
1942shutdown_status_panic(status)
1943 Bit16u status;
1944{
1945 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1946}
1947
1948#ifdef VBOX
1949#include "logo.c"
1950#endif /* VBOX */
1951
1952//--------------------------------------------------------------------------
1953// print_bios_banner
1954// displays a the bios version
1955//--------------------------------------------------------------------------
1956void
1957print_bios_banner()
1958{
1959#ifdef VBOX
1960 // Skip the logo if a warm boot is requested.
1961 Bit16u warm_boot = read_word(0x0040,0x0072);
1962 write_word(0x0040,0x0072, 0);
1963 if (warm_boot == 0x1234)
1964 return;
1965#if !defined(DEBUG) || defined(DEBUG_sunlover)
1966 /* show graphical logo */
1967 show_logo();
1968#else
1969 /* set text mode */
1970 ASM_START
1971 mov ax, #0x0003
1972 int #0x10
1973 ASM_END
1974#endif /* !DEBUG */
1975#else /* !VBOX */
1976 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1977 BIOS_BUILD_DATE, bios_cvs_version_string);
1978 printf(
1979#if BX_APM
1980 "apmbios "
1981#endif
1982#if BX_PCIBIOS
1983 "pcibios "
1984#endif
1985#if BX_ELTORITO_BOOT
1986 "eltorito "
1987#endif
1988#if BX_ROMBIOS32
1989 "rombios32 "
1990#endif
1991 "\n\n");
1992#endif /* VBOX */
1993}
1994
1995//--------------------------------------------------------------------------
1996// print_boot_device
1997// displays the boot device
1998//--------------------------------------------------------------------------
1999
2000#ifdef VBOX
2001static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
2002#else /* !VBOX */
2003static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
2004#endif /* !VBOX */
2005
2006#ifdef VBOX
2007void
2008print_boot_device(cdboot, lanboot, drive)
2009 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2010#else /* !VBOX */
2011void
2012print_boot_device(cdboot, drive)
2013 Bit8u cdboot; Bit16u drive;
2014#endif /* !VBOX */
2015{
2016 Bit8u i;
2017
2018#ifdef VBOX
2019 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2020 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2021#else /* !VBOX */
2022 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2023#endif /* !VBOX */
2024 // drive contains real/emulated boot drive
2025
2026 if(cdboot)i=2; // CD-Rom
2027#ifdef VBOX
2028 else if(lanboot)i=3; // LAN
2029#endif /* VBOX */
2030 else if((drive&0x0080)==0x00)i=0; // Floppy
2031 else if((drive&0x0080)==0x80)i=1; // Hard drive
2032 else return;
2033
2034#ifdef VBOX
2035 BX_INFO("Booting from %s...\n",drivetypes[i]);
2036#else /* !VBOX */
2037 printf("Booting from %s...\n",drivetypes[i]);
2038#endif /* !VBOX */
2039}
2040
2041//--------------------------------------------------------------------------
2042// print_boot_failure
2043// displays the reason why boot failed
2044//--------------------------------------------------------------------------
2045#ifdef VBOX
2046 void
2047print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2048 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2049#else /* !VBOX */
2050 void
2051print_boot_failure(cdboot, drive, reason, lastdrive)
2052 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2053#endif /* !VBOX */
2054{
2055 Bit16u drivenum = drive&0x7f;
2056
2057 // cdboot: 1 if boot from cd, 0 otherwise
2058#ifdef VBOX
2059 // lanboot: 1 if boot from lan, 0 otherwise
2060#endif /* VBOX */
2061 // drive : drive number
2062 // reason: 0 signature check failed, 1 read error
2063 // lastdrive: 1 boot drive is the last one in boot sequence
2064
2065 if (cdboot)
2066#ifndef VBOX
2067 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2068#else /* VBOX */
2069 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2070 else if (lanboot)
2071 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2072#endif /* VBOX */
2073 else if (drive & 0x80)
2074#ifndef VBOX
2075 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2076#else /* VBOX */
2077 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2078#endif /* VBOX */
2079 else
2080#ifndef VBOX
2081 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2082#else /* VBOX */
2083 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2084#endif /* VBOX */
2085
2086 if (lastdrive==1) {
2087 if (reason==0)
2088#ifndef VBOX
2089 BX_PANIC("Not a bootable disk\n");
2090#else /* VBOX */
2091 BX_PANIC("No bootable medium found! System halted.\n");
2092#endif /* VBOX */
2093 else
2094#ifndef VBOX
2095 BX_PANIC("Could not read the boot disk\n");
2096#else /* VBOX */
2097 BX_PANIC("Could not read from the boot medium! System halted.\n");
2098#endif /* VBOX */
2099 }
2100}
2101
2102//--------------------------------------------------------------------------
2103// print_cdromboot_failure
2104// displays the reason why boot failed
2105//--------------------------------------------------------------------------
2106 void
2107print_cdromboot_failure( code )
2108 Bit16u code;
2109{
2110#ifndef VBOX
2111 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2112#else /* VBOX */
2113 BX_INFO("CDROM boot failure code : %04x\n",code);
2114#endif /* VBOX */
2115
2116 return;
2117}
2118
2119void
2120nmi_handler_msg()
2121{
2122 BX_PANIC("NMI Handler called\n");
2123}
2124
2125void
2126int18_panic_msg()
2127{
2128 BX_PANIC("INT18: BOOT FAILURE\n");
2129}
2130
2131void
2132log_bios_start()
2133{
2134#if BX_DEBUG_SERIAL
2135 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2136#endif
2137 BX_INFO("%s\n", bios_cvs_version_string);
2138}
2139
2140 bx_bool
2141set_enable_a20(val)
2142 bx_bool val;
2143{
2144 Bit8u oldval;
2145
2146 // Use PS2 System Control port A to set A20 enable
2147
2148 // get current setting first
2149 oldval = inb(0x92);
2150
2151 // change A20 status
2152 if (val)
2153 outb(0x92, oldval | 0x02);
2154 else
2155 outb(0x92, oldval & 0xfd);
2156
2157 return((oldval & 0x02) != 0);
2158}
2159
2160 void
2161debugger_on()
2162{
2163 outb(0xfedc, 0x01);
2164}
2165
2166 void
2167debugger_off()
2168{
2169 outb(0xfedc, 0x00);
2170}
2171
2172#if BX_USE_ATADRV
2173
2174// ---------------------------------------------------------------------------
2175// Start of ATA/ATAPI Driver
2176// ---------------------------------------------------------------------------
2177
2178// Global defines -- ATA register and register bits.
2179// command block & control block regs
2180#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2181#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2182#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2183#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2184#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2185#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2186#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2187#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2188#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2189#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2190#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2191#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2192#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2193
2194#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2195#define ATA_CB_ER_BBK 0x80 // ATA bad block
2196#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2197#define ATA_CB_ER_MC 0x20 // ATA media change
2198#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2199#define ATA_CB_ER_MCR 0x08 // ATA media change request
2200#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2201#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2202#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2203
2204#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2205#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2206#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2207#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2208#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2209
2210// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2211#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2212#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2213#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2214#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2215
2216// bits 7-4 of the device/head (CB_DH) reg
2217#define ATA_CB_DH_DEV0 0xa0 // select device 0
2218#define ATA_CB_DH_DEV1 0xb0 // select device 1
2219
2220// status reg (CB_STAT and CB_ASTAT) bits
2221#define ATA_CB_STAT_BSY 0x80 // busy
2222#define ATA_CB_STAT_RDY 0x40 // ready
2223#define ATA_CB_STAT_DF 0x20 // device fault
2224#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2225#define ATA_CB_STAT_SKC 0x10 // seek complete
2226#define ATA_CB_STAT_SERV 0x10 // service
2227#define ATA_CB_STAT_DRQ 0x08 // data request
2228#define ATA_CB_STAT_CORR 0x04 // corrected
2229#define ATA_CB_STAT_IDX 0x02 // index
2230#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2231#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2232
2233// device control reg (CB_DC) bits
2234#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2235#define ATA_CB_DC_SRST 0x04 // soft reset
2236#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2237
2238// Most mandtory and optional ATA commands (from ATA-3),
2239#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2240#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2241#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2242#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2243#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2244#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2245#define ATA_CMD_CHECK_POWER_MODE2 0x98
2246#define ATA_CMD_DEVICE_RESET 0x08
2247#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2248#define ATA_CMD_FLUSH_CACHE 0xE7
2249#define ATA_CMD_FORMAT_TRACK 0x50
2250#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2251#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2252#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2253#define ATA_CMD_IDLE1 0xE3
2254#define ATA_CMD_IDLE2 0x97
2255#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2256#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2257#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2258#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2259#define ATA_CMD_NOP 0x00
2260#define ATA_CMD_PACKET 0xA0
2261#define ATA_CMD_READ_BUFFER 0xE4
2262#define ATA_CMD_READ_DMA 0xC8
2263#define ATA_CMD_READ_DMA_QUEUED 0xC7
2264#define ATA_CMD_READ_MULTIPLE 0xC4
2265#define ATA_CMD_READ_SECTORS 0x20
2266#ifdef VBOX
2267#define ATA_CMD_READ_SECTORS_EXT 0x24
2268#endif /* VBOX */
2269#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2270#define ATA_CMD_RECALIBRATE 0x10
2271#define ATA_CMD_SEEK 0x70
2272#define ATA_CMD_SET_FEATURES 0xEF
2273#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2274#define ATA_CMD_SLEEP1 0xE6
2275#define ATA_CMD_SLEEP2 0x99
2276#define ATA_CMD_STANDBY1 0xE2
2277#define ATA_CMD_STANDBY2 0x96
2278#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2279#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2280#define ATA_CMD_WRITE_BUFFER 0xE8
2281#define ATA_CMD_WRITE_DMA 0xCA
2282#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2283#define ATA_CMD_WRITE_MULTIPLE 0xC5
2284#define ATA_CMD_WRITE_SECTORS 0x30
2285#ifdef VBOX
2286#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2287#endif /* VBOX */
2288#define ATA_CMD_WRITE_VERIFY 0x3C
2289
2290#define ATA_IFACE_NONE 0x00
2291#define ATA_IFACE_ISA 0x00
2292#define ATA_IFACE_PCI 0x01
2293
2294#define ATA_TYPE_NONE 0x00
2295#define ATA_TYPE_UNKNOWN 0x01
2296#define ATA_TYPE_ATA 0x02
2297#define ATA_TYPE_ATAPI 0x03
2298#ifdef VBOX
2299#define ATA_TYPE_SCSI 0x04 // SCSI disk
2300#endif
2301
2302#define ATA_DEVICE_NONE 0x00
2303#define ATA_DEVICE_HD 0xFF
2304#define ATA_DEVICE_CDROM 0x05
2305
2306#define ATA_MODE_NONE 0x00
2307#define ATA_MODE_PIO16 0x00
2308#define ATA_MODE_PIO32 0x01
2309#define ATA_MODE_ISADMA 0x02
2310#define ATA_MODE_PCIDMA 0x03
2311#define ATA_MODE_USEIRQ 0x10
2312
2313#define ATA_TRANSLATION_NONE 0
2314#define ATA_TRANSLATION_LBA 1
2315#define ATA_TRANSLATION_LARGE 2
2316#define ATA_TRANSLATION_RECHS 3
2317
2318#define ATA_DATA_NO 0x00
2319#define ATA_DATA_IN 0x01
2320#define ATA_DATA_OUT 0x02
2321
2322// ---------------------------------------------------------------------------
2323// ATA/ATAPI driver : initialization
2324// ---------------------------------------------------------------------------
2325void ata_init( )
2326{
2327 Bit16u ebda_seg=read_word(0x0040,0x000E);
2328 Bit8u channel, device;
2329
2330 // Channels info init.
2331 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2332 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2333 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2334 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2335 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2336 }
2337
2338 // Devices info init.
2339 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2340 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2341 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2342 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2343 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2344 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2345 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2346 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2347 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2348 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2349 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2350 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2351 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2352 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2353
2354 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2355 }
2356
2357 // hdidmap and cdidmap init.
2358 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2359 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2360 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2361 }
2362
2363 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2364 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2365}
2366
2367// ---------------------------------------------------------------------------
2368// ATA/ATAPI driver : device detection
2369// ---------------------------------------------------------------------------
2370
2371void ata_detect( )
2372{
2373 Bit16u ebda_seg=read_word(0x0040,0x000E);
2374 Bit8u hdcount, cdcount, device, type;
2375 Bit8u buffer[0x0200];
2376
2377#if BX_MAX_ATA_INTERFACES > 0
2378 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2379 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2380 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2381 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2382#endif
2383#if BX_MAX_ATA_INTERFACES > 1
2384 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2385 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2386 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2387 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2388#endif
2389#if BX_MAX_ATA_INTERFACES > 2
2390 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2391 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2392 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2393 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2394#endif
2395#if BX_MAX_ATA_INTERFACES > 3
2396 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2397 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2398 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2399 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2400#endif
2401#if BX_MAX_ATA_INTERFACES > 4
2402#error Please fill the ATA interface informations
2403#endif
2404
2405 // Device detection
2406 hdcount=cdcount=0;
2407
2408 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2409 Bit16u iobase1, iobase2;
2410 Bit8u channel, slave, shift;
2411 Bit8u sc, sn, cl, ch, st;
2412
2413 channel = device / 2;
2414 slave = device % 2;
2415
2416 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2417 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2418
2419 // Disable interrupts
2420 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2421
2422 // Look for device
2423 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2424 outb(iobase1+ATA_CB_SC, 0x55);
2425 outb(iobase1+ATA_CB_SN, 0xaa);
2426 outb(iobase1+ATA_CB_SC, 0xaa);
2427 outb(iobase1+ATA_CB_SN, 0x55);
2428 outb(iobase1+ATA_CB_SC, 0x55);
2429 outb(iobase1+ATA_CB_SN, 0xaa);
2430
2431 // If we found something
2432 sc = inb(iobase1+ATA_CB_SC);
2433 sn = inb(iobase1+ATA_CB_SN);
2434
2435 if ( (sc == 0x55) && (sn == 0xaa) ) {
2436 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2437
2438 // reset the channel
2439 ata_reset(device);
2440
2441 // check for ATA or ATAPI
2442 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2443 sc = inb(iobase1+ATA_CB_SC);
2444 sn = inb(iobase1+ATA_CB_SN);
2445 if ((sc==0x01) && (sn==0x01)) {
2446 cl = inb(iobase1+ATA_CB_CL);
2447 ch = inb(iobase1+ATA_CB_CH);
2448 st = inb(iobase1+ATA_CB_STAT);
2449
2450 if ((cl==0x14) && (ch==0xeb)) {
2451 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2452 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2453 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2454 } else if ((cl==0xff) && (ch==0xff)) {
2455 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2456 }
2457 }
2458 }
2459
2460#ifdef VBOX
2461 // Enable interrupts
2462 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2463#endif /* VBOX */
2464
2465 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2466
2467 // Now we send a IDENTIFY command to ATA device
2468 if(type == ATA_TYPE_ATA) {
2469 Bit32u sectors;
2470 Bit16u cylinders, heads, spt, blksize;
2471#ifdef VBOX
2472 Bit16u lcylinders, lheads, lspt;
2473 Bit8u chsgeo_base;
2474#endif /* VBOX */
2475 Bit8u translation, removable, mode;
2476
2477 //Temporary values to do the transfer
2478 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2479 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2480
2481 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2482 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2483
2484 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2485 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2486#ifdef VBOX
2487 blksize = 512; /* There is no sector size field any more. */
2488#else /* !VBOX */
2489 blksize = read_word(get_SS(),buffer+10);
2490#endif /* !VBOX */
2491
2492 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2493 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2494 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2495
2496 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2497#ifdef VBOX
2498 /** @todo update sectors to be a 64 bit number (also lba...). */
2499 if (sectors == 268435455)
2500 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2501 switch (device)
2502 {
2503 case 0:
2504 chsgeo_base = 0x1e;
2505 break;
2506 case 1:
2507 chsgeo_base = 0x26;
2508 break;
2509 case 2:
2510 chsgeo_base = 0x67;
2511 break;
2512 case 3:
2513 chsgeo_base = 0x70;
2514 break;
2515 case 4:
2516 chsgeo_base = 0x40;
2517 break;
2518 case 5:
2519 chsgeo_base = 0x48;
2520 break;
2521 case 6:
2522 chsgeo_base = 0x50;
2523 break;
2524 case 7:
2525 chsgeo_base = 0x58;
2526 break;
2527 default:
2528 chsgeo_base = 0;
2529 }
2530 if (chsgeo_base != 0)
2531 {
2532 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2533 lheads = inb_cmos(chsgeo_base+2);
2534 lspt = inb_cmos(chsgeo_base+7);
2535 }
2536 else
2537 {
2538 lcylinders = 0;
2539 lheads = 0;
2540 lspt = 0;
2541 }
2542 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2543#endif /* VBOX */
2544
2545 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2546 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2547 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2548 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2551 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2552 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2553#ifdef VBOX
2554 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2555 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2556 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2557 if (device < 2)
2558 {
2559 Bit8u sum, i;
2560 unsigned char *fdpt;
2561 if (device == 0)
2562 fdpt = &EbdaData->fdpt0;
2563 else
2564 fdpt = &EbdaData->fdpt1;
2565
2566 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2567 * to be done at POST time with lots of ugly assembler code, which
2568 * isn't worth the effort of converting from AMI to Award CMOS
2569 * format. Just do it here. */
2570 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2571 write_byte(ebda_seg, fdpt + 0x02, lheads);
2572 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2573 write_word(ebda_seg, fdpt + 0x09, cylinders);
2574 write_byte(ebda_seg, fdpt + 0x0b, heads);
2575 write_byte(ebda_seg, fdpt + 0x04, spt);
2576 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2577 sum = 0;
2578 for (i = 0; i < 0xf; i++)
2579 sum += read_byte(ebda_seg, fdpt + i);
2580 sum = 1 - sum;
2581 write_byte(ebda_seg, fdpt + 0x0f, sum);
2582 }
2583#else /* !VBOX */
2584 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2585
2586 translation = inb_cmos(0x39 + channel/2);
2587 for (shift=device%4; shift>0; shift--) translation >>= 2;
2588 translation &= 0x03;
2589
2590 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2591
2592 switch (translation) {
2593 case ATA_TRANSLATION_NONE:
2594 BX_INFO("none");
2595 break;
2596 case ATA_TRANSLATION_LBA:
2597 BX_INFO("lba");
2598 break;
2599 case ATA_TRANSLATION_LARGE:
2600 BX_INFO("large");
2601 break;
2602 case ATA_TRANSLATION_RECHS:
2603 BX_INFO("r-echs");
2604 break;
2605 }
2606 switch (translation) {
2607 case ATA_TRANSLATION_NONE:
2608 break;
2609 case ATA_TRANSLATION_LBA:
2610 spt = 63;
2611 sectors /= 63;
2612 heads = sectors / 1024;
2613 if (heads>128) heads = 255;
2614 else if (heads>64) heads = 128;
2615 else if (heads>32) heads = 64;
2616 else if (heads>16) heads = 32;
2617 else heads=16;
2618 cylinders = sectors / heads;
2619 break;
2620 case ATA_TRANSLATION_RECHS:
2621 // Take care not to overflow
2622 if (heads==16) {
2623 if(cylinders>61439) cylinders=61439;
2624 heads=15;
2625 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2626 }
2627 // then go through the large bitshift process
2628 case ATA_TRANSLATION_LARGE:
2629 while(cylinders > 1024) {
2630 cylinders >>= 1;
2631 heads <<= 1;
2632
2633 // If we max out the head count
2634 if (heads > 127) break;
2635 }
2636 break;
2637 }
2638 // clip to 1024 cylinders in lchs
2639 if (cylinders > 1024) cylinders=1024;
2640 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2641
2642 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2643 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2644 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2645#endif /* VBOX */
2646
2647 // fill hdidmap
2648 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2649 hdcount++;
2650 }
2651
2652 // Now we send a IDENTIFY command to ATAPI device
2653 if(type == ATA_TYPE_ATAPI) {
2654
2655 Bit8u type, removable, mode;
2656 Bit16u blksize;
2657
2658 //Temporary values to do the transfer
2659 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2660 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2661
2662 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2663 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2664
2665 type = read_byte(get_SS(),buffer+1) & 0x1f;
2666 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2667 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2668 blksize = 2048;
2669
2670 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2671 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2672 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2673 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2674
2675 // fill cdidmap
2676 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2677 cdcount++;
2678 }
2679
2680 {
2681 Bit32u sizeinmb;
2682 Bit16u ataversion;
2683 Bit8u c, i, version, model[41];
2684
2685 switch (type) {
2686 case ATA_TYPE_ATA:
2687 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2688 sizeinmb >>= 11;
2689 case ATA_TYPE_ATAPI:
2690 // Read ATA/ATAPI version
2691 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2692 for(version=15;version>0;version--) {
2693 if((ataversion&(1<<version))!=0)
2694 break;
2695 }
2696
2697 // Read model name
2698 for(i=0;i<20;i++){
2699 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2700 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2701 }
2702
2703 // Reformat
2704 write_byte(get_SS(),model+40,0x00);
2705 for(i=39;i>0;i--){
2706 if(read_byte(get_SS(),model+i)==0x20)
2707 write_byte(get_SS(),model+i,0x00);
2708 else break;
2709 }
2710 break;
2711 }
2712
2713#ifdef VBOX
2714 // we don't want any noisy output for now
2715#else /* !VBOX */
2716 switch (type) {
2717 case ATA_TYPE_ATA:
2718 printf("ata%d %s: ",channel,slave?" slave":"master");
2719 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2720 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2721 break;
2722 case ATA_TYPE_ATAPI:
2723 printf("ata%d %s: ",channel,slave?" slave":"master");
2724 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2725 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2726 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2727 else
2728 printf(" ATAPI-%d Device\n",version);
2729 break;
2730 case ATA_TYPE_UNKNOWN:
2731 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2732 break;
2733 }
2734#endif /* !VBOX */
2735 }
2736 }
2737
2738 // Store the devices counts
2739 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2740 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2741 write_byte(0x40,0x75, hdcount);
2742
2743#ifdef VBOX
2744 // we don't want any noisy output for now
2745#else /* !VBOX */
2746 printf("\n");
2747#endif /* !VBOX */
2748
2749 // FIXME : should use bios=cmos|auto|disable bits
2750 // FIXME : should know about translation bits
2751 // FIXME : move hard_drive_post here
2752
2753}
2754
2755// ---------------------------------------------------------------------------
2756// ATA/ATAPI driver : software reset
2757// ---------------------------------------------------------------------------
2758// ATA-3
2759// 8.2.1 Software reset - Device 0
2760
2761void ata_reset(device)
2762Bit16u device;
2763{
2764 Bit16u ebda_seg=read_word(0x0040,0x000E);
2765 Bit16u iobase1, iobase2;
2766 Bit8u channel, slave, sn, sc;
2767 Bit16u max;
2768#ifdef VBOX
2769 Bit16u pdelay;
2770#endif /* VBOX */
2771
2772 channel = device / 2;
2773 slave = device % 2;
2774
2775 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2776 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2777
2778 // Reset
2779
2780// 8.2.1 (a) -- set SRST in DC
2781 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2782
2783// 8.2.1 (b) -- wait for BSY
2784 max=0xff;
2785 while(--max>0) {
2786 Bit8u status = inb(iobase1+ATA_CB_STAT);
2787 if ((status & ATA_CB_STAT_BSY) != 0) break;
2788 }
2789
2790// 8.2.1 (f) -- clear SRST
2791 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2792
2793 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2794
2795// 8.2.1 (g) -- check for sc==sn==0x01
2796 // select device
2797 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2798 sc = inb(iobase1+ATA_CB_SC);
2799 sn = inb(iobase1+ATA_CB_SN);
2800
2801 if ( (sc==0x01) && (sn==0x01) ) {
2802
2803// 8.2.1 (h) -- wait for not BSY
2804#ifdef VBOX
2805 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2806#else /* !VBOX */
2807 max=0xff;
2808#endif /* !VBOX */
2809 while(--max>0) {
2810 Bit8u status = inb(iobase1+ATA_CB_STAT);
2811 if ((status & ATA_CB_STAT_BSY) == 0) break;
2812#ifdef VBOX
2813 pdelay=0xffff;
2814 while (--pdelay>0) {
2815 /* nothing */
2816 }
2817#endif /* VBOX */
2818 }
2819 }
2820 }
2821
2822// 8.2.1 (i) -- wait for DRDY
2823#ifdef VBOX
2824 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2825#else /* !VBOX */
2826 max=0xfff;
2827#endif /* !VBOX */
2828 while(--max>0) {
2829 Bit8u status = inb(iobase1+ATA_CB_STAT);
2830 if ((status & ATA_CB_STAT_RDY) != 0) break;
2831 }
2832
2833 // Enable interrupts
2834 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2835}
2836
2837// ---------------------------------------------------------------------------
2838// ATA/ATAPI driver : execute a non data command
2839// ---------------------------------------------------------------------------
2840
2841Bit16u ata_cmd_non_data()
2842{return 0;}
2843
2844// ---------------------------------------------------------------------------
2845// ATA/ATAPI driver : execute a data-in command
2846// ---------------------------------------------------------------------------
2847 // returns
2848 // 0 : no error
2849 // 1 : BUSY bit set
2850 // 2 : read error
2851 // 3 : expected DRQ=1
2852 // 4 : no sectors left to read/verify
2853 // 5 : more sectors to read/verify
2854 // 6 : no sectors left to write
2855 // 7 : more sectors to write
2856Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2857Bit16u device, command, count, cylinder, head, sector, segment, offset;
2858Bit32u lba;
2859{
2860 Bit16u ebda_seg=read_word(0x0040,0x000E);
2861 Bit16u iobase1, iobase2, blksize;
2862 Bit8u channel, slave;
2863 Bit8u status, current, mode;
2864
2865 channel = device / 2;
2866 slave = device % 2;
2867
2868 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2869 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2870 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2871 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2872 if (mode == ATA_MODE_PIO32) blksize>>=2;
2873 else blksize>>=1;
2874
2875#ifdef VBOX
2876 status = inb(iobase1 + ATA_CB_STAT);
2877 if (status & ATA_CB_STAT_BSY)
2878 {
2879 // Enable interrupts
2880 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2881 return 1;
2882 }
2883#endif /* VBOX */
2884
2885 // sector will be 0 only on lba access. Convert to lba-chs
2886 if (sector == 0) {
2887#ifdef VBOX
2888 if (count >= 256 || lba + count >= 268435456)
2889 {
2890 sector = (lba & 0xff000000L) >> 24;
2891 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2892 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2893 outb(iobase1 + ATA_CB_SN, sector);
2894 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2895 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2896 /* Leave the bottom 24 bits as is, they are treated correctly by the
2897 * LBA28 code path. */
2898 lba &= 0xffffff;
2899 }
2900#endif /* VBOX */
2901 sector = (Bit16u) (lba & 0x000000ffL);
2902 lba >>= 8;
2903 cylinder = (Bit16u) (lba & 0x0000ffffL);
2904 lba >>= 16;
2905 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2906 }
2907
2908 // Reset count of transferred data
2909 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2910 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2911 current = 0;
2912
2913#ifndef VBOX
2914 status = inb(iobase1 + ATA_CB_STAT);
2915 if (status & ATA_CB_STAT_BSY) return 1;
2916#endif /* !VBOX */
2917
2918 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2919 outb(iobase1 + ATA_CB_FR, 0x00);
2920 outb(iobase1 + ATA_CB_SC, count);
2921 outb(iobase1 + ATA_CB_SN, sector);
2922 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2923 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2924 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2925 outb(iobase1 + ATA_CB_CMD, command);
2926
2927 while (1) {
2928 status = inb(iobase1 + ATA_CB_STAT);
2929 if ( !(status & ATA_CB_STAT_BSY) ) break;
2930 }
2931
2932 if (status & ATA_CB_STAT_ERR) {
2933 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2934#ifdef VBOX
2935 // Enable interrupts
2936 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2937#endif /* VBOX */
2938 return 2;
2939 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2940 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2941#ifdef VBOX
2942 // Enable interrupts
2943 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2944#endif /* VBOX */
2945 return 3;
2946 }
2947
2948 // FIXME : move seg/off translation here
2949
2950ASM_START
2951 sti ;; enable higher priority interrupts
2952ASM_END
2953
2954 while (1) {
2955
2956ASM_START
2957 push bp
2958 mov bp, sp
2959 mov di, _ata_cmd_data_in.offset + 2[bp]
2960 mov ax, _ata_cmd_data_in.segment + 2[bp]
2961 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2962
2963 ;; adjust if there will be an overrun. 2K max sector size
2964 cmp di, #0xf800 ;;
2965 jbe ata_in_no_adjust
2966
2967ata_in_adjust:
2968 sub di, #0x0800 ;; sub 2 kbytes from offset
2969 add ax, #0x0080 ;; add 2 Kbytes to segment
2970
2971ata_in_no_adjust:
2972 mov es, ax ;; segment in es
2973
2974 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2975
2976 mov ah, _ata_cmd_data_in.mode + 2[bp]
2977 cmp ah, #ATA_MODE_PIO32
2978 je ata_in_32
2979
2980ata_in_16:
2981 rep
2982 insw ;; CX words transfered from port(DX) to ES:[DI]
2983 jmp ata_in_done
2984
2985ata_in_32:
2986 rep
2987 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2988
2989ata_in_done:
2990 mov _ata_cmd_data_in.offset + 2[bp], di
2991 mov _ata_cmd_data_in.segment + 2[bp], es
2992 pop bp
2993ASM_END
2994
2995 current++;
2996 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2997 count--;
2998#ifdef VBOX
2999 while (1) {
3000 status = inb(iobase1 + ATA_CB_STAT);
3001 if ( !(status & ATA_CB_STAT_BSY) ) break;
3002 }
3003#else /* !VBOX */
3004 status = inb(iobase1 + ATA_CB_STAT);
3005#endif /* !VBOX */
3006 if (count == 0) {
3007 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3008 != ATA_CB_STAT_RDY ) {
3009 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3010#ifdef VBOX
3011 // Enable interrupts
3012 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3013#endif /* VBOX */
3014 return 4;
3015 }
3016 break;
3017 }
3018 else {
3019 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3020 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3021 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3022#ifdef VBOX
3023 // Enable interrupts
3024 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3025#endif /* VBOX */
3026 return 5;
3027 }
3028 continue;
3029 }
3030 }
3031 // Enable interrupts
3032 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3033 return 0;
3034}
3035
3036// ---------------------------------------------------------------------------
3037// ATA/ATAPI driver : execute a data-out command
3038// ---------------------------------------------------------------------------
3039 // returns
3040 // 0 : no error
3041 // 1 : BUSY bit set
3042 // 2 : read error
3043 // 3 : expected DRQ=1
3044 // 4 : no sectors left to read/verify
3045 // 5 : more sectors to read/verify
3046 // 6 : no sectors left to write
3047 // 7 : more sectors to write
3048Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3049Bit16u device, command, count, cylinder, head, sector, segment, offset;
3050Bit32u lba;
3051{
3052 Bit16u ebda_seg=read_word(0x0040,0x000E);
3053 Bit16u iobase1, iobase2, blksize;
3054 Bit8u channel, slave;
3055 Bit8u status, current, mode;
3056
3057 channel = device / 2;
3058 slave = device % 2;
3059
3060 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3061 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3062 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3063 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3064 if (mode == ATA_MODE_PIO32) blksize>>=2;
3065 else blksize>>=1;
3066
3067#ifdef VBOX
3068 status = inb(iobase1 + ATA_CB_STAT);
3069 if (status & ATA_CB_STAT_BSY)
3070 {
3071 // Enable interrupts
3072 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3073 return 1;
3074 }
3075#endif /* VBOX */
3076
3077 // sector will be 0 only on lba access. Convert to lba-chs
3078 if (sector == 0) {
3079#ifdef VBOX
3080 if (count >= 256 || lba + count >= 268435456)
3081 {
3082 sector = (lba & 0xff000000L) >> 24;
3083 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3084 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3085 outb(iobase1 + ATA_CB_SN, sector);
3086 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3087 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3088 /* Leave the bottom 24 bits as is, they are treated correctly by the
3089 * LBA28 code path. */
3090 lba &= 0xffffff;
3091 }
3092#endif /* VBOX */
3093 sector = (Bit16u) (lba & 0x000000ffL);
3094 lba >>= 8;
3095 cylinder = (Bit16u) (lba & 0x0000ffffL);
3096 lba >>= 16;
3097 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3098 }
3099
3100 // Reset count of transferred data
3101 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3102 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3103 current = 0;
3104
3105#ifndef VBOX
3106 status = inb(iobase1 + ATA_CB_STAT);
3107 if (status & ATA_CB_STAT_BSY) return 1;
3108#endif /* !VBOX */
3109
3110 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3111 outb(iobase1 + ATA_CB_FR, 0x00);
3112 outb(iobase1 + ATA_CB_SC, count);
3113 outb(iobase1 + ATA_CB_SN, sector);
3114 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3115 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3116 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3117 outb(iobase1 + ATA_CB_CMD, command);
3118
3119 while (1) {
3120 status = inb(iobase1 + ATA_CB_STAT);
3121 if ( !(status & ATA_CB_STAT_BSY) ) break;
3122 }
3123
3124 if (status & ATA_CB_STAT_ERR) {
3125 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3126#ifdef VBOX
3127 // Enable interrupts
3128 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3129#endif /* VBOX */
3130 return 2;
3131 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3132 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3133#ifdef VBOX
3134 // Enable interrupts
3135 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3136#endif /* VBOX */
3137 return 3;
3138 }
3139
3140 // FIXME : move seg/off translation here
3141
3142ASM_START
3143 sti ;; enable higher priority interrupts
3144ASM_END
3145
3146 while (1) {
3147
3148ASM_START
3149 push bp
3150 mov bp, sp
3151 mov si, _ata_cmd_data_out.offset + 2[bp]
3152 mov ax, _ata_cmd_data_out.segment + 2[bp]
3153 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3154
3155 ;; adjust if there will be an overrun. 2K max sector size
3156 cmp si, #0xf800 ;;
3157 jbe ata_out_no_adjust
3158
3159ata_out_adjust:
3160 sub si, #0x0800 ;; sub 2 kbytes from offset
3161 add ax, #0x0080 ;; add 2 Kbytes to segment
3162
3163ata_out_no_adjust:
3164 mov es, ax ;; segment in es
3165
3166 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3167
3168 mov ah, _ata_cmd_data_out.mode + 2[bp]
3169 cmp ah, #ATA_MODE_PIO32
3170 je ata_out_32
3171
3172ata_out_16:
3173 seg ES
3174 rep
3175 outsw ;; CX words transfered from port(DX) to ES:[SI]
3176 jmp ata_out_done
3177
3178ata_out_32:
3179 seg ES
3180 rep
3181 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3182
3183ata_out_done:
3184 mov _ata_cmd_data_out.offset + 2[bp], si
3185 mov _ata_cmd_data_out.segment + 2[bp], es
3186 pop bp
3187ASM_END
3188
3189 current++;
3190 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3191 count--;
3192#ifdef VBOX
3193 while (1) {
3194 status = inb(iobase1 + ATA_CB_STAT);
3195 if ( !(status & ATA_CB_STAT_BSY) ) break;
3196 }
3197#else /* !VBOX */
3198 status = inb(iobase1 + ATA_CB_STAT);
3199#endif /* VBOX */
3200 if (count == 0) {
3201 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3202 != ATA_CB_STAT_RDY ) {
3203 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3204#ifdef VBOX
3205 // Enable interrupts
3206 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3207#endif /* VBOX */
3208 return 6;
3209 }
3210 break;
3211 }
3212 else {
3213 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3214 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3215 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3216#ifdef VBOX
3217 // Enable interrupts
3218 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3219#endif /* VBOX */
3220 return 7;
3221 }
3222 continue;
3223 }
3224 }
3225 // Enable interrupts
3226 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3227 return 0;
3228}
3229
3230// ---------------------------------------------------------------------------
3231// ATA/ATAPI driver : execute a packet command
3232// ---------------------------------------------------------------------------
3233 // returns
3234 // 0 : no error
3235 // 1 : error in parameters
3236 // 2 : BUSY bit set
3237 // 3 : error
3238 // 4 : not ready
3239Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3240Bit8u cmdlen,inout;
3241Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3242Bit16u header;
3243Bit32u length;
3244{
3245 Bit16u ebda_seg=read_word(0x0040,0x000E);
3246 Bit16u iobase1, iobase2;
3247 Bit16u lcount, lbefore, lafter, count;
3248 Bit8u channel, slave;
3249 Bit8u status, mode, lmode;
3250 Bit32u total, transfer;
3251
3252 channel = device / 2;
3253 slave = device % 2;
3254
3255 // Data out is not supported yet
3256 if (inout == ATA_DATA_OUT) {
3257 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3258 return 1;
3259 }
3260
3261 // The header length must be even
3262 if (header & 1) {
3263 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3264 return 1;
3265 }
3266
3267 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3268 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3269 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3270 transfer= 0L;
3271
3272 if (cmdlen < 12) cmdlen=12;
3273 if (cmdlen > 12) cmdlen=16;
3274 cmdlen>>=1;
3275
3276 // Reset count of transferred data
3277 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3278 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3279
3280 status = inb(iobase1 + ATA_CB_STAT);
3281 if (status & ATA_CB_STAT_BSY) return 2;
3282
3283 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3284 // outb(iobase1 + ATA_CB_FR, 0x00);
3285 // outb(iobase1 + ATA_CB_SC, 0x00);
3286 // outb(iobase1 + ATA_CB_SN, 0x00);
3287 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3288 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3289 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3290 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3291
3292 // Device should ok to receive command
3293 while (1) {
3294 status = inb(iobase1 + ATA_CB_STAT);
3295 if ( !(status & ATA_CB_STAT_BSY) ) break;
3296 }
3297
3298 if (status & ATA_CB_STAT_ERR) {
3299 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3300#ifdef VBOX
3301 // Enable interrupts
3302 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3303#endif /* VBOX */
3304 return 3;
3305 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3306 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3307#ifdef VBOX
3308 // Enable interrupts
3309 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3310#endif /* VBOX */
3311 return 4;
3312 }
3313
3314 // Normalize address
3315 cmdseg += (cmdoff / 16);
3316 cmdoff %= 16;
3317
3318 // Send command to device
3319ASM_START
3320 sti ;; enable higher priority interrupts
3321
3322 push bp
3323 mov bp, sp
3324
3325 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3326 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3327 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3328 mov es, ax ;; segment in es
3329
3330 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3331
3332 seg ES
3333 rep
3334 outsw ;; CX words transfered from port(DX) to ES:[SI]
3335
3336 pop bp
3337ASM_END
3338
3339 if (inout == ATA_DATA_NO) {
3340 status = inb(iobase1 + ATA_CB_STAT);
3341 }
3342 else {
3343 while (1) {
3344
3345#ifdef VBOX
3346 while (1) {
3347 status = inb(iobase1 + ATA_CB_STAT);
3348 if ( !(status & ATA_CB_STAT_BSY) ) break;
3349 }
3350#else /* VBOX */
3351 status = inb(iobase1 + ATA_CB_STAT);
3352#endif /* VBOX */
3353
3354 // Check if command completed
3355 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3356
3357 if (status & ATA_CB_STAT_ERR) {
3358 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3359#ifdef VBOX
3360 // Enable interrupts
3361 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3362#endif /* VBOX */
3363 return 3;
3364 }
3365
3366 // Device must be ready to send data
3367 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3368 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3369 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3370#ifdef VBOX
3371 // Enable interrupts
3372 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3373#endif /* VBOX */
3374 return 4;
3375 }
3376
3377 // Normalize address
3378 bufseg += (bufoff / 16);
3379 bufoff %= 16;
3380
3381 // Get the byte count
3382 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3383
3384 // adjust to read what we want
3385 if(header>lcount) {
3386 lbefore=lcount;
3387 header-=lcount;
3388 lcount=0;
3389 }
3390 else {
3391 lbefore=header;
3392 header=0;
3393 lcount-=lbefore;
3394 }
3395
3396 if(lcount>length) {
3397 lafter=lcount-length;
3398 lcount=length;
3399 length=0;
3400 }
3401 else {
3402 lafter=0;
3403 length-=lcount;
3404 }
3405
3406 // Save byte count
3407 count = lcount;
3408
3409 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3410 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3411
3412 // If counts not dividable by 4, use 16bits mode
3413 lmode = mode;
3414 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3415 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3416 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3417
3418 // adds an extra byte if count are odd. before is always even
3419 if (lcount & 0x01) {
3420 lcount+=1;
3421 if ((lafter > 0) && (lafter & 0x01)) {
3422 lafter-=1;
3423 }
3424 }
3425
3426 if (lmode == ATA_MODE_PIO32) {
3427 lcount>>=2; lbefore>>=2; lafter>>=2;
3428 }
3429 else {
3430 lcount>>=1; lbefore>>=1; lafter>>=1;
3431 }
3432
3433 ; // FIXME bcc bug
3434
3435ASM_START
3436 push bp
3437 mov bp, sp
3438
3439 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3440
3441 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3442 jcxz ata_packet_no_before
3443
3444 mov ah, _ata_cmd_packet.lmode + 2[bp]
3445 cmp ah, #ATA_MODE_PIO32
3446 je ata_packet_in_before_32
3447
3448ata_packet_in_before_16:
3449 in ax, dx
3450 loop ata_packet_in_before_16
3451 jmp ata_packet_no_before
3452
3453ata_packet_in_before_32:
3454 push eax
3455ata_packet_in_before_32_loop:
3456 in eax, dx
3457 loop ata_packet_in_before_32_loop
3458 pop eax
3459
3460ata_packet_no_before:
3461 mov cx, _ata_cmd_packet.lcount + 2[bp]
3462 jcxz ata_packet_after
3463
3464 mov di, _ata_cmd_packet.bufoff + 2[bp]
3465 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3466 mov es, ax
3467
3468 mov ah, _ata_cmd_packet.lmode + 2[bp]
3469 cmp ah, #ATA_MODE_PIO32
3470 je ata_packet_in_32
3471
3472ata_packet_in_16:
3473 rep
3474 insw ;; CX words transfered tp port(DX) to ES:[DI]
3475 jmp ata_packet_after
3476
3477ata_packet_in_32:
3478 rep
3479 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3480
3481ata_packet_after:
3482 mov cx, _ata_cmd_packet.lafter + 2[bp]
3483 jcxz ata_packet_done
3484
3485 mov ah, _ata_cmd_packet.lmode + 2[bp]
3486 cmp ah, #ATA_MODE_PIO32
3487 je ata_packet_in_after_32
3488
3489ata_packet_in_after_16:
3490 in ax, dx
3491 loop ata_packet_in_after_16
3492 jmp ata_packet_done
3493
3494ata_packet_in_after_32:
3495 push eax
3496ata_packet_in_after_32_loop:
3497 in eax, dx
3498 loop ata_packet_in_after_32_loop
3499 pop eax
3500
3501ata_packet_done:
3502 pop bp
3503ASM_END
3504
3505 // Compute new buffer address
3506 bufoff += count;
3507
3508 // Save transferred bytes count
3509 transfer += count;
3510 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3511 }
3512 }
3513
3514 // Final check, device must be ready
3515 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3516 != ATA_CB_STAT_RDY ) {
3517 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3518#ifdef VBOX
3519 // Enable interrupts
3520 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3521#endif /* VBOX */
3522 return 4;
3523 }
3524
3525 // Enable interrupts
3526 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3527 return 0;
3528}
3529
3530// ---------------------------------------------------------------------------
3531// End of ATA/ATAPI Driver
3532// ---------------------------------------------------------------------------
3533
3534// ---------------------------------------------------------------------------
3535// Start of ATA/ATAPI generic functions
3536// ---------------------------------------------------------------------------
3537
3538 Bit16u
3539atapi_get_sense(device)
3540 Bit16u device;
3541{
3542 Bit8u atacmd[12];
3543 Bit8u buffer[16];
3544 Bit8u i;
3545
3546 memsetb(get_SS(),atacmd,0,12);
3547
3548 // Request SENSE
3549 atacmd[0]=0x03;
3550 atacmd[4]=0x20;
3551 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3552 return 0x0002;
3553
3554 if ((buffer[0] & 0x7e) == 0x70) {
3555 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3556 }
3557
3558 return 0;
3559}
3560
3561 Bit16u
3562atapi_is_ready(device)
3563 Bit16u device;
3564{
3565 Bit8u atacmd[12];
3566 Bit8u buffer[];
3567
3568 memsetb(get_SS(),atacmd,0,12);
3569
3570 // Test Unit Ready
3571 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3572 return 0x000f;
3573
3574 if (atapi_get_sense(device) !=0 ) {
3575 memsetb(get_SS(),atacmd,0,12);
3576
3577 // try to send Test Unit Ready again
3578 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3579 return 0x000f;
3580
3581 return atapi_get_sense(device);
3582 }
3583 return 0;
3584}
3585
3586 Bit16u
3587atapi_is_cdrom(device)
3588 Bit8u device;
3589{
3590 Bit16u ebda_seg=read_word(0x0040,0x000E);
3591
3592 if (device >= BX_MAX_ATA_DEVICES)
3593 return 0;
3594
3595 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3596 return 0;
3597
3598 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3599 return 0;
3600
3601 return 1;
3602}
3603
3604// ---------------------------------------------------------------------------
3605// End of ATA/ATAPI generic functions
3606// ---------------------------------------------------------------------------
3607
3608#endif // BX_USE_ATADRV
3609
3610#if BX_ELTORITO_BOOT
3611
3612// ---------------------------------------------------------------------------
3613// Start of El-Torito boot functions
3614// ---------------------------------------------------------------------------
3615
3616 void
3617cdemu_init()
3618{
3619 Bit16u ebda_seg=read_word(0x0040,0x000E);
3620
3621 // the only important data is this one for now
3622 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3623}
3624
3625 Bit8u
3626cdemu_isactive()
3627{
3628 Bit16u ebda_seg=read_word(0x0040,0x000E);
3629
3630 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3631}
3632
3633 Bit8u
3634cdemu_emulated_drive()
3635{
3636 Bit16u ebda_seg=read_word(0x0040,0x000E);
3637
3638 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3639}
3640
3641static char isotag[6]="CD001";
3642static char eltorito[24]="EL TORITO SPECIFICATION";
3643//
3644// Returns ah: emulated drive, al: error code
3645//
3646 Bit16u
3647cdrom_boot()
3648{
3649 Bit16u ebda_seg=read_word(0x0040,0x000E);
3650 Bit8u atacmd[12], buffer[2048];
3651 Bit32u lba;
3652 Bit16u boot_segment, nbsectors, i, error;
3653 Bit8u device;
3654#ifdef VBOX
3655 Bit8u read_try;
3656#endif /* VBOX */
3657
3658 // Find out the first cdrom
3659 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3660 if (atapi_is_cdrom(device)) break;
3661 }
3662
3663 // if not found
3664 if(device >= BX_MAX_ATA_DEVICES) return 2;
3665
3666 // Read the Boot Record Volume Descriptor
3667 memsetb(get_SS(),atacmd,0,12);
3668 atacmd[0]=0x28; // READ command
3669 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3670 atacmd[8]=(0x01 & 0x00ff); // Sectors
3671 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3672 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3673 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3674 atacmd[5]=(0x11 & 0x000000ff);
3675#ifdef VBOX
3676 for (read_try = 0; read_try <= 4; read_try++)
3677 {
3678 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3679 if (!error)
3680 break;
3681 }
3682 if (error)
3683 return 3;
3684#else /* !VBOX */
3685 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3686 return 3;
3687#endif /* !VBOX */
3688
3689 // Validity checks
3690 if(buffer[0]!=0)return 4;
3691 for(i=0;i<5;i++){
3692 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3693 }
3694 for(i=0;i<23;i++)
3695 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3696
3697 // ok, now we calculate the Boot catalog address
3698 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3699
3700 // And we read the Boot Catalog
3701 memsetb(get_SS(),atacmd,0,12);
3702 atacmd[0]=0x28; // READ command
3703 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3704 atacmd[8]=(0x01 & 0x00ff); // Sectors
3705 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3706 atacmd[3]=(lba & 0x00ff0000) >> 16;
3707 atacmd[4]=(lba & 0x0000ff00) >> 8;
3708 atacmd[5]=(lba & 0x000000ff);
3709 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3710 return 7;
3711
3712 // Validation entry
3713 if(buffer[0x00]!=0x01)return 8; // Header
3714 if(buffer[0x01]!=0x00)return 9; // Platform
3715 if(buffer[0x1E]!=0x55)return 10; // key 1
3716 if(buffer[0x1F]!=0xAA)return 10; // key 2
3717
3718 // Initial/Default Entry
3719 if(buffer[0x20]!=0x88)return 11; // Bootable
3720
3721 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3722 if(buffer[0x21]==0){
3723 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3724 // Win2000 cd boot needs to know it booted from cd
3725 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3726 }
3727 else if(buffer[0x21]<4)
3728 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3729 else
3730 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3731
3732 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3733 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3734
3735 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3736 if(boot_segment==0x0000)boot_segment=0x07C0;
3737
3738 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3739 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3740
3741 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3742 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3743
3744 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3745 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3746
3747 // And we read the image in memory
3748 memsetb(get_SS(),atacmd,0,12);
3749 atacmd[0]=0x28; // READ command
3750 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3751 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3752 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3753 atacmd[3]=(lba & 0x00ff0000) >> 16;
3754 atacmd[4]=(lba & 0x0000ff00) >> 8;
3755 atacmd[5]=(lba & 0x000000ff);
3756 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3757 return 12;
3758
3759 // Remember the media type
3760 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3761 case 0x01: // 1.2M floppy
3762 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3763 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3764 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3765 break;
3766 case 0x02: // 1.44M floppy
3767 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3768 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3769 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3770 break;
3771 case 0x03: // 2.88M floppy
3772 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3773 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3775 break;
3776 case 0x04: // Harddrive
3777 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3778 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3779 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3780 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3781 break;
3782 }
3783
3784 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3785 // Increase bios installed hardware number of devices
3786 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3787 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3788 else
3789 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3790 }
3791
3792
3793 // everything is ok, so from now on, the emulation is active
3794 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3795 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3796
3797 // return the boot drive + no error
3798 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3799}
3800
3801// ---------------------------------------------------------------------------
3802// End of El-Torito boot functions
3803// ---------------------------------------------------------------------------
3804#endif // BX_ELTORITO_BOOT
3805
3806#ifdef VBOX_WITH_SCSI
3807# include "scsi.c"
3808#endif
3809
3810 void
3811int14_function(regs, ds, iret_addr)
3812 pusha_regs_t regs; // regs pushed from PUSHA instruction
3813 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3814 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3815{
3816 Bit16u addr,timer,val16;
3817 Bit8u timeout;
3818
3819 ASM_START
3820 sti
3821 ASM_END
3822
3823 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3824 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3825 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3826 switch (regs.u.r8.ah) {
3827 case 0:
3828 outb(addr+3, inb(addr+3) | 0x80);
3829 if (regs.u.r8.al & 0xE0 == 0) {
3830 outb(addr, 0x17);
3831 outb(addr+1, 0x04);
3832 } else {
3833 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3834 outb(addr, val16 & 0xFF);
3835 outb(addr+1, val16 >> 8);
3836 }
3837 outb(addr+3, regs.u.r8.al & 0x1F);
3838 regs.u.r8.ah = inb(addr+5);
3839 regs.u.r8.al = inb(addr+6);
3840 ClearCF(iret_addr.flags);
3841 break;
3842 case 1:
3843 timer = read_word(0x0040, 0x006C);
3844 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3845 val16 = read_word(0x0040, 0x006C);
3846 if (val16 != timer) {
3847 timer = val16;
3848 timeout--;
3849 }
3850 }
3851 if (timeout) outb(addr, regs.u.r8.al);
3852 regs.u.r8.ah = inb(addr+5);
3853 if (!timeout) regs.u.r8.ah |= 0x80;
3854 ClearCF(iret_addr.flags);
3855 break;
3856 case 2:
3857 timer = read_word(0x0040, 0x006C);
3858 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3859 val16 = read_word(0x0040, 0x006C);
3860 if (val16 != timer) {
3861 timer = val16;
3862 timeout--;
3863 }
3864 }
3865 if (timeout) {
3866 regs.u.r8.ah = 0;
3867 regs.u.r8.al = inb(addr);
3868 } else {
3869 regs.u.r8.ah = inb(addr+5);
3870 }
3871 ClearCF(iret_addr.flags);
3872 break;
3873 case 3:
3874 regs.u.r8.ah = inb(addr+5);
3875 regs.u.r8.al = inb(addr+6);
3876 ClearCF(iret_addr.flags);
3877 break;
3878 default:
3879 SetCF(iret_addr.flags); // Unsupported
3880 }
3881 } else {
3882 SetCF(iret_addr.flags); // Unsupported
3883 }
3884}
3885
3886 void
3887int15_function(regs, ES, DS, FLAGS)
3888 pusha_regs_t regs; // REGS pushed via pusha
3889 Bit16u ES, DS, FLAGS;
3890{
3891 Bit16u ebda_seg=read_word(0x0040,0x000E);
3892 bx_bool prev_a20_enable;
3893 Bit16u base15_00;
3894 Bit8u base23_16;
3895 Bit16u ss;
3896 Bit16u BX,CX,DX;
3897
3898 Bit16u bRegister;
3899 Bit8u irqDisable;
3900
3901BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3902
3903 switch (regs.u.r8.ah) {
3904#ifdef VBOX
3905 case 0x00: /* assorted functions */
3906 if (regs.u.r8.al != 0xc0)
3907 goto undecoded;
3908 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3909 * which we don't support, but logging that event is annoying. In fact
3910 * it is likely that they just misread some specs, because there is a
3911 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3912 * wants to achieve. */
3913 SET_CF();
3914 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3915 break;
3916#endif
3917 case 0x24: /* A20 Control */
3918 switch (regs.u.r8.al) {
3919 case 0x00:
3920 set_enable_a20(0);
3921 CLEAR_CF();
3922 regs.u.r8.ah = 0;
3923 break;
3924 case 0x01:
3925 set_enable_a20(1);
3926 CLEAR_CF();
3927 regs.u.r8.ah = 0;
3928 break;
3929 case 0x02:
3930 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3931 CLEAR_CF();
3932 regs.u.r8.ah = 0;
3933 break;
3934 case 0x03:
3935 CLEAR_CF();
3936 regs.u.r8.ah = 0;
3937 regs.u.r16.bx = 3;
3938 break;
3939 default:
3940 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3941 SET_CF();
3942 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3943 }
3944 break;
3945
3946 case 0x41:
3947 SET_CF();
3948 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3949 break;
3950
3951 case 0x4f:
3952 /* keyboard intercept */
3953#if BX_CPU < 2
3954 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3955#else
3956 // nop
3957#endif
3958 SET_CF();
3959 break;
3960
3961 case 0x52: // removable media eject
3962 CLEAR_CF();
3963 regs.u.r8.ah = 0; // "ok ejection may proceed"
3964 break;
3965
3966 case 0x83: {
3967 if( regs.u.r8.al == 0 ) {
3968 // Set Interval requested.
3969 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3970 // Interval not already set.
3971 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3972 write_word( 0x40, 0x98, ES ); // Byte location, segment
3973 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3974 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3975 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3976 CLEAR_CF( );
3977 irqDisable = inb( 0xA1 );
3978 outb( 0xA1, irqDisable & 0xFE );
3979 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3980 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3981 } else {
3982 // Interval already set.
3983 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3984 SET_CF();
3985 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3986 }
3987 } else if( regs.u.r8.al == 1 ) {
3988 // Clear Interval requested
3989 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3990 CLEAR_CF( );
3991 bRegister = inb_cmos( 0xB );
3992 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3993 } else {
3994 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3995 SET_CF();
3996 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3997 regs.u.r8.al--;
3998 }
3999
4000 break;
4001 }
4002
4003 case 0x87:
4004#if BX_CPU < 3
4005# error "Int15 function 87h not supported on < 80386"
4006#endif
4007 // +++ should probably have descriptor checks
4008 // +++ should have exception handlers
4009
4010 // turn off interrupts
4011ASM_START
4012 cli
4013ASM_END
4014
4015 prev_a20_enable = set_enable_a20(1); // enable A20 line
4016
4017 // 128K max of transfer on 386+ ???
4018 // source == destination ???
4019
4020 // ES:SI points to descriptor table
4021 // offset use initially comments
4022 // ==============================================
4023 // 00..07 Unused zeros Null descriptor
4024 // 08..0f GDT zeros filled in by BIOS
4025 // 10..17 source ssssssss source of data
4026 // 18..1f dest dddddddd destination of data
4027 // 20..27 CS zeros filled in by BIOS
4028 // 28..2f SS zeros filled in by BIOS
4029
4030 //es:si
4031 //eeee0
4032 //0ssss
4033 //-----
4034
4035// check for access rights of source & dest here
4036
4037 // Initialize GDT descriptor
4038 base15_00 = (ES << 4) + regs.u.r16.si;
4039 base23_16 = ES >> 12;
4040 if (base15_00 < (ES<<4))
4041 base23_16++;
4042 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4043 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4044 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4045 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4046 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4047
4048 // Initialize CS descriptor
4049 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4050 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4051 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4052 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4053 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4054
4055 // Initialize SS descriptor
4056 ss = get_SS();
4057 base15_00 = ss << 4;
4058 base23_16 = ss >> 12;
4059 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4060 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4061 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4062 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4063 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4064
4065 CX = regs.u.r16.cx;
4066ASM_START
4067 // Compile generates locals offset info relative to SP.
4068 // Get CX (word count) from stack.
4069 mov bx, sp
4070 SEG SS
4071 mov cx, _int15_function.CX [bx]
4072
4073 // since we need to set SS:SP, save them to the BDA
4074 // for future restore
4075 push eax
4076 xor eax, eax
4077 mov ds, ax
4078 mov 0x0469, ss
4079 mov 0x0467, sp
4080
4081 SEG ES
4082 lgdt [si + 0x08]
4083 SEG CS
4084 lidt [pmode_IDT_info]
4085 ;; perhaps do something with IDT here
4086
4087 ;; set PE bit in CR0
4088 mov eax, cr0
4089 or al, #0x01
4090 mov cr0, eax
4091 ;; far jump to flush CPU queue after transition to protected mode
4092 JMP_AP(0x0020, protected_mode)
4093
4094protected_mode:
4095 ;; GDT points to valid descriptor table, now load SS, DS, ES
4096 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4097 mov ss, ax
4098 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4099 mov ds, ax
4100 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4101 mov es, ax
4102 xor si, si
4103 xor di, di
4104 cld
4105 rep
4106 movsw ;; move CX words from DS:SI to ES:DI
4107
4108 ;; make sure DS and ES limits are 64KB
4109 mov ax, #0x28
4110 mov ds, ax
4111 mov es, ax
4112
4113 ;; reset PG bit in CR0 ???
4114 mov eax, cr0
4115 and al, #0xFE
4116 mov cr0, eax
4117
4118 ;; far jump to flush CPU queue after transition to real mode
4119 JMP_AP(0xf000, real_mode)
4120
4121real_mode:
4122 ;; restore IDT to normal real-mode defaults
4123 SEG CS
4124 lidt [rmode_IDT_info]
4125
4126 // restore SS:SP from the BDA
4127 xor ax, ax
4128 mov ds, ax
4129 mov ss, 0x0469
4130 mov sp, 0x0467
4131 pop eax
4132ASM_END
4133
4134 set_enable_a20(prev_a20_enable);
4135
4136 // turn back on interrupts
4137ASM_START
4138 sti
4139ASM_END
4140
4141 regs.u.r8.ah = 0;
4142 CLEAR_CF();
4143 break;
4144
4145
4146 case 0x88:
4147 // Get the amount of extended memory (above 1M)
4148#if BX_CPU < 2
4149 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4150 SET_CF();
4151#else
4152 regs.u.r8.al = inb_cmos(0x30);
4153 regs.u.r8.ah = inb_cmos(0x31);
4154
4155 // According to Ralf Brown's interrupt the limit should be 15M,
4156 // but real machines mostly return max. 63M.
4157 if(regs.u.r16.ax > 0xffc0)
4158 regs.u.r16.ax = 0xffc0;
4159
4160 CLEAR_CF();
4161#endif
4162 break;
4163
4164#ifdef VBOX
4165 case 0x89:
4166 // Switch to Protected Mode.
4167 // ES:DI points to user-supplied GDT
4168 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4169 // This subfunction does not return!
4170
4171// turn off interrupts
4172ASM_START
4173 cli
4174ASM_END
4175
4176 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4177
4178 // Initialize CS descriptor for BIOS
4179 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4180 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4181 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4182 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4183 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4184
4185 BX = regs.u.r16.bx;
4186ASM_START
4187 // Compiler generates locals offset info relative to SP.
4188 // Get BX (PIC offsets) from stack.
4189 mov bx, sp
4190 SEG SS
4191 mov bx, _int15_function.BX [bx]
4192
4193 // Program PICs
4194 mov al, #0x11 ; send initialisation commands
4195 out 0x20, al
4196 out 0xa0, al
4197 mov al, bh
4198 out 0x21, al
4199 mov al, bl
4200 out 0xa1, al
4201 mov al, #0x04
4202 out 0x21, al
4203 mov al, #0x02
4204 out 0xa1, al
4205 mov al, #0x01
4206 out 0x21, al
4207 out 0xa1, al
4208 mov al, #0xff ; mask all IRQs, user must re-enable
4209 out 0x21, al
4210 out 0xa1, al
4211
4212 // Load GDT and IDT from supplied data
4213 SEG ES
4214 lgdt [si + 0x08]
4215 SEG ES
4216 lidt [si + 0x10]
4217
4218 // set PE bit in CR0
4219 mov eax, cr0
4220 or al, #0x01
4221 mov cr0, eax
4222 // far jump to flush CPU queue after transition to protected mode
4223 JMP_AP(0x0038, protmode_switch)
4224
4225protmode_switch:
4226 ;; GDT points to valid descriptor table, now load SS, DS, ES
4227 mov ax, #0x28
4228 mov ss, ax
4229 mov ax, #0x18
4230 mov ds, ax
4231 mov ax, #0x20
4232 mov es, ax
4233
4234 // unwind the stack - this will break if calling sequence changes!
4235 mov sp,bp
4236 add sp,#4 ; skip return address
4237 popa ; restore regs
4238 pop ax ; skip saved es
4239 pop ax ; skip saved ds
4240 pop ax ; skip saved flags
4241
4242 // return to caller - note that we do not use IRET because
4243 // we cannot enable interrupts
4244 pop cx ; get return offset
4245 pop ax ; skip return segment
4246 pop ax ; skip flags
4247 mov ax, #0x30 ; ah must be 0 on successful exit
4248 push ax
4249 push cx ; re-create modified ret address on stack
4250 retf
4251
4252ASM_END
4253
4254 break;
4255#endif /* VBOX */
4256
4257 case 0x90:
4258 /* Device busy interrupt. Called by Int 16h when no key available */
4259 break;
4260
4261 case 0x91:
4262 /* Interrupt complete. Called by Int 16h when key becomes available */
4263 break;
4264
4265 case 0xbf:
4266 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4267 SET_CF();
4268 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4269 break;
4270
4271 case 0xC0:
4272#if 0
4273 SET_CF();
4274 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4275 break;
4276#endif
4277 CLEAR_CF();
4278 regs.u.r8.ah = 0;
4279 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4280 ES = 0xF000;
4281 break;
4282
4283 case 0xc1:
4284 ES = ebda_seg;
4285 CLEAR_CF();
4286 break;
4287
4288 case 0xd8:
4289 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4290 SET_CF();
4291 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4292 break;
4293
4294#ifdef VBOX
4295 /* Make the BIOS warning for pretty much every Linux kernel start
4296 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4297 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4298 SET_CF();
4299 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4300 break;
4301undecoded:
4302#endif /* VBOX */
4303 default:
4304 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4305 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4306 SET_CF();
4307 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4308 break;
4309 }
4310}
4311
4312#if BX_USE_PS2_MOUSE
4313 void
4314int15_function_mouse(regs, ES, DS, FLAGS)
4315 pusha_regs_t regs; // REGS pushed via pusha
4316 Bit16u ES, DS, FLAGS;
4317{
4318 Bit16u ebda_seg=read_word(0x0040,0x000E);
4319 Bit8u mouse_flags_1, mouse_flags_2;
4320 Bit16u mouse_driver_seg;
4321 Bit16u mouse_driver_offset;
4322 Bit8u mouse_cmd;
4323 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4324
4325BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4326
4327 switch (regs.u.r8.ah) {
4328 case 0xC2:
4329 // Return Codes status in AH
4330 // =========================
4331 // 00: success
4332 // 01: invalid subfunction (AL > 7)
4333 // 02: invalid input value (out of allowable range)
4334 // 03: interface error
4335 // 04: resend command received from mouse controller,
4336 // device driver should attempt command again
4337 // 05: cannot enable mouse, since no far call has been installed
4338 // 80/86: mouse service not implemented
4339
4340 if (regs.u.r8.al > 7) {
4341BX_DEBUG_INT15("unsupported subfn\n");
4342 // invalid function
4343 SET_CF();
4344 regs.u.r8.ah = 1;
4345 break;
4346 }
4347
4348 // Valid subfn; disable AUX input and IRQ12, assume no error
4349 set_kbd_command_byte(0x65);
4350 CLEAR_CF();
4351 regs.u.r8.ah = 0;
4352
4353 switch (regs.u.r8.al) {
4354 case 0: // Disable/Enable Mouse
4355BX_DEBUG_INT15("case 0: ");
4356 if (regs.u.r8.bh > 1) {
4357 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4358 // invalid subfunction
4359 SET_CF();
4360 regs.u.r8.ah = 1;
4361 break;
4362 }
4363 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4364 if ( (mouse_flags_2 & 0x80) == 0 ) {
4365 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4366 SET_CF();
4367 regs.u.r8.ah = 5; // no far call installed
4368 break;
4369 }
4370 if (regs.u.r8.bh == 0) {
4371BX_DEBUG_INT15("Disable Mouse\n");
4372 mouse_cmd = 0xF5; // disable mouse command
4373 } else {
4374BX_DEBUG_INT15("Enable Mouse\n");
4375 mouse_cmd = 0xF4; // enable mouse command
4376 }
4377
4378 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4379 if (ret == 0) {
4380 ret = get_mouse_data(&mouse_data1);
4381 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4382 // success
4383 break;
4384 }
4385 }
4386
4387 // interface error
4388 SET_CF();
4389 regs.u.r8.ah = 3;
4390 break;
4391
4392 case 5: // Initialize Mouse
4393 // Valid package sizes are 1 to 8
4394 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4395 SET_CF();
4396 regs.u.r8.ah = 2; // invalid input
4397 break;
4398 }
4399 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4400 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4401 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4402 // fall through!
4403
4404 case 1: // Reset Mouse
4405BX_DEBUG_INT15("case 1 or 5:\n");
4406 // clear current package byte index
4407 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4408 mouse_flags_1 = mouse_flags_1 & 0xf8;
4409 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4410 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4411 if (ret == 0) {
4412 ret = get_mouse_data(&mouse_data3);
4413 // if no mouse attached, it will return RESEND
4414 if (mouse_data3 == 0xfe) {
4415 SET_CF();
4416 regs.u.r8.ah = 4; // resend
4417 break;
4418 }
4419 if (mouse_data3 != 0xfa)
4420 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4421 if ( ret == 0 ) {
4422 ret = get_mouse_data(&mouse_data1);
4423 if ( ret == 0 ) {
4424 ret = get_mouse_data(&mouse_data2);
4425 if ( ret == 0 ) {
4426 // success
4427 regs.u.r8.bl = mouse_data1;
4428 regs.u.r8.bh = mouse_data2;
4429 break;
4430 }
4431 }
4432 }
4433 }
4434
4435 // interface error
4436 SET_CF();
4437 regs.u.r8.ah = 3;
4438 break;
4439
4440 case 2: // Set Sample Rate
4441BX_DEBUG_INT15("case 2:\n");
4442 switch (regs.u.r8.bh) {
4443 case 0: mouse_data1 = 10; break; // 10 reports/sec
4444 case 1: mouse_data1 = 20; break; // 20 reports/sec
4445 case 2: mouse_data1 = 40; break; // 40 reports/sec
4446 case 3: mouse_data1 = 60; break; // 60 reports/sec
4447 case 4: mouse_data1 = 80; break; // 80 reports/sec
4448 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4449 case 6: mouse_data1 = 200; break; // 200 reports/sec
4450 default: mouse_data1 = 0;
4451 }
4452 if (mouse_data1 > 0) {
4453 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4454 if (ret == 0) {
4455 ret = get_mouse_data(&mouse_data2);
4456 ret = send_to_mouse_ctrl(mouse_data1);
4457 ret = get_mouse_data(&mouse_data2);
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 3: // Set Resolution
4472BX_DEBUG_INT15("case 3:\n");
4473 // BX:
4474 // 0 = 25 dpi, 1 count per millimeter
4475 // 1 = 50 dpi, 2 counts per millimeter
4476 // 2 = 100 dpi, 4 counts per millimeter
4477 // 3 = 200 dpi, 8 counts per millimeter
4478 if (regs.u.r8.bh < 4) {
4479 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4480 if (ret == 0) {
4481 ret = get_mouse_data(&mouse_data1);
4482 if (mouse_data1 != 0xfa)
4483 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4484 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4485 ret = get_mouse_data(&mouse_data1);
4486 if (mouse_data1 != 0xfa)
4487 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4488 // success
4489 } else {
4490 // interface error
4491 SET_CF();
4492 regs.u.r8.ah = 3;
4493 }
4494 } else {
4495 // invalid input
4496 SET_CF();
4497 regs.u.r8.ah = 2;
4498 }
4499 break;
4500
4501 case 4: // Get Device ID
4502BX_DEBUG_INT15("case 4:\n");
4503 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4504 if (ret == 0) {
4505 ret = get_mouse_data(&mouse_data1);
4506 ret = get_mouse_data(&mouse_data2);
4507 regs.u.r8.bh = mouse_data2;
4508 // success
4509 } else {
4510 // interface error
4511 SET_CF();
4512 regs.u.r8.ah = 3;
4513 }
4514 break;
4515
4516 case 6: // Return Status & Set Scaling Factor...
4517BX_DEBUG_INT15("case 6:\n");
4518 switch (regs.u.r8.bh) {
4519 case 0: // Return Status
4520 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4521 if (ret == 0) {
4522 ret = get_mouse_data(&mouse_data1);
4523 if (mouse_data1 != 0xfa)
4524 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4525 if (ret == 0) {
4526 ret = get_mouse_data(&mouse_data1);
4527 if ( ret == 0 ) {
4528 ret = get_mouse_data(&mouse_data2);
4529 if ( ret == 0 ) {
4530 ret = get_mouse_data(&mouse_data3);
4531 if ( ret == 0 ) {
4532 regs.u.r8.bl = mouse_data1;
4533 regs.u.r8.cl = mouse_data2;
4534 regs.u.r8.dl = mouse_data3;
4535 // success
4536 break;
4537 }
4538 }
4539 }
4540 }
4541 }
4542
4543 // interface error
4544 SET_CF();
4545 regs.u.r8.ah = 3;
4546 break;
4547
4548 case 1: // Set Scaling Factor to 1:1
4549 case 2: // Set Scaling Factor to 2:1
4550 if (regs.u.r8.bh == 1) {
4551 ret = send_to_mouse_ctrl(0xE6);
4552 } else {
4553 ret = send_to_mouse_ctrl(0xE7);
4554 }
4555 if (ret == 0) {
4556 get_mouse_data(&mouse_data1);
4557 ret = (mouse_data1 != 0xFA);
4558 }
4559 if (ret != 0) {
4560 // interface error
4561 SET_CF();
4562 regs.u.r8.ah = 3;
4563 }
4564 break;
4565
4566 default:
4567 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4568 // invalid subfunction
4569 SET_CF();
4570 regs.u.r8.ah = 1;
4571 }
4572 break;
4573
4574 case 7: // Set Mouse Handler Address
4575BX_DEBUG_INT15("case 7:\n");
4576 mouse_driver_seg = ES;
4577 mouse_driver_offset = regs.u.r16.bx;
4578 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4579 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4580 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4581 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4582 /* remove handler */
4583 if ( (mouse_flags_2 & 0x80) != 0 ) {
4584 mouse_flags_2 &= ~0x80;
4585 }
4586 }
4587 else {
4588 /* install handler */
4589 mouse_flags_2 |= 0x80;
4590 }
4591 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4592 break;
4593
4594 default:
4595 BX_PANIC("INT 15h C2 default case entered\n");
4596 // invalid subfunction
4597 SET_CF();
4598 regs.u.r8.ah = 1;
4599 }
4600BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4601 // Re-enable AUX input and IRQ12
4602 set_kbd_command_byte(0x47);
4603 break;
4604
4605 default:
4606 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4607 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4608 SET_CF();
4609 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4610 break;
4611 }
4612}
4613#endif // BX_USE_PS2_MOUSE
4614
4615
4616void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4617 Bit16u ES;
4618 Bit16u DI;
4619 Bit32u start;
4620 Bit32u end;
4621 Bit8u extra_start;
4622 Bit8u extra_end;
4623 Bit16u type;
4624{
4625 write_word(ES, DI, start);
4626 write_word(ES, DI+2, start >> 16);
4627 write_word(ES, DI+4, extra_start);
4628 write_word(ES, DI+6, 0x00);
4629
4630 end -= start;
4631 extra_end -= extra_start;
4632 write_word(ES, DI+8, end);
4633 write_word(ES, DI+10, end >> 16);
4634 write_word(ES, DI+12, extra_end);
4635 write_word(ES, DI+14, 0x0000);
4636
4637 write_word(ES, DI+16, type);
4638 write_word(ES, DI+18, 0x0);
4639}
4640
4641 void
4642int15_function32(regs, ES, DS, FLAGS)
4643 pushad_regs_t regs; // REGS pushed via pushad
4644 Bit16u ES, DS, FLAGS;
4645{
4646 Bit32u extended_memory_size=0; // 64bits long
4647 Bit32u extra_lowbits_memory_size=0;
4648 Bit16u CX,DX;
4649 Bit8u extra_highbits_memory_size=0;
4650
4651BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4652
4653 switch (regs.u.r8.ah) {
4654 case 0x86:
4655 // Wait for CX:DX microseconds. currently using the
4656 // refresh request port 0x61 bit4, toggling every 15usec
4657
4658 CX = regs.u.r16.cx;
4659 DX = regs.u.r16.dx;
4660
4661ASM_START
4662 sti
4663
4664 ;; Get the count in eax
4665 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4666 mov bx, sp
4667 SEG SS
4668 mov ax, _int15_function32.CX [bx]
4669 shl eax, #16
4670 SEG SS
4671 mov ax, _int15_function32.DX [bx]
4672
4673 ;; convert to numbers of 15usec ticks
4674 mov ebx, #15
4675 xor edx, edx
4676 div eax, ebx
4677 mov ecx, eax
4678
4679 ;; wait for ecx number of refresh requests
4680 in al, #0x61
4681 and al,#0x10
4682 mov ah, al
4683
4684 or ecx, ecx
4685 je int1586_tick_end
4686int1586_tick:
4687 in al, #0x61
4688 and al,#0x10
4689 cmp al, ah
4690 je int1586_tick
4691 mov ah, al
4692 dec ecx
4693 jnz int1586_tick
4694int1586_tick_end:
4695ASM_END
4696
4697 break;
4698
4699 case 0xe8:
4700 switch(regs.u.r8.al)
4701 {
4702 case 0x20: // coded by osmaker aka K.J.
4703 if(regs.u.r32.edx == 0x534D4150)
4704 {
4705 extended_memory_size = inb_cmos(0x35);
4706 extended_memory_size <<= 8;
4707 extended_memory_size |= inb_cmos(0x34);
4708 extended_memory_size *= 64;
4709#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4710 // greater than EFF00000???
4711 if(extended_memory_size > 0x3bc000) {
4712 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4713 }
4714#endif /* !VBOX */
4715 extended_memory_size *= 1024;
4716 extended_memory_size += (16L * 1024 * 1024);
4717
4718 if(extended_memory_size <= (16L * 1024 * 1024)) {
4719 extended_memory_size = inb_cmos(0x31);
4720 extended_memory_size <<= 8;
4721 extended_memory_size |= inb_cmos(0x30);
4722 extended_memory_size *= 1024;
4723 extended_memory_size += (1L * 1024 * 1024);
4724 }
4725
4726#ifdef VBOX /* We've already used the CMOS entries for SATA.
4727 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4728 extra_lowbits_memory_size = inb_cmos(0x62);
4729 extra_lowbits_memory_size <<= 8;
4730 extra_lowbits_memory_size |= inb_cmos(0x61);
4731 extra_lowbits_memory_size <<= 16;
4732 extra_highbits_memory_size = inb_cmos(0x63);
4733 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4734#else
4735 extra_lowbits_memory_size = inb_cmos(0x5c);
4736 extra_lowbits_memory_size <<= 8;
4737 extra_lowbits_memory_size |= inb_cmos(0x5b);
4738 extra_lowbits_memory_size *= 64;
4739 extra_lowbits_memory_size *= 1024;
4740 extra_highbits_memory_size = inb_cmos(0x5d);
4741#endif /* !VBOX */
4742
4743 switch(regs.u.r16.bx)
4744 {
4745 case 0:
4746 set_e820_range(ES, regs.u.r16.di,
4747#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4748 0x0000000L, 0x0009f000L, 0, 0, 1);
4749#else
4750 0x0000000L, 0x0009fc00L, 0, 0, 1);
4751#endif
4752 regs.u.r32.ebx = 1;
4753 break;
4754 case 1:
4755 set_e820_range(ES, regs.u.r16.di,
4756#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4757 0x0009f000L, 0x000a0000L, 0, 0, 2);
4758#else
4759 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4760#endif
4761 regs.u.r32.ebx = 2;
4762 break;
4763 case 2:
4764#ifdef VBOX
4765 /* Mark the BIOS as reserved. VBox doesn't currently
4766 * use the 0xe0000-0xeffff area. It does use the
4767 * 0xd0000-0xdffff area for the BIOS logo, but it's
4768 * not worth marking it as reserved. Note that various
4769 * Windows versions don't accept (read: in debug builds
4770 * they trigger the "Too many similar traps" assertion)
4771 * a single reserved range from 0xd0000 to 0xffffff.
4772 * A 128K area starting from 0xd0000 works. */
4773 set_e820_range(ES, regs.u.r16.di,
4774 0x000f0000L, 0x00100000L, 0, 0, 2);
4775#else /* !VBOX */
4776 set_e820_range(ES, regs.u.r16.di,
4777 0x000e8000L, 0x00100000L, 0, 0, 2);
4778#endif /* !VBOX */
4779 regs.u.r32.ebx = 3;
4780 break;
4781 case 3:
4782#if BX_ROMBIOS32 || defined(VBOX)
4783 set_e820_range(ES, regs.u.r16.di,
4784 0x00100000L,
4785 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4786 regs.u.r32.ebx = 4;
4787#else
4788 set_e820_range(ES, regs.u.r16.di,
4789 0x00100000L,
4790 extended_memory_size, 1);
4791 regs.u.r32.ebx = 5;
4792#endif
4793 break;
4794 case 4:
4795 set_e820_range(ES, regs.u.r16.di,
4796 extended_memory_size - ACPI_DATA_SIZE,
4797 extended_memory_size, 0, 0, 3); // ACPI RAM
4798 regs.u.r32.ebx = 5;
4799 break;
4800 case 5:
4801 /* 256KB BIOS area at the end of 4 GB */
4802#ifdef VBOX
4803 /* We don't set the end to 1GB here and rely on the 32-bit
4804 unsigned wrap around effect (0-0xfffc0000L). */
4805#endif
4806 set_e820_range(ES, regs.u.r16.di,
4807 0xfffc0000L, 0x00000000L, 0, 0, 2);
4808 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4809 regs.u.r32.ebx = 6;
4810 else
4811 regs.u.r32.ebx = 0;
4812 break;
4813 case 6:
4814#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4815 /* Mapping of memory above 4 GB if present.
4816 Note: set_e820_range needs do no borrowing in the
4817 subtraction because of the nice numbers. */
4818 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4819 {
4820 set_e820_range(ES, regs.u.r16.di,
4821 0x00000000L, extra_lowbits_memory_size,
4822 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4823 regs.u.r32.ebx = 0;
4824 break;
4825 }
4826 /* fall thru */
4827#else /* !VBOX */
4828 /* Maping of memory above 4 GB */
4829 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4830 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4831 + 1, 1);
4832 regs.u.r32.ebx = 0;
4833 break;
4834#endif /* !VBOX */
4835 default: /* AX=E820, DX=534D4150, BX unrecognized */
4836 goto int15_unimplemented;
4837 break;
4838 }
4839 regs.u.r32.eax = 0x534D4150;
4840 regs.u.r32.ecx = 0x14;
4841 CLEAR_CF();
4842 } else {
4843 // if DX != 0x534D4150)
4844 goto int15_unimplemented;
4845 }
4846 break;
4847
4848 case 0x01:
4849 // do we have any reason to fail here ?
4850 CLEAR_CF();
4851
4852 // my real system sets ax and bx to 0
4853 // this is confirmed by Ralph Brown list
4854 // but syslinux v1.48 is known to behave
4855 // strangely if ax is set to 0
4856 // regs.u.r16.ax = 0;
4857 // regs.u.r16.bx = 0;
4858
4859 // Get the amount of extended memory (above 1M)
4860 regs.u.r8.cl = inb_cmos(0x30);
4861 regs.u.r8.ch = inb_cmos(0x31);
4862
4863 // limit to 15M
4864 if(regs.u.r16.cx > 0x3c00)
4865 {
4866 regs.u.r16.cx = 0x3c00;
4867 }
4868
4869 // Get the amount of extended memory above 16M in 64k blocs
4870 regs.u.r8.dl = inb_cmos(0x34);
4871 regs.u.r8.dh = inb_cmos(0x35);
4872
4873 // Set configured memory equal to extended memory
4874 regs.u.r16.ax = regs.u.r16.cx;
4875 regs.u.r16.bx = regs.u.r16.dx;
4876 break;
4877 default: /* AH=0xE8?? but not implemented */
4878 goto int15_unimplemented;
4879 }
4880 break;
4881 int15_unimplemented:
4882 // fall into the default
4883 default:
4884 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4885 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4886 SET_CF();
4887 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4888 break;
4889 }
4890}
4891
4892 void
4893int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4894 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4895{
4896 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4897 Bit16u kbd_code, max;
4898
4899 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4900
4901 shift_flags = read_byte(0x0040, 0x17);
4902 led_flags = read_byte(0x0040, 0x97);
4903 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4904ASM_START
4905 cli
4906ASM_END
4907 outb(0x60, 0xed);
4908 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4909 if ((inb(0x60) == 0xfa)) {
4910 led_flags &= 0xf8;
4911 led_flags |= ((shift_flags >> 4) & 0x07);
4912 outb(0x60, led_flags & 0x07);
4913 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4914 inb(0x60);
4915 write_byte(0x0040, 0x97, led_flags);
4916 }
4917ASM_START
4918 sti
4919ASM_END
4920 }
4921
4922 switch (GET_AH()) {
4923 case 0x00: /* read keyboard input */
4924
4925 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4926 BX_PANIC("KBD: int16h: out of keyboard input\n");
4927 }
4928 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4929 else if (ascii_code == 0xE0) ascii_code = 0;
4930 AX = (scan_code << 8) | ascii_code;
4931 break;
4932
4933 case 0x01: /* check keyboard status */
4934 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4935 SET_ZF();
4936 return;
4937 }
4938 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4939 else if (ascii_code == 0xE0) ascii_code = 0;
4940 AX = (scan_code << 8) | ascii_code;
4941 CLEAR_ZF();
4942 break;
4943
4944 case 0x02: /* get shift flag status */
4945 shift_flags = read_byte(0x0040, 0x17);
4946 SET_AL(shift_flags);
4947 break;
4948
4949 case 0x05: /* store key-stroke into buffer */
4950 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4951 SET_AL(1);
4952 }
4953 else {
4954 SET_AL(0);
4955 }
4956 break;
4957
4958 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4959 // bit Bochs Description
4960 // 7 0 reserved
4961 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4962 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4963 // 4 1 INT 16/AH=0Ah supported
4964 // 3 0 INT 16/AX=0306h supported
4965 // 2 0 INT 16/AX=0305h supported
4966 // 1 0 INT 16/AX=0304h supported
4967 // 0 0 INT 16/AX=0300h supported
4968 //
4969 SET_AL(0x30);
4970 break;
4971
4972 case 0x0A: /* GET KEYBOARD ID */
4973 count = 2;
4974 kbd_code = 0x0;
4975 outb(0x60, 0xf2);
4976 /* Wait for data */
4977 max=0xffff;
4978 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4979 if (max>0x0) {
4980 if ((inb(0x60) == 0xfa)) {
4981 do {
4982 max=0xffff;
4983 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4984 if (max>0x0) {
4985 kbd_code >>= 8;
4986 kbd_code |= (inb(0x60) << 8);
4987 }
4988 } while (--count>0);
4989 }
4990 }
4991 BX=kbd_code;
4992 break;
4993
4994 case 0x10: /* read MF-II keyboard input */
4995
4996 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4997 BX_PANIC("KBD: int16h: out of keyboard input\n");
4998 }
4999 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5000 AX = (scan_code << 8) | ascii_code;
5001 break;
5002
5003 case 0x11: /* check MF-II keyboard status */
5004 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5005 SET_ZF();
5006 return;
5007 }
5008 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5009 AX = (scan_code << 8) | ascii_code;
5010 CLEAR_ZF();
5011 break;
5012
5013 case 0x12: /* get extended keyboard status */
5014 shift_flags = read_byte(0x0040, 0x17);
5015 SET_AL(shift_flags);
5016 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5017 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5018 SET_AH(shift_flags);
5019 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5020 break;
5021
5022 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5023 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5024 break;
5025
5026 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5027 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5028 break;
5029
5030 case 0x6F:
5031 if (GET_AL() == 0x08)
5032 SET_AH(0x02); // unsupported, aka normal keyboard
5033
5034 default:
5035 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5036 }
5037}
5038
5039 unsigned int
5040dequeue_key(scan_code, ascii_code, incr)
5041 Bit8u *scan_code;
5042 Bit8u *ascii_code;
5043 unsigned int incr;
5044{
5045 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5046 Bit16u ss;
5047 Bit8u acode, scode;
5048
5049#if BX_CPU < 2
5050 buffer_start = 0x001E;
5051 buffer_end = 0x003E;
5052#else
5053 buffer_start = read_word(0x0040, 0x0080);
5054 buffer_end = read_word(0x0040, 0x0082);
5055#endif
5056
5057 buffer_head = read_word(0x0040, 0x001a);
5058 buffer_tail = read_word(0x0040, 0x001c);
5059
5060 if (buffer_head != buffer_tail) {
5061 ss = get_SS();
5062 acode = read_byte(0x0040, buffer_head);
5063 scode = read_byte(0x0040, buffer_head+1);
5064 write_byte(ss, ascii_code, acode);
5065 write_byte(ss, scan_code, scode);
5066
5067 if (incr) {
5068 buffer_head += 2;
5069 if (buffer_head >= buffer_end)
5070 buffer_head = buffer_start;
5071 write_word(0x0040, 0x001a, buffer_head);
5072 }
5073 return(1);
5074 }
5075 else {
5076 return(0);
5077 }
5078}
5079
5080static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5081
5082 Bit8u
5083send_to_mouse_ctrl(sendbyte)
5084 Bit8u sendbyte;
5085{
5086 Bit8u response;
5087
5088 // wait for chance to write to ctrl
5089 if ( inb(0x64) & 0x02 )
5090 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5091 outb(0x64, 0xD4);
5092 outb(0x60, sendbyte);
5093 return(0);
5094}
5095
5096
5097 Bit8u
5098get_mouse_data(data)
5099 Bit8u *data;
5100{
5101 Bit8u response;
5102 Bit16u ss;
5103
5104 while ( (inb(0x64) & 0x21) != 0x21 ) {
5105 }
5106
5107 response = inb(0x60);
5108
5109 ss = get_SS();
5110 write_byte(ss, data, response);
5111 return(0);
5112}
5113
5114 void
5115set_kbd_command_byte(command_byte)
5116 Bit8u command_byte;
5117{
5118 if ( inb(0x64) & 0x02 )
5119 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5120
5121 outb(0x64, 0x60); // write command byte
5122 outb(0x60, command_byte);
5123}
5124
5125 void
5126int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5127 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5128{
5129 Bit8u scancode, asciicode, shift_flags;
5130 Bit8u mf2_flags, mf2_state;
5131
5132 //
5133 // DS has been set to F000 before call
5134 //
5135
5136
5137 scancode = GET_AL();
5138
5139 if (scancode == 0) {
5140 BX_INFO("KBD: int09 handler: AL=0\n");
5141 return;
5142 }
5143
5144
5145 shift_flags = read_byte(0x0040, 0x17);
5146 mf2_flags = read_byte(0x0040, 0x18);
5147 mf2_state = read_byte(0x0040, 0x96);
5148 asciicode = 0;
5149
5150 switch (scancode) {
5151 case 0x3a: /* Caps Lock press */
5152 shift_flags ^= 0x40;
5153 write_byte(0x0040, 0x17, shift_flags);
5154 mf2_flags |= 0x40;
5155 write_byte(0x0040, 0x18, mf2_flags);
5156 break;
5157 case 0xba: /* Caps Lock release */
5158 mf2_flags &= ~0x40;
5159 write_byte(0x0040, 0x18, mf2_flags);
5160 break;
5161
5162 case 0x2a: /* L Shift press */
5163 shift_flags |= 0x02;
5164 write_byte(0x0040, 0x17, shift_flags);
5165 break;
5166 case 0xaa: /* L Shift release */
5167 shift_flags &= ~0x02;
5168 write_byte(0x0040, 0x17, shift_flags);
5169 break;
5170
5171 case 0x36: /* R Shift press */
5172 shift_flags |= 0x01;
5173 write_byte(0x0040, 0x17, shift_flags);
5174 break;
5175 case 0xb6: /* R Shift release */
5176 shift_flags &= ~0x01;
5177 write_byte(0x0040, 0x17, shift_flags);
5178 break;
5179
5180 case 0x1d: /* Ctrl press */
5181 if ((mf2_state & 0x01) == 0) {
5182 shift_flags |= 0x04;
5183 write_byte(0x0040, 0x17, shift_flags);
5184 if (mf2_state & 0x02) {
5185 mf2_state |= 0x04;
5186 write_byte(0x0040, 0x96, mf2_state);
5187 } else {
5188 mf2_flags |= 0x01;
5189 write_byte(0x0040, 0x18, mf2_flags);
5190 }
5191 }
5192 break;
5193 case 0x9d: /* Ctrl release */
5194 if ((mf2_state & 0x01) == 0) {
5195 shift_flags &= ~0x04;
5196 write_byte(0x0040, 0x17, shift_flags);
5197 if (mf2_state & 0x02) {
5198 mf2_state &= ~0x04;
5199 write_byte(0x0040, 0x96, mf2_state);
5200 } else {
5201 mf2_flags &= ~0x01;
5202 write_byte(0x0040, 0x18, mf2_flags);
5203 }
5204 }
5205 break;
5206
5207 case 0x38: /* Alt press */
5208 shift_flags |= 0x08;
5209 write_byte(0x0040, 0x17, shift_flags);
5210 if (mf2_state & 0x02) {
5211 mf2_state |= 0x08;
5212 write_byte(0x0040, 0x96, mf2_state);
5213 } else {
5214 mf2_flags |= 0x02;
5215 write_byte(0x0040, 0x18, mf2_flags);
5216 }
5217 break;
5218 case 0xb8: /* Alt release */
5219 shift_flags &= ~0x08;
5220 write_byte(0x0040, 0x17, shift_flags);
5221 if (mf2_state & 0x02) {
5222 mf2_state &= ~0x08;
5223 write_byte(0x0040, 0x96, mf2_state);
5224 } else {
5225 mf2_flags &= ~0x02;
5226 write_byte(0x0040, 0x18, mf2_flags);
5227 }
5228 break;
5229
5230 case 0x45: /* Num Lock press */
5231 if ((mf2_state & 0x03) == 0) {
5232 mf2_flags |= 0x20;
5233 write_byte(0x0040, 0x18, mf2_flags);
5234 shift_flags ^= 0x20;
5235 write_byte(0x0040, 0x17, shift_flags);
5236 }
5237 break;
5238 case 0xc5: /* Num Lock release */
5239 if ((mf2_state & 0x03) == 0) {
5240 mf2_flags &= ~0x20;
5241 write_byte(0x0040, 0x18, mf2_flags);
5242 }
5243 break;
5244
5245 case 0x46: /* Scroll Lock press */
5246 mf2_flags |= 0x10;
5247 write_byte(0x0040, 0x18, mf2_flags);
5248 shift_flags ^= 0x10;
5249 write_byte(0x0040, 0x17, shift_flags);
5250 break;
5251
5252 case 0xc6: /* Scroll Lock release */
5253 mf2_flags &= ~0x10;
5254 write_byte(0x0040, 0x18, mf2_flags);
5255 break;
5256
5257#ifdef VBOX
5258 case 0x53: /* Del press */
5259 if ((shift_flags & 0x0f) == 0x0c)
5260 {
5261ASM_START
5262 /* Ctrl+Alt+Del => Reboot */
5263 jmp 0xf000:post
5264ASM_END
5265 }
5266 /* fall through */
5267#endif
5268
5269 default:
5270 if (scancode & 0x80) {
5271 break; /* toss key releases ... */
5272 }
5273 if (scancode > MAX_SCAN_CODE) {
5274 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5275 return;
5276 }
5277 if (shift_flags & 0x08) { /* ALT */
5278 asciicode = scan_to_scanascii[scancode].alt;
5279 scancode = scan_to_scanascii[scancode].alt >> 8;
5280 } else if (shift_flags & 0x04) { /* CONTROL */
5281 asciicode = scan_to_scanascii[scancode].control;
5282 scancode = scan_to_scanascii[scancode].control >> 8;
5283 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5284 /* extended keys handling */
5285 asciicode = 0xe0;
5286 scancode = scan_to_scanascii[scancode].normal >> 8;
5287 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5288 /* check if lock state should be ignored
5289 * because a SHIFT key are pressed */
5290
5291 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5292 asciicode = scan_to_scanascii[scancode].normal;
5293 scancode = scan_to_scanascii[scancode].normal >> 8;
5294 } else {
5295 asciicode = scan_to_scanascii[scancode].shift;
5296 scancode = scan_to_scanascii[scancode].shift >> 8;
5297 }
5298 } else {
5299 /* check if lock is on */
5300 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5301 asciicode = scan_to_scanascii[scancode].shift;
5302 scancode = scan_to_scanascii[scancode].shift >> 8;
5303 } else {
5304 asciicode = scan_to_scanascii[scancode].normal;
5305 scancode = scan_to_scanascii[scancode].normal >> 8;
5306 }
5307 }
5308 if (scancode==0 && asciicode==0) {
5309 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5310 }
5311 enqueue_key(scancode, asciicode);
5312 break;
5313 }
5314 if ((scancode & 0x7f) != 0x1d) {
5315 mf2_state &= ~0x01;
5316 }
5317 mf2_state &= ~0x02;
5318 write_byte(0x0040, 0x96, mf2_state);
5319}
5320
5321 unsigned int
5322enqueue_key(scan_code, ascii_code)
5323 Bit8u scan_code, ascii_code;
5324{
5325 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5326
5327#if BX_CPU < 2
5328 buffer_start = 0x001E;
5329 buffer_end = 0x003E;
5330#else
5331 buffer_start = read_word(0x0040, 0x0080);
5332 buffer_end = read_word(0x0040, 0x0082);
5333#endif
5334
5335 buffer_head = read_word(0x0040, 0x001A);
5336 buffer_tail = read_word(0x0040, 0x001C);
5337
5338 temp_tail = buffer_tail;
5339 buffer_tail += 2;
5340 if (buffer_tail >= buffer_end)
5341 buffer_tail = buffer_start;
5342
5343 if (buffer_tail == buffer_head) {
5344 return(0);
5345 }
5346
5347 write_byte(0x0040, temp_tail, ascii_code);
5348 write_byte(0x0040, temp_tail+1, scan_code);
5349 write_word(0x0040, 0x001C, buffer_tail);
5350 return(1);
5351}
5352
5353
5354 void
5355int74_function(make_farcall, Z, Y, X, status)
5356 Bit16u make_farcall, Z, Y, X, status;
5357{
5358 Bit16u ebda_seg=read_word(0x0040,0x000E);
5359 Bit8u in_byte, index, package_count;
5360 Bit8u mouse_flags_1, mouse_flags_2;
5361
5362BX_DEBUG_INT74("entering int74_function\n");
5363 make_farcall = 0;
5364
5365 in_byte = inb(0x64);
5366 if ( (in_byte & 0x21) != 0x21 ) {
5367 return;
5368 }
5369 in_byte = inb(0x60);
5370BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5371
5372 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5373 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5374
5375 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5376 return;
5377 }
5378
5379 package_count = mouse_flags_2 & 0x07;
5380 index = mouse_flags_1 & 0x07;
5381 write_byte(ebda_seg, 0x28 + index, in_byte);
5382
5383 if ( index >= package_count ) {
5384BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5385 status = read_byte(ebda_seg, 0x0028 + 0);
5386 X = read_byte(ebda_seg, 0x0028 + 1);
5387 Y = read_byte(ebda_seg, 0x0028 + 2);
5388 Z = 0;
5389 mouse_flags_1 = 0;
5390 // check if far call handler installed
5391 if (mouse_flags_2 & 0x80)
5392 make_farcall = 1;
5393 }
5394 else {
5395 mouse_flags_1++;
5396 }
5397 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5398}
5399
5400#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5401
5402#if BX_USE_ATADRV
5403
5404 void
5405int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5406 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5407{
5408 Bit32u lba;
5409 Bit16u ebda_seg=read_word(0x0040,0x000E);
5410 Bit16u cylinder, head, sector;
5411 Bit16u segment, offset;
5412 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5413 Bit16u size, count;
5414 Bit8u device, status;
5415
5416 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5417
5418 write_byte(0x0040, 0x008e, 0); // clear completion flag
5419
5420#ifdef VBOX_WITH_SCSI
5421 // basic check : device has to be defined
5422 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) ) {
5423 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5424 goto int13_fail;
5425 }
5426#else
5427 // basic check : device has to be defined
5428 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5429 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5430 goto int13_fail;
5431 }
5432#endif
5433
5434 // Get the ata channel
5435 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5436
5437#ifdef VBOX_WITH_SCSI
5438 // basic check : device has to be valid
5439 if (device >= BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) {
5440 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5441 goto int13_fail;
5442 }
5443#else
5444 // basic check : device has to be valid
5445 if (device >= BX_MAX_ATA_DEVICES) {
5446 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5447 goto int13_fail;
5448 }
5449#endif
5450
5451 switch (GET_AH()) {
5452
5453 case 0x00: /* disk controller reset */
5454#ifdef VBOX_WITH_SCSI
5455 /* SCSI controller does not need a reset. */
5456 if (!VBOX_IS_SCSI_DEVICE(device))
5457#endif
5458 ata_reset (device);
5459 goto int13_success;
5460 break;
5461
5462 case 0x01: /* read disk status */
5463 status = read_byte(0x0040, 0x0074);
5464 SET_AH(status);
5465 SET_DISK_RET_STATUS(0);
5466 /* set CF if error status read */
5467 if (status) goto int13_fail_nostatus;
5468 else goto int13_success_noah;
5469 break;
5470
5471 case 0x02: // read disk sectors
5472 case 0x03: // write disk sectors
5473 case 0x04: // verify disk sectors
5474
5475 count = GET_AL();
5476 cylinder = GET_CH();
5477 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5478 sector = (GET_CL() & 0x3f);
5479 head = GET_DH();
5480
5481 segment = ES;
5482 offset = BX;
5483
5484 if ( (count > 128) || (count == 0) ) {
5485 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5486 goto int13_fail;
5487 }
5488
5489#ifdef VBOX_WITH_SCSI
5490 if (!VBOX_IS_SCSI_DEVICE(device))
5491#endif
5492 {
5493 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5494 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5495 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5496 }
5497#ifdef VBOX_WITH_SCSI
5498 else
5499 {
5500 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5501
5502 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5503 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5504 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5505 }
5506#endif
5507
5508 // sanity check on cyl heads, sec
5509 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5510 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5511 goto int13_fail;
5512 }
5513
5514 // FIXME verify
5515 if ( GET_AH() == 0x04 ) goto int13_success;
5516
5517#ifdef VBOX_WITH_SCSI
5518 if (!VBOX_IS_SCSI_DEVICE(device))
5519#endif
5520 {
5521 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5522 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5523 }
5524#ifdef VBOX_WITH_SCSI
5525 else
5526 {
5527 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5528 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5529 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5530 }
5531#endif
5532
5533 // if needed, translate lchs to lba, and execute command
5534#ifdef VBOX_WITH_SCSI
5535 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5536 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5537 sector = 0; // this forces the command to be lba
5538 }
5539#else
5540 if (( (nph != nlh) || (npspt != nlspt)) ) {
5541 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5542 sector = 0; // this forces the command to be lba
5543 }
5544#endif
5545
5546 if ( GET_AH() == 0x02 )
5547 {
5548#ifdef VBOX_WITH_SCSI
5549 if (VBOX_IS_SCSI_DEVICE(device))
5550 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5551 else
5552#endif
5553 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5554 }
5555 else
5556 {
5557#ifdef VBOX_WITH_SCSI
5558 if (VBOX_IS_SCSI_DEVICE(device))
5559 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5560 else
5561#endif
5562 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5563 }
5564
5565 // Set nb of sector transferred
5566 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5567
5568 if (status != 0) {
5569 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5570 SET_AH(0x0c);
5571 goto int13_fail_noah;
5572 }
5573
5574 goto int13_success;
5575 break;
5576
5577 case 0x05: /* format disk track */
5578 BX_INFO("format disk track called\n");
5579 goto int13_success;
5580 return;
5581 break;
5582
5583 case 0x08: /* read disk drive parameters */
5584
5585 // Get logical geometry from table
5586#ifdef VBOX_WITH_SCSI
5587 if (!VBOX_IS_SCSI_DEVICE(device))
5588#endif
5589 {
5590 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5591 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5592 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5593 }
5594#ifdef VBOX_WITH_SCSI
5595 else
5596 {
5597 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5598 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5599 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5600 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5601 }
5602#endif
5603
5604 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5605#ifndef VBOX
5606 nlc = nlc - 2; /* 0 based , last sector not used */
5607#else /* VBOX */
5608 /* Maximum cylinder number is just one less than the number of cylinders. */
5609 nlc = nlc - 1; /* 0 based , last sector not used */
5610#endif /* VBOX */
5611 SET_AL(0);
5612 SET_CH(nlc & 0xff);
5613 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5614 SET_DH(nlh - 1);
5615 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5616
5617 // FIXME should set ES & DI
5618
5619 goto int13_success;
5620 break;
5621
5622 case 0x10: /* check drive ready */
5623 // should look at 40:8E also???
5624
5625 // Read the status from controller
5626 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5627 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5628 goto int13_success;
5629 }
5630 else {
5631 SET_AH(0xAA);
5632 goto int13_fail_noah;
5633 }
5634 break;
5635
5636 case 0x15: /* read disk drive size */
5637
5638 // Get physical geometry from table
5639#ifdef VBOX_WITH_SCSI
5640 if (!VBOX_IS_SCSI_DEVICE(device))
5641#endif
5642 {
5643 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5644 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5645 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5646 }
5647#ifdef VBOX_WITH_SCSI
5648 else
5649 {
5650 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5651 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5652 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5653 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5654 }
5655#endif
5656
5657 // Compute sector count seen by int13
5658#ifndef VBOX
5659 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5660#else /* VBOX */
5661 /* Is it so hard to multiply a couple of counts (without introducing
5662 * arbitrary off by one errors)? */
5663 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5664#endif /* VBOX */
5665 CX = lba >> 16;
5666 DX = lba & 0xffff;
5667
5668 SET_AH(3); // hard disk accessible
5669 goto int13_success_noah;
5670 break;
5671
5672 case 0x41: // IBM/MS installation check
5673 BX=0xaa55; // install check
5674 SET_AH(0x30); // EDD 3.0
5675 CX=0x0007; // ext disk access and edd, removable supported
5676 goto int13_success_noah;
5677 break;
5678
5679 case 0x42: // IBM/MS extended read
5680 case 0x43: // IBM/MS extended write
5681 case 0x44: // IBM/MS verify
5682 case 0x47: // IBM/MS extended seek
5683
5684 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5685 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5686 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5687
5688 // Can't use 64 bits lba
5689 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5690 if (lba != 0L) {
5691 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5692 goto int13_fail;
5693 }
5694
5695 // Get 32 bits lba and check
5696 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5697
5698#ifdef VBOX_WITH_SCSI
5699 if (VBOX_IS_SCSI_DEVICE(device))
5700 {
5701 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5702 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5703 goto int13_fail;
5704 }
5705 }
5706 else
5707#endif
5708 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5709 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5710 goto int13_fail;
5711 }
5712
5713
5714 // If verify or seek
5715 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5716 goto int13_success;
5717
5718 // Execute the command
5719 if ( GET_AH() == 0x42 )
5720#ifdef VBOX
5721 {
5722#ifdef VBOX_WITH_SCSI
5723 if (VBOX_IS_SCSI_DEVICE(device))
5724 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5725 else
5726#endif
5727 {
5728 if (count >= 256 || lba + count >= 268435456)
5729 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5730 else
5731 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5732 }
5733 }
5734#else /* !VBOX */
5735 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5736#endif /* VBOX */
5737 else
5738#ifdef VBOX
5739 {
5740#ifdef VBOX_WITH_SCSI
5741 if (VBOX_IS_SCSI_DEVICE(device))
5742 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5743 else
5744#endif
5745 {
5746 if (count >= 256 || lba + count >= 268435456)
5747 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5748 else
5749 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5750 }
5751 }
5752#else /* !VBOX */
5753 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5754#endif /* VBOX */
5755
5756 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5757 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5758
5759 if (status != 0) {
5760 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5761 SET_AH(0x0c);
5762 goto int13_fail_noah;
5763 }
5764
5765 goto int13_success;
5766 break;
5767
5768 case 0x45: // IBM/MS lock/unlock drive
5769 case 0x49: // IBM/MS extended media change
5770 goto int13_success; // Always success for HD
5771 break;
5772
5773 case 0x46: // IBM/MS eject media
5774 SET_AH(0xb2); // Volume Not Removable
5775 goto int13_fail_noah; // Always fail for HD
5776 break;
5777
5778 case 0x48: // IBM/MS get drive parameters
5779 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5780
5781 // Buffer is too small
5782 if(size < 0x1a)
5783 goto int13_fail;
5784
5785 // EDD 1.x
5786 if(size >= 0x1a) {
5787 Bit16u blksize;
5788
5789#ifdef VBOX_WITH_SCSI
5790 if (!VBOX_IS_SCSI_DEVICE(device))
5791#endif
5792 {
5793 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5794 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5795 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5796 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5797 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5798 }
5799#ifdef VBOX_WITH_SCSI
5800 else
5801 {
5802 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5803 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5804 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5805 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5806 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5807 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5808 }
5809#endif
5810
5811 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5812 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5813 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5814 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5815 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5816 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5817 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5818 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5819 }
5820
5821 // EDD 2.x
5822 if(size >= 0x1e) {
5823 Bit8u channel, dev, irq, mode, checksum, i, translation;
5824 Bit16u iobase1, iobase2, options;
5825
5826 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5827
5828 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5829 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5830
5831 // Fill in dpte
5832 channel = device / 2;
5833 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5834 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5835 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5836 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5837 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5838
5839 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5840 options |= (1<<4); // lba translation
5841 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5842 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5843 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5844
5845 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5846 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5847 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5848 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5849 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5850 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5851 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5852 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5853 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5854 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5855 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5856
5857 checksum=0;
5858 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5859 checksum = ~checksum;
5860 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5861 }
5862
5863 // EDD 3.x
5864 if(size >= 0x42) {
5865 Bit8u channel, iface, checksum, i;
5866 Bit16u iobase1;
5867
5868 channel = device / 2;
5869 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5870 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5871
5872 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5873 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5874 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5875 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5876 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5877
5878 if (iface==ATA_IFACE_ISA) {
5879 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5880 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5881 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5882 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5883 }
5884 else {
5885 // FIXME PCI
5886 }
5887 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5888 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5889 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5890 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5891
5892 if (iface==ATA_IFACE_ISA) {
5893 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5894 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5895 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5896 }
5897 else {
5898 // FIXME PCI
5899 }
5900 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5901 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5902 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5903 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5904
5905 checksum=0;
5906 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5907 checksum = ~checksum;
5908 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5909 }
5910
5911 goto int13_success;
5912 break;
5913
5914 case 0x4e: // // IBM/MS set hardware configuration
5915 // DMA, prefetch, PIO maximum not supported
5916 switch (GET_AL()) {
5917 case 0x01:
5918 case 0x03:
5919 case 0x04:
5920 case 0x06:
5921 goto int13_success;
5922 break;
5923 default :
5924 goto int13_fail;
5925 }
5926 break;
5927
5928 case 0x09: /* initialize drive parameters */
5929 case 0x0c: /* seek to specified cylinder */
5930 case 0x0d: /* alternate disk reset */
5931 case 0x11: /* recalibrate */
5932 case 0x14: /* controller internal diagnostic */
5933 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5934 goto int13_success;
5935 break;
5936
5937 case 0x0a: /* read disk sectors with ECC */
5938 case 0x0b: /* write disk sectors with ECC */
5939 case 0x18: // set media type for format
5940 case 0x50: // IBM/MS send packet command
5941 default:
5942 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5943 goto int13_fail;
5944 break;
5945 }
5946
5947int13_fail:
5948 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5949int13_fail_noah:
5950 SET_DISK_RET_STATUS(GET_AH());
5951int13_fail_nostatus:
5952 SET_CF(); // error occurred
5953 return;
5954
5955int13_success:
5956 SET_AH(0x00); // no error
5957int13_success_noah:
5958 SET_DISK_RET_STATUS(0x00);
5959 CLEAR_CF(); // no error
5960 return;
5961}
5962
5963// ---------------------------------------------------------------------------
5964// Start of int13 for cdrom
5965// ---------------------------------------------------------------------------
5966
5967 void
5968int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5969 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5970{
5971 Bit16u ebda_seg=read_word(0x0040,0x000E);
5972 Bit8u device, status, locks;
5973 Bit8u atacmd[12];
5974 Bit32u lba;
5975 Bit16u count, segment, offset, i, size;
5976
5977 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5978
5979 SET_DISK_RET_STATUS(0x00);
5980
5981 /* basic check : device should be 0xE0+ */
5982 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5983 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5984 goto int13_fail;
5985 }
5986
5987 // Get the ata channel
5988 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5989
5990 /* basic check : device has to be valid */
5991 if (device >= BX_MAX_ATA_DEVICES) {
5992 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5993 goto int13_fail;
5994 }
5995
5996 switch (GET_AH()) {
5997
5998 // all those functions return SUCCESS
5999 case 0x00: /* disk controller reset */
6000 case 0x09: /* initialize drive parameters */
6001 case 0x0c: /* seek to specified cylinder */
6002 case 0x0d: /* alternate disk reset */
6003 case 0x10: /* check drive ready */
6004 case 0x11: /* recalibrate */
6005 case 0x14: /* controller internal diagnostic */
6006 case 0x16: /* detect disk change */
6007 goto int13_success;
6008 break;
6009
6010 // all those functions return disk write-protected
6011 case 0x03: /* write disk sectors */
6012 case 0x05: /* format disk track */
6013 case 0x43: // IBM/MS extended write
6014 SET_AH(0x03);
6015 goto int13_fail_noah;
6016 break;
6017
6018 case 0x01: /* read disk status */
6019 status = read_byte(0x0040, 0x0074);
6020 SET_AH(status);
6021 SET_DISK_RET_STATUS(0);
6022
6023 /* set CF if error status read */
6024 if (status) goto int13_fail_nostatus;
6025 else goto int13_success_noah;
6026 break;
6027
6028 case 0x15: /* read disk drive size */
6029 SET_AH(0x02);
6030 goto int13_fail_noah;
6031 break;
6032
6033 case 0x41: // IBM/MS installation check
6034 BX=0xaa55; // install check
6035 SET_AH(0x30); // EDD 2.1
6036 CX=0x0007; // ext disk access, removable and edd
6037 goto int13_success_noah;
6038 break;
6039
6040 case 0x42: // IBM/MS extended read
6041 case 0x44: // IBM/MS verify sectors
6042 case 0x47: // IBM/MS extended seek
6043
6044 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6045 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6046 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6047
6048 // Can't use 64 bits lba
6049 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6050 if (lba != 0L) {
6051 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6052 goto int13_fail;
6053 }
6054
6055 // Get 32 bits lba
6056 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6057
6058 // If verify or seek
6059 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6060 goto int13_success;
6061
6062 memsetb(get_SS(),atacmd,0,12);
6063 atacmd[0]=0x28; // READ command
6064 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6065 atacmd[8]=(count & 0x00ff); // Sectors
6066 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6067 atacmd[3]=(lba & 0x00ff0000) >> 16;
6068 atacmd[4]=(lba & 0x0000ff00) >> 8;
6069 atacmd[5]=(lba & 0x000000ff);
6070 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6071
6072 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6073 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6074
6075 if (status != 0) {
6076 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6077 SET_AH(0x0c);
6078 goto int13_fail_noah;
6079 }
6080
6081 goto int13_success;
6082 break;
6083
6084 case 0x45: // IBM/MS lock/unlock drive
6085 if (GET_AL() > 2) goto int13_fail;
6086
6087 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6088
6089 switch (GET_AL()) {
6090 case 0 : // lock
6091 if (locks == 0xff) {
6092 SET_AH(0xb4);
6093 SET_AL(1);
6094 goto int13_fail_noah;
6095 }
6096 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6097 SET_AL(1);
6098 break;
6099 case 1 : // unlock
6100 if (locks == 0x00) {
6101 SET_AH(0xb0);
6102 SET_AL(0);
6103 goto int13_fail_noah;
6104 }
6105 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6106 SET_AL(locks==0?0:1);
6107 break;
6108 case 2 : // status
6109 SET_AL(locks==0?0:1);
6110 break;
6111 }
6112 goto int13_success;
6113 break;
6114
6115 case 0x46: // IBM/MS eject media
6116 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6117
6118 if (locks != 0) {
6119 SET_AH(0xb1); // media locked
6120 goto int13_fail_noah;
6121 }
6122 // FIXME should handle 0x31 no media in device
6123 // FIXME should handle 0xb5 valid request failed
6124
6125 // Call removable media eject
6126 ASM_START
6127 push bp
6128 mov bp, sp
6129
6130 mov ah, #0x52
6131 int #0x15
6132 mov _int13_cdrom.status + 2[bp], ah
6133 jnc int13_cdrom_rme_end
6134 mov _int13_cdrom.status, #1
6135int13_cdrom_rme_end:
6136 pop bp
6137 ASM_END
6138
6139 if (status != 0) {
6140 SET_AH(0xb1); // media locked
6141 goto int13_fail_noah;
6142 }
6143
6144 goto int13_success;
6145 break;
6146
6147 case 0x48: // IBM/MS get drive parameters
6148 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6149
6150 // Buffer is too small
6151 if(size < 0x1a)
6152 goto int13_fail;
6153
6154 // EDD 1.x
6155 if(size >= 0x1a) {
6156 Bit16u cylinders, heads, spt, blksize;
6157
6158 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6159
6160 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6161 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6162 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6163 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6164 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6165 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6166 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6167 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6168 }
6169
6170 // EDD 2.x
6171 if(size >= 0x1e) {
6172 Bit8u channel, dev, irq, mode, checksum, i;
6173 Bit16u iobase1, iobase2, options;
6174
6175 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6176
6177 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6178 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6179
6180 // Fill in dpte
6181 channel = device / 2;
6182 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6183 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6184 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6185 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6186
6187 // FIXME atapi device
6188 options = (1<<4); // lba translation
6189 options |= (1<<5); // removable device
6190 options |= (1<<6); // atapi device
6191 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6192
6193 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6194 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6195 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6196 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6197 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6198 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6199 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6200 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6201 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6202 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6203 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6204
6205 checksum=0;
6206 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6207 checksum = ~checksum;
6208 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6209 }
6210
6211 // EDD 3.x
6212 if(size >= 0x42) {
6213 Bit8u channel, iface, checksum, i;
6214 Bit16u iobase1;
6215
6216 channel = device / 2;
6217 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6218 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6219
6220 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6221 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6222 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6223 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6224 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6225
6226 if (iface==ATA_IFACE_ISA) {
6227 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6228 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6229 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6230 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6231 }
6232 else {
6233 // FIXME PCI
6234 }
6235 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6236 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6237 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6238 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6239
6240 if (iface==ATA_IFACE_ISA) {
6241 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6242 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6243 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6244 }
6245 else {
6246 // FIXME PCI
6247 }
6248 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6249 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6250 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6251 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6252
6253 checksum=0;
6254 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6255 checksum = ~checksum;
6256 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6257 }
6258
6259 goto int13_success;
6260 break;
6261
6262 case 0x49: // IBM/MS extended media change
6263 // always send changed ??
6264 SET_AH(06);
6265 goto int13_fail_nostatus;
6266 break;
6267
6268 case 0x4e: // // IBM/MS set hardware configuration
6269 // DMA, prefetch, PIO maximum not supported
6270 switch (GET_AL()) {
6271 case 0x01:
6272 case 0x03:
6273 case 0x04:
6274 case 0x06:
6275 goto int13_success;
6276 break;
6277 default :
6278 goto int13_fail;
6279 }
6280 break;
6281
6282 // all those functions return unimplemented
6283 case 0x02: /* read sectors */
6284 case 0x04: /* verify sectors */
6285 case 0x08: /* read disk drive parameters */
6286 case 0x0a: /* read disk sectors with ECC */
6287 case 0x0b: /* write disk sectors with ECC */
6288 case 0x18: /* set media type for format */
6289 case 0x50: // ? - send packet command
6290 default:
6291 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6292 goto int13_fail;
6293 break;
6294 }
6295
6296int13_fail:
6297 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6298int13_fail_noah:
6299 SET_DISK_RET_STATUS(GET_AH());
6300int13_fail_nostatus:
6301 SET_CF(); // error occurred
6302 return;
6303
6304int13_success:
6305 SET_AH(0x00); // no error
6306int13_success_noah:
6307 SET_DISK_RET_STATUS(0x00);
6308 CLEAR_CF(); // no error
6309 return;
6310}
6311
6312// ---------------------------------------------------------------------------
6313// End of int13 for cdrom
6314// ---------------------------------------------------------------------------
6315
6316#if BX_ELTORITO_BOOT
6317// ---------------------------------------------------------------------------
6318// Start of int13 for eltorito functions
6319// ---------------------------------------------------------------------------
6320
6321 void
6322int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6323 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6324{
6325 Bit16u ebda_seg=read_word(0x0040,0x000E);
6326
6327 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6328 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6329
6330 switch (GET_AH()) {
6331
6332 // FIXME ElTorito Various. Should be implemented
6333 case 0x4a: // ElTorito - Initiate disk emu
6334 case 0x4c: // ElTorito - Initiate disk emu and boot
6335 case 0x4d: // ElTorito - Return Boot catalog
6336 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6337 goto int13_fail;
6338 break;
6339
6340 case 0x4b: // ElTorito - Terminate disk emu
6341 // FIXME ElTorito Hardcoded
6342 write_byte(DS,SI+0x00,0x13);
6343 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6344 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6345 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6346 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6347 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6348 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6349 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6350 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6351 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6352 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6353 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6354
6355 // If we have to terminate emulation
6356 if(GET_AL() == 0x00) {
6357 // FIXME ElTorito Various. Should be handled accordingly to spec
6358 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6359 }
6360
6361 goto int13_success;
6362 break;
6363
6364 default:
6365 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6366 goto int13_fail;
6367 break;
6368 }
6369
6370int13_fail:
6371 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6372 SET_DISK_RET_STATUS(GET_AH());
6373 SET_CF(); // error occurred
6374 return;
6375
6376int13_success:
6377 SET_AH(0x00); // no error
6378 SET_DISK_RET_STATUS(0x00);
6379 CLEAR_CF(); // no error
6380 return;
6381}
6382
6383// ---------------------------------------------------------------------------
6384// End of int13 for eltorito functions
6385// ---------------------------------------------------------------------------
6386
6387// ---------------------------------------------------------------------------
6388// Start of int13 when emulating a device from the cd
6389// ---------------------------------------------------------------------------
6390
6391 void
6392int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6393 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6394{
6395 Bit16u ebda_seg=read_word(0x0040,0x000E);
6396 Bit8u device, status;
6397 Bit16u vheads, vspt, vcylinders;
6398 Bit16u head, sector, cylinder, nbsectors;
6399 Bit32u vlba, ilba, slba, elba;
6400 Bit16u before, segment, offset;
6401 Bit8u atacmd[12];
6402
6403 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6404
6405 /* at this point, we are emulating a floppy/harddisk */
6406
6407 // Recompute the device number
6408 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6409 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6410
6411 SET_DISK_RET_STATUS(0x00);
6412
6413 /* basic checks : emulation should be active, dl should equal the emulated drive */
6414 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6415 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6416 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6417 goto int13_fail;
6418 }
6419
6420 switch (GET_AH()) {
6421
6422 // all those functions return SUCCESS
6423 case 0x00: /* disk controller reset */
6424 case 0x09: /* initialize drive parameters */
6425 case 0x0c: /* seek to specified cylinder */
6426 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6427 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6428 case 0x11: /* recalibrate */
6429 case 0x14: /* controller internal diagnostic */
6430 case 0x16: /* detect disk change */
6431 goto int13_success;
6432 break;
6433
6434 // all those functions return disk write-protected
6435 case 0x03: /* write disk sectors */
6436 case 0x05: /* format disk track */
6437 SET_AH(0x03);
6438 goto int13_fail_noah;
6439 break;
6440
6441 case 0x01: /* read disk status */
6442 status=read_byte(0x0040, 0x0074);
6443 SET_AH(status);
6444 SET_DISK_RET_STATUS(0);
6445
6446 /* set CF if error status read */
6447 if (status) goto int13_fail_nostatus;
6448 else goto int13_success_noah;
6449 break;
6450
6451 case 0x02: // read disk sectors
6452 case 0x04: // verify disk sectors
6453 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6454 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6455 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6456
6457 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6458
6459 sector = GET_CL() & 0x003f;
6460 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6461 head = GET_DH();
6462 nbsectors = GET_AL();
6463 segment = ES;
6464 offset = BX;
6465
6466 // no sector to read ?
6467 if(nbsectors==0) goto int13_success;
6468
6469 // sanity checks sco openserver needs this!
6470 if ((sector > vspt)
6471 || (cylinder >= vcylinders)
6472 || (head >= vheads)) {
6473 goto int13_fail;
6474 }
6475
6476 // After controls, verify do nothing
6477 if (GET_AH() == 0x04) goto int13_success;
6478
6479 segment = ES+(BX / 16);
6480 offset = BX % 16;
6481
6482 // calculate the virtual lba inside the image
6483 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6484
6485 // In advance so we don't loose the count
6486 SET_AL(nbsectors);
6487
6488 // start lba on cd
6489 slba = (Bit32u)vlba/4;
6490 before= (Bit16u)vlba%4;
6491
6492 // end lba on cd
6493 elba = (Bit32u)(vlba+nbsectors-1)/4;
6494
6495 memsetb(get_SS(),atacmd,0,12);
6496 atacmd[0]=0x28; // READ command
6497 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6498 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6499 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6500 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6501 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6502 atacmd[5]=(ilba+slba & 0x000000ff);
6503 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6504 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6505 SET_AH(0x02);
6506 SET_AL(0);
6507 goto int13_fail_noah;
6508 }
6509
6510 goto int13_success;
6511 break;
6512
6513 case 0x08: /* read disk drive parameters */
6514 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6515 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6516 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6517
6518 SET_AL( 0x00 );
6519 SET_BL( 0x00 );
6520 SET_CH( vcylinders & 0xff );
6521 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6522 SET_DH( vheads );
6523 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6524 // FIXME ElTorito Harddisk. should send the HD count
6525
6526 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6527 case 0x01: SET_BL( 0x02 ); break;
6528 case 0x02: SET_BL( 0x04 ); break;
6529 case 0x03: SET_BL( 0x06 ); break;
6530 }
6531
6532ASM_START
6533 push bp
6534 mov bp, sp
6535 mov ax, #diskette_param_table2
6536 mov _int13_cdemu.DI+2[bp], ax
6537 mov _int13_cdemu.ES+2[bp], cs
6538 pop bp
6539ASM_END
6540 goto int13_success;
6541 break;
6542
6543 case 0x15: /* read disk drive size */
6544 // FIXME ElTorito Harddisk. What geometry to send ?
6545 SET_AH(0x03);
6546 goto int13_success_noah;
6547 break;
6548
6549 // all those functions return unimplemented
6550 case 0x0a: /* read disk sectors with ECC */
6551 case 0x0b: /* write disk sectors with ECC */
6552 case 0x18: /* set media type for format */
6553 case 0x41: // IBM/MS installation check
6554 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6555 case 0x42: // IBM/MS extended read
6556 case 0x43: // IBM/MS extended write
6557 case 0x44: // IBM/MS verify sectors
6558 case 0x45: // IBM/MS lock/unlock drive
6559 case 0x46: // IBM/MS eject media
6560 case 0x47: // IBM/MS extended seek
6561 case 0x48: // IBM/MS get drive parameters
6562 case 0x49: // IBM/MS extended media change
6563 case 0x4e: // ? - set hardware configuration
6564 case 0x50: // ? - send packet command
6565 default:
6566 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6567 goto int13_fail;
6568 break;
6569 }
6570
6571int13_fail:
6572 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6573int13_fail_noah:
6574 SET_DISK_RET_STATUS(GET_AH());
6575int13_fail_nostatus:
6576 SET_CF(); // error occurred
6577 return;
6578
6579int13_success:
6580 SET_AH(0x00); // no error
6581int13_success_noah:
6582 SET_DISK_RET_STATUS(0x00);
6583 CLEAR_CF(); // no error
6584 return;
6585}
6586
6587// ---------------------------------------------------------------------------
6588// End of int13 when emulating a device from the cd
6589// ---------------------------------------------------------------------------
6590
6591#endif // BX_ELTORITO_BOOT
6592
6593#else //BX_USE_ATADRV
6594
6595 void
6596outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6597 Bit16u cylinder;
6598 Bit16u hd_heads;
6599 Bit16u head;
6600 Bit16u hd_sectors;
6601 Bit16u sector;
6602 Bit16u dl;
6603{
6604ASM_START
6605 push bp
6606 mov bp, sp
6607 push eax
6608 push ebx
6609 push edx
6610 xor eax,eax
6611 mov ax,4[bp] // cylinder
6612 xor ebx,ebx
6613 mov bl,6[bp] // hd_heads
6614 imul ebx
6615
6616 mov bl,8[bp] // head
6617 add eax,ebx
6618 mov bl,10[bp] // hd_sectors
6619 imul ebx
6620 mov bl,12[bp] // sector
6621 add eax,ebx
6622
6623 dec eax
6624 mov dx,#0x1f3
6625 out dx,al
6626 mov dx,#0x1f4
6627 mov al,ah
6628 out dx,al
6629 shr eax,#16
6630 mov dx,#0x1f5
6631 out dx,al
6632 and ah,#0xf
6633 mov bl,14[bp] // dl
6634 and bl,#1
6635 shl bl,#4
6636 or ah,bl
6637 or ah,#0xe0
6638 mov al,ah
6639 mov dx,#0x01f6
6640 out dx,al
6641 pop edx
6642 pop ebx
6643 pop eax
6644 pop bp
6645ASM_END
6646}
6647
6648 void
6649int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6650 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6651{
6652 Bit8u drive, num_sectors, sector, head, status, mod;
6653 Bit8u drive_map;
6654 Bit8u n_drives;
6655 Bit16u cyl_mod, ax;
6656 Bit16u max_cylinder, cylinder, total_sectors;
6657 Bit16u hd_cylinders;
6658 Bit8u hd_heads, hd_sectors;
6659 Bit16u val16;
6660 Bit8u sector_count;
6661 unsigned int i;
6662 Bit16u tempbx;
6663 Bit16u dpsize;
6664
6665 Bit16u count, segment, offset;
6666 Bit32u lba;
6667 Bit16u error;
6668
6669 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6670
6671 write_byte(0x0040, 0x008e, 0); // clear completion flag
6672
6673 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6674 handler code */
6675 /* check how many disks first (cmos reg 0x12), return an error if
6676 drive not present */
6677 drive_map = inb_cmos(0x12);
6678 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6679 (((drive_map & 0x0f)==0) ? 0 : 2);
6680 n_drives = (drive_map==0) ? 0 :
6681 ((drive_map==3) ? 2 : 1);
6682
6683 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6684 SET_AH(0x01);
6685 SET_DISK_RET_STATUS(0x01);
6686 SET_CF(); /* error occurred */
6687 return;
6688 }
6689
6690 switch (GET_AH()) {
6691
6692 case 0x00: /* disk controller reset */
6693BX_DEBUG_INT13_HD("int13_f00\n");
6694
6695 SET_AH(0);
6696 SET_DISK_RET_STATUS(0);
6697 set_diskette_ret_status(0);
6698 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6699 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6700 CLEAR_CF(); /* successful */
6701 return;
6702 break;
6703
6704 case 0x01: /* read disk status */
6705BX_DEBUG_INT13_HD("int13_f01\n");
6706 status = read_byte(0x0040, 0x0074);
6707 SET_AH(status);
6708 SET_DISK_RET_STATUS(0);
6709 /* set CF if error status read */
6710 if (status) SET_CF();
6711 else CLEAR_CF();
6712 return;
6713 break;
6714
6715 case 0x04: // verify disk sectors
6716 case 0x02: // read disk sectors
6717 drive = GET_ELDL();
6718 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6719
6720 num_sectors = GET_AL();
6721 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6722 sector = (GET_CL() & 0x3f);
6723 head = GET_DH();
6724
6725
6726 if (hd_cylinders > 1024) {
6727 if (hd_cylinders <= 2048) {
6728 cylinder <<= 1;
6729 }
6730 else if (hd_cylinders <= 4096) {
6731 cylinder <<= 2;
6732 }
6733 else if (hd_cylinders <= 8192) {
6734 cylinder <<= 3;
6735 }
6736 else { // hd_cylinders <= 16384
6737 cylinder <<= 4;
6738 }
6739
6740 ax = head / hd_heads;
6741 cyl_mod = ax & 0xff;
6742 head = ax >> 8;
6743 cylinder |= cyl_mod;
6744 }
6745
6746 if ( (cylinder >= hd_cylinders) ||
6747 (sector > hd_sectors) ||
6748 (head >= hd_heads) ) {
6749 SET_AH(1);
6750 SET_DISK_RET_STATUS(1);
6751 SET_CF(); /* error occurred */
6752 return;
6753 }
6754
6755 if ( (num_sectors > 128) || (num_sectors == 0) )
6756 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6757
6758 if (head > 15)
6759 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6760
6761 if ( GET_AH() == 0x04 ) {
6762 SET_AH(0);
6763 SET_DISK_RET_STATUS(0);
6764 CLEAR_CF();
6765 return;
6766 }
6767
6768 status = inb(0x1f7);
6769 if (status & 0x80) {
6770 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6771 }
6772 outb(0x01f2, num_sectors);
6773 /* activate LBA? (tomv) */
6774 if (hd_heads > 16) {
6775BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6776 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6777 }
6778 else {
6779 outb(0x01f3, sector);
6780 outb(0x01f4, cylinder & 0x00ff);
6781 outb(0x01f5, cylinder >> 8);
6782 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6783 }
6784 outb(0x01f7, 0x20);
6785
6786 while (1) {
6787 status = inb(0x1f7);
6788 if ( !(status & 0x80) ) break;
6789 }
6790
6791 if (status & 0x01) {
6792 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6793 } else if ( !(status & 0x08) ) {
6794 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6795 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6796 }
6797
6798 sector_count = 0;
6799 tempbx = BX;
6800
6801ASM_START
6802 sti ;; enable higher priority interrupts
6803ASM_END
6804
6805 while (1) {
6806ASM_START
6807 ;; store temp bx in real DI register
6808 push bp
6809 mov bp, sp
6810 mov di, _int13_harddisk.tempbx + 2 [bp]
6811 pop bp
6812
6813 ;; adjust if there will be an overrun
6814 cmp di, #0xfe00
6815 jbe i13_f02_no_adjust
6816i13_f02_adjust:
6817 sub di, #0x0200 ; sub 512 bytes from offset
6818 mov ax, es
6819 add ax, #0x0020 ; add 512 to segment
6820 mov es, ax
6821
6822i13_f02_no_adjust:
6823 mov cx, #0x0100 ;; counter (256 words = 512b)
6824 mov dx, #0x01f0 ;; AT data read port
6825
6826 rep
6827 insw ;; CX words transfered from port(DX) to ES:[DI]
6828
6829i13_f02_done:
6830 ;; store real DI register back to temp bx
6831 push bp
6832 mov bp, sp
6833 mov _int13_harddisk.tempbx + 2 [bp], di
6834 pop bp
6835ASM_END
6836
6837 sector_count++;
6838 num_sectors--;
6839 if (num_sectors == 0) {
6840 status = inb(0x1f7);
6841 if ( (status & 0xc9) != 0x40 )
6842 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6843 break;
6844 }
6845 else {
6846 status = inb(0x1f7);
6847 if ( (status & 0xc9) != 0x48 )
6848 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6849 continue;
6850 }
6851 }
6852
6853 SET_AH(0);
6854 SET_DISK_RET_STATUS(0);
6855 SET_AL(sector_count);
6856 CLEAR_CF(); /* successful */
6857 return;
6858 break;
6859
6860
6861 case 0x03: /* write disk sectors */
6862BX_DEBUG_INT13_HD("int13_f03\n");
6863 drive = GET_ELDL ();
6864 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6865
6866 num_sectors = GET_AL();
6867 cylinder = GET_CH();
6868 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6869 sector = (GET_CL() & 0x3f);
6870 head = GET_DH();
6871
6872 if (hd_cylinders > 1024) {
6873 if (hd_cylinders <= 2048) {
6874 cylinder <<= 1;
6875 }
6876 else if (hd_cylinders <= 4096) {
6877 cylinder <<= 2;
6878 }
6879 else if (hd_cylinders <= 8192) {
6880 cylinder <<= 3;
6881 }
6882 else { // hd_cylinders <= 16384
6883 cylinder <<= 4;
6884 }
6885
6886 ax = head / hd_heads;
6887 cyl_mod = ax & 0xff;
6888 head = ax >> 8;
6889 cylinder |= cyl_mod;
6890 }
6891
6892 if ( (cylinder >= hd_cylinders) ||
6893 (sector > hd_sectors) ||
6894 (head >= hd_heads) ) {
6895 SET_AH( 1);
6896 SET_DISK_RET_STATUS(1);
6897 SET_CF(); /* error occurred */
6898 return;
6899 }
6900
6901 if ( (num_sectors > 128) || (num_sectors == 0) )
6902 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6903
6904 if (head > 15)
6905 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6906
6907 status = inb(0x1f7);
6908 if (status & 0x80) {
6909 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6910 }
6911// should check for Drive Ready Bit also in status reg
6912 outb(0x01f2, num_sectors);
6913
6914 /* activate LBA? (tomv) */
6915 if (hd_heads > 16) {
6916BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6917 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6918 }
6919 else {
6920 outb(0x01f3, sector);
6921 outb(0x01f4, cylinder & 0x00ff);
6922 outb(0x01f5, cylinder >> 8);
6923 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6924 }
6925 outb(0x01f7, 0x30);
6926
6927 // wait for busy bit to turn off after seeking
6928 while (1) {
6929 status = inb(0x1f7);
6930 if ( !(status & 0x80) ) break;
6931 }
6932
6933 if ( !(status & 0x08) ) {
6934 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6935 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6936 }
6937
6938 sector_count = 0;
6939 tempbx = BX;
6940
6941ASM_START
6942 sti ;; enable higher priority interrupts
6943ASM_END
6944
6945 while (1) {
6946ASM_START
6947 ;; store temp bx in real SI register
6948 push bp
6949 mov bp, sp
6950 mov si, _int13_harddisk.tempbx + 2 [bp]
6951 pop bp
6952
6953 ;; adjust if there will be an overrun
6954 cmp si, #0xfe00
6955 jbe i13_f03_no_adjust
6956i13_f03_adjust:
6957 sub si, #0x0200 ; sub 512 bytes from offset
6958 mov ax, es
6959 add ax, #0x0020 ; add 512 to segment
6960 mov es, ax
6961
6962i13_f03_no_adjust:
6963 mov cx, #0x0100 ;; counter (256 words = 512b)
6964 mov dx, #0x01f0 ;; AT data read port
6965
6966 seg ES
6967 rep
6968 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6969
6970 ;; store real SI register back to temp bx
6971 push bp
6972 mov bp, sp
6973 mov _int13_harddisk.tempbx + 2 [bp], si
6974 pop bp
6975ASM_END
6976
6977 sector_count++;
6978 num_sectors--;
6979 if (num_sectors == 0) {
6980 status = inb(0x1f7);
6981 if ( (status & 0xe9) != 0x40 )
6982 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6983 break;
6984 }
6985 else {
6986 status = inb(0x1f7);
6987 if ( (status & 0xc9) != 0x48 )
6988 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6989 continue;
6990 }
6991 }
6992
6993 SET_AH(0);
6994 SET_DISK_RET_STATUS(0);
6995 SET_AL(sector_count);
6996 CLEAR_CF(); /* successful */
6997 return;
6998 break;
6999
7000 case 0x05: /* format disk track */
7001BX_DEBUG_INT13_HD("int13_f05\n");
7002 BX_PANIC("format disk track called\n");
7003 /* nop */
7004 SET_AH(0);
7005 SET_DISK_RET_STATUS(0);
7006 CLEAR_CF(); /* successful */
7007 return;
7008 break;
7009
7010 case 0x08: /* read disk drive parameters */
7011BX_DEBUG_INT13_HD("int13_f08\n");
7012
7013 drive = GET_ELDL ();
7014 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7015
7016 // translate CHS
7017 //
7018 if (hd_cylinders <= 1024) {
7019 // hd_cylinders >>= 0;
7020 // hd_heads <<= 0;
7021 }
7022 else if (hd_cylinders <= 2048) {
7023 hd_cylinders >>= 1;
7024 hd_heads <<= 1;
7025 }
7026 else if (hd_cylinders <= 4096) {
7027 hd_cylinders >>= 2;
7028 hd_heads <<= 2;
7029 }
7030 else if (hd_cylinders <= 8192) {
7031 hd_cylinders >>= 3;
7032 hd_heads <<= 3;
7033 }
7034 else { // hd_cylinders <= 16384
7035 hd_cylinders >>= 4;
7036 hd_heads <<= 4;
7037 }
7038
7039 max_cylinder = hd_cylinders - 2; /* 0 based */
7040 SET_AL(0);
7041 SET_CH(max_cylinder & 0xff);
7042 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7043 SET_DH(hd_heads - 1);
7044 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7045 SET_AH(0);
7046 SET_DISK_RET_STATUS(0);
7047 CLEAR_CF(); /* successful */
7048
7049 return;
7050 break;
7051
7052 case 0x09: /* initialize drive parameters */
7053BX_DEBUG_INT13_HD("int13_f09\n");
7054 SET_AH(0);
7055 SET_DISK_RET_STATUS(0);
7056 CLEAR_CF(); /* successful */
7057 return;
7058 break;
7059
7060 case 0x0a: /* read disk sectors with ECC */
7061BX_DEBUG_INT13_HD("int13_f0a\n");
7062 case 0x0b: /* write disk sectors with ECC */
7063BX_DEBUG_INT13_HD("int13_f0b\n");
7064 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7065 return;
7066 break;
7067
7068 case 0x0c: /* seek to specified cylinder */
7069BX_DEBUG_INT13_HD("int13_f0c\n");
7070 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7071 SET_AH(0);
7072 SET_DISK_RET_STATUS(0);
7073 CLEAR_CF(); /* successful */
7074 return;
7075 break;
7076
7077 case 0x0d: /* alternate disk reset */
7078BX_DEBUG_INT13_HD("int13_f0d\n");
7079 SET_AH(0);
7080 SET_DISK_RET_STATUS(0);
7081 CLEAR_CF(); /* successful */
7082 return;
7083 break;
7084
7085 case 0x10: /* check drive ready */
7086BX_DEBUG_INT13_HD("int13_f10\n");
7087 //SET_AH(0);
7088 //SET_DISK_RET_STATUS(0);
7089 //CLEAR_CF(); /* successful */
7090 //return;
7091 //break;
7092
7093 // should look at 40:8E also???
7094 status = inb(0x01f7);
7095 if ( (status & 0xc0) == 0x40 ) {
7096 SET_AH(0);
7097 SET_DISK_RET_STATUS(0);
7098 CLEAR_CF(); // drive ready
7099 return;
7100 }
7101 else {
7102 SET_AH(0xAA);
7103 SET_DISK_RET_STATUS(0xAA);
7104 SET_CF(); // not ready
7105 return;
7106 }
7107 break;
7108
7109 case 0x11: /* recalibrate */
7110BX_DEBUG_INT13_HD("int13_f11\n");
7111 SET_AH(0);
7112 SET_DISK_RET_STATUS(0);
7113 CLEAR_CF(); /* successful */
7114 return;
7115 break;
7116
7117 case 0x14: /* controller internal diagnostic */
7118BX_DEBUG_INT13_HD("int13_f14\n");
7119 SET_AH(0);
7120 SET_DISK_RET_STATUS(0);
7121 CLEAR_CF(); /* successful */
7122 SET_AL(0);
7123 return;
7124 break;
7125
7126 case 0x15: /* read disk drive size */
7127 drive = GET_ELDL();
7128 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7129ASM_START
7130 push bp
7131 mov bp, sp
7132 mov al, _int13_harddisk.hd_heads + 2 [bp]
7133 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7134 mul al, ah ;; ax = heads * sectors
7135 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7136 dec bx ;; use (cylinders - 1) ???
7137 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7138 ;; now we need to move the 32bit result dx:ax to what the
7139 ;; BIOS wants which is cx:dx.
7140 ;; and then into CX:DX on the stack
7141 mov _int13_harddisk.CX + 2 [bp], dx
7142 mov _int13_harddisk.DX + 2 [bp], ax
7143 pop bp
7144ASM_END
7145 SET_AH(3); // hard disk accessible
7146 SET_DISK_RET_STATUS(0); // ??? should this be 0
7147 CLEAR_CF(); // successful
7148 return;
7149 break;
7150
7151 case 0x18: // set media type for format
7152 case 0x41: // IBM/MS
7153 case 0x42: // IBM/MS
7154 case 0x43: // IBM/MS
7155 case 0x44: // IBM/MS
7156 case 0x45: // IBM/MS lock/unlock drive
7157 case 0x46: // IBM/MS eject media
7158 case 0x47: // IBM/MS extended seek
7159 case 0x49: // IBM/MS extended media change
7160 case 0x50: // IBM/MS send packet command
7161 default:
7162 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7163
7164 SET_AH(1); // code=invalid function in AH or invalid parameter
7165 SET_DISK_RET_STATUS(1);
7166 SET_CF(); /* unsuccessful */
7167 return;
7168 break;
7169 }
7170}
7171
7172static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7173static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7174
7175 void
7176get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7177 Bit8u drive;
7178 Bit16u *hd_cylinders;
7179 Bit8u *hd_heads;
7180 Bit8u *hd_sectors;
7181{
7182 Bit8u hd_type;
7183 Bit16u ss;
7184 Bit16u cylinders;
7185 Bit8u iobase;
7186
7187 ss = get_SS();
7188 if (drive == 0x80) {
7189 hd_type = inb_cmos(0x12) & 0xf0;
7190 if (hd_type != 0xf0)
7191 BX_INFO(panic_msg_reg12h,0);
7192 hd_type = inb_cmos(0x19); // HD0: extended type
7193 if (hd_type != 47)
7194 BX_INFO(panic_msg_reg19h,0,0x19);
7195 iobase = 0x1b;
7196 } else {
7197 hd_type = inb_cmos(0x12) & 0x0f;
7198 if (hd_type != 0x0f)
7199 BX_INFO(panic_msg_reg12h,1);
7200 hd_type = inb_cmos(0x1a); // HD1: extended type
7201 if (hd_type != 47)
7202 BX_INFO(panic_msg_reg19h,0,0x1a);
7203 iobase = 0x24;
7204 }
7205
7206 // cylinders
7207 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7208 write_word(ss, hd_cylinders, cylinders);
7209
7210 // heads
7211 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7212
7213 // sectors per track
7214 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7215}
7216
7217#endif //else BX_USE_ATADRV
7218
7219#if BX_SUPPORT_FLOPPY
7220
7221//////////////////////
7222// FLOPPY functions //
7223//////////////////////
7224
7225void floppy_reset_controller()
7226{
7227 Bit8u val8;
7228
7229 // Reset controller
7230 val8 = inb(0x03f2);
7231 outb(0x03f2, val8 & ~0x04);
7232 outb(0x03f2, val8 | 0x04);
7233
7234 // Wait for controller to come out of reset
7235 do {
7236 val8 = inb(0x3f4);
7237 } while ( (val8 & 0xc0) != 0x80 );
7238}
7239
7240void floppy_prepare_controller(drive)
7241 Bit16u drive;
7242{
7243 Bit8u val8, dor, prev_reset;
7244
7245 // set 40:3e bit 7 to 0
7246 val8 = read_byte(0x0040, 0x003e);
7247 val8 &= 0x7f;
7248 write_byte(0x0040, 0x003e, val8);
7249
7250 // turn on motor of selected drive, DMA & int enabled, normal operation
7251 prev_reset = inb(0x03f2) & 0x04;
7252 if (drive)
7253 dor = 0x20;
7254 else
7255 dor = 0x10;
7256 dor |= 0x0c;
7257 dor |= drive;
7258 outb(0x03f2, dor);
7259
7260 // reset the disk motor timeout value of INT 08
7261 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7262
7263#ifdef VBOX
7264 // program data rate
7265 val8 = read_byte(0x0040, 0x008b);
7266 val8 >>= 6;
7267 outb(0x03f7, val8);
7268#endif
7269
7270 // wait for drive readiness
7271 do {
7272 val8 = inb(0x3f4);
7273 } while ( (val8 & 0xc0) != 0x80 );
7274
7275 if (prev_reset == 0) {
7276 // turn on interrupts
7277ASM_START
7278 sti
7279ASM_END
7280 // wait on 40:3e bit 7 to become 1
7281 do {
7282 val8 = read_byte(0x0040, 0x003e);
7283 } while ( (val8 & 0x80) == 0 );
7284 val8 &= 0x7f;
7285ASM_START
7286 cli
7287ASM_END
7288 write_byte(0x0040, 0x003e, val8);
7289 }
7290}
7291
7292 bx_bool
7293floppy_media_known(drive)
7294 Bit16u drive;
7295{
7296 Bit8u val8;
7297 Bit16u media_state_offset;
7298
7299 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7300 if (drive)
7301 val8 >>= 1;
7302 val8 &= 0x01;
7303 if (val8 == 0)
7304 return(0);
7305
7306 media_state_offset = 0x0090;
7307 if (drive)
7308 media_state_offset += 1;
7309
7310 val8 = read_byte(0x0040, media_state_offset);
7311 val8 = (val8 >> 4) & 0x01;
7312 if (val8 == 0)
7313 return(0);
7314
7315 // check pass, return KNOWN
7316 return(1);
7317}
7318
7319 bx_bool
7320floppy_media_sense(drive)
7321 Bit16u drive;
7322{
7323 bx_bool retval;
7324 Bit16u media_state_offset;
7325 Bit8u drive_type, config_data, media_state;
7326
7327 if (floppy_drive_recal(drive) == 0) {
7328 return(0);
7329 }
7330
7331 // for now cheat and get drive type from CMOS,
7332 // assume media is same as drive type
7333
7334 // ** config_data **
7335 // Bitfields for diskette media control:
7336 // Bit(s) Description (Table M0028)
7337 // 7-6 last data rate set by controller
7338 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7339 // 5-4 last diskette drive step rate selected
7340 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7341 // 3-2 {data rate at start of operation}
7342 // 1-0 reserved
7343
7344 // ** media_state **
7345 // Bitfields for diskette drive media state:
7346 // Bit(s) Description (Table M0030)
7347 // 7-6 data rate
7348 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7349 // 5 double stepping required (e.g. 360kB in 1.2MB)
7350 // 4 media type established
7351 // 3 drive capable of supporting 4MB media
7352 // 2-0 on exit from BIOS, contains
7353 // 000 trying 360kB in 360kB
7354 // 001 trying 360kB in 1.2MB
7355 // 010 trying 1.2MB in 1.2MB
7356 // 011 360kB in 360kB established
7357 // 100 360kB in 1.2MB established
7358 // 101 1.2MB in 1.2MB established
7359 // 110 reserved
7360 // 111 all other formats/drives
7361
7362 drive_type = inb_cmos(0x10);
7363 if (drive == 0)
7364 drive_type >>= 4;
7365 else
7366 drive_type &= 0x0f;
7367 if ( drive_type == 1 ) {
7368 // 360K 5.25" drive
7369 config_data = 0x00; // 0000 0000
7370 media_state = 0x25; // 0010 0101
7371 retval = 1;
7372 }
7373 else if ( drive_type == 2 ) {
7374 // 1.2 MB 5.25" drive
7375 config_data = 0x00; // 0000 0000
7376 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7377 retval = 1;
7378 }
7379 else if ( drive_type == 3 ) {
7380 // 720K 3.5" drive
7381 config_data = 0x00; // 0000 0000 ???
7382 media_state = 0x17; // 0001 0111
7383 retval = 1;
7384 }
7385 else if ( drive_type == 4 ) {
7386 // 1.44 MB 3.5" drive
7387 config_data = 0x00; // 0000 0000
7388 media_state = 0x17; // 0001 0111
7389 retval = 1;
7390 }
7391 else if ( drive_type == 5 ) {
7392 // 2.88 MB 3.5" drive
7393 config_data = 0xCC; // 1100 1100
7394 media_state = 0xD7; // 1101 0111
7395 retval = 1;
7396 }
7397 //
7398 // Extended floppy size uses special cmos setting
7399 else if ( drive_type == 6 ) {
7400 // 160k 5.25" drive
7401 config_data = 0x00; // 0000 0000
7402 media_state = 0x27; // 0010 0111
7403 retval = 1;
7404 }
7405 else if ( drive_type == 7 ) {
7406 // 180k 5.25" drive
7407 config_data = 0x00; // 0000 0000
7408 media_state = 0x27; // 0010 0111
7409 retval = 1;
7410 }
7411 else if ( drive_type == 8 ) {
7412 // 320k 5.25" drive
7413 config_data = 0x00; // 0000 0000
7414 media_state = 0x27; // 0010 0111
7415 retval = 1;
7416 }
7417
7418 else {
7419 // not recognized
7420 config_data = 0x00; // 0000 0000
7421 media_state = 0x00; // 0000 0000
7422 retval = 0;
7423 }
7424
7425 if (drive == 0)
7426 media_state_offset = 0x90;
7427 else
7428 media_state_offset = 0x91;
7429 write_byte(0x0040, 0x008B, config_data);
7430 write_byte(0x0040, media_state_offset, media_state);
7431
7432 return(retval);
7433}
7434
7435 bx_bool
7436floppy_drive_recal(drive)
7437 Bit16u drive;
7438{
7439 Bit8u val8;
7440 Bit16u curr_cyl_offset;
7441
7442 floppy_prepare_controller(drive);
7443
7444 // send Recalibrate command (2 bytes) to controller
7445 outb(0x03f5, 0x07); // 07: Recalibrate
7446 outb(0x03f5, drive); // 0=drive0, 1=drive1
7447
7448 // turn on interrupts
7449ASM_START
7450 sti
7451ASM_END
7452
7453 // wait on 40:3e bit 7 to become 1
7454 do {
7455 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7456 } while ( val8 == 0 );
7457
7458 val8 = 0; // separate asm from while() loop
7459 // turn off interrupts
7460ASM_START
7461 cli
7462ASM_END
7463
7464 // set 40:3e bit 7 to 0, and calibrated bit
7465 val8 = read_byte(0x0040, 0x003e);
7466 val8 &= 0x7f;
7467 if (drive) {
7468 val8 |= 0x02; // Drive 1 calibrated
7469 curr_cyl_offset = 0x0095;
7470 } else {
7471 val8 |= 0x01; // Drive 0 calibrated
7472 curr_cyl_offset = 0x0094;
7473 }
7474 write_byte(0x0040, 0x003e, val8);
7475 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7476
7477 return(1);
7478}
7479
7480
7481
7482 bx_bool
7483floppy_drive_exists(drive)
7484 Bit16u drive;
7485{
7486 Bit8u drive_type;
7487
7488 // check CMOS to see if drive exists
7489 drive_type = inb_cmos(0x10);
7490 if (drive == 0)
7491 drive_type >>= 4;
7492 else
7493 drive_type &= 0x0f;
7494 if ( drive_type == 0 )
7495 return(0);
7496 else
7497 return(1);
7498}
7499
7500 void
7501int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7502 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7503{
7504 Bit8u drive, num_sectors, track, sector, head, status;
7505 Bit16u base_address, base_count, base_es;
7506 Bit8u page, mode_register, val8, dor;
7507 Bit8u return_status[7];
7508 Bit8u drive_type, num_floppies, ah;
7509 Bit16u es, last_addr;
7510
7511 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7512
7513 ah = GET_AH();
7514
7515 switch ( ah ) {
7516 case 0x00: // diskette controller reset
7517BX_DEBUG_INT13_FL("floppy f00\n");
7518 drive = GET_ELDL();
7519 if (drive > 1) {
7520 SET_AH(1); // invalid param
7521 set_diskette_ret_status(1);
7522 SET_CF();
7523 return;
7524 }
7525 drive_type = inb_cmos(0x10);
7526
7527 if (drive == 0)
7528 drive_type >>= 4;
7529 else
7530 drive_type &= 0x0f;
7531 if (drive_type == 0) {
7532 SET_AH(0x80); // drive not responding
7533 set_diskette_ret_status(0x80);
7534 SET_CF();
7535 return;
7536 }
7537 SET_AH(0);
7538 set_diskette_ret_status(0);
7539 CLEAR_CF(); // successful
7540 set_diskette_current_cyl(drive, 0); // current cylinder
7541 return;
7542
7543 case 0x01: // Read Diskette Status
7544 CLEAR_CF();
7545 val8 = read_byte(0x0000, 0x0441);
7546 SET_AH(val8);
7547 if (val8) {
7548 SET_CF();
7549 }
7550 return;
7551
7552 case 0x02: // Read Diskette Sectors
7553 case 0x03: // Write Diskette Sectors
7554 case 0x04: // Verify Diskette Sectors
7555 num_sectors = GET_AL();
7556 track = GET_CH();
7557 sector = GET_CL();
7558 head = GET_DH();
7559 drive = GET_ELDL();
7560
7561 if ( (drive > 1) || (head > 1) ||
7562 (num_sectors == 0) || (num_sectors > 72) ) {
7563BX_INFO("floppy: drive>1 || head>1 ...\n");
7564 SET_AH(1);
7565 set_diskette_ret_status(1);
7566 SET_AL(0); // no sectors read
7567 SET_CF(); // error occurred
7568 return;
7569 }
7570
7571 // see if drive exists
7572 if (floppy_drive_exists(drive) == 0) {
7573 SET_AH(0x80); // not responding
7574 set_diskette_ret_status(0x80);
7575 SET_AL(0); // no sectors read
7576 SET_CF(); // error occurred
7577 return;
7578 }
7579
7580 // see if media in drive, and type is known
7581 if (floppy_media_known(drive) == 0) {
7582 if (floppy_media_sense(drive) == 0) {
7583 SET_AH(0x0C); // Media type not found
7584 set_diskette_ret_status(0x0C);
7585 SET_AL(0); // no sectors read
7586 SET_CF(); // error occurred
7587 return;
7588 }
7589 }
7590
7591 if (ah == 0x02) {
7592 // Read Diskette Sectors
7593
7594 //-----------------------------------
7595 // set up DMA controller for transfer
7596 //-----------------------------------
7597
7598 // es:bx = pointer to where to place information from diskette
7599 // port 04: DMA-1 base and current address, channel 2
7600 // port 05: DMA-1 base and current count, channel 2
7601 page = (ES >> 12); // upper 4 bits
7602 base_es = (ES << 4); // lower 16bits contributed by ES
7603 base_address = base_es + BX; // lower 16 bits of address
7604 // contributed by ES:BX
7605 if ( base_address < base_es ) {
7606 // in case of carry, adjust page by 1
7607 page++;
7608 }
7609 base_count = (num_sectors * 512) - 1;
7610
7611 // check for 64K boundary overrun
7612 last_addr = base_address + base_count;
7613 if (last_addr < base_address) {
7614 SET_AH(0x09);
7615 set_diskette_ret_status(0x09);
7616 SET_AL(0); // no sectors read
7617 SET_CF(); // error occurred
7618 return;
7619 }
7620
7621 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7622 outb(0x000a, 0x06);
7623
7624 BX_DEBUG_INT13_FL("clear flip-flop\n");
7625 outb(0x000c, 0x00); // clear flip-flop
7626 outb(0x0004, base_address);
7627 outb(0x0004, base_address>>8);
7628 BX_DEBUG_INT13_FL("clear flip-flop\n");
7629 outb(0x000c, 0x00); // clear flip-flop
7630 outb(0x0005, base_count);
7631 outb(0x0005, base_count>>8);
7632
7633 // port 0b: DMA-1 Mode Register
7634 mode_register = 0x46; // single mode, increment, autoinit disable,
7635 // transfer type=write, channel 2
7636 BX_DEBUG_INT13_FL("setting mode register\n");
7637 outb(0x000b, mode_register);
7638
7639 BX_DEBUG_INT13_FL("setting page register\n");
7640 // port 81: DMA-1 Page Register, channel 2
7641 outb(0x0081, page);
7642
7643 BX_DEBUG_INT13_FL("unmask chan 2\n");
7644 outb(0x000a, 0x02); // unmask channel 2
7645
7646 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7647 outb(0x000a, 0x02);
7648
7649 //--------------------------------------
7650 // set up floppy controller for transfer
7651 //--------------------------------------
7652 floppy_prepare_controller(drive);
7653
7654 // send read-normal-data command (9 bytes) to controller
7655 outb(0x03f5, 0xe6); // e6: read normal data
7656 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7657 outb(0x03f5, track);
7658 outb(0x03f5, head);
7659 outb(0x03f5, sector);
7660 outb(0x03f5, 2); // 512 byte sector size
7661 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7662 outb(0x03f5, 0); // Gap length
7663 outb(0x03f5, 0xff); // Gap length
7664
7665 // turn on interrupts
7666 ASM_START
7667 sti
7668 ASM_END
7669
7670 // wait on 40:3e bit 7 to become 1
7671 do {
7672 val8 = read_byte(0x0040, 0x0040);
7673 if (val8 == 0) {
7674 floppy_reset_controller();
7675 SET_AH(0x80); // drive not ready (timeout)
7676 set_diskette_ret_status(0x80);
7677 SET_AL(0); // no sectors read
7678 SET_CF(); // error occurred
7679 return;
7680 }
7681 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7682 } while ( val8 == 0 );
7683
7684 val8 = 0; // separate asm from while() loop
7685 // turn off interrupts
7686 ASM_START
7687 cli
7688 ASM_END
7689
7690 // set 40:3e bit 7 to 0
7691 val8 = read_byte(0x0040, 0x003e);
7692 val8 &= 0x7f;
7693 write_byte(0x0040, 0x003e, val8);
7694
7695 // check port 3f4 for accessibility to status bytes
7696 val8 = inb(0x3f4);
7697 if ( (val8 & 0xc0) != 0xc0 )
7698 BX_PANIC("int13_diskette: ctrl not ready\n");
7699
7700 // read 7 return status bytes from controller
7701 // using loop index broken, have to unroll...
7702 return_status[0] = inb(0x3f5);
7703 return_status[1] = inb(0x3f5);
7704 return_status[2] = inb(0x3f5);
7705 return_status[3] = inb(0x3f5);
7706 return_status[4] = inb(0x3f5);
7707 return_status[5] = inb(0x3f5);
7708 return_status[6] = inb(0x3f5);
7709 // record in BIOS Data Area
7710 write_byte(0x0040, 0x0042, return_status[0]);
7711 write_byte(0x0040, 0x0043, return_status[1]);
7712 write_byte(0x0040, 0x0044, return_status[2]);
7713 write_byte(0x0040, 0x0045, return_status[3]);
7714 write_byte(0x0040, 0x0046, return_status[4]);
7715 write_byte(0x0040, 0x0047, return_status[5]);
7716 write_byte(0x0040, 0x0048, return_status[6]);
7717
7718 if ( (return_status[0] & 0xc0) != 0 ) {
7719 SET_AH(0x20);
7720 set_diskette_ret_status(0x20);
7721 SET_AL(0); // no sectors read
7722 SET_CF(); // error occurred
7723 return;
7724 }
7725
7726 // ??? should track be new val from return_status[3] ?
7727 set_diskette_current_cyl(drive, track);
7728 // AL = number of sectors read (same value as passed)
7729 SET_AH(0x00); // success
7730 CLEAR_CF(); // success
7731 return;
7732 } else if (ah == 0x03) {
7733 // Write Diskette Sectors
7734
7735 //-----------------------------------
7736 // set up DMA controller for transfer
7737 //-----------------------------------
7738
7739 // es:bx = pointer to where to place information from diskette
7740 // port 04: DMA-1 base and current address, channel 2
7741 // port 05: DMA-1 base and current count, channel 2
7742 page = (ES >> 12); // upper 4 bits
7743 base_es = (ES << 4); // lower 16bits contributed by ES
7744 base_address = base_es + BX; // lower 16 bits of address
7745 // contributed by ES:BX
7746 if ( base_address < base_es ) {
7747 // in case of carry, adjust page by 1
7748 page++;
7749 }
7750 base_count = (num_sectors * 512) - 1;
7751
7752 // check for 64K boundary overrun
7753 last_addr = base_address + base_count;
7754 if (last_addr < base_address) {
7755 SET_AH(0x09);
7756 set_diskette_ret_status(0x09);
7757 SET_AL(0); // no sectors read
7758 SET_CF(); // error occurred
7759 return;
7760 }
7761
7762 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7763 outb(0x000a, 0x06);
7764
7765 outb(0x000c, 0x00); // clear flip-flop
7766 outb(0x0004, base_address);
7767 outb(0x0004, base_address>>8);
7768 outb(0x000c, 0x00); // clear flip-flop
7769 outb(0x0005, base_count);
7770 outb(0x0005, base_count>>8);
7771
7772 // port 0b: DMA-1 Mode Register
7773 mode_register = 0x4a; // single mode, increment, autoinit disable,
7774 // transfer type=read, channel 2
7775 outb(0x000b, mode_register);
7776
7777 // port 81: DMA-1 Page Register, channel 2
7778 outb(0x0081, page);
7779
7780 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7781 outb(0x000a, 0x02);
7782
7783 //--------------------------------------
7784 // set up floppy controller for transfer
7785 //--------------------------------------
7786 floppy_prepare_controller(drive);
7787
7788 // send write-normal-data command (9 bytes) to controller
7789 outb(0x03f5, 0xc5); // c5: write normal data
7790 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7791 outb(0x03f5, track);
7792 outb(0x03f5, head);
7793 outb(0x03f5, sector);
7794 outb(0x03f5, 2); // 512 byte sector size
7795 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7796 outb(0x03f5, 0); // Gap length
7797 outb(0x03f5, 0xff); // Gap length
7798
7799 // turn on interrupts
7800 ASM_START
7801 sti
7802 ASM_END
7803
7804 // wait on 40:3e bit 7 to become 1
7805 do {
7806 val8 = read_byte(0x0040, 0x0040);
7807 if (val8 == 0) {
7808 floppy_reset_controller();
7809 SET_AH(0x80); // drive not ready (timeout)
7810 set_diskette_ret_status(0x80);
7811 SET_AL(0); // no sectors written
7812 SET_CF(); // error occurred
7813 return;
7814 }
7815 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7816 } while ( val8 == 0 );
7817
7818 val8 = 0; // separate asm from while() loop
7819 // turn off interrupts
7820 ASM_START
7821 cli
7822 ASM_END
7823
7824 // set 40:3e bit 7 to 0
7825 val8 = read_byte(0x0040, 0x003e);
7826 val8 &= 0x7f;
7827 write_byte(0x0040, 0x003e, val8);
7828
7829 // check port 3f4 for accessibility to status bytes
7830 val8 = inb(0x3f4);
7831 if ( (val8 & 0xc0) != 0xc0 )
7832 BX_PANIC("int13_diskette: ctrl not ready\n");
7833
7834 // read 7 return status bytes from controller
7835 // using loop index broken, have to unroll...
7836 return_status[0] = inb(0x3f5);
7837 return_status[1] = inb(0x3f5);
7838 return_status[2] = inb(0x3f5);
7839 return_status[3] = inb(0x3f5);
7840 return_status[4] = inb(0x3f5);
7841 return_status[5] = inb(0x3f5);
7842 return_status[6] = inb(0x3f5);
7843 // record in BIOS Data Area
7844 write_byte(0x0040, 0x0042, return_status[0]);
7845 write_byte(0x0040, 0x0043, return_status[1]);
7846 write_byte(0x0040, 0x0044, return_status[2]);
7847 write_byte(0x0040, 0x0045, return_status[3]);
7848 write_byte(0x0040, 0x0046, return_status[4]);
7849 write_byte(0x0040, 0x0047, return_status[5]);
7850 write_byte(0x0040, 0x0048, return_status[6]);
7851
7852 if ( (return_status[0] & 0xc0) != 0 ) {
7853 if ( (return_status[1] & 0x02) != 0 ) {
7854 // diskette not writable.
7855 // AH=status code=0x03 (tried to write on write-protected disk)
7856 // AL=number of sectors written=0
7857 AX = 0x0300;
7858 SET_CF();
7859 return;
7860 } else {
7861 BX_PANIC("int13_diskette_function: read error\n");
7862 }
7863 }
7864
7865 // ??? should track be new val from return_status[3] ?
7866 set_diskette_current_cyl(drive, track);
7867 // AL = number of sectors read (same value as passed)
7868 SET_AH(0x00); // success
7869 CLEAR_CF(); // success
7870 return;
7871 } else { // if (ah == 0x04)
7872 // Verify Diskette Sectors
7873
7874 // ??? should track be new val from return_status[3] ?
7875 set_diskette_current_cyl(drive, track);
7876 // AL = number of sectors verified (same value as passed)
7877 CLEAR_CF(); // success
7878 SET_AH(0x00); // success
7879 return;
7880 }
7881 break;
7882
7883 case 0x05: // format diskette track
7884BX_DEBUG_INT13_FL("floppy f05\n");
7885
7886 num_sectors = GET_AL();
7887 track = GET_CH();
7888 head = GET_DH();
7889 drive = GET_ELDL();
7890
7891 if ((drive > 1) || (head > 1) || (track > 79) ||
7892 (num_sectors == 0) || (num_sectors > 18)) {
7893 SET_AH(1);
7894 set_diskette_ret_status(1);
7895 SET_CF(); // error occurred
7896 }
7897
7898 // see if drive exists
7899 if (floppy_drive_exists(drive) == 0) {
7900 SET_AH(0x80); // drive not responding
7901 set_diskette_ret_status(0x80);
7902 SET_CF(); // error occurred
7903 return;
7904 }
7905
7906 // see if media in drive, and type is known
7907 if (floppy_media_known(drive) == 0) {
7908 if (floppy_media_sense(drive) == 0) {
7909 SET_AH(0x0C); // Media type not found
7910 set_diskette_ret_status(0x0C);
7911 SET_AL(0); // no sectors read
7912 SET_CF(); // error occurred
7913 return;
7914 }
7915 }
7916
7917 // set up DMA controller for transfer
7918 page = (ES >> 12); // upper 4 bits
7919 base_es = (ES << 4); // lower 16bits contributed by ES
7920 base_address = base_es + BX; // lower 16 bits of address
7921 // contributed by ES:BX
7922 if ( base_address < base_es ) {
7923 // in case of carry, adjust page by 1
7924 page++;
7925 }
7926 base_count = (num_sectors * 4) - 1;
7927
7928 // check for 64K boundary overrun
7929 last_addr = base_address + base_count;
7930 if (last_addr < base_address) {
7931 SET_AH(0x09);
7932 set_diskette_ret_status(0x09);
7933 SET_AL(0); // no sectors read
7934 SET_CF(); // error occurred
7935 return;
7936 }
7937
7938 outb(0x000a, 0x06);
7939 outb(0x000c, 0x00); // clear flip-flop
7940 outb(0x0004, base_address);
7941 outb(0x0004, base_address>>8);
7942 outb(0x000c, 0x00); // clear flip-flop
7943 outb(0x0005, base_count);
7944 outb(0x0005, base_count>>8);
7945 mode_register = 0x4a; // single mode, increment, autoinit disable,
7946 // transfer type=read, channel 2
7947 outb(0x000b, mode_register);
7948 // port 81: DMA-1 Page Register, channel 2
7949 outb(0x0081, page);
7950 outb(0x000a, 0x02);
7951
7952 // set up floppy controller for transfer
7953 floppy_prepare_controller(drive);
7954
7955 // send format-track command (6 bytes) to controller
7956 outb(0x03f5, 0x4d); // 4d: format track
7957 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7958 outb(0x03f5, 2); // 512 byte sector size
7959 outb(0x03f5, num_sectors); // number of sectors per track
7960 outb(0x03f5, 0); // Gap length
7961 outb(0x03f5, 0xf6); // Fill byte
7962 // turn on interrupts
7963 ASM_START
7964 sti
7965 ASM_END
7966
7967 // wait on 40:3e bit 7 to become 1
7968 do {
7969 val8 = read_byte(0x0040, 0x0040);
7970 if (val8 == 0) {
7971 floppy_reset_controller();
7972 SET_AH(0x80); // drive not ready (timeout)
7973 set_diskette_ret_status(0x80);
7974 SET_CF(); // error occurred
7975 return;
7976 }
7977 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7978 } while ( val8 == 0 );
7979
7980 val8 = 0; // separate asm from while() loop
7981 // turn off interrupts
7982 ASM_START
7983 cli
7984 ASM_END
7985 // set 40:3e bit 7 to 0
7986 val8 = read_byte(0x0040, 0x003e);
7987 val8 &= 0x7f;
7988 write_byte(0x0040, 0x003e, val8);
7989 // check port 3f4 for accessibility to status bytes
7990 val8 = inb(0x3f4);
7991 if ( (val8 & 0xc0) != 0xc0 )
7992 BX_PANIC("int13_diskette: ctrl not ready\n");
7993
7994 // read 7 return status bytes from controller
7995 // using loop index broken, have to unroll...
7996 return_status[0] = inb(0x3f5);
7997 return_status[1] = inb(0x3f5);
7998 return_status[2] = inb(0x3f5);
7999 return_status[3] = inb(0x3f5);
8000 return_status[4] = inb(0x3f5);
8001 return_status[5] = inb(0x3f5);
8002 return_status[6] = inb(0x3f5);
8003 // record in BIOS Data Area
8004 write_byte(0x0040, 0x0042, return_status[0]);
8005 write_byte(0x0040, 0x0043, return_status[1]);
8006 write_byte(0x0040, 0x0044, return_status[2]);
8007 write_byte(0x0040, 0x0045, return_status[3]);
8008 write_byte(0x0040, 0x0046, return_status[4]);
8009 write_byte(0x0040, 0x0047, return_status[5]);
8010 write_byte(0x0040, 0x0048, return_status[6]);
8011
8012 if ( (return_status[0] & 0xc0) != 0 ) {
8013 if ( (return_status[1] & 0x02) != 0 ) {
8014 // diskette not writable.
8015 // AH=status code=0x03 (tried to write on write-protected disk)
8016 // AL=number of sectors written=0
8017 AX = 0x0300;
8018 SET_CF();
8019 return;
8020 } else {
8021 BX_PANIC("int13_diskette_function: write error\n");
8022 }
8023 }
8024
8025 SET_AH(0);
8026 set_diskette_ret_status(0);
8027 set_diskette_current_cyl(drive, 0);
8028 CLEAR_CF(); // successful
8029 return;
8030
8031
8032 case 0x08: // read diskette drive parameters
8033BX_DEBUG_INT13_FL("floppy f08\n");
8034 drive = GET_ELDL();
8035
8036 if (drive > 1) {
8037 AX = 0;
8038 BX = 0;
8039 CX = 0;
8040 DX = 0;
8041 ES = 0;
8042 DI = 0;
8043 SET_DL(num_floppies);
8044 SET_CF();
8045 return;
8046 }
8047
8048 drive_type = inb_cmos(0x10);
8049 num_floppies = 0;
8050 if (drive_type & 0xf0)
8051 num_floppies++;
8052 if (drive_type & 0x0f)
8053 num_floppies++;
8054
8055 if (drive == 0)
8056 drive_type >>= 4;
8057 else
8058 drive_type &= 0x0f;
8059
8060 SET_BH(0);
8061 SET_BL(drive_type);
8062 SET_AH(0);
8063 SET_AL(0);
8064 SET_DL(num_floppies);
8065
8066 switch (drive_type) {
8067 case 0: // none
8068 CX = 0;
8069 SET_DH(0); // max head #
8070 break;
8071
8072 case 1: // 360KB, 5.25"
8073 CX = 0x2709; // 40 tracks, 9 sectors
8074 SET_DH(1); // max head #
8075 break;
8076
8077 case 2: // 1.2MB, 5.25"
8078 CX = 0x4f0f; // 80 tracks, 15 sectors
8079 SET_DH(1); // max head #
8080 break;
8081
8082 case 3: // 720KB, 3.5"
8083 CX = 0x4f09; // 80 tracks, 9 sectors
8084 SET_DH(1); // max head #
8085 break;
8086
8087 case 4: // 1.44MB, 3.5"
8088 CX = 0x4f12; // 80 tracks, 18 sectors
8089 SET_DH(1); // max head #
8090 break;
8091
8092 case 5: // 2.88MB, 3.5"
8093 CX = 0x4f24; // 80 tracks, 36 sectors
8094 SET_DH(1); // max head #
8095 break;
8096
8097 case 6: // 160k, 5.25"
8098 CX = 0x2708; // 40 tracks, 8 sectors
8099 SET_DH(0); // max head #
8100 break;
8101
8102 case 7: // 180k, 5.25"
8103 CX = 0x2709; // 40 tracks, 9 sectors
8104 SET_DH(0); // max head #
8105 break;
8106
8107 case 8: // 320k, 5.25"
8108 CX = 0x2708; // 40 tracks, 8 sectors
8109 SET_DH(1); // max head #
8110 break;
8111
8112 default: // ?
8113 BX_PANIC("floppy: int13: bad floppy type\n");
8114 }
8115
8116 /* set es & di to point to 11 byte diskette param table in ROM */
8117ASM_START
8118 push bp
8119 mov bp, sp
8120 mov ax, #diskette_param_table2
8121 mov _int13_diskette_function.DI+2[bp], ax
8122 mov _int13_diskette_function.ES+2[bp], cs
8123 pop bp
8124ASM_END
8125 CLEAR_CF(); // success
8126 /* disk status not changed upon success */
8127 return;
8128
8129
8130 case 0x15: // read diskette drive type
8131BX_DEBUG_INT13_FL("floppy f15\n");
8132 drive = GET_ELDL();
8133 if (drive > 1) {
8134 SET_AH(0); // only 2 drives supported
8135 // set_diskette_ret_status here ???
8136 SET_CF();
8137 return;
8138 }
8139 drive_type = inb_cmos(0x10);
8140
8141 if (drive == 0)
8142 drive_type >>= 4;
8143 else
8144 drive_type &= 0x0f;
8145 CLEAR_CF(); // successful, not present
8146 if (drive_type==0) {
8147 SET_AH(0); // drive not present
8148 }
8149 else {
8150 SET_AH(1); // drive present, does not support change line
8151 }
8152
8153 return;
8154
8155 case 0x16: // get diskette change line status
8156BX_DEBUG_INT13_FL("floppy f16\n");
8157 drive = GET_ELDL();
8158 if (drive > 1) {
8159 SET_AH(0x01); // invalid drive
8160 set_diskette_ret_status(0x01);
8161 SET_CF();
8162 return;
8163 }
8164
8165 SET_AH(0x06); // change line not supported
8166 set_diskette_ret_status(0x06);
8167 SET_CF();
8168 return;
8169
8170 case 0x17: // set diskette type for format(old)
8171BX_DEBUG_INT13_FL("floppy f17\n");
8172 /* not used for 1.44M floppies */
8173 SET_AH(0x01); // not supported
8174 set_diskette_ret_status(1); /* not supported */
8175 SET_CF();
8176 return;
8177
8178 case 0x18: // set diskette type for format(new)
8179BX_DEBUG_INT13_FL("floppy f18\n");
8180 SET_AH(0x01); // do later
8181 set_diskette_ret_status(1);
8182 SET_CF();
8183 return;
8184
8185 default:
8186 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8187
8188 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8189 SET_AH(0x01); // ???
8190 set_diskette_ret_status(1);
8191 SET_CF();
8192 return;
8193 // }
8194 }
8195}
8196#else // #if BX_SUPPORT_FLOPPY
8197 void
8198int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8199 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8200{
8201 Bit8u val8;
8202
8203 switch ( GET_AH() ) {
8204
8205 case 0x01: // Read Diskette Status
8206 CLEAR_CF();
8207 val8 = read_byte(0x0000, 0x0441);
8208 SET_AH(val8);
8209 if (val8) {
8210 SET_CF();
8211 }
8212 return;
8213
8214 default:
8215 SET_CF();
8216 write_byte(0x0000, 0x0441, 0x01);
8217 SET_AH(0x01);
8218 }
8219}
8220#endif // #if BX_SUPPORT_FLOPPY
8221
8222 void
8223set_diskette_ret_status(value)
8224 Bit8u value;
8225{
8226 write_byte(0x0040, 0x0041, value);
8227}
8228
8229 void
8230set_diskette_current_cyl(drive, cyl)
8231 Bit8u drive;
8232 Bit8u cyl;
8233{
8234 if (drive > 1)
8235 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8236 write_byte(0x0040, 0x0094+drive, cyl);
8237}
8238
8239 void
8240determine_floppy_media(drive)
8241 Bit16u drive;
8242{
8243#if 0
8244 Bit8u val8, DOR, ctrl_info;
8245
8246 ctrl_info = read_byte(0x0040, 0x008F);
8247 if (drive==1)
8248 ctrl_info >>= 4;
8249 else
8250 ctrl_info &= 0x0f;
8251
8252#if 0
8253 if (drive == 0) {
8254 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8255 }
8256 else {
8257 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8258 }
8259#endif
8260
8261 if ( (ctrl_info & 0x04) != 0x04 ) {
8262 // Drive not determined means no drive exists, done.
8263 return;
8264 }
8265
8266#if 0
8267 // check Main Status Register for readiness
8268 val8 = inb(0x03f4) & 0x80; // Main Status Register
8269 if (val8 != 0x80)
8270 BX_PANIC("d_f_m: MRQ bit not set\n");
8271
8272 // change line
8273
8274 // existing BDA values
8275
8276 // turn on drive motor
8277 outb(0x03f2, DOR); // Digital Output Register
8278 //
8279#endif
8280 BX_PANIC("d_f_m: OK so far\n");
8281#endif
8282}
8283
8284 void
8285int17_function(regs, ds, iret_addr)
8286 pusha_regs_t regs; // regs pushed from PUSHA instruction
8287 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8288 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8289{
8290 Bit16u addr,timeout;
8291 Bit8u val8;
8292
8293 ASM_START
8294 sti
8295 ASM_END
8296
8297 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8298 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8299 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8300 if (regs.u.r8.ah == 0) {
8301 outb(addr, regs.u.r8.al);
8302 val8 = inb(addr+2);
8303 outb(addr+2, val8 | 0x01); // send strobe
8304 ASM_START
8305 nop
8306 ASM_END
8307 outb(addr+2, val8 & ~0x01);
8308 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8309 timeout--;
8310 }
8311 }
8312 if (regs.u.r8.ah == 1) {
8313 val8 = inb(addr+2);
8314 outb(addr+2, val8 & ~0x04); // send init
8315 ASM_START
8316 nop
8317 ASM_END
8318 outb(addr+2, val8 | 0x04);
8319 }
8320 val8 = inb(addr+1);
8321 regs.u.r8.ah = (val8 ^ 0x48);
8322 if (!timeout) regs.u.r8.ah |= 0x01;
8323 ClearCF(iret_addr.flags);
8324 } else {
8325 SetCF(iret_addr.flags); // Unsupported
8326 }
8327}
8328
8329// returns bootsegment in ax, drive in bl
8330 Bit32u
8331int19_function(bseqnr)
8332Bit8u bseqnr;
8333{
8334 Bit16u ebda_seg=read_word(0x0040,0x000E);
8335 Bit16u bootseq;
8336 Bit8u bootdrv;
8337 Bit8u bootcd;
8338#ifdef VBOX
8339 Bit8u bootlan;
8340#endif /* VBOX */
8341 Bit8u bootchk;
8342 Bit16u bootseg;
8343 Bit16u status;
8344 Bit8u lastdrive=0;
8345
8346 // if BX_ELTORITO_BOOT is not defined, old behavior
8347 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8348 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8349 // 0: system boot sequence, first drive C: then A:
8350 // 1: system boot sequence, first drive A: then C:
8351 // else BX_ELTORITO_BOOT is defined
8352 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8353 // CMOS reg 0x3D & 0x0f : 1st boot device
8354 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8355 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8356#ifdef VBOX
8357 // CMOS reg 0x3C & 0x0f : 4th boot device
8358#endif /* VBOX */
8359 // boot device codes:
8360 // 0x00 : not defined
8361 // 0x01 : first floppy
8362 // 0x02 : first harddrive
8363 // 0x03 : first cdrom
8364#ifdef VBOX
8365 // 0x04 : local area network
8366#endif /* VBOX */
8367 // else : boot failure
8368
8369 // Get the boot sequence
8370#if BX_ELTORITO_BOOT
8371 bootseq=inb_cmos(0x3d);
8372 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8373#ifdef VBOX
8374 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8375 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8376 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8377 /* Boot delay hack. */
8378 if (bseqnr == 1)
8379 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8380#endif /* VBOX */
8381
8382 if (bseqnr==2) bootseq >>= 4;
8383 if (bseqnr==3) bootseq >>= 8;
8384#ifdef VBOX
8385 if (bseqnr==4) bootseq >>= 12;
8386#endif /* VBOX */
8387 if (bootseq<0x10) lastdrive = 1;
8388 bootdrv=0x00; bootcd=0;
8389#ifdef VBOX
8390 bootlan=0;
8391#endif /* VBOX */
8392
8393 switch(bootseq & 0x0f) {
8394 case 0x01:
8395 bootdrv=0x00;
8396 bootcd=0;
8397 break;
8398 case 0x02:
8399 {
8400 // Get the Boot drive.
8401 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8402
8403 bootdrv = boot_drive + 0x80;
8404 bootcd=0;
8405 break;
8406 }
8407 case 0x03:
8408 bootdrv=0x00;
8409 bootcd=1;
8410 break;
8411#ifdef VBOX
8412 case 0x04: bootlan=1; break;
8413#endif /* VBOX */
8414 default: return 0x00000000;
8415 }
8416#else
8417 bootseq=inb_cmos(0x2d);
8418
8419 if (bseqnr==2) {
8420 bootseq ^= 0x20;
8421 lastdrive = 1;
8422 }
8423 bootdrv=0x00; bootcd=0;
8424 if((bootseq&0x20)==0) bootdrv=0x80;
8425#endif // BX_ELTORITO_BOOT
8426
8427#if BX_ELTORITO_BOOT
8428 // We have to boot from cd
8429 if (bootcd != 0) {
8430 status = cdrom_boot();
8431
8432 // If failure
8433 if ( (status & 0x00ff) !=0 ) {
8434 print_cdromboot_failure(status);
8435#ifdef VBOX
8436 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8437#else /* !VBOX */
8438 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8439#endif /* !VBOX */
8440 return 0x00000000;
8441 }
8442
8443 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8444 bootdrv = (Bit8u)(status>>8);
8445 }
8446
8447#endif // BX_ELTORITO_BOOT
8448
8449#ifdef VBOX
8450 // Check for boot from LAN first
8451 if (bootlan == 1) {
8452 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8453 Bit16u pnpoff;
8454 Bit32u manuf;
8455 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8456 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8457 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8458 // Found PnP signature
8459 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8460 if (manuf == 0x65687445) {
8461 // Found Etherboot ROM
8462 print_boot_device(bootcd, bootlan, bootdrv);
8463ASM_START
8464 push ds
8465 push es
8466 pusha
8467 calli 0x0006,VBOX_LANBOOT_SEG
8468 popa
8469 pop es
8470 pop ds
8471ASM_END
8472 } else if (manuf == 0x65746E49) {
8473 // Found Intel PXE ROM
8474 print_boot_device(bootcd, bootlan, bootdrv);
8475ASM_START
8476 push ds
8477 push es
8478 pusha
8479 sti ; Why are interrupts disabled now? Because we were called through an INT!
8480 push #VBOX_LANBOOT_SEG
8481 pop ds
8482 mov bx,#0x1a ; PnP header offset
8483 mov bx,[bx]
8484 add bx,#0x1a ; BEV offset in PnP header
8485 mov ax,[bx]
8486 test ax,ax
8487 jz no_rom
8488bev_jump:
8489 push cs
8490 push #no_rom
8491 push #VBOX_LANBOOT_SEG
8492 push ax
8493 retf ; call Boot Entry Vector
8494no_rom:
8495 popa
8496 pop es
8497 pop ds
8498ASM_END
8499 }
8500 }
8501 }
8502
8503 // boot from LAN will not return if successful.
8504 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8505 return 0x00000000;
8506 }
8507#endif /* VBOX */
8508 // We have to boot from harddisk or floppy
8509#ifdef VBOX
8510 if (bootcd == 0 && bootlan == 0) {
8511#else /* !VBOX */
8512 if (bootcd == 0) {
8513#endif /* !VBOX */
8514 bootseg=0x07c0;
8515
8516ASM_START
8517 push bp
8518 mov bp, sp
8519
8520 xor ax, ax
8521 mov _int19_function.status + 2[bp], ax
8522 mov dl, _int19_function.bootdrv + 2[bp]
8523 mov ax, _int19_function.bootseg + 2[bp]
8524 mov es, ax ;; segment
8525 xor bx, bx ;; offset
8526 mov ah, #0x02 ;; function 2, read diskette sector
8527 mov al, #0x01 ;; read 1 sector
8528 mov ch, #0x00 ;; track 0
8529 mov cl, #0x01 ;; sector 1
8530 mov dh, #0x00 ;; head 0
8531 int #0x13 ;; read sector
8532 jnc int19_load_done
8533 mov ax, #0x0001
8534 mov _int19_function.status + 2[bp], ax
8535
8536int19_load_done:
8537 pop bp
8538ASM_END
8539
8540 if (status != 0) {
8541#ifdef VBOX
8542 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8543#else /* !VBOX */
8544 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8545#endif /* !VBOX */
8546 return 0x00000000;
8547 }
8548 }
8549
8550#ifdef VBOX
8551 // Don't check boot sectors on floppies and don't read CMOS - byte
8552 // 0x38 in CMOS always has the low bit clear.
8553 // There is *no* requirement whatsoever for a valid boot sector to
8554 // have a 55AAh signature. UNIX boot floppies typically have no such
8555 // signature. In general, it is impossible to tell a valid bootsector
8556 // from an invalid one.
8557 // NB: It is somewhat common for failed OS installs to have the
8558 // 0x55AA signature and a valid partition table but zeros in the
8559 // rest of the boot sector. We do a quick check by comparing the first
8560 // two words of boot sector; if identical, the boot sector is
8561 // extremely unlikely to be valid.
8562#endif
8563 // check signature if instructed by cmos reg 0x38, only for floppy
8564 // bootchk = 1 : signature check disabled
8565 // bootchk = 0 : signature check enabled
8566 if (bootdrv != 0) bootchk = 0;
8567#ifdef VBOX
8568 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8569#else
8570 else bootchk = inb_cmos(0x38) & 0x01;
8571#endif
8572
8573#if BX_ELTORITO_BOOT
8574 // if boot from cd, no signature check
8575 if (bootcd != 0)
8576 bootchk = 1;
8577#endif // BX_ELTORITO_BOOT
8578
8579 if (bootchk == 0) {
8580 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8581 read_word(bootseg,0) == read_word(bootseg,2)) {
8582#ifdef VBOX
8583 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8584#else /* !VBOX */
8585 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8586#endif /* VBOX */
8587 return 0x00000000;
8588 }
8589 }
8590
8591#if BX_ELTORITO_BOOT
8592 // Print out the boot string
8593#ifdef VBOX
8594 print_boot_device(bootcd, bootlan, bootdrv);
8595#else /* !VBOX */
8596 print_boot_device(bootcd, bootdrv);
8597#endif /* !VBOX */
8598#else // BX_ELTORITO_BOOT
8599#ifdef VBOX
8600 print_boot_device(0, bootlan, bootdrv);
8601#else /* !VBOX */
8602 print_boot_device(0, bootdrv);
8603#endif /* !VBOX */
8604#endif // BX_ELTORITO_BOOT
8605
8606 // return the boot segment
8607 return (((Bit32u)bootdrv) << 16) + bootseg;
8608}
8609
8610 void
8611int1a_function(regs, ds, iret_addr)
8612 pusha_regs_t regs; // regs pushed from PUSHA instruction
8613 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8614 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8615{
8616 Bit8u val8;
8617
8618 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);
8619
8620 ASM_START
8621 sti
8622 ASM_END
8623
8624 switch (regs.u.r8.ah) {
8625 case 0: // get current clock count
8626 ASM_START
8627 cli
8628 ASM_END
8629 regs.u.r16.cx = BiosData->ticks_high;
8630 regs.u.r16.dx = BiosData->ticks_low;
8631 regs.u.r8.al = BiosData->midnight_flag;
8632 BiosData->midnight_flag = 0; // reset flag
8633 ASM_START
8634 sti
8635 ASM_END
8636 // AH already 0
8637 ClearCF(iret_addr.flags); // OK
8638 break;
8639
8640 case 1: // Set Current Clock Count
8641 ASM_START
8642 cli
8643 ASM_END
8644 BiosData->ticks_high = regs.u.r16.cx;
8645 BiosData->ticks_low = regs.u.r16.dx;
8646 BiosData->midnight_flag = 0; // reset flag
8647 ASM_START
8648 sti
8649 ASM_END
8650 regs.u.r8.ah = 0;
8651 ClearCF(iret_addr.flags); // OK
8652 break;
8653
8654
8655 case 2: // Read CMOS Time
8656 if (rtc_updating()) {
8657 SetCF(iret_addr.flags);
8658 break;
8659 }
8660
8661 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8662 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8663 regs.u.r8.ch = inb_cmos(0x04); // Hours
8664 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8665 regs.u.r8.ah = 0;
8666 regs.u.r8.al = regs.u.r8.ch;
8667 ClearCF(iret_addr.flags); // OK
8668 break;
8669
8670 case 3: // Set CMOS Time
8671 // Using a debugger, I notice the following masking/setting
8672 // of bits in Status Register B, by setting Reg B to
8673 // a few values and getting its value after INT 1A was called.
8674 //
8675 // try#1 try#2 try#3
8676 // before 1111 1101 0111 1101 0000 0000
8677 // after 0110 0010 0110 0010 0000 0010
8678 //
8679 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8680 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8681 if (rtc_updating()) {
8682 init_rtc();
8683 // fall through as if an update were not in progress
8684 }
8685 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8686 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8687 outb_cmos(0x04, regs.u.r8.ch); // Hours
8688 // Set Daylight Savings time enabled bit to requested value
8689 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8690 // (reg B already selected)
8691 outb_cmos(0x0b, val8);
8692 regs.u.r8.ah = 0;
8693 regs.u.r8.al = val8; // val last written to Reg B
8694 ClearCF(iret_addr.flags); // OK
8695 break;
8696
8697 case 4: // Read CMOS Date
8698 regs.u.r8.ah = 0;
8699 if (rtc_updating()) {
8700 SetCF(iret_addr.flags);
8701 break;
8702 }
8703 regs.u.r8.cl = inb_cmos(0x09); // Year
8704 regs.u.r8.dh = inb_cmos(0x08); // Month
8705 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8706 regs.u.r8.ch = inb_cmos(0x32); // Century
8707 regs.u.r8.al = regs.u.r8.ch;
8708 ClearCF(iret_addr.flags); // OK
8709 break;
8710
8711 case 5: // Set CMOS Date
8712 // Using a debugger, I notice the following masking/setting
8713 // of bits in Status Register B, by setting Reg B to
8714 // a few values and getting its value after INT 1A was called.
8715 //
8716 // try#1 try#2 try#3 try#4
8717 // before 1111 1101 0111 1101 0000 0010 0000 0000
8718 // after 0110 1101 0111 1101 0000 0010 0000 0000
8719 //
8720 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8721 // My assumption: RegB = (RegB & 01111111b)
8722 if (rtc_updating()) {
8723 init_rtc();
8724 SetCF(iret_addr.flags);
8725 break;
8726 }
8727 outb_cmos(0x09, regs.u.r8.cl); // Year
8728 outb_cmos(0x08, regs.u.r8.dh); // Month
8729 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8730 outb_cmos(0x32, regs.u.r8.ch); // Century
8731 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8732 outb_cmos(0x0b, val8);
8733 regs.u.r8.ah = 0;
8734 regs.u.r8.al = val8; // AL = val last written to Reg B
8735 ClearCF(iret_addr.flags); // OK
8736 break;
8737
8738 case 6: // Set Alarm Time in CMOS
8739 // Using a debugger, I notice the following masking/setting
8740 // of bits in Status Register B, by setting Reg B to
8741 // a few values and getting its value after INT 1A was called.
8742 //
8743 // try#1 try#2 try#3
8744 // before 1101 1111 0101 1111 0000 0000
8745 // after 0110 1111 0111 1111 0010 0000
8746 //
8747 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8748 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8749 val8 = inb_cmos(0x0b); // Get Status Reg B
8750 regs.u.r16.ax = 0;
8751 if (val8 & 0x20) {
8752 // Alarm interrupt enabled already
8753 SetCF(iret_addr.flags); // Error: alarm in use
8754 break;
8755 }
8756 if (rtc_updating()) {
8757 init_rtc();
8758 // fall through as if an update were not in progress
8759 }
8760 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8761 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8762 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8763 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8764 // enable Status Reg B alarm bit, clear halt clock bit
8765 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8766 ClearCF(iret_addr.flags); // OK
8767 break;
8768
8769 case 7: // Turn off Alarm
8770 // Using a debugger, I notice the following masking/setting
8771 // of bits in Status Register B, by setting Reg B to
8772 // a few values and getting its value after INT 1A was called.
8773 //
8774 // try#1 try#2 try#3 try#4
8775 // before 1111 1101 0111 1101 0010 0000 0010 0010
8776 // after 0100 0101 0101 0101 0000 0000 0000 0010
8777 //
8778 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8779 // My assumption: RegB = (RegB & 01010111b)
8780 val8 = inb_cmos(0x0b); // Get Status Reg B
8781 // clear clock-halt bit, disable alarm bit
8782 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8783 regs.u.r8.ah = 0;
8784 regs.u.r8.al = val8; // val last written to Reg B
8785 ClearCF(iret_addr.flags); // OK
8786 break;
8787#if BX_PCIBIOS
8788 case 0xb1:
8789 // real mode PCI BIOS functions now handled in assembler code
8790 // this C code handles the error code for information only
8791 if (regs.u.r8.bl == 0xff) {
8792 BX_INFO("PCI BIOS: PCI not present\n");
8793 } else if (regs.u.r8.bl == 0x81) {
8794 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8795 } else if (regs.u.r8.bl == 0x83) {
8796 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8797 } else if (regs.u.r8.bl == 0x86) {
8798 if (regs.u.r8.al == 0x02) {
8799 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8800 } else {
8801 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);
8802 }
8803 }
8804 regs.u.r8.ah = regs.u.r8.bl;
8805 SetCF(iret_addr.flags);
8806 break;
8807#endif
8808
8809 default:
8810 SetCF(iret_addr.flags); // Unsupported
8811 }
8812}
8813
8814 void
8815int70_function(regs, ds, iret_addr)
8816 pusha_regs_t regs; // regs pushed from PUSHA instruction
8817 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8818 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8819{
8820 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8821 Bit8u registerB = 0, registerC = 0;
8822
8823 // Check which modes are enabled and have occurred.
8824 registerB = inb_cmos( 0xB );
8825 registerC = inb_cmos( 0xC );
8826
8827 if( ( registerB & 0x60 ) != 0 ) {
8828 if( ( registerC & 0x20 ) != 0 ) {
8829 // Handle Alarm Interrupt.
8830ASM_START
8831 sti
8832 int #0x4a
8833 cli
8834ASM_END
8835 }
8836 if( ( registerC & 0x40 ) != 0 ) {
8837 // Handle Periodic Interrupt.
8838
8839 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8840 // Wait Interval (Int 15, AH=83) active.
8841 Bit32u time, toggle;
8842
8843 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8844 if( time < 0x3D1 ) {
8845 // Done waiting.
8846 Bit16u segment, offset;
8847
8848 segment = read_word( 0x40, 0x98 );
8849 offset = read_word( 0x40, 0x9A );
8850 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8851 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8852 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8853 } else {
8854 // Continue waiting.
8855 time -= 0x3D1;
8856 write_dword( 0x40, 0x9C, time );
8857 }
8858 }
8859 }
8860 }
8861
8862ASM_START
8863 call eoi_both_pics
8864ASM_END
8865}
8866
8867 void
8868dummy_isr_function(regs, ds, iret_addr)
8869 pusha_regs_t regs; // regs pushed from PUSHA instruction
8870 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8871 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8872{
8873 // Interrupt handler for unexpected hardware interrupts. We have to clear
8874 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8875 // and all hell will break loose! This routine also masks the unexpected
8876 // interrupt so it will generally be called only once for each unexpected
8877 // interrupt level.
8878 Bit8u isrA, isrB, imr, last_int = 0xFF;
8879
8880 outb( 0x20, 0x0B );
8881 isrA = inb( 0x20 );
8882 if (isrA) {
8883 outb( 0xA0, 0x0B );
8884 isrB = inb( 0xA0 );
8885 if (isrB) {
8886 imr = inb( 0xA1 );
8887 outb( 0xA1, imr | isrB ); // Mask this interrupt
8888 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8889 } else {
8890 imr = inb( 0x21 );
8891 isrA &= 0xFB; // Never mask the cascade interrupt
8892 outb( 0x21, imr | isrA); // Mask this interrupt
8893 }
8894 outb( 0x20, 0x20 ); // Send EOI on master PIC
8895 last_int = isrA;
8896 }
8897 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8898}
8899
8900ASM_START
8901;------------------------------------------
8902;- INT74h : PS/2 mouse hardware interrupt -
8903;------------------------------------------
8904int74_handler:
8905 sti
8906 pusha
8907 push ds ;; save DS
8908 push #0x00 ;; placeholder for status
8909 push #0x00 ;; placeholder for X
8910 push #0x00 ;; placeholder for Y
8911 push #0x00 ;; placeholder for Z
8912 push #0x00 ;; placeholder for make_far_call boolean
8913 call _int74_function
8914 pop cx ;; remove make_far_call from stack
8915 jcxz int74_done
8916
8917 ;; make far call to EBDA:0022
8918 push #0x00
8919 pop ds
8920 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8921 pop ds
8922 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8923 call far ptr[0x22]
8924int74_done:
8925 cli
8926 call eoi_both_pics
8927 add sp, #8 ;; pop status, x, y, z
8928
8929 pop ds ;; restore DS
8930 popa
8931 iret
8932
8933
8934;; This will perform an IRET, but will retain value of current CF
8935;; by altering flags on stack. Better than RETF #02.
8936iret_modify_cf:
8937 jc carry_set
8938 push bp
8939 mov bp, sp
8940 and BYTE [bp + 0x06], #0xfe
8941 pop bp
8942 iret
8943carry_set:
8944 push bp
8945 mov bp, sp
8946 or BYTE [bp + 0x06], #0x01
8947 pop bp
8948 iret
8949
8950
8951;----------------------
8952;- INT13h (relocated) -
8953;----------------------
8954;
8955; int13_relocated is a little bit messed up since I played with it
8956; I have to rewrite it:
8957; - call a function that detect which function to call
8958; - make all called C function get the same parameters list
8959;
8960int13_relocated:
8961
8962#if BX_ELTORITO_BOOT
8963 ;; check for an eltorito function
8964 cmp ah,#0x4a
8965 jb int13_not_eltorito
8966 cmp ah,#0x4d
8967 ja int13_not_eltorito
8968
8969 pusha
8970 push es
8971 push ds
8972 push ss
8973 pop ds
8974
8975 push #int13_out
8976 jmp _int13_eltorito ;; ELDX not used
8977
8978int13_not_eltorito:
8979 push ax
8980 push bx
8981 push cx
8982 push dx
8983
8984 ;; check if emulation active
8985 call _cdemu_isactive
8986 cmp al,#0x00
8987 je int13_cdemu_inactive
8988
8989 ;; check if access to the emulated drive
8990 call _cdemu_emulated_drive
8991 pop dx
8992 push dx
8993 cmp al,dl ;; int13 on emulated drive
8994 jne int13_nocdemu
8995
8996 pop dx
8997 pop cx
8998 pop bx
8999 pop ax
9000
9001 pusha
9002 push es
9003 push ds
9004 push ss
9005 pop ds
9006
9007 push #int13_out
9008 jmp _int13_cdemu ;; ELDX not used
9009
9010int13_nocdemu:
9011 and dl,#0xE0 ;; mask to get device class, including cdroms
9012 cmp al,dl ;; al is 0x00 or 0x80
9013 jne int13_cdemu_inactive ;; inactive for device class
9014
9015 pop dx
9016 pop cx
9017 pop bx
9018 pop ax
9019
9020 push ax
9021 push cx
9022 push dx
9023 push bx
9024
9025 dec dl ;; real drive is dl - 1
9026 jmp int13_legacy
9027
9028int13_cdemu_inactive:
9029 pop dx
9030 pop cx
9031 pop bx
9032 pop ax
9033
9034#endif // BX_ELTORITO_BOOT
9035
9036int13_noeltorito:
9037
9038 push ax
9039 push cx
9040 push dx
9041 push bx
9042
9043int13_legacy:
9044
9045 push dx ;; push eltorito value of dx instead of sp
9046
9047 push bp
9048 push si
9049 push di
9050
9051 push es
9052 push ds
9053 push ss
9054 pop ds
9055
9056 ;; now the 16-bit registers can be restored with:
9057 ;; pop ds; pop es; popa; iret
9058 ;; arguments passed to functions should be
9059 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9060
9061 test dl, #0x80
9062 jnz int13_notfloppy
9063
9064 push #int13_out
9065 jmp _int13_diskette_function
9066
9067int13_notfloppy:
9068
9069#if BX_USE_ATADRV
9070
9071 cmp dl, #0xE0
9072 jb int13_notcdrom
9073
9074 // ebx is modified: BSD 5.2.1 boot loader problem
9075 // someone should figure out which 32 bit register that actually are used
9076
9077 shr ebx, #16
9078 push bx
9079
9080 call _int13_cdrom
9081
9082 pop bx
9083 shl ebx, #16
9084
9085 jmp int13_out
9086
9087int13_notcdrom:
9088
9089#endif
9090
9091int13_disk:
9092 ;; int13_harddisk modifies high word of EAX
9093 shr eax, #16
9094 push ax
9095 call _int13_harddisk
9096 pop ax
9097 shl eax, #16
9098
9099int13_out:
9100 pop ds
9101 pop es
9102 popa
9103 iret
9104
9105;----------
9106;- INT18h -
9107;----------
9108int18_handler: ;; Boot Failure routing
9109 call _int18_panic_msg
9110 hlt
9111 iret
9112
9113;----------
9114;- INT19h -
9115;----------
9116int19_relocated: ;; Boot function, relocated
9117
9118#ifdef VBOX
9119 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9120 // just to try booting from the configured drives. All BIOS variables and
9121 // interrupt vectors need to be reset, otherwise strange things may happen.
9122 // The approach used is faking a warm reboot (which just skips showing the
9123 // logo), which is a bit more than what we need, but hey, it's fast.
9124 mov bp, sp
9125 mov ax, 2[bp]
9126 cmp ax, #0xf000
9127 jz bios_initiated_boot
9128 xor ax, ax
9129 mov ds, ax
9130 mov ax, #0x1234
9131 mov 0x472, ax
9132 jmp post
9133bios_initiated_boot:
9134#endif /* VBOX */
9135
9136 ;; int19 was beginning to be really complex, so now it
9137 ;; just calls a C function that does the work
9138 ;; it returns in BL the boot drive, and in AX the boot segment
9139 ;; the boot segment will be 0x0000 if something has failed
9140
9141 push bp
9142 mov bp, sp
9143
9144 ;; drop ds
9145 xor ax, ax
9146 mov ds, ax
9147
9148 ;; 1st boot device
9149 mov ax, #0x0001
9150 push ax
9151 call _int19_function
9152 inc sp
9153 inc sp
9154 ;; bl contains the boot drive
9155 ;; ax contains the boot segment or 0 if failure
9156
9157 test ax, ax ;; if ax is 0 try next boot device
9158 jnz boot_setup
9159
9160 ;; 2nd boot device
9161 mov ax, #0x0002
9162 push ax
9163 call _int19_function
9164 inc sp
9165 inc sp
9166 test ax, ax ;; if ax is 0 try next boot device
9167 jnz boot_setup
9168
9169 ;; 3rd boot device
9170 mov ax, #0x0003
9171 push ax
9172 call _int19_function
9173 inc sp
9174 inc sp
9175#ifdef VBOX
9176 test ax, ax ;; if ax is 0 try next boot device
9177 jnz boot_setup
9178
9179 ;; 4th boot device
9180 mov ax, #0x0004
9181 push ax
9182 call _int19_function
9183 inc sp
9184 inc sp
9185#endif /* VBOX */
9186 test ax, ax ;; if ax is 0 call int18
9187 jz int18_handler
9188
9189boot_setup:
9190 mov dl, bl ;; set drive so guest os find it
9191 shl eax, #0x04 ;; convert seg to ip
9192 mov 2[bp], ax ;; set ip
9193
9194 shr eax, #0x04 ;; get cs back
9195 and ax, #0xF000 ;; remove what went in ip
9196 mov 4[bp], ax ;; set cs
9197 xor ax, ax
9198 mov es, ax ;; set es to zero fixes [ 549815 ]
9199 mov [bp], ax ;; set bp to zero
9200 mov ax, #0xaa55 ;; set ok flag
9201
9202 pop bp
9203 iret ;; Beam me up Scotty
9204
9205;----------
9206;- INT1Ch -
9207;----------
9208int1c_handler: ;; User Timer Tick
9209 iret
9210
9211
9212;----------------------
9213;- POST: Floppy Drive -
9214;----------------------
9215floppy_drive_post:
9216 xor ax, ax
9217 mov ds, ax
9218
9219 mov al, #0x00
9220 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9221
9222 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9223
9224 mov 0x0440, al ;; diskette motor timeout counter: not active
9225 mov 0x0441, al ;; diskette controller status return code
9226
9227 mov 0x0442, al ;; disk & diskette controller status register 0
9228 mov 0x0443, al ;; diskette controller status register 1
9229 mov 0x0444, al ;; diskette controller status register 2
9230 mov 0x0445, al ;; diskette controller cylinder number
9231 mov 0x0446, al ;; diskette controller head number
9232 mov 0x0447, al ;; diskette controller sector number
9233 mov 0x0448, al ;; diskette controller bytes written
9234
9235 mov 0x048b, al ;; diskette configuration data
9236
9237 ;; -----------------------------------------------------------------
9238 ;; (048F) diskette controller information
9239 ;;
9240 mov al, #0x10 ;; get CMOS diskette drive type
9241 out 0x70, AL
9242 in AL, 0x71
9243 mov ah, al ;; save byte to AH
9244
9245look_drive0:
9246 shr al, #4 ;; look at top 4 bits for drive 0
9247 jz f0_missing ;; jump if no drive0
9248 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9249 jmp look_drive1
9250f0_missing:
9251 mov bl, #0x00 ;; no drive0
9252
9253look_drive1:
9254 mov al, ah ;; restore from AH
9255 and al, #0x0f ;; look at bottom 4 bits for drive 1
9256 jz f1_missing ;; jump if no drive1
9257 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9258f1_missing:
9259 ;; leave high bits in BL zerod
9260 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9261 ;; -----------------------------------------------------------------
9262
9263 mov al, #0x00
9264 mov 0x0490, al ;; diskette 0 media state
9265 mov 0x0491, al ;; diskette 1 media state
9266
9267 ;; diskette 0,1 operational starting state
9268 ;; drive type has not been determined,
9269 ;; has no changed detection line
9270 mov 0x0492, al
9271 mov 0x0493, al
9272
9273 mov 0x0494, al ;; diskette 0 current cylinder
9274 mov 0x0495, al ;; diskette 1 current cylinder
9275
9276 mov al, #0x02
9277 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9278
9279 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9280 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9281 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9282
9283 ret
9284
9285
9286;--------------------
9287;- POST: HARD DRIVE -
9288;--------------------
9289; relocated here because the primary POST area isnt big enough.
9290hard_drive_post:
9291 // IRQ 14 = INT 76h
9292 // INT 76h calls INT 15h function ax=9100
9293
9294 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9295 mov dx, #0x03f6
9296 out dx, al
9297
9298 xor ax, ax
9299 mov ds, ax
9300 mov 0x0474, al /* hard disk status of last operation */
9301 mov 0x0477, al /* hard disk port offset (XT only ???) */
9302 mov 0x048c, al /* hard disk status register */
9303 mov 0x048d, al /* hard disk error register */
9304 mov 0x048e, al /* hard disk task complete flag */
9305 mov al, #0x01
9306 mov 0x0475, al /* hard disk number attached */
9307 mov al, #0xc0
9308 mov 0x0476, al /* hard disk control byte */
9309 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9310 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9311 ;; INT 41h: hard disk 0 configuration pointer
9312 ;; INT 46h: hard disk 1 configuration pointer
9313 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9314 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9315
9316#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9317 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9318 mov al, #0x12
9319 out #0x70, al
9320 in al, #0x71
9321 and al, #0xf0
9322 cmp al, #0xf0
9323 je post_d0_extended
9324 jmp check_for_hd1
9325post_d0_extended:
9326 mov al, #0x19
9327 out #0x70, al
9328 in al, #0x71
9329 cmp al, #47 ;; decimal 47 - user definable
9330 je post_d0_type47
9331 HALT(__LINE__)
9332post_d0_type47:
9333 ;; CMOS purpose param table offset
9334 ;; 1b cylinders low 0
9335 ;; 1c cylinders high 1
9336 ;; 1d heads 2
9337 ;; 1e write pre-comp low 5
9338 ;; 1f write pre-comp high 6
9339 ;; 20 retries/bad map/heads>8 8
9340 ;; 21 landing zone low C
9341 ;; 22 landing zone high D
9342 ;; 23 sectors/track E
9343
9344 mov ax, #EBDA_SEG
9345 mov ds, ax
9346
9347 ;;; Filling EBDA table for hard disk 0.
9348 mov al, #0x1f
9349 out #0x70, al
9350 in al, #0x71
9351 mov ah, al
9352 mov al, #0x1e
9353 out #0x70, al
9354 in al, #0x71
9355 mov (0x003d + 0x05), ax ;; write precomp word
9356
9357 mov al, #0x20
9358 out #0x70, al
9359 in al, #0x71
9360 mov (0x003d + 0x08), al ;; drive control byte
9361
9362 mov al, #0x22
9363 out #0x70, al
9364 in al, #0x71
9365 mov ah, al
9366 mov al, #0x21
9367 out #0x70, al
9368 in al, #0x71
9369 mov (0x003d + 0x0C), ax ;; landing zone word
9370
9371 mov al, #0x1c ;; get cylinders word in AX
9372 out #0x70, al
9373 in al, #0x71 ;; high byte
9374 mov ah, al
9375 mov al, #0x1b
9376 out #0x70, al
9377 in al, #0x71 ;; low byte
9378 mov bx, ax ;; BX = cylinders
9379
9380 mov al, #0x1d
9381 out #0x70, al
9382 in al, #0x71
9383 mov cl, al ;; CL = heads
9384
9385 mov al, #0x23
9386 out #0x70, al
9387 in al, #0x71
9388 mov dl, al ;; DL = sectors
9389
9390 cmp bx, #1024
9391 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9392
9393hd0_post_physical_chs:
9394 ;; no logical CHS mapping used, just physical CHS
9395 ;; use Standard Fixed Disk Parameter Table (FDPT)
9396 mov (0x003d + 0x00), bx ;; number of physical cylinders
9397 mov (0x003d + 0x02), cl ;; number of physical heads
9398 mov (0x003d + 0x0E), dl ;; number of physical sectors
9399 jmp check_for_hd1
9400
9401hd0_post_logical_chs:
9402 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9403 mov (0x003d + 0x09), bx ;; number of physical cylinders
9404 mov (0x003d + 0x0b), cl ;; number of physical heads
9405 mov (0x003d + 0x04), dl ;; number of physical sectors
9406 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9407 mov al, #0xa0
9408 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9409
9410 cmp bx, #2048
9411 jnbe hd0_post_above_2048
9412 ;; 1024 < c <= 2048 cylinders
9413 shr bx, #0x01
9414 shl cl, #0x01
9415 jmp hd0_post_store_logical
9416
9417hd0_post_above_2048:
9418 cmp bx, #4096
9419 jnbe hd0_post_above_4096
9420 ;; 2048 < c <= 4096 cylinders
9421 shr bx, #0x02
9422 shl cl, #0x02
9423 jmp hd0_post_store_logical
9424
9425hd0_post_above_4096:
9426 cmp bx, #8192
9427 jnbe hd0_post_above_8192
9428 ;; 4096 < c <= 8192 cylinders
9429 shr bx, #0x03
9430 shl cl, #0x03
9431 jmp hd0_post_store_logical
9432
9433hd0_post_above_8192:
9434 ;; 8192 < c <= 16384 cylinders
9435 shr bx, #0x04
9436 shl cl, #0x04
9437
9438hd0_post_store_logical:
9439 mov (0x003d + 0x00), bx ;; number of physical cylinders
9440 mov (0x003d + 0x02), cl ;; number of physical heads
9441 ;; checksum
9442 mov cl, #0x0f ;; repeat count
9443 mov si, #0x003d ;; offset to disk0 FDPT
9444 mov al, #0x00 ;; sum
9445hd0_post_checksum_loop:
9446 add al, [si]
9447 inc si
9448 dec cl
9449 jnz hd0_post_checksum_loop
9450 not al ;; now take 2s complement
9451 inc al
9452 mov [si], al
9453;;; Done filling EBDA table for hard disk 0.
9454
9455
9456check_for_hd1:
9457 ;; is there really a second hard disk? if not, return now
9458 mov al, #0x12
9459 out #0x70, al
9460 in al, #0x71
9461 and al, #0x0f
9462 jnz post_d1_exists
9463 ret
9464post_d1_exists:
9465 ;; check that the hd type is really 0x0f.
9466 cmp al, #0x0f
9467 jz post_d1_extended
9468 HALT(__LINE__)
9469post_d1_extended:
9470 ;; check that the extended type is 47 - user definable
9471 mov al, #0x1a
9472 out #0x70, al
9473 in al, #0x71
9474 cmp al, #47 ;; decimal 47 - user definable
9475 je post_d1_type47
9476 HALT(__LINE__)
9477post_d1_type47:
9478 ;; Table for disk1.
9479 ;; CMOS purpose param table offset
9480 ;; 0x24 cylinders low 0
9481 ;; 0x25 cylinders high 1
9482 ;; 0x26 heads 2
9483 ;; 0x27 write pre-comp low 5
9484 ;; 0x28 write pre-comp high 6
9485 ;; 0x29 heads>8 8
9486 ;; 0x2a landing zone low C
9487 ;; 0x2b landing zone high D
9488 ;; 0x2c sectors/track E
9489;;; Fill EBDA table for hard disk 1.
9490 mov ax, #EBDA_SEG
9491 mov ds, ax
9492 mov al, #0x28
9493 out #0x70, al
9494 in al, #0x71
9495 mov ah, al
9496 mov al, #0x27
9497 out #0x70, al
9498 in al, #0x71
9499 mov (0x004d + 0x05), ax ;; write precomp word
9500
9501 mov al, #0x29
9502 out #0x70, al
9503 in al, #0x71
9504 mov (0x004d + 0x08), al ;; drive control byte
9505
9506 mov al, #0x2b
9507 out #0x70, al
9508 in al, #0x71
9509 mov ah, al
9510 mov al, #0x2a
9511 out #0x70, al
9512 in al, #0x71
9513 mov (0x004d + 0x0C), ax ;; landing zone word
9514
9515 mov al, #0x25 ;; get cylinders word in AX
9516 out #0x70, al
9517 in al, #0x71 ;; high byte
9518 mov ah, al
9519 mov al, #0x24
9520 out #0x70, al
9521 in al, #0x71 ;; low byte
9522 mov bx, ax ;; BX = cylinders
9523
9524 mov al, #0x26
9525 out #0x70, al
9526 in al, #0x71
9527 mov cl, al ;; CL = heads
9528
9529 mov al, #0x2c
9530 out #0x70, al
9531 in al, #0x71
9532 mov dl, al ;; DL = sectors
9533
9534 cmp bx, #1024
9535 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9536
9537hd1_post_physical_chs:
9538 ;; no logical CHS mapping used, just physical CHS
9539 ;; use Standard Fixed Disk Parameter Table (FDPT)
9540 mov (0x004d + 0x00), bx ;; number of physical cylinders
9541 mov (0x004d + 0x02), cl ;; number of physical heads
9542 mov (0x004d + 0x0E), dl ;; number of physical sectors
9543 ret
9544
9545hd1_post_logical_chs:
9546 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9547 mov (0x004d + 0x09), bx ;; number of physical cylinders
9548 mov (0x004d + 0x0b), cl ;; number of physical heads
9549 mov (0x004d + 0x04), dl ;; number of physical sectors
9550 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9551 mov al, #0xa0
9552 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9553
9554 cmp bx, #2048
9555 jnbe hd1_post_above_2048
9556 ;; 1024 < c <= 2048 cylinders
9557 shr bx, #0x01
9558 shl cl, #0x01
9559 jmp hd1_post_store_logical
9560
9561hd1_post_above_2048:
9562 cmp bx, #4096
9563 jnbe hd1_post_above_4096
9564 ;; 2048 < c <= 4096 cylinders
9565 shr bx, #0x02
9566 shl cl, #0x02
9567 jmp hd1_post_store_logical
9568
9569hd1_post_above_4096:
9570 cmp bx, #8192
9571 jnbe hd1_post_above_8192
9572 ;; 4096 < c <= 8192 cylinders
9573 shr bx, #0x03
9574 shl cl, #0x03
9575 jmp hd1_post_store_logical
9576
9577hd1_post_above_8192:
9578 ;; 8192 < c <= 16384 cylinders
9579 shr bx, #0x04
9580 shl cl, #0x04
9581
9582hd1_post_store_logical:
9583 mov (0x004d + 0x00), bx ;; number of physical cylinders
9584 mov (0x004d + 0x02), cl ;; number of physical heads
9585 ;; checksum
9586 mov cl, #0x0f ;; repeat count
9587 mov si, #0x004d ;; offset to disk0 FDPT
9588 mov al, #0x00 ;; sum
9589hd1_post_checksum_loop:
9590 add al, [si]
9591 inc si
9592 dec cl
9593 jnz hd1_post_checksum_loop
9594 not al ;; now take 2s complement
9595 inc al
9596 mov [si], al
9597;;; Done filling EBDA table for hard disk 1.
9598#endif /* !VBOX */
9599
9600 ret
9601
9602;--------------------
9603;- POST: EBDA segment
9604;--------------------
9605; relocated here because the primary POST area isnt big enough.
9606; the SET_INT_VECTORs have nothing to do with EBDA but do not
9607; fit into the primary POST area either
9608ebda_post:
9609 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9610 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9611 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9612 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9613
9614#if BX_USE_EBDA
9615 mov ax, #EBDA_SEG
9616 mov ds, ax
9617 mov byte ptr [0x0], #EBDA_SIZE
9618#endif
9619 xor ax, ax ; mov EBDA seg into 40E
9620 mov ds, ax
9621 mov word ptr [0x40E], #EBDA_SEG
9622 ret;;
9623
9624;--------------------
9625;- POST: EOI + jmp via [0x40:67)
9626;--------------------
9627; relocated here because the primary POST area isnt big enough.
9628eoi_jmp_post:
9629 call eoi_both_pics
9630
9631 xor ax, ax
9632 mov ds, ax
9633
9634 jmp far ptr [0x467]
9635
9636
9637;--------------------
9638eoi_both_pics:
9639 mov al, #0x20
9640 out #0xA0, al ;; slave PIC EOI
9641eoi_master_pic:
9642 mov al, #0x20
9643 out #0x20, al ;; master PIC EOI
9644 ret
9645
9646;--------------------
9647BcdToBin:
9648 ;; in: AL in BCD format
9649 ;; out: AL in binary format, AH will always be 0
9650 ;; trashes BX
9651 mov bl, al
9652 and bl, #0x0f ;; bl has low digit
9653 shr al, #4 ;; al has high digit
9654 mov bh, #10
9655 mul al, bh ;; multiply high digit by 10 (result in AX)
9656 add al, bl ;; then add low digit
9657 ret
9658
9659;--------------------
9660timer_tick_post:
9661 ;; Setup the Timer Ticks Count (0x46C:dword) and
9662 ;; Timer Ticks Roller Flag (0x470:byte)
9663 ;; The Timer Ticks Count needs to be set according to
9664 ;; the current CMOS time, as if ticks have been occurring
9665 ;; at 18.2hz since midnight up to this point. Calculating
9666 ;; this is a little complicated. Here are the factors I gather
9667 ;; regarding this. 14,318,180 hz was the original clock speed,
9668 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9669 ;; at the time, or 4 to drive the CGA video adapter. The div3
9670 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9671 ;; the timer. With a maximum 16bit timer count, this is again
9672 ;; divided down by 65536 to 18.2hz.
9673 ;;
9674 ;; 14,318,180 Hz clock
9675 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9676 ;; /4 = 1,193,181 Hz fed to timer
9677 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9678 ;; 1 second = 18.20650736 ticks
9679 ;; 1 minute = 1092.390442 ticks
9680 ;; 1 hour = 65543.42651 ticks
9681 ;;
9682 ;; Given the values in the CMOS clock, one could calculate
9683 ;; the number of ticks by the following:
9684 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9685 ;; (BcdToBin(minutes) * 1092.3904)
9686 ;; (BcdToBin(hours) * 65543.427)
9687 ;; To get a little more accuracy, since Im using integer
9688 ;; arithmatic, I use:
9689 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9690 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9691 ;; (BcdToBin(hours) * 65543427) / 1000
9692
9693 ;; assuming DS=0000
9694
9695 ;; get CMOS seconds
9696 xor eax, eax ;; clear EAX
9697 mov al, #0x00
9698 out #0x70, al
9699 in al, #0x71 ;; AL has CMOS seconds in BCD
9700 call BcdToBin ;; EAX now has seconds in binary
9701 mov edx, #18206507
9702 mul eax, edx
9703 mov ebx, #1000000
9704 xor edx, edx
9705 div eax, ebx
9706 mov ecx, eax ;; ECX will accumulate total ticks
9707
9708 ;; get CMOS minutes
9709 xor eax, eax ;; clear EAX
9710 mov al, #0x02
9711 out #0x70, al
9712 in al, #0x71 ;; AL has CMOS minutes in BCD
9713 call BcdToBin ;; EAX now has minutes in binary
9714 mov edx, #10923904
9715 mul eax, edx
9716 mov ebx, #10000
9717 xor edx, edx
9718 div eax, ebx
9719 add ecx, eax ;; add to total ticks
9720
9721 ;; get CMOS hours
9722 xor eax, eax ;; clear EAX
9723 mov al, #0x04
9724 out #0x70, al
9725 in al, #0x71 ;; AL has CMOS hours in BCD
9726 call BcdToBin ;; EAX now has hours in binary
9727 mov edx, #65543427
9728 mul eax, edx
9729 mov ebx, #1000
9730 xor edx, edx
9731 div eax, ebx
9732 add ecx, eax ;; add to total ticks
9733
9734 mov 0x46C, ecx ;; Timer Ticks Count
9735 xor al, al
9736 mov 0x470, al ;; Timer Ticks Rollover Flag
9737 ret
9738
9739;--------------------
9740int76_handler:
9741 ;; record completion in BIOS task complete flag
9742 push ax
9743 push ds
9744 mov ax, #0x0040
9745 mov ds, ax
9746 mov 0x008E, #0xff
9747 call eoi_both_pics
9748 pop ds
9749 pop ax
9750 iret
9751
9752
9753;--------------------
9754#ifdef VBOX
9755init_pic:
9756 ;; init PIC
9757 mov al, #0x11 ; send initialisation commands
9758 out 0x20, al
9759 out 0xa0, al
9760 mov al, #0x08
9761 out 0x21, al
9762 mov al, #0x70
9763 out 0xa1, al
9764 mov al, #0x04
9765 out 0x21, al
9766 mov al, #0x02
9767 out 0xa1, al
9768 mov al, #0x01
9769 out 0x21, al
9770 out 0xa1, al
9771 mov al, #0xb8
9772 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9773#if BX_USE_PS2_MOUSE
9774 mov al, #0x8f
9775#else
9776 mov al, #0x9f
9777#endif
9778 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9779 ret
9780#endif /* VBOX */
9781
9782;--------------------
9783#if BX_APM
9784
9785use32 386
9786#define APM_PROT32
9787#include "apmbios.S"
9788
9789use16 386
9790#define APM_PROT16
9791#include "apmbios.S"
9792
9793#define APM_REAL
9794#include "apmbios.S"
9795
9796#endif
9797
9798;--------------------
9799#if BX_PCIBIOS
9800use32 386
9801.align 16
9802bios32_structure:
9803 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9804 dw bios32_entry_point, 0xf ;; 32 bit physical address
9805 db 0 ;; revision level
9806 ;; length in paragraphs and checksum stored in a word to prevent errors
9807 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9808 & 0xff) << 8) + 0x01
9809 db 0,0,0,0,0 ;; reserved
9810
9811.align 16
9812bios32_entry_point:
9813 pushfd
9814 cmp eax, #0x49435024 ;; "$PCI"
9815 jne unknown_service
9816 mov eax, #0x80000000
9817 mov dx, #0x0cf8
9818 out dx, eax
9819 mov dx, #0x0cfc
9820 in eax, dx
9821#ifdef PCI_FIXED_HOST_BRIDGE
9822 cmp eax, #PCI_FIXED_HOST_BRIDGE
9823 jne unknown_service
9824#else
9825 ;; say ok if a device is present
9826 cmp eax, #0xffffffff
9827 je unknown_service
9828#endif
9829 mov ebx, #0x000f0000
9830 mov ecx, #0
9831 mov edx, #pcibios_protected
9832 xor al, al
9833 jmp bios32_end
9834unknown_service:
9835 mov al, #0x80
9836bios32_end:
9837#ifdef BX_QEMU
9838 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9839#endif
9840 popfd
9841 retf
9842
9843.align 16
9844pcibios_protected:
9845 pushfd
9846 cli
9847 push esi
9848 push edi
9849 cmp al, #0x01 ;; installation check
9850 jne pci_pro_f02
9851 mov bx, #0x0210
9852 mov cx, #0
9853 mov edx, #0x20494350 ;; "PCI "
9854 mov al, #0x01
9855 jmp pci_pro_ok
9856pci_pro_f02: ;; find pci device
9857 cmp al, #0x02
9858 jne pci_pro_f03
9859 shl ecx, #16
9860 mov cx, dx
9861 xor ebx, ebx
9862 mov di, #0x00
9863pci_pro_devloop:
9864 call pci_pro_select_reg
9865 mov dx, #0x0cfc
9866 in eax, dx
9867 cmp eax, ecx
9868 jne pci_pro_nextdev
9869 cmp si, #0
9870 je pci_pro_ok
9871 dec si
9872pci_pro_nextdev:
9873 inc ebx
9874 cmp ebx, #0x10000
9875 jne pci_pro_devloop
9876 mov ah, #0x86
9877 jmp pci_pro_fail
9878pci_pro_f03: ;; find class code
9879 cmp al, #0x03
9880 jne pci_pro_f08
9881 xor ebx, ebx
9882 mov di, #0x08
9883pci_pro_devloop2:
9884 call pci_pro_select_reg
9885 mov dx, #0x0cfc
9886 in eax, dx
9887 shr eax, #8
9888 cmp eax, ecx
9889 jne pci_pro_nextdev2
9890 cmp si, #0
9891 je pci_pro_ok
9892 dec si
9893pci_pro_nextdev2:
9894 inc ebx
9895 cmp ebx, #0x10000
9896 jne pci_pro_devloop2
9897 mov ah, #0x86
9898 jmp pci_pro_fail
9899pci_pro_f08: ;; read configuration byte
9900 cmp al, #0x08
9901 jne pci_pro_f09
9902 call pci_pro_select_reg
9903 push edx
9904 mov dx, di
9905 and dx, #0x03
9906 add dx, #0x0cfc
9907 in al, dx
9908 pop edx
9909 mov cl, al
9910 jmp pci_pro_ok
9911pci_pro_f09: ;; read configuration word
9912 cmp al, #0x09
9913 jne pci_pro_f0a
9914 call pci_pro_select_reg
9915 push edx
9916 mov dx, di
9917 and dx, #0x02
9918 add dx, #0x0cfc
9919 in ax, dx
9920 pop edx
9921 mov cx, ax
9922 jmp pci_pro_ok
9923pci_pro_f0a: ;; read configuration dword
9924 cmp al, #0x0a
9925 jne pci_pro_f0b
9926 call pci_pro_select_reg
9927 push edx
9928 mov dx, #0x0cfc
9929 in eax, dx
9930 pop edx
9931 mov ecx, eax
9932 jmp pci_pro_ok
9933pci_pro_f0b: ;; write configuration byte
9934 cmp al, #0x0b
9935 jne pci_pro_f0c
9936 call pci_pro_select_reg
9937 push edx
9938 mov dx, di
9939 and dx, #0x03
9940 add dx, #0x0cfc
9941 mov al, cl
9942 out dx, al
9943 pop edx
9944 jmp pci_pro_ok
9945pci_pro_f0c: ;; write configuration word
9946 cmp al, #0x0c
9947 jne pci_pro_f0d
9948 call pci_pro_select_reg
9949 push edx
9950 mov dx, di
9951 and dx, #0x02
9952 add dx, #0x0cfc
9953 mov ax, cx
9954 out dx, ax
9955 pop edx
9956 jmp pci_pro_ok
9957pci_pro_f0d: ;; write configuration dword
9958 cmp al, #0x0d
9959 jne pci_pro_unknown
9960 call pci_pro_select_reg
9961 push edx
9962 mov dx, #0x0cfc
9963 mov eax, ecx
9964 out dx, eax
9965 pop edx
9966 jmp pci_pro_ok
9967pci_pro_unknown:
9968 mov ah, #0x81
9969pci_pro_fail:
9970 pop edi
9971 pop esi
9972#ifdef BX_QEMU
9973 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9974#endif
9975 popfd
9976 stc
9977 retf
9978pci_pro_ok:
9979 xor ah, ah
9980 pop edi
9981 pop esi
9982#ifdef BX_QEMU
9983 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9984#endif
9985 popfd
9986 clc
9987 retf
9988
9989pci_pro_select_reg:
9990 push edx
9991 mov eax, #0x800000
9992 mov ax, bx
9993 shl eax, #8
9994 and di, #0xff
9995 or ax, di
9996 and al, #0xfc
9997 mov dx, #0x0cf8
9998 out dx, eax
9999 pop edx
10000 ret
10001
10002use16 386
10003
10004pcibios_real:
10005 push eax
10006 push dx
10007 mov eax, #0x80000000
10008 mov dx, #0x0cf8
10009 out dx, eax
10010 mov dx, #0x0cfc
10011 in eax, dx
10012#ifdef PCI_FIXED_HOST_BRIDGE
10013 cmp eax, #PCI_FIXED_HOST_BRIDGE
10014 je pci_present
10015#else
10016 ;; say ok if a device is present
10017 cmp eax, #0xffffffff
10018 jne pci_present
10019#endif
10020 pop dx
10021 pop eax
10022 mov ah, #0xff
10023 stc
10024 ret
10025pci_present:
10026 pop dx
10027 pop eax
10028 cmp al, #0x01 ;; installation check
10029 jne pci_real_f02
10030 mov ax, #0x0001
10031 mov bx, #0x0210
10032 mov cx, #0
10033 mov edx, #0x20494350 ;; "PCI "
10034 mov edi, #0xf0000
10035 mov di, #pcibios_protected
10036 clc
10037 ret
10038pci_real_f02: ;; find pci device
10039 push esi
10040 push edi
10041 cmp al, #0x02
10042 jne pci_real_f03
10043 shl ecx, #16
10044 mov cx, dx
10045 xor ebx, ebx
10046 mov di, #0x00
10047pci_real_devloop:
10048 call pci_real_select_reg
10049 mov dx, #0x0cfc
10050 in eax, dx
10051 cmp eax, ecx
10052 jne pci_real_nextdev
10053 cmp si, #0
10054 je pci_real_ok
10055 dec si
10056pci_real_nextdev:
10057 inc ebx
10058 cmp ebx, #0x10000
10059 jne pci_real_devloop
10060 mov dx, cx
10061 shr ecx, #16
10062 mov ax, #0x8602
10063 jmp pci_real_fail
10064pci_real_f03: ;; find class code
10065 cmp al, #0x03
10066 jne pci_real_f08
10067 xor ebx, ebx
10068 mov di, #0x08
10069pci_real_devloop2:
10070 call pci_real_select_reg
10071 mov dx, #0x0cfc
10072 in eax, dx
10073 shr eax, #8
10074 cmp eax, ecx
10075 jne pci_real_nextdev2
10076 cmp si, #0
10077 je pci_real_ok
10078 dec si
10079pci_real_nextdev2:
10080 inc ebx
10081 cmp ebx, #0x10000
10082 jne pci_real_devloop2
10083 mov dx, cx
10084 shr ecx, #16
10085 mov ax, #0x8603
10086 jmp pci_real_fail
10087pci_real_f08: ;; read configuration byte
10088 cmp al, #0x08
10089 jne pci_real_f09
10090 call pci_real_select_reg
10091 push dx
10092 mov dx, di
10093 and dx, #0x03
10094 add dx, #0x0cfc
10095 in al, dx
10096 pop dx
10097 mov cl, al
10098 jmp pci_real_ok
10099pci_real_f09: ;; read configuration word
10100 cmp al, #0x09
10101 jne pci_real_f0a
10102 call pci_real_select_reg
10103 push dx
10104 mov dx, di
10105 and dx, #0x02
10106 add dx, #0x0cfc
10107 in ax, dx
10108 pop dx
10109 mov cx, ax
10110 jmp pci_real_ok
10111pci_real_f0a: ;; read configuration dword
10112 cmp al, #0x0a
10113 jne pci_real_f0b
10114 call pci_real_select_reg
10115 push dx
10116 mov dx, #0x0cfc
10117 in eax, dx
10118 pop dx
10119 mov ecx, eax
10120 jmp pci_real_ok
10121pci_real_f0b: ;; write configuration byte
10122 cmp al, #0x0b
10123 jne pci_real_f0c
10124 call pci_real_select_reg
10125 push dx
10126 mov dx, di
10127 and dx, #0x03
10128 add dx, #0x0cfc
10129 mov al, cl
10130 out dx, al
10131 pop dx
10132 jmp pci_real_ok
10133pci_real_f0c: ;; write configuration word
10134 cmp al, #0x0c
10135 jne pci_real_f0d
10136 call pci_real_select_reg
10137 push dx
10138 mov dx, di
10139 and dx, #0x02
10140 add dx, #0x0cfc
10141 mov ax, cx
10142 out dx, ax
10143 pop dx
10144 jmp pci_real_ok
10145pci_real_f0d: ;; write configuration dword
10146 cmp al, #0x0d
10147 jne pci_real_f0e
10148 call pci_real_select_reg
10149 push dx
10150 mov dx, #0x0cfc
10151 mov eax, ecx
10152 out dx, eax
10153 pop dx
10154 jmp pci_real_ok
10155pci_real_f0e: ;; get irq routing options
10156 cmp al, #0x0e
10157 jne pci_real_unknown
10158 SEG ES
10159 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10160 jb pci_real_too_small
10161 SEG ES
10162 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10163 pushf
10164 push ds
10165 push es
10166 push cx
10167 push si
10168 push di
10169 cld
10170 mov si, #pci_routing_table_structure_start
10171 push cs
10172 pop ds
10173 SEG ES
10174 mov cx, [di+2]
10175 SEG ES
10176 mov es, [di+4]
10177 mov di, cx
10178 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10179 rep
10180 movsb
10181 pop di
10182 pop si
10183 pop cx
10184 pop es
10185 pop ds
10186 popf
10187 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10188 jmp pci_real_ok
10189pci_real_too_small:
10190 SEG ES
10191 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10192 mov ah, #0x89
10193 jmp pci_real_fail
10194
10195pci_real_unknown:
10196 mov ah, #0x81
10197pci_real_fail:
10198 pop edi
10199 pop esi
10200 stc
10201 ret
10202pci_real_ok:
10203 xor ah, ah
10204 pop edi
10205 pop esi
10206 clc
10207 ret
10208
10209pci_real_select_reg:
10210 push dx
10211 mov eax, #0x800000
10212 mov ax, bx
10213 shl eax, #8
10214 and di, #0xff
10215 or ax, di
10216 and al, #0xfc
10217 mov dx, #0x0cf8
10218 out dx, eax
10219 pop dx
10220 ret
10221
10222.align 16
10223pci_routing_table_structure:
10224 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10225 db 0, 1 ;; version
10226#ifdef VBOX
10227#if 0
10228 dw 32 + (30 * 16) ;; table size
10229#else
10230 dw 32 + (10 * 16) ;; table size
10231#endif
10232#else /* !VBOX */
10233 dw 32 + (6 * 16) ;; table size
10234#endif /* !VBOX */
10235 db 0 ;; PCI interrupt router bus
10236 db 0x08 ;; PCI interrupt router DevFunc
10237 dw 0x0000 ;; PCI exclusive IRQs
10238 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10239 dw 0x7000 ;; compatible PCI interrupt router device ID
10240 dw 0,0 ;; Miniport data
10241 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10242#ifdef VBOX
10243 db 0x00 ;; checksum (set by biossums)
10244#else /* !VBOX */
10245 db 0x07 ;; checksum
10246#endif /* !VBOX */
10247pci_routing_table_structure_start:
10248 ;; first slot entry PCI-to-ISA (embedded)
10249 db 0 ;; pci bus number
10250 db 0x08 ;; pci device number (bit 7-3)
10251 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10252 dw 0xdef8 ;; IRQ bitmap INTA#
10253 db 0x61 ;; link value INTB#
10254 dw 0xdef8 ;; IRQ bitmap INTB#
10255 db 0x62 ;; link value INTC#
10256 dw 0xdef8 ;; IRQ bitmap INTC#
10257 db 0x63 ;; link value INTD#
10258 dw 0xdef8 ;; IRQ bitmap INTD#
10259 db 0 ;; physical slot (0 = embedded)
10260 db 0 ;; reserved
10261 ;; second slot entry: 1st PCI slot
10262 db 0 ;; pci bus number
10263 db 0x10 ;; pci device number (bit 7-3)
10264 db 0x61 ;; link value INTA#
10265 dw 0xdef8 ;; IRQ bitmap INTA#
10266 db 0x62 ;; link value INTB#
10267 dw 0xdef8 ;; IRQ bitmap INTB#
10268 db 0x63 ;; link value INTC#
10269 dw 0xdef8 ;; IRQ bitmap INTC#
10270 db 0x60 ;; link value INTD#
10271 dw 0xdef8 ;; IRQ bitmap INTD#
10272 db 1 ;; physical slot (0 = embedded)
10273 db 0 ;; reserved
10274 ;; third slot entry: 2nd PCI slot
10275 db 0 ;; pci bus number
10276 db 0x18 ;; pci device number (bit 7-3)
10277 db 0x62 ;; link value INTA#
10278 dw 0xdef8 ;; IRQ bitmap INTA#
10279 db 0x63 ;; link value INTB#
10280 dw 0xdef8 ;; IRQ bitmap INTB#
10281 db 0x60 ;; link value INTC#
10282 dw 0xdef8 ;; IRQ bitmap INTC#
10283 db 0x61 ;; link value INTD#
10284 dw 0xdef8 ;; IRQ bitmap INTD#
10285 db 2 ;; physical slot (0 = embedded)
10286 db 0 ;; reserved
10287 ;; 4th slot entry: 3rd PCI slot
10288 db 0 ;; pci bus number
10289 db 0x20 ;; pci device number (bit 7-3)
10290 db 0x63 ;; link value INTA#
10291 dw 0xdef8 ;; IRQ bitmap INTA#
10292 db 0x60 ;; link value INTB#
10293 dw 0xdef8 ;; IRQ bitmap INTB#
10294 db 0x61 ;; link value INTC#
10295 dw 0xdef8 ;; IRQ bitmap INTC#
10296 db 0x62 ;; link value INTD#
10297 dw 0xdef8 ;; IRQ bitmap INTD#
10298 db 3 ;; physical slot (0 = embedded)
10299 db 0 ;; reserved
10300 ;; 5th slot entry: 4rd PCI slot
10301 db 0 ;; pci bus number
10302 db 0x28 ;; pci device number (bit 7-3)
10303 db 0x60 ;; link value INTA#
10304 dw 0xdef8 ;; IRQ bitmap INTA#
10305 db 0x61 ;; link value INTB#
10306 dw 0xdef8 ;; IRQ bitmap INTB#
10307 db 0x62 ;; link value INTC#
10308 dw 0xdef8 ;; IRQ bitmap INTC#
10309 db 0x63 ;; link value INTD#
10310 dw 0xdef8 ;; IRQ bitmap INTD#
10311 db 4 ;; physical slot (0 = embedded)
10312 db 0 ;; reserved
10313 ;; 6th slot entry: 5rd PCI slot
10314 db 0 ;; pci bus number
10315 db 0x30 ;; pci device number (bit 7-3)
10316 db 0x61 ;; link value INTA#
10317 dw 0xdef8 ;; IRQ bitmap INTA#
10318 db 0x62 ;; link value INTB#
10319 dw 0xdef8 ;; IRQ bitmap INTB#
10320 db 0x63 ;; link value INTC#
10321 dw 0xdef8 ;; IRQ bitmap INTC#
10322 db 0x60 ;; link value INTD#
10323 dw 0xdef8 ;; IRQ bitmap INTD#
10324 db 5 ;; physical slot (0 = embedded)
10325 db 0 ;; reserved
10326#ifdef VBOX
10327 ;; 7th slot entry: 6th PCI slot
10328 db 0 ;; pci bus number
10329 db 0x38 ;; pci device number (bit 7-3)
10330 db 0x62 ;; link value INTA#
10331 dw 0xdef8 ;; IRQ bitmap INTA#
10332 db 0x63 ;; link value INTB#
10333 dw 0xdef8 ;; IRQ bitmap INTB#
10334 db 0x60 ;; link value INTC#
10335 dw 0xdef8 ;; IRQ bitmap INTC#
10336 db 0x61 ;; link value INTD#
10337 dw 0xdef8 ;; IRQ bitmap INTD#
10338 db 6 ;; physical slot (0 = embedded)
10339 db 0 ;; reserved
10340 ;; 8th slot entry: 7th PCI slot
10341 db 0 ;; pci bus number
10342 db 0x40 ;; pci device number (bit 7-3)
10343 db 0x63 ;; link value INTA#
10344 dw 0xdef8 ;; IRQ bitmap INTA#
10345 db 0x60 ;; link value INTB#
10346 dw 0xdef8 ;; IRQ bitmap INTB#
10347 db 0x61 ;; link value INTC#
10348 dw 0xdef8 ;; IRQ bitmap INTC#
10349 db 0x62 ;; link value INTD#
10350 dw 0xdef8 ;; IRQ bitmap INTD#
10351 db 7 ;; physical slot (0 = embedded)
10352 db 0 ;; reserved
10353 ;; 9th slot entry: 8th PCI slot
10354 db 0 ;; pci bus number
10355 db 0x48 ;; pci device number (bit 7-3)
10356 db 0x60 ;; link value INTA#
10357 dw 0xdef8 ;; IRQ bitmap INTA#
10358 db 0x61 ;; link value INTB#
10359 dw 0xdef8 ;; IRQ bitmap INTB#
10360 db 0x62 ;; link value INTC#
10361 dw 0xdef8 ;; IRQ bitmap INTC#
10362 db 0x63 ;; link value INTD#
10363 dw 0xdef8 ;; IRQ bitmap INTD#
10364 db 8 ;; physical slot (0 = embedded)
10365 db 0 ;; reserved
10366 ;; 10th slot entry: 9th PCI slot
10367 db 0 ;; pci bus number
10368 db 0x50 ;; pci device number (bit 7-3)
10369 db 0x61 ;; link value INTA#
10370 dw 0xdef8 ;; IRQ bitmap INTA#
10371 db 0x62 ;; link value INTB#
10372 dw 0xdef8 ;; IRQ bitmap INTB#
10373 db 0x63 ;; link value INTC#
10374 dw 0xdef8 ;; IRQ bitmap INTC#
10375 db 0x60 ;; link value INTD#
10376 dw 0xdef8 ;; IRQ bitmap INTD#
10377 db 9 ;; physical slot (0 = embedded)
10378 db 0 ;; reserved
10379 ;; 11th slot entry: 10th PCI slot
10380 db 0 ;; pci bus number
10381 db 0x58 ;; pci device number (bit 7-3)
10382 db 0x61 ;; link value INTA#
10383 dw 0xdef8 ;; IRQ bitmap INTA#
10384 db 0x62 ;; link value INTB#
10385 dw 0xdef8 ;; IRQ bitmap INTB#
10386 db 0x63 ;; link value INTC#
10387 dw 0xdef8 ;; IRQ bitmap INTC#
10388 db 0x60 ;; link value INTD#
10389 dw 0xdef8 ;; IRQ bitmap INTD#
10390 db 10 ;; physical slot (0 = embedded)
10391 db 0 ;; reserved
10392 ;; 12th slot entry: 11th PCI slot
10393 db 0 ;; pci bus number
10394 db 0x60 ;; pci device number (bit 7-3)
10395 db 0x61 ;; link value INTA#
10396 dw 0xdef8 ;; IRQ bitmap INTA#
10397 db 0x62 ;; link value INTB#
10398 dw 0xdef8 ;; IRQ bitmap INTB#
10399 db 0x63 ;; link value INTC#
10400 dw 0xdef8 ;; IRQ bitmap INTC#
10401 db 0x60 ;; link value INTD#
10402 dw 0xdef8 ;; IRQ bitmap INTD#
10403 db 11 ;; physical slot (0 = embedded)
10404 db 0 ;; reserved
10405 ;; 13th slot entry: 12th PCI slot
10406 db 0 ;; pci bus number
10407 db 0x68 ;; pci device number (bit 7-3)
10408 db 0x61 ;; link value INTA#
10409 dw 0xdef8 ;; IRQ bitmap INTA#
10410 db 0x62 ;; link value INTB#
10411 dw 0xdef8 ;; IRQ bitmap INTB#
10412 db 0x63 ;; link value INTC#
10413 dw 0xdef8 ;; IRQ bitmap INTC#
10414 db 0x60 ;; link value INTD#
10415 dw 0xdef8 ;; IRQ bitmap INTD#
10416 db 12 ;; physical slot (0 = embedded)
10417 db 0 ;; reserved
10418 ;; 14th slot entry: 13th PCI slot
10419 db 0 ;; pci bus number
10420 db 0x70 ;; pci device number (bit 7-3)
10421 db 0x61 ;; link value INTA#
10422 dw 0xdef8 ;; IRQ bitmap INTA#
10423 db 0x62 ;; link value INTB#
10424 dw 0xdef8 ;; IRQ bitmap INTB#
10425 db 0x63 ;; link value INTC#
10426 dw 0xdef8 ;; IRQ bitmap INTC#
10427 db 0x60 ;; link value INTD#
10428 dw 0xdef8 ;; IRQ bitmap INTD#
10429 db 13 ;; physical slot (0 = embedded)
10430 db 0 ;; reserved
10431 ;; 15th slot entry: 14th PCI slot
10432 db 0 ;; pci bus number
10433 db 0x78 ;; pci device number (bit 7-3)
10434 db 0x61 ;; link value INTA#
10435 dw 0xdef8 ;; IRQ bitmap INTA#
10436 db 0x62 ;; link value INTB#
10437 dw 0xdef8 ;; IRQ bitmap INTB#
10438 db 0x63 ;; link value INTC#
10439 dw 0xdef8 ;; IRQ bitmap INTC#
10440 db 0x60 ;; link value INTD#
10441 dw 0xdef8 ;; IRQ bitmap INTD#
10442 db 14 ;; physical slot (0 = embedded)
10443 db 0 ;; reserved
10444 ;; 16th slot entry: 15th PCI slot
10445 db 0 ;; pci bus number
10446 db 0x80 ;; pci device number (bit 7-3)
10447 db 0x61 ;; link value INTA#
10448 dw 0xdef8 ;; IRQ bitmap INTA#
10449 db 0x62 ;; link value INTB#
10450 dw 0xdef8 ;; IRQ bitmap INTB#
10451 db 0x63 ;; link value INTC#
10452 dw 0xdef8 ;; IRQ bitmap INTC#
10453 db 0x60 ;; link value INTD#
10454 dw 0xdef8 ;; IRQ bitmap INTD#
10455 db 15 ;; physical slot (0 = embedded)
10456 db 0 ;; reserved
10457 ;; 17th slot entry: 16th PCI slot
10458 db 0 ;; pci bus number
10459 db 0x88 ;; pci device number (bit 7-3)
10460 db 0x61 ;; link value INTA#
10461 dw 0xdef8 ;; IRQ bitmap INTA#
10462 db 0x62 ;; link value INTB#
10463 dw 0xdef8 ;; IRQ bitmap INTB#
10464 db 0x63 ;; link value INTC#
10465 dw 0xdef8 ;; IRQ bitmap INTC#
10466 db 0x60 ;; link value INTD#
10467 dw 0xdef8 ;; IRQ bitmap INTD#
10468 db 16 ;; physical slot (0 = embedded)
10469 db 0 ;; reserved
10470 ;; 18th slot entry: 17th PCI slot
10471 db 0 ;; pci bus number
10472 db 0x90 ;; pci device number (bit 7-3)
10473 db 0x61 ;; link value INTA#
10474 dw 0xdef8 ;; IRQ bitmap INTA#
10475 db 0x62 ;; link value INTB#
10476 dw 0xdef8 ;; IRQ bitmap INTB#
10477 db 0x63 ;; link value INTC#
10478 dw 0xdef8 ;; IRQ bitmap INTC#
10479 db 0x60 ;; link value INTD#
10480 dw 0xdef8 ;; IRQ bitmap INTD#
10481 db 17 ;; physical slot (0 = embedded)
10482 db 0 ;; reserved
10483 ;; 19th slot entry: 18th PCI slot
10484 db 0 ;; pci bus number
10485 db 0x98 ;; pci device number (bit 7-3)
10486 db 0x61 ;; link value INTA#
10487 dw 0xdef8 ;; IRQ bitmap INTA#
10488 db 0x62 ;; link value INTB#
10489 dw 0xdef8 ;; IRQ bitmap INTB#
10490 db 0x63 ;; link value INTC#
10491 dw 0xdef8 ;; IRQ bitmap INTC#
10492 db 0x60 ;; link value INTD#
10493 dw 0xdef8 ;; IRQ bitmap INTD#
10494 db 18 ;; physical slot (0 = embedded)
10495 db 0 ;; reserved
10496 ;; 20th slot entry: 19th PCI slot
10497 db 0 ;; pci bus number
10498 db 0xa0 ;; pci device number (bit 7-3)
10499 db 0x61 ;; link value INTA#
10500 dw 0xdef8 ;; IRQ bitmap INTA#
10501 db 0x62 ;; link value INTB#
10502 dw 0xdef8 ;; IRQ bitmap INTB#
10503 db 0x63 ;; link value INTC#
10504 dw 0xdef8 ;; IRQ bitmap INTC#
10505 db 0x60 ;; link value INTD#
10506 dw 0xdef8 ;; IRQ bitmap INTD#
10507 db 19 ;; physical slot (0 = embedded)
10508 db 0 ;; reserved
10509 ;; 21th slot entry: 20th PCI slot
10510 db 0 ;; pci bus number
10511 db 0xa8 ;; pci device number (bit 7-3)
10512 db 0x61 ;; link value INTA#
10513 dw 0xdef8 ;; IRQ bitmap INTA#
10514 db 0x62 ;; link value INTB#
10515 dw 0xdef8 ;; IRQ bitmap INTB#
10516 db 0x63 ;; link value INTC#
10517 dw 0xdef8 ;; IRQ bitmap INTC#
10518 db 0x60 ;; link value INTD#
10519 dw 0xdef8 ;; IRQ bitmap INTD#
10520 db 20 ;; physical slot (0 = embedded)
10521 db 0 ;; reserved
10522 ;; 21th slot entry: 20th PCI slot
10523 db 0 ;; pci bus number
10524 db 0xb0 ;; pci device number (bit 7-3)
10525 db 0x61 ;; link value INTA#
10526 dw 0xdef8 ;; IRQ bitmap INTA#
10527 db 0x62 ;; link value INTB#
10528 dw 0xdef8 ;; IRQ bitmap INTB#
10529 db 0x63 ;; link value INTC#
10530 dw 0xdef8 ;; IRQ bitmap INTC#
10531 db 0x60 ;; link value INTD#
10532 dw 0xdef8 ;; IRQ bitmap INTD#
10533 db 20 ;; physical slot (0 = embedded)
10534 db 0 ;; reserved
10535 ;; 22th slot entry: 21th PCI slot
10536 db 0 ;; pci bus number
10537 db 0xb8 ;; pci device number (bit 7-3)
10538 db 0x61 ;; link value INTA#
10539 dw 0xdef8 ;; IRQ bitmap INTA#
10540 db 0x62 ;; link value INTB#
10541 dw 0xdef8 ;; IRQ bitmap INTB#
10542 db 0x63 ;; link value INTC#
10543 dw 0xdef8 ;; IRQ bitmap INTC#
10544 db 0x60 ;; link value INTD#
10545 dw 0xdef8 ;; IRQ bitmap INTD#
10546 db 21 ;; physical slot (0 = embedded)
10547 db 0 ;; reserved
10548 ;; 23th slot entry: 22th PCI slot
10549 db 0 ;; pci bus number
10550 db 0xc0 ;; pci device number (bit 7-3)
10551 db 0x61 ;; link value INTA#
10552 dw 0xdef8 ;; IRQ bitmap INTA#
10553 db 0x62 ;; link value INTB#
10554 dw 0xdef8 ;; IRQ bitmap INTB#
10555 db 0x63 ;; link value INTC#
10556 dw 0xdef8 ;; IRQ bitmap INTC#
10557 db 0x60 ;; link value INTD#
10558 dw 0xdef8 ;; IRQ bitmap INTD#
10559 db 22 ;; physical slot (0 = embedded)
10560 db 0 ;; reserved
10561 ;; 24th slot entry: 23th PCI slot
10562 db 0 ;; pci bus number
10563 db 0xc8 ;; pci device number (bit 7-3)
10564 db 0x61 ;; link value INTA#
10565 dw 0xdef8 ;; IRQ bitmap INTA#
10566 db 0x62 ;; link value INTB#
10567 dw 0xdef8 ;; IRQ bitmap INTB#
10568 db 0x63 ;; link value INTC#
10569 dw 0xdef8 ;; IRQ bitmap INTC#
10570 db 0x60 ;; link value INTD#
10571 dw 0xdef8 ;; IRQ bitmap INTD#
10572 db 23 ;; physical slot (0 = embedded)
10573 db 0 ;; reserved
10574 ;; 25th slot entry: 24th PCI slot
10575 db 0 ;; pci bus number
10576 db 0xd0 ;; pci device number (bit 7-3)
10577 db 0x61 ;; link value INTA#
10578 dw 0xdef8 ;; IRQ bitmap INTA#
10579 db 0x62 ;; link value INTB#
10580 dw 0xdef8 ;; IRQ bitmap INTB#
10581 db 0x63 ;; link value INTC#
10582 dw 0xdef8 ;; IRQ bitmap INTC#
10583 db 0x60 ;; link value INTD#
10584 dw 0xdef8 ;; IRQ bitmap INTD#
10585 db 24 ;; physical slot (0 = embedded)
10586 db 0 ;; reserved
10587 ;; 26th slot entry: 25th PCI slot
10588 db 0 ;; pci bus number
10589 db 0xd8 ;; pci device number (bit 7-3)
10590 db 0x61 ;; link value INTA#
10591 dw 0xdef8 ;; IRQ bitmap INTA#
10592 db 0x62 ;; link value INTB#
10593 dw 0xdef8 ;; IRQ bitmap INTB#
10594 db 0x63 ;; link value INTC#
10595 dw 0xdef8 ;; IRQ bitmap INTC#
10596 db 0x60 ;; link value INTD#
10597 dw 0xdef8 ;; IRQ bitmap INTD#
10598 db 25 ;; physical slot (0 = embedded)
10599 db 0 ;; reserved
10600 ;; 27th slot entry: 26th PCI slot
10601 db 0 ;; pci bus number
10602 db 0xe0 ;; pci device number (bit 7-3)
10603 db 0x61 ;; link value INTA#
10604 dw 0xdef8 ;; IRQ bitmap INTA#
10605 db 0x62 ;; link value INTB#
10606 dw 0xdef8 ;; IRQ bitmap INTB#
10607 db 0x63 ;; link value INTC#
10608 dw 0xdef8 ;; IRQ bitmap INTC#
10609 db 0x60 ;; link value INTD#
10610 dw 0xdef8 ;; IRQ bitmap INTD#
10611 db 26 ;; physical slot (0 = embedded)
10612 db 0 ;; reserved
10613 ;; 28th slot entry: 27th PCI slot
10614 db 0 ;; pci bus number
10615 db 0xe8 ;; pci device number (bit 7-3)
10616 db 0x61 ;; link value INTA#
10617 dw 0xdef8 ;; IRQ bitmap INTA#
10618 db 0x62 ;; link value INTB#
10619 dw 0xdef8 ;; IRQ bitmap INTB#
10620 db 0x63 ;; link value INTC#
10621 dw 0xdef8 ;; IRQ bitmap INTC#
10622 db 0x60 ;; link value INTD#
10623 dw 0xdef8 ;; IRQ bitmap INTD#
10624 db 27 ;; physical slot (0 = embedded)
10625 db 0 ;; reserved
10626 ;; 29th slot entry: 28th PCI slot
10627 db 0 ;; pci bus number
10628 db 0xf0 ;; pci device number (bit 7-3)
10629 db 0x61 ;; link value INTA#
10630 dw 0xdef8 ;; IRQ bitmap INTA#
10631 db 0x62 ;; link value INTB#
10632 dw 0xdef8 ;; IRQ bitmap INTB#
10633 db 0x63 ;; link value INTC#
10634 dw 0xdef8 ;; IRQ bitmap INTC#
10635 db 0x60 ;; link value INTD#
10636 dw 0xdef8 ;; IRQ bitmap INTD#
10637 db 28 ;; physical slot (0 = embedded)
10638 db 0 ;; reserved
10639 ;; 30th slot entry: 29th PCI slot
10640 db 0 ;; pci bus number
10641 db 0xf8 ;; pci device number (bit 7-3)
10642 db 0x61 ;; link value INTA#
10643 dw 0xdef8 ;; IRQ bitmap INTA#
10644 db 0x62 ;; link value INTB#
10645 dw 0xdef8 ;; IRQ bitmap INTB#
10646 db 0x63 ;; link value INTC#
10647 dw 0xdef8 ;; IRQ bitmap INTC#
10648 db 0x60 ;; link value INTD#
10649 dw 0xdef8 ;; IRQ bitmap INTD#
10650 db 29 ;; physical slot (0 = embedded)
10651 db 0 ;; reserved
10652#endif /* VBOX */
10653pci_routing_table_structure_end:
10654
10655#if !BX_ROMBIOS32
10656pci_irq_list:
10657 db 11, 10, 9, 5;
10658
10659pcibios_init_sel_reg:
10660 push eax
10661 mov eax, #0x800000
10662 mov ax, bx
10663 shl eax, #8
10664 and dl, #0xfc
10665 or al, dl
10666 mov dx, #0x0cf8
10667 out dx, eax
10668 pop eax
10669 ret
10670
10671pcibios_init_iomem_bases:
10672 push bp
10673 mov bp, sp
10674 mov eax, #0xe0000000 ;; base for memory init
10675 push eax
10676 mov ax, #0xc000 ;; base for i/o init
10677 push ax
10678 mov ax, #0x0010 ;; start at base address #0
10679 push ax
10680 mov bx, #0x0008
10681pci_init_io_loop1:
10682 mov dl, #0x00
10683 call pcibios_init_sel_reg
10684 mov dx, #0x0cfc
10685 in ax, dx
10686 cmp ax, #0xffff
10687 jz next_pci_dev
10688#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10689 mov dl, #0x04 ;; disable i/o and memory space access
10690 call pcibios_init_sel_reg
10691 mov dx, #0x0cfc
10692 in al, dx
10693 and al, #0xfc
10694 out dx, al
10695pci_init_io_loop2:
10696 mov dl, [bp-8]
10697 call pcibios_init_sel_reg
10698 mov dx, #0x0cfc
10699 in eax, dx
10700 test al, #0x01
10701 jnz init_io_base
10702 mov ecx, eax
10703 mov eax, #0xffffffff
10704 out dx, eax
10705 in eax, dx
10706 cmp eax, ecx
10707 je next_pci_base
10708 xor eax, #0xffffffff
10709 mov ecx, eax
10710 mov eax, [bp-4]
10711 out dx, eax
10712 add eax, ecx ;; calculate next free mem base
10713 add eax, #0x01000000
10714 and eax, #0xff000000
10715 mov [bp-4], eax
10716 jmp next_pci_base
10717init_io_base:
10718 mov cx, ax
10719 mov ax, #0xffff
10720 out dx, ax
10721 in ax, dx
10722 cmp ax, cx
10723 je next_pci_base
10724 xor ax, #0xfffe
10725 mov cx, ax
10726 mov ax, [bp-6]
10727 out dx, ax
10728 add ax, cx ;; calculate next free i/o base
10729 add ax, #0x0100
10730 and ax, #0xff00
10731 mov [bp-6], ax
10732next_pci_base:
10733 mov al, [bp-8]
10734 add al, #0x04
10735 cmp al, #0x28
10736 je enable_iomem_space
10737 mov byte ptr[bp-8], al
10738 jmp pci_init_io_loop2
10739#endif /* !VBOX */
10740enable_iomem_space:
10741 mov dl, #0x04 ;; enable i/o and memory space access if available
10742 call pcibios_init_sel_reg
10743 mov dx, #0x0cfc
10744 in al, dx
10745 or al, #0x07
10746 out dx, al
10747#ifdef VBOX
10748 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10749 call pcibios_init_sel_reg
10750 mov dx, #0x0cfc
10751 in eax, dx
10752 cmp eax, #0x20001022
10753 jne next_pci_dev
10754 mov dl, #0x10 ;; get I/O address
10755 call pcibios_init_sel_reg
10756 mov dx, #0x0cfc
10757 in ax, dx
10758 and ax, #0xfffc
10759 mov cx, ax
10760 mov dx, cx
10761 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10762 in ax, dx ;; reset is performed by reading the reset register
10763 mov dx, cx
10764 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10765 in eax, dx ;; reset is performed by reading the reset register
10766#endif /* VBOX */
10767next_pci_dev:
10768 mov byte ptr[bp-8], #0x10
10769 inc bx
10770 cmp bx, #0x0100
10771 jne pci_init_io_loop1
10772 mov sp, bp
10773 pop bp
10774 ret
10775
10776pcibios_init_set_elcr:
10777 push ax
10778 push cx
10779 mov dx, #0x04d0
10780 test al, #0x08
10781 jz is_master_pic
10782 inc dx
10783 and al, #0x07
10784is_master_pic:
10785 mov cl, al
10786 mov bl, #0x01
10787 shl bl, cl
10788 in al, dx
10789 or al, bl
10790 out dx, al
10791 pop cx
10792 pop ax
10793 ret
10794
10795pcibios_init_irqs:
10796 push ds
10797 push bp
10798 mov ax, #0xf000
10799 mov ds, ax
10800 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10801 mov al, #0x00
10802 out dx, al
10803 inc dx
10804 out dx, al
10805 mov si, #pci_routing_table_structure
10806 mov bh, [si+8]
10807 mov bl, [si+9]
10808 mov dl, #0x00
10809 call pcibios_init_sel_reg
10810 mov dx, #0x0cfc
10811 in eax, dx
10812 cmp eax, [si+12] ;; check irq router
10813 jne pci_init_end
10814 mov dl, [si+34]
10815 call pcibios_init_sel_reg
10816 push bx ;; save irq router bus + devfunc
10817 mov dx, #0x0cfc
10818 mov ax, #0x8080
10819 out dx, ax ;; reset PIRQ route control
10820 add dx, #2
10821 out dx, ax
10822 mov ax, [si+6]
10823 sub ax, #0x20
10824 shr ax, #4
10825 mov cx, ax
10826 add si, #0x20 ;; set pointer to 1st entry
10827 mov bp, sp
10828 mov ax, #pci_irq_list
10829 push ax
10830 xor ax, ax
10831 push ax
10832pci_init_irq_loop1:
10833 mov bh, [si]
10834 mov bl, [si+1]
10835pci_init_irq_loop2:
10836 mov dl, #0x00
10837 call pcibios_init_sel_reg
10838 mov dx, #0x0cfc
10839 in ax, dx
10840 cmp ax, #0xffff
10841 jnz pci_test_int_pin
10842 test bl, #0x07
10843 jz next_pir_entry
10844 jmp next_pci_func
10845pci_test_int_pin:
10846 mov dl, #0x3c
10847 call pcibios_init_sel_reg
10848 mov dx, #0x0cfd
10849 in al, dx
10850 and al, #0x07
10851 jz next_pci_func
10852 dec al ;; determine pirq reg
10853 mov dl, #0x03
10854 mul al, dl
10855 add al, #0x02
10856 xor ah, ah
10857 mov bx, ax
10858 mov al, [si+bx]
10859 mov dl, al
10860 mov bx, [bp]
10861 call pcibios_init_sel_reg
10862 mov dx, #0x0cfc
10863 and al, #0x03
10864 add dl, al
10865 in al, dx
10866 cmp al, #0x80
10867 jb pirq_found
10868 mov bx, [bp-2] ;; pci irq list pointer
10869 mov al, [bx]
10870 out dx, al
10871 inc bx
10872 mov [bp-2], bx
10873 call pcibios_init_set_elcr
10874pirq_found:
10875 mov bh, [si]
10876 mov bl, [si+1]
10877 add bl, [bp-3] ;; pci function number
10878 mov dl, #0x3c
10879 call pcibios_init_sel_reg
10880 mov dx, #0x0cfc
10881 out dx, al
10882next_pci_func:
10883 inc byte ptr[bp-3]
10884 inc bl
10885 test bl, #0x07
10886 jnz pci_init_irq_loop2
10887next_pir_entry:
10888 add si, #0x10
10889 mov byte ptr[bp-3], #0x00
10890 loop pci_init_irq_loop1
10891 mov sp, bp
10892 pop bx
10893pci_init_end:
10894 pop bp
10895 pop ds
10896 ret
10897#endif // !BX_ROMBIOS32
10898#endif // BX_PCIBIOS
10899
10900#if BX_ROMBIOS32
10901rombios32_init:
10902 ;; save a20 and enable it
10903 in al, 0x92
10904 push ax
10905 or al, #0x02
10906 out 0x92, al
10907
10908 ;; save SS:SP to the BDA
10909 xor ax, ax
10910 mov ds, ax
10911 mov 0x0469, ss
10912 mov 0x0467, sp
10913
10914 SEG CS
10915 lidt [pmode_IDT_info]
10916 SEG CS
10917 lgdt [rombios32_gdt_48]
10918 ;; set PE bit in CR0
10919 mov eax, cr0
10920 or al, #0x01
10921 mov cr0, eax
10922 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10923 db 0x66, 0xea
10924 dw rombios32_05
10925 dw 0x000f ;; high 16 bit address
10926 dw 0x0010
10927
10928use32 386
10929rombios32_05:
10930 ;; init data segments
10931 mov eax, #0x18
10932 mov ds, ax
10933 mov es, ax
10934 mov ss, ax
10935 xor eax, eax
10936 mov fs, ax
10937 mov gs, ax
10938 cld
10939
10940 ;; copy rombios32 code to ram (ram offset = 1MB)
10941 mov esi, #0xfffe0000
10942 mov edi, #0x00040000
10943 mov ecx, #0x10000 / 4
10944 rep
10945 movsd
10946
10947 ;; init the stack pointer
10948 mov esp, #0x00080000
10949
10950 ;; call rombios32 code
10951 mov eax, #0x00040000
10952 call eax
10953
10954 ;; return to 16 bit protected mode first
10955 db 0xea
10956 dd rombios32_10
10957 dw 0x20
10958
10959use16 386
10960rombios32_10:
10961 ;; restore data segment limits to 0xffff
10962 mov ax, #0x28
10963 mov ds, ax
10964 mov es, ax
10965 mov ss, ax
10966 mov fs, ax
10967 mov gs, ax
10968
10969 ;; reset PE bit in CR0
10970 mov eax, cr0
10971 and al, #0xFE
10972 mov cr0, eax
10973
10974 ;; far jump to flush CPU queue after transition to real mode
10975 JMP_AP(0xf000, rombios32_real_mode)
10976
10977rombios32_real_mode:
10978 ;; restore IDT to normal real-mode defaults
10979 SEG CS
10980 lidt [rmode_IDT_info]
10981
10982 xor ax, ax
10983 mov ds, ax
10984 mov es, ax
10985 mov fs, ax
10986 mov gs, ax
10987
10988 ;; restore SS:SP from the BDA
10989 mov ss, 0x0469
10990 xor esp, esp
10991 mov sp, 0x0467
10992 ;; restore a20
10993 pop ax
10994 out 0x92, al
10995 ret
10996
10997rombios32_gdt_48:
10998 dw 0x30
10999 dw rombios32_gdt
11000 dw 0x000f
11001
11002rombios32_gdt:
11003 dw 0, 0, 0, 0
11004 dw 0, 0, 0, 0
11005 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11006 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11007 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11008 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11009#endif // BX_ROMBIOS32
11010
11011
11012; parallel port detection: base address in DX, index in BX, timeout in CL
11013detect_parport:
11014 push dx
11015 add dx, #2
11016 in al, dx
11017 and al, #0xdf ; clear input mode
11018 out dx, al
11019 pop dx
11020 mov al, #0xaa
11021 out dx, al
11022 in al, dx
11023 cmp al, #0xaa
11024 jne no_parport
11025 push bx
11026 shl bx, #1
11027 mov [bx+0x408], dx ; Parallel I/O address
11028 pop bx
11029 mov [bx+0x478], cl ; Parallel printer timeout
11030 inc bx
11031no_parport:
11032 ret
11033
11034; serial port detection: base address in DX, index in BX, timeout in CL
11035detect_serial:
11036 push dx
11037 inc dx
11038 mov al, #0x02
11039 out dx, al
11040 in al, dx
11041 cmp al, #0x02
11042 jne no_serial
11043 inc dx
11044 in al, dx
11045 cmp al, #0x02
11046 jne no_serial
11047 dec dx
11048 xor al, al
11049 out dx, al
11050 pop dx
11051 push bx
11052 shl bx, #1
11053 mov [bx+0x400], dx ; Serial I/O address
11054 pop bx
11055 mov [bx+0x47c], cl ; Serial timeout
11056 inc bx
11057 ret
11058no_serial:
11059 pop dx
11060 ret
11061
11062rom_checksum:
11063 push ax
11064 push bx
11065 push cx
11066 xor ax, ax
11067 xor bx, bx
11068 xor cx, cx
11069 mov ch, [2]
11070 shl cx, #1
11071checksum_loop:
11072 add al, [bx]
11073 inc bx
11074 loop checksum_loop
11075 and al, #0xff
11076 pop cx
11077 pop bx
11078 pop ax
11079 ret
11080
11081rom_scan:
11082 ;; Scan for existence of valid expansion ROMS.
11083 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11084 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11085 ;; System ROM: only 0xE0000
11086 ;;
11087 ;; Header:
11088 ;; Offset Value
11089 ;; 0 0x55
11090 ;; 1 0xAA
11091 ;; 2 ROM length in 512-byte blocks
11092 ;; 3 ROM initialization entry point (FAR CALL)
11093
11094 mov cx, #0xc000
11095rom_scan_loop:
11096 mov ds, cx
11097 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11098 cmp [0], #0xAA55 ;; look for signature
11099 jne rom_scan_increment
11100 call rom_checksum
11101 jnz rom_scan_increment
11102 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11103
11104 ;; We want our increment in 512-byte quantities, rounded to
11105 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11106 test al, #0x03
11107 jz block_count_rounded
11108 and al, #0xfc ;; needs rounding up
11109 add al, #0x04
11110block_count_rounded:
11111
11112 xor bx, bx ;; Restore DS back to 0000:
11113 mov ds, bx
11114 push ax ;; Save AX
11115 ;; Push addr of ROM entry point
11116 push cx ;; Push seg
11117 push #0x0003 ;; Push offset
11118 mov bp, sp ;; Call ROM init routine using seg:off on stack
11119 db 0xff ;; call_far ss:[bp+0]
11120 db 0x5e
11121 db 0
11122 cli ;; In case expansion ROM BIOS turns IF on
11123 add sp, #2 ;; Pop offset value
11124 pop cx ;; Pop seg value (restore CX)
11125 pop ax ;; Restore AX
11126rom_scan_increment:
11127 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11128 ;; because the segment selector is shifted left 4 bits.
11129 add cx, ax
11130 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11131 jbe rom_scan_loop
11132
11133 xor ax, ax ;; Restore DS back to 0000:
11134 mov ds, ax
11135 ret
11136
11137;; for 'C' strings and other data, insert them here with
11138;; a the following hack:
11139;; DATA_SEG_DEFS_HERE
11140
11141
11142;; the following area can be used to write dynamically generated tables
11143 .align 16
11144bios_table_area_start:
11145 dd 0xaafb4442
11146 dd bios_table_area_end - bios_table_area_start - 8;
11147
11148;--------
11149;- POST -
11150;--------
11151.org 0xe05b ; POST Entry Point
11152bios_table_area_end:
11153post:
11154
11155 xor ax, ax
11156
11157 ;; first reset the DMA controllers
11158 out 0x0d,al
11159 out 0xda,al
11160
11161 ;; then initialize the DMA controllers
11162 mov al, #0xC0
11163 out 0xD6, al ; cascade mode of channel 4 enabled
11164 mov al, #0x00
11165 out 0xD4, al ; unmask channel 4
11166
11167 ;; Examine CMOS shutdown status.
11168 mov AL, #0x0f
11169 out 0x70, AL
11170 in AL, 0x71
11171
11172 ;; backup status
11173 mov bl, al
11174
11175 ;; Reset CMOS shutdown status.
11176 mov AL, #0x0f
11177 out 0x70, AL ; select CMOS register Fh
11178 mov AL, #0x00
11179 out 0x71, AL ; set shutdown action to normal
11180
11181 ;; Examine CMOS shutdown status.
11182 mov al, bl
11183
11184 ;; 0x00, 0x09, 0x0D+ = normal startup
11185 cmp AL, #0x00
11186 jz normal_post
11187 cmp AL, #0x0d
11188 jae normal_post
11189 cmp AL, #0x09
11190 je normal_post
11191
11192 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11193 cmp al, #0x05
11194 je eoi_jmp_post
11195
11196 ;; Examine CMOS shutdown status.
11197 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11198 push bx
11199 call _shutdown_status_panic
11200
11201#if 0
11202 HALT(__LINE__)
11203 ;
11204 ;#if 0
11205 ; 0xb0, 0x20, /* mov al, #0x20 */
11206 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11207 ;#endif
11208 ;
11209 pop es
11210 pop ds
11211 popa
11212 iret
11213#endif
11214
11215normal_post:
11216 ; case 0: normal startup
11217
11218 cli
11219 mov ax, #0xfffe
11220 mov sp, ax
11221 xor ax, ax
11222 mov ds, ax
11223 mov ss, ax
11224
11225#ifndef VBOX
11226 ;; zero out BIOS data area (40:00..40:ff)
11227 mov es, ax
11228 mov cx, #0x0080 ;; 128 words
11229 mov di, #0x0400
11230 cld
11231 rep
11232 stosw
11233#else /* VBOX */
11234 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11235 mov es, ax
11236 xor di, di
11237 cld
11238 mov cx, #0x0239 ;; 569 words
11239 rep
11240 stosw
11241 inc di
11242 inc di
11243 mov cx, #0x7dc6 ;; 32198 words
11244 rep
11245 stosw
11246 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11247 ;; because we store the MP table there
11248 xor eax, eax
11249 xor bx, bx
11250memory_zero_loop:
11251 add bx, #0x1000
11252 cmp bx, #0x9000
11253 jae memory_cleared
11254 mov es, bx
11255 xor di, di
11256 mov cx, #0x4000
11257 rep
11258 stosd
11259 jmp memory_zero_loop
11260memory_cleared:
11261 mov es, bx
11262 xor di, di
11263 mov cx, #0x3f00
11264 rep
11265 stosd
11266 xor bx, bx
11267#endif
11268
11269 call _log_bios_start
11270
11271 ;; set all interrupts to default handler
11272 xor bx, bx ;; offset index
11273 mov cx, #0x0100 ;; counter (256 interrupts)
11274 mov ax, #dummy_iret_handler
11275 mov dx, #0xF000
11276
11277post_default_ints:
11278 mov [bx], ax
11279 add bx, #2
11280 mov [bx], dx
11281 add bx, #2
11282 loop post_default_ints
11283
11284 ;; set vector 0x79 to zero
11285 ;; this is used by 'gardian angel' protection system
11286 SET_INT_VECTOR(0x79, #0, #0)
11287
11288 ;; base memory in K 40:13 (word)
11289 mov ax, #BASE_MEM_IN_K
11290 mov 0x0413, ax
11291
11292
11293 ;; Manufacturing Test 40:12
11294 ;; zerod out above
11295
11296#ifndef VBOX
11297 ;; Warm Boot Flag 0040:0072
11298 ;; value of 1234h = skip memory checks
11299 ;; zerod out above
11300#endif /* !VBOX */
11301
11302
11303 ;; Printer Services vector
11304 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11305
11306 ;; Bootstrap failure vector
11307 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11308
11309 ;; Bootstrap Loader vector
11310 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11311
11312 ;; User Timer Tick vector
11313 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11314
11315 ;; Memory Size Check vector
11316 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11317
11318 ;; Equipment Configuration Check vector
11319 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11320
11321 ;; System Services
11322 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11323
11324 ;; EBDA setup
11325 call ebda_post
11326
11327 ;; PIT setup
11328 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11329 ;; int 1C already points at dummy_iret_handler (above)
11330 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11331 out 0x43, al
11332 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11333 out 0x40, al
11334 out 0x40, al
11335
11336 ;; Keyboard
11337 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11338 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11339
11340 xor ax, ax
11341 mov ds, ax
11342 mov 0x0417, al /* keyboard shift flags, set 1 */
11343 mov 0x0418, al /* keyboard shift flags, set 2 */
11344 mov 0x0419, al /* keyboard alt-numpad work area */
11345 mov 0x0471, al /* keyboard ctrl-break flag */
11346 mov 0x0497, al /* keyboard status flags 4 */
11347 mov al, #0x10
11348 mov 0x0496, al /* keyboard status flags 3 */
11349
11350
11351 /* keyboard head of buffer pointer */
11352 mov bx, #0x001E
11353 mov 0x041A, bx
11354
11355 /* keyboard end of buffer pointer */
11356 mov 0x041C, bx
11357
11358 /* keyboard pointer to start of buffer */
11359 mov bx, #0x001E
11360 mov 0x0480, bx
11361
11362 /* keyboard pointer to end of buffer */
11363 mov bx, #0x003E
11364 mov 0x0482, bx
11365
11366 /* init the keyboard */
11367 call _keyboard_init
11368
11369 ;; mov CMOS Equipment Byte to BDA Equipment Word
11370 mov ax, 0x0410
11371 mov al, #0x14
11372 out 0x70, al
11373 in al, 0x71
11374 mov 0x0410, ax
11375
11376
11377 ;; Parallel setup
11378 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11379 xor ax, ax
11380 mov ds, ax
11381 xor bx, bx
11382 mov cl, #0x14 ; timeout value
11383 mov dx, #0x378 ; Parallel I/O address, port 1
11384 call detect_parport
11385 mov dx, #0x278 ; Parallel I/O address, port 2
11386 call detect_parport
11387 shl bx, #0x0e
11388 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
11389 and ax, #0x3fff
11390 or ax, bx ; set number of parallel ports
11391 mov 0x410, ax
11392
11393 ;; Serial setup
11394 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11395 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11396 xor bx, bx
11397 mov cl, #0x0a ; timeout value
11398 mov dx, #0x03f8 ; Serial I/O address, port 1
11399 call detect_serial
11400 mov dx, #0x02f8 ; Serial I/O address, port 2
11401 call detect_serial
11402 mov dx, #0x03e8 ; Serial I/O address, port 3
11403 call detect_serial
11404 mov dx, #0x02e8 ; Serial I/O address, port 4
11405 call detect_serial
11406 shl bx, #0x09
11407 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11408 and ax, #0xf1ff
11409 or ax, bx ; set number of serial port
11410 mov 0x410, ax
11411
11412 ;; CMOS RTC
11413 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11414 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11415 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11416 ;; BIOS DATA AREA 0x4CE ???
11417 call timer_tick_post
11418
11419 ;; PS/2 mouse setup
11420 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11421
11422 ;; IRQ13 (FPU exception) setup
11423 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11424
11425 ;; Video setup
11426 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11427
11428#ifdef VBOX
11429 ;; moved the PIC initialization to another place as we need
11430 ;; some space for additions init calls. Otherwise this code
11431 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11432 call init_pic
11433#else /* !VBOX */
11434 ;; PIC
11435 mov al, #0x11 ; send initialisation commands
11436 out 0x20, al
11437 out 0xa0, al
11438 mov al, #0x08
11439 out 0x21, al
11440 mov al, #0x70
11441 out 0xa1, al
11442 mov al, #0x04
11443 out 0x21, al
11444 mov al, #0x02
11445 out 0xa1, al
11446 mov al, #0x01
11447 out 0x21, al
11448 out 0xa1, al
11449 mov al, #0xb8
11450 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11451#if BX_USE_PS2_MOUSE
11452 mov al, #0x8f
11453#else
11454 mov al, #0x9f
11455#endif
11456 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11457#endif /* !VBOX */
11458
11459#if BX_ROMBIOS32
11460 call rombios32_init
11461#else
11462 call pcibios_init_iomem_bases
11463 call pcibios_init_irqs
11464#endif
11465 call rom_scan
11466
11467#if BX_USE_ATADRV
11468 ;;
11469 ;; ATA/ATAPI driver setup
11470 ;;
11471 call _ata_init
11472 call _ata_detect
11473 ;;
11474#endif
11475
11476#ifdef VBOX_WITH_SCSI
11477 ;;
11478 ;; SCSI driver setup
11479 ;;
11480 call _scsi_init
11481 ;;
11482#endif
11483
11484 call _print_bios_banner
11485
11486 ;;
11487 ;; Floppy setup
11488 ;;
11489 call floppy_drive_post
11490
11491 ;;
11492 ;; Hard Drive setup
11493 ;;
11494 call hard_drive_post
11495
11496#if BX_ELTORITO_BOOT
11497 ;;
11498 ;; eltorito floppy/harddisk emulation from cd
11499 ;;
11500 call _cdemu_init
11501 ;;
11502#endif // BX_ELTORITO_BOOT
11503
11504 sti ;; enable interrupts
11505 int #0x19
11506
11507.org 0xe2c3 ; NMI Handler Entry Point
11508nmi:
11509 ;; FIXME the NMI handler should not panic
11510 ;; but iret when called from int75 (fpu exception)
11511 call _nmi_handler_msg
11512 iret
11513
11514int75_handler:
11515 out 0xf0, al // clear irq13
11516 call eoi_both_pics // clear interrupt
11517 int 2 // legacy nmi call
11518 iret
11519
11520;-------------------------------------------
11521;- INT 13h Fixed Disk Services Entry Point -
11522;-------------------------------------------
11523.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11524int13_handler:
11525 //JMPL(int13_relocated)
11526 jmp int13_relocated
11527
11528.org 0xe401 ; Fixed Disk Parameter Table
11529
11530;----------
11531;- INT19h -
11532;----------
11533.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11534int19_handler:
11535
11536 jmp int19_relocated
11537;-------------------------------------------
11538;- System BIOS Configuration Data Table
11539;-------------------------------------------
11540.org BIOS_CONFIG_TABLE
11541db 0x08 ; Table size (bytes) -Lo
11542db 0x00 ; Table size (bytes) -Hi
11543db SYS_MODEL_ID
11544db SYS_SUBMODEL_ID
11545db BIOS_REVISION
11546; Feature byte 1
11547; b7: 1=DMA channel 3 used by hard disk
11548; b6: 1=2 interrupt controllers present
11549; b5: 1=RTC present
11550; b4: 1=BIOS calls int 15h/4Fh every key
11551; b3: 1=wait for extern event supported (Int 15h/41h)
11552; b2: 1=extended BIOS data area used
11553; b1: 0=AT or ESDI bus, 1=MicroChannel
11554; b0: 1=Dual bus (MicroChannel + ISA)
11555db (0 << 7) | \
11556 (1 << 6) | \
11557 (1 << 5) | \
11558 (BX_CALL_INT15_4F << 4) | \
11559 (0 << 3) | \
11560 (BX_USE_EBDA << 2) | \
11561 (0 << 1) | \
11562 (0 << 0)
11563; Feature byte 2
11564; b7: 1=32-bit DMA supported
11565; b6: 1=int16h, function 9 supported
11566; b5: 1=int15h/C6h (get POS data) supported
11567; b4: 1=int15h/C7h (get mem map info) supported
11568; b3: 1=int15h/C8h (en/dis CPU) supported
11569; b2: 1=non-8042 kb controller
11570; b1: 1=data streaming supported
11571; b0: reserved
11572db (0 << 7) | \
11573 (1 << 6) | \
11574 (0 << 5) | \
11575 (0 << 4) | \
11576 (0 << 3) | \
11577 (0 << 2) | \
11578 (0 << 1) | \
11579 (0 << 0)
11580; Feature byte 3
11581; b7: not used
11582; b6: reserved
11583; b5: reserved
11584; b4: POST supports ROM-to-RAM enable/disable
11585; b3: SCSI on system board
11586; b2: info panel installed
11587; b1: Initial Machine Load (IML) system - BIOS on disk
11588; b0: SCSI supported in IML
11589db 0x00
11590; Feature byte 4
11591; b7: IBM private
11592; b6: EEPROM present
11593; b5-3: ABIOS presence (011 = not supported)
11594; b2: private
11595; b1: memory split above 16Mb supported
11596; b0: POSTEXT directly supported by POST
11597db 0x00
11598; Feature byte 5 (IBM)
11599; b1: enhanced mouse
11600; b0: flash EPROM
11601db 0x00
11602
11603
11604
11605.org 0xe729 ; Baud Rate Generator Table
11606
11607;----------
11608;- INT14h -
11609;----------
11610.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11611int14_handler:
11612 push ds
11613 pusha
11614 xor ax, ax
11615 mov ds, ax
11616 call _int14_function
11617 popa
11618 pop ds
11619 iret
11620
11621
11622;----------------------------------------
11623;- INT 16h Keyboard Service Entry Point -
11624;----------------------------------------
11625.org 0xe82e
11626int16_handler:
11627
11628 sti
11629 push ds
11630 pushf
11631 pusha
11632
11633 cmp ah, #0x00
11634 je int16_F00
11635 cmp ah, #0x10
11636 je int16_F00
11637
11638 mov bx, #0xf000
11639 mov ds, bx
11640 call _int16_function
11641 popa
11642 popf
11643 pop ds
11644 jz int16_zero_set
11645
11646int16_zero_clear:
11647 push bp
11648 mov bp, sp
11649 //SEG SS
11650 and BYTE [bp + 0x06], #0xbf
11651 pop bp
11652 iret
11653
11654int16_zero_set:
11655 push bp
11656 mov bp, sp
11657 //SEG SS
11658 or BYTE [bp + 0x06], #0x40
11659 pop bp
11660 iret
11661
11662int16_F00:
11663 mov bx, #0x0040
11664 mov ds, bx
11665
11666int16_wait_for_key:
11667 cli
11668 mov bx, 0x001a
11669 cmp bx, 0x001c
11670 jne int16_key_found
11671 sti
11672 nop
11673#if 0
11674 /* no key yet, call int 15h, function AX=9002 */
11675 0x50, /* push AX */
11676 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11677 0xcd, 0x15, /* int 15h */
11678 0x58, /* pop AX */
11679 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11680#endif
11681 jmp int16_wait_for_key
11682
11683int16_key_found:
11684 mov bx, #0xf000
11685 mov ds, bx
11686 call _int16_function
11687 popa
11688 popf
11689 pop ds
11690#if 0
11691 /* notify int16 complete w/ int 15h, function AX=9102 */
11692 0x50, /* push AX */
11693 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11694 0xcd, 0x15, /* int 15h */
11695 0x58, /* pop AX */
11696#endif
11697 iret
11698
11699
11700
11701;-------------------------------------------------
11702;- INT09h : Keyboard Hardware Service Entry Point -
11703;-------------------------------------------------
11704.org 0xe987
11705int09_handler:
11706 cli
11707 push ax
11708
11709 mov al, #0xAD ;;disable keyboard
11710 out #0x64, al
11711
11712 mov al, #0x0B
11713 out #0x20, al
11714 in al, #0x20
11715 and al, #0x02
11716 jz int09_finish
11717
11718 in al, #0x60 ;;read key from keyboard controller
11719 sti
11720 push ds
11721 pusha
11722#ifdef BX_CALL_INT15_4F
11723 mov ah, #0x4f ;; allow for keyboard intercept
11724 stc
11725 int #0x15
11726 jnc int09_done
11727#endif
11728
11729 ;; check for extended key
11730 cmp al, #0xe0
11731 jne int09_check_pause
11732 xor ax, ax
11733 mov ds, ax
11734 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11735 or al, #0x02
11736 mov BYTE [0x496], al
11737 jmp int09_done
11738
11739int09_check_pause: ;; check for pause key
11740 cmp al, #0xe1
11741 jne int09_process_key
11742 xor ax, ax
11743 mov ds, ax
11744 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11745 or al, #0x01
11746 mov BYTE [0x496], al
11747 jmp int09_done
11748
11749int09_process_key:
11750 mov bx, #0xf000
11751 mov ds, bx
11752 call _int09_function
11753
11754int09_done:
11755 popa
11756 pop ds
11757 cli
11758 call eoi_master_pic
11759
11760int09_finish:
11761 mov al, #0xAE ;;enable keyboard
11762 out #0x64, al
11763 pop ax
11764 iret
11765
11766
11767;----------------------------------------
11768;- INT 13h Diskette Service Entry Point -
11769;----------------------------------------
11770.org 0xec59
11771int13_diskette:
11772 jmp int13_noeltorito
11773
11774;---------------------------------------------
11775;- INT 0Eh Diskette Hardware ISR Entry Point -
11776;---------------------------------------------
11777.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11778int0e_handler:
11779 push ax
11780 push dx
11781 mov dx, #0x03f4
11782 in al, dx
11783 and al, #0xc0
11784 cmp al, #0xc0
11785 je int0e_normal
11786 mov dx, #0x03f5
11787 mov al, #0x08 ; sense interrupt status
11788 out dx, al
11789int0e_loop1:
11790 mov dx, #0x03f4
11791 in al, dx
11792 and al, #0xc0
11793 cmp al, #0xc0
11794 jne int0e_loop1
11795int0e_loop2:
11796 mov dx, #0x03f5
11797 in al, dx
11798 mov dx, #0x03f4
11799 in al, dx
11800 and al, #0xc0
11801 cmp al, #0xc0
11802 je int0e_loop2
11803int0e_normal:
11804 push ds
11805 xor ax, ax ;; segment 0000
11806 mov ds, ax
11807 call eoi_master_pic
11808 mov al, 0x043e
11809 or al, #0x80 ;; diskette interrupt has occurred
11810 mov 0x043e, al
11811 pop ds
11812 pop dx
11813 pop ax
11814 iret
11815
11816
11817.org 0xefc7 ; Diskette Controller Parameter Table
11818diskette_param_table:
11819;; Since no provisions are made for multiple drive types, most
11820;; values in this table are ignored. I set parameters for 1.44M
11821;; floppy here
11822db 0xAF
11823db 0x02 ;; head load time 0000001, DMA used
11824db 0x25
11825db 0x02
11826db 18
11827db 0x1B
11828db 0xFF
11829db 0x6C
11830db 0xF6
11831db 0x0F
11832db 0x08
11833
11834
11835;----------------------------------------
11836;- INT17h : Printer Service Entry Point -
11837;----------------------------------------
11838.org 0xefd2
11839int17_handler:
11840 push ds
11841 pusha
11842 xor ax, ax
11843 mov ds, ax
11844 call _int17_function
11845 popa
11846 pop ds
11847 iret
11848
11849diskette_param_table2:
11850;; New diskette parameter table adding 3 parameters from IBM
11851;; Since no provisions are made for multiple drive types, most
11852;; values in this table are ignored. I set parameters for 1.44M
11853;; floppy here
11854db 0xAF
11855db 0x02 ;; head load time 0000001, DMA used
11856db 0x25
11857db 0x02
11858db 18
11859db 0x1B
11860db 0xFF
11861db 0x6C
11862db 0xF6
11863db 0x0F
11864db 0x08
11865db 79 ;; maximum track
11866db 0 ;; data transfer rate
11867db 4 ;; drive type in cmos
11868
11869.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11870 HALT(__LINE__)
11871 iret
11872
11873;----------
11874;- INT10h -
11875;----------
11876.org 0xf065 ; INT 10h Video Support Service Entry Point
11877int10_handler:
11878 ;; dont do anything, since the VGA BIOS handles int10h requests
11879 iret
11880
11881.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11882
11883;----------
11884;- INT12h -
11885;----------
11886.org 0xf841 ; INT 12h Memory Size Service Entry Point
11887; ??? different for Pentium (machine check)?
11888int12_handler:
11889 push ds
11890 mov ax, #0x0040
11891 mov ds, ax
11892 mov ax, 0x0013
11893 pop ds
11894 iret
11895
11896;----------
11897;- INT11h -
11898;----------
11899.org 0xf84d ; INT 11h Equipment List Service Entry Point
11900int11_handler:
11901 push ds
11902 mov ax, #0x0040
11903 mov ds, ax
11904 mov ax, 0x0010
11905 pop ds
11906 iret
11907
11908;----------
11909;- INT15h -
11910;----------
11911.org 0xf859 ; INT 15h System Services Entry Point
11912int15_handler:
11913 pushf
11914#if BX_APM
11915 cmp ah, #0x53
11916 je apm_call
11917#endif
11918 push ds
11919 push es
11920 cmp ah, #0x86
11921 je int15_handler32
11922 cmp ah, #0xE8
11923 je int15_handler32
11924 pusha
11925#if BX_USE_PS2_MOUSE
11926 cmp ah, #0xC2
11927 je int15_handler_mouse
11928#endif
11929 call _int15_function
11930int15_handler_mouse_ret:
11931 popa
11932int15_handler32_ret:
11933 pop es
11934 pop ds
11935 popf
11936 jmp iret_modify_cf
11937#if BX_APM
11938apm_call:
11939 jmp _apmreal_entry
11940#endif
11941
11942#if BX_USE_PS2_MOUSE
11943int15_handler_mouse:
11944 call _int15_function_mouse
11945 jmp int15_handler_mouse_ret
11946#endif
11947
11948int15_handler32:
11949 pushad
11950 call _int15_function32
11951 popad
11952 jmp int15_handler32_ret
11953
11954;; Protected mode IDT descriptor
11955;;
11956;; I just make the limit 0, so the machine will shutdown
11957;; if an exception occurs during protected mode memory
11958;; transfers.
11959;;
11960;; Set base to f0000 to correspond to beginning of BIOS,
11961;; in case I actually define an IDT later
11962;; Set limit to 0
11963
11964pmode_IDT_info:
11965dw 0x0000 ;; limit 15:00
11966dw 0x0000 ;; base 15:00
11967db 0x0f ;; base 23:16
11968
11969;; Real mode IDT descriptor
11970;;
11971;; Set to typical real-mode values.
11972;; base = 000000
11973;; limit = 03ff
11974
11975rmode_IDT_info:
11976dw 0x03ff ;; limit 15:00
11977dw 0x0000 ;; base 15:00
11978db 0x00 ;; base 23:16
11979
11980;;
11981;; Handler for unexpected hardware interrupts
11982;;
11983dummy_isr:
11984 push ds
11985 pushad
11986 xor ax, ax
11987 mov ds, ax
11988 call _dummy_isr_function
11989 popad
11990 pop ds
11991 iret
11992
11993;----------
11994;- INT1Ah -
11995;----------
11996.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
11997int1a_handler:
11998#if BX_PCIBIOS
11999 cmp ah, #0xb1
12000 jne int1a_normal
12001 call pcibios_real
12002 jc pcibios_error
12003 retf 2
12004pcibios_error:
12005 mov bl, ah
12006 mov ah, #0xb1
12007 push ds
12008 pusha
12009 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12010 mov ds, ax ; on 16bit protected mode.
12011 jmp int1a_callfunction
12012int1a_normal:
12013#endif
12014 push ds
12015 pusha
12016 xor ax, ax
12017 mov ds, ax
12018int1a_callfunction:
12019 call _int1a_function
12020 popa
12021 pop ds
12022 iret
12023
12024;;
12025;; int70h: IRQ8 - CMOS RTC
12026;;
12027int70_handler:
12028 push ds
12029 pushad
12030 xor ax, ax
12031 mov ds, ax
12032 call _int70_function
12033 popad
12034 pop ds
12035 iret
12036
12037;---------
12038;- INT08 -
12039;---------
12040.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12041int08_handler:
12042 sti
12043 push eax
12044 push ds
12045 xor ax, ax
12046 mov ds, ax
12047
12048 ;; time to turn off drive(s)?
12049 mov al,0x0440
12050 or al,al
12051 jz int08_floppy_off
12052 dec al
12053 mov 0x0440,al
12054 jnz int08_floppy_off
12055 ;; turn motor(s) off
12056 push dx
12057 mov dx,#0x03f2
12058 in al,dx
12059 and al,#0xcf
12060 out dx,al
12061 pop dx
12062int08_floppy_off:
12063
12064 mov eax, 0x046c ;; get ticks dword
12065 inc eax
12066
12067 ;; compare eax to one days worth of timer ticks at 18.2 hz
12068 cmp eax, #0x001800B0
12069 jb int08_store_ticks
12070 ;; there has been a midnight rollover at this point
12071 xor eax, eax ;; zero out counter
12072 inc BYTE 0x0470 ;; increment rollover flag
12073
12074int08_store_ticks:
12075 mov 0x046c, eax ;; store new ticks dword
12076 ;; chain to user timer tick INT #0x1c
12077 //pushf
12078 //;; call_ep [ds:loc]
12079 //CALL_EP( 0x1c << 2 )
12080 int #0x1c
12081 cli
12082 call eoi_master_pic
12083 pop ds
12084 pop eax
12085 iret
12086
12087.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12088
12089
12090.org 0xff00
12091.ascii BIOS_COPYRIGHT_STRING
12092
12093#ifdef VBOX
12094// The SMBIOS header
12095.org 0xff30
12096.align 16
12097 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12098 db 0x00 ; checksum (set by biossums)
12099 db 0x1f ; EPS length, defined by standard
12100 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12101 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12102 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12103 db 0x00 ; Entry point revision
12104 db 0x00, 0x00, 0x00, 0x00, 0x00
12105
12106// The DMI header
12107 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12108 db 0x00 ; checksum (set by biossums)
12109 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12110 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12111 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12112 db VBOX_DMI_TABLE_VER ; DMI version
12113 db 0x00 ; Just for alignment
12114#endif
12115
12116;------------------------------------------------
12117;- IRET Instruction for Dummy Interrupt Handler -
12118;------------------------------------------------
12119.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12120dummy_iret_handler:
12121 iret
12122
12123.org 0xff54 ; INT 05h Print Screen Service Entry Point
12124 HALT(__LINE__)
12125 iret
12126
12127.org 0xfff0 ; Power-up Entry Point
12128 jmp 0xf000:post
12129
12130.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12131.ascii BIOS_BUILD_DATE
12132
12133.org 0xfffe ; System Model ID
12134db SYS_MODEL_ID
12135db 0x00 ; filler
12136
12137.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12138ASM_END
12139/*
12140 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12141 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12142 * This font is public domain
12143 */
12144static Bit8u vgafont8[128*8]=
12145{
12146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12147 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12148 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12149 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12150 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12151 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12152 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12153 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12154 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12155 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12156 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12157 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12158 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12159 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12160 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12161 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12162 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12163 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12164 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12165 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12166 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12167 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12168 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12169 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12170 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12171 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12172 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12173 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12174 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12175 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12176 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12177 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12179 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12180 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12181 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12182 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12183 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12184 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12185 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12186 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12187 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12188 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12189 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12190 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12191 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12192 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12193 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12194 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12195 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12196 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12197 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12198 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12199 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12200 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12201 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12202 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12203 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12204 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12205 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12206 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12207 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12208 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12209 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12210 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12211 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12212 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12213 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12214 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12215 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12216 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12217 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12218 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12219 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12220 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12221 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12222 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12223 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12224 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12225 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12226 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12227 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12228 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12229 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12230 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12231 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12232 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12233 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12234 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12235 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12236 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12237 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12238 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12239 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12240 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12242 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12243 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12244 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12245 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12246 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12247 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12248 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12249 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12250 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12251 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12252 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12253 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12254 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12255 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12256 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12257 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12258 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12259 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12260 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12261 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12262 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12263 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12264 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12265 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12266 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12267 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12268 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12269 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12270 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12271 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12272 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12273 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12274};
12275
12276ASM_START
12277.org 0xcc00
12278// bcc-generated data will be placed here
12279ASM_END
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use