VirtualBox

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

最後變更 在這個檔案從20958是 18687,由 vboxsync 提交於 16 年 前

BIOS printf fix

  • 屬性 svn:eol-style 設為 native
檔案大小: 332.2 KB
 
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 ([email protected])
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 ([email protected])
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 default:
5258 if (scancode & 0x80) {
5259 break; /* toss key releases ... */
5260 }
5261 if (scancode > MAX_SCAN_CODE) {
5262 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5263 return;
5264 }
5265 if (shift_flags & 0x08) { /* ALT */
5266 asciicode = scan_to_scanascii[scancode].alt;
5267 scancode = scan_to_scanascii[scancode].alt >> 8;
5268 } else if (shift_flags & 0x04) { /* CONTROL */
5269 asciicode = scan_to_scanascii[scancode].control;
5270 scancode = scan_to_scanascii[scancode].control >> 8;
5271 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5272 /* extended keys handling */
5273 asciicode = 0xe0;
5274 scancode = scan_to_scanascii[scancode].normal >> 8;
5275 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5276 /* check if lock state should be ignored
5277 * because a SHIFT key are pressed */
5278
5279 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5280 asciicode = scan_to_scanascii[scancode].normal;
5281 scancode = scan_to_scanascii[scancode].normal >> 8;
5282 } else {
5283 asciicode = scan_to_scanascii[scancode].shift;
5284 scancode = scan_to_scanascii[scancode].shift >> 8;
5285 }
5286 } else {
5287 /* check if lock is on */
5288 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5289 asciicode = scan_to_scanascii[scancode].shift;
5290 scancode = scan_to_scanascii[scancode].shift >> 8;
5291 } else {
5292 asciicode = scan_to_scanascii[scancode].normal;
5293 scancode = scan_to_scanascii[scancode].normal >> 8;
5294 }
5295 }
5296 if (scancode==0 && asciicode==0) {
5297 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5298 }
5299 enqueue_key(scancode, asciicode);
5300 break;
5301 }
5302 if ((scancode & 0x7f) != 0x1d) {
5303 mf2_state &= ~0x01;
5304 }
5305 mf2_state &= ~0x02;
5306 write_byte(0x0040, 0x96, mf2_state);
5307}
5308
5309 unsigned int
5310enqueue_key(scan_code, ascii_code)
5311 Bit8u scan_code, ascii_code;
5312{
5313 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5314
5315#if BX_CPU < 2
5316 buffer_start = 0x001E;
5317 buffer_end = 0x003E;
5318#else
5319 buffer_start = read_word(0x0040, 0x0080);
5320 buffer_end = read_word(0x0040, 0x0082);
5321#endif
5322
5323 buffer_head = read_word(0x0040, 0x001A);
5324 buffer_tail = read_word(0x0040, 0x001C);
5325
5326 temp_tail = buffer_tail;
5327 buffer_tail += 2;
5328 if (buffer_tail >= buffer_end)
5329 buffer_tail = buffer_start;
5330
5331 if (buffer_tail == buffer_head) {
5332 return(0);
5333 }
5334
5335 write_byte(0x0040, temp_tail, ascii_code);
5336 write_byte(0x0040, temp_tail+1, scan_code);
5337 write_word(0x0040, 0x001C, buffer_tail);
5338 return(1);
5339}
5340
5341
5342 void
5343int74_function(make_farcall, Z, Y, X, status)
5344 Bit16u make_farcall, Z, Y, X, status;
5345{
5346 Bit16u ebda_seg=read_word(0x0040,0x000E);
5347 Bit8u in_byte, index, package_count;
5348 Bit8u mouse_flags_1, mouse_flags_2;
5349
5350BX_DEBUG_INT74("entering int74_function\n");
5351 make_farcall = 0;
5352
5353 in_byte = inb(0x64);
5354 if ( (in_byte & 0x21) != 0x21 ) {
5355 return;
5356 }
5357 in_byte = inb(0x60);
5358BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5359
5360 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5361 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5362
5363 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5364 return;
5365 }
5366
5367 package_count = mouse_flags_2 & 0x07;
5368 index = mouse_flags_1 & 0x07;
5369 write_byte(ebda_seg, 0x28 + index, in_byte);
5370
5371 if ( index >= package_count ) {
5372BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5373 status = read_byte(ebda_seg, 0x0028 + 0);
5374 X = read_byte(ebda_seg, 0x0028 + 1);
5375 Y = read_byte(ebda_seg, 0x0028 + 2);
5376 Z = 0;
5377 mouse_flags_1 = 0;
5378 // check if far call handler installed
5379 if (mouse_flags_2 & 0x80)
5380 make_farcall = 1;
5381 }
5382 else {
5383 mouse_flags_1++;
5384 }
5385 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5386}
5387
5388#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5389
5390#if BX_USE_ATADRV
5391
5392 void
5393int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5394 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5395{
5396 Bit32u lba;
5397 Bit16u ebda_seg=read_word(0x0040,0x000E);
5398 Bit16u cylinder, head, sector;
5399 Bit16u segment, offset;
5400 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5401 Bit16u size, count;
5402 Bit8u device, status;
5403
5404 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5405
5406 write_byte(0x0040, 0x008e, 0); // clear completion flag
5407
5408#ifdef VBOX_WITH_SCSI
5409 // basic check : device has to be defined
5410 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) ) {
5411 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5412 goto int13_fail;
5413 }
5414#else
5415 // basic check : device has to be defined
5416 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5417 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5418 goto int13_fail;
5419 }
5420#endif
5421
5422 // Get the ata channel
5423 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5424
5425#ifdef VBOX_WITH_SCSI
5426 // basic check : device has to be valid
5427 if (device >= BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) {
5428 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5429 goto int13_fail;
5430 }
5431#else
5432 // basic check : device has to be valid
5433 if (device >= BX_MAX_ATA_DEVICES) {
5434 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5435 goto int13_fail;
5436 }
5437#endif
5438
5439 switch (GET_AH()) {
5440
5441 case 0x00: /* disk controller reset */
5442#ifdef VBOX_WITH_SCSI
5443 /* SCSI controller does not need a reset. */
5444 if (!VBOX_IS_SCSI_DEVICE(device))
5445#endif
5446 ata_reset (device);
5447 goto int13_success;
5448 break;
5449
5450 case 0x01: /* read disk status */
5451 status = read_byte(0x0040, 0x0074);
5452 SET_AH(status);
5453 SET_DISK_RET_STATUS(0);
5454 /* set CF if error status read */
5455 if (status) goto int13_fail_nostatus;
5456 else goto int13_success_noah;
5457 break;
5458
5459 case 0x02: // read disk sectors
5460 case 0x03: // write disk sectors
5461 case 0x04: // verify disk sectors
5462
5463 count = GET_AL();
5464 cylinder = GET_CH();
5465 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5466 sector = (GET_CL() & 0x3f);
5467 head = GET_DH();
5468
5469 segment = ES;
5470 offset = BX;
5471
5472 if ( (count > 128) || (count == 0) ) {
5473 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5474 goto int13_fail;
5475 }
5476
5477#ifdef VBOX_WITH_SCSI
5478 if (!VBOX_IS_SCSI_DEVICE(device))
5479#endif
5480 {
5481 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5482 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5483 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5484 }
5485#ifdef VBOX_WITH_SCSI
5486 else
5487 {
5488 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5489
5490 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5491 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5492 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5493 }
5494#endif
5495
5496 // sanity check on cyl heads, sec
5497 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5498 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5499 goto int13_fail;
5500 }
5501
5502 // FIXME verify
5503 if ( GET_AH() == 0x04 ) goto int13_success;
5504
5505#ifdef VBOX_WITH_SCSI
5506 if (!VBOX_IS_SCSI_DEVICE(device))
5507#endif
5508 {
5509 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5510 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5511 }
5512#ifdef VBOX_WITH_SCSI
5513 else
5514 {
5515 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5516 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5517 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5518 }
5519#endif
5520
5521 // if needed, translate lchs to lba, and execute command
5522#ifdef VBOX_WITH_SCSI
5523 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5524 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5525 sector = 0; // this forces the command to be lba
5526 }
5527#else
5528 if (( (nph != nlh) || (npspt != nlspt)) ) {
5529 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5530 sector = 0; // this forces the command to be lba
5531 }
5532#endif
5533
5534 if ( GET_AH() == 0x02 )
5535 {
5536#ifdef VBOX_WITH_SCSI
5537 if (VBOX_IS_SCSI_DEVICE(device))
5538 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5539 else
5540#endif
5541 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5542 }
5543 else
5544 {
5545#ifdef VBOX_WITH_SCSI
5546 if (VBOX_IS_SCSI_DEVICE(device))
5547 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5548 else
5549#endif
5550 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5551 }
5552
5553 // Set nb of sector transferred
5554 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5555
5556 if (status != 0) {
5557 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5558 SET_AH(0x0c);
5559 goto int13_fail_noah;
5560 }
5561
5562 goto int13_success;
5563 break;
5564
5565 case 0x05: /* format disk track */
5566 BX_INFO("format disk track called\n");
5567 goto int13_success;
5568 return;
5569 break;
5570
5571 case 0x08: /* read disk drive parameters */
5572
5573 // Get logical geometry from table
5574#ifdef VBOX_WITH_SCSI
5575 if (!VBOX_IS_SCSI_DEVICE(device))
5576#endif
5577 {
5578 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5579 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5580 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5581 }
5582#ifdef VBOX_WITH_SCSI
5583 else
5584 {
5585 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5586 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5587 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5588 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5589 }
5590#endif
5591
5592 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5593#ifndef VBOX
5594 nlc = nlc - 2; /* 0 based , last sector not used */
5595#else /* VBOX */
5596 /* Maximum cylinder number is just one less than the number of cylinders. */
5597 nlc = nlc - 1; /* 0 based , last sector not used */
5598#endif /* VBOX */
5599 SET_AL(0);
5600 SET_CH(nlc & 0xff);
5601 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5602 SET_DH(nlh - 1);
5603 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5604
5605 // FIXME should set ES & DI
5606
5607 goto int13_success;
5608 break;
5609
5610 case 0x10: /* check drive ready */
5611 // should look at 40:8E also???
5612
5613 // Read the status from controller
5614 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5615 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5616 goto int13_success;
5617 }
5618 else {
5619 SET_AH(0xAA);
5620 goto int13_fail_noah;
5621 }
5622 break;
5623
5624 case 0x15: /* read disk drive size */
5625
5626 // Get physical geometry from table
5627#ifdef VBOX_WITH_SCSI
5628 if (!VBOX_IS_SCSI_DEVICE(device))
5629#endif
5630 {
5631 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5632 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5633 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5634 }
5635#ifdef VBOX_WITH_SCSI
5636 else
5637 {
5638 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5639 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5640 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5641 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5642 }
5643#endif
5644
5645 // Compute sector count seen by int13
5646#ifndef VBOX
5647 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5648#else /* VBOX */
5649 /* Is it so hard to multiply a couple of counts (without introducing
5650 * arbitrary off by one errors)? */
5651 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5652#endif /* VBOX */
5653 CX = lba >> 16;
5654 DX = lba & 0xffff;
5655
5656 SET_AH(3); // hard disk accessible
5657 goto int13_success_noah;
5658 break;
5659
5660 case 0x41: // IBM/MS installation check
5661 BX=0xaa55; // install check
5662 SET_AH(0x30); // EDD 3.0
5663 CX=0x0007; // ext disk access and edd, removable supported
5664 goto int13_success_noah;
5665 break;
5666
5667 case 0x42: // IBM/MS extended read
5668 case 0x43: // IBM/MS extended write
5669 case 0x44: // IBM/MS verify
5670 case 0x47: // IBM/MS extended seek
5671
5672 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5673 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5674 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5675
5676 // Can't use 64 bits lba
5677 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5678 if (lba != 0L) {
5679 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5680 goto int13_fail;
5681 }
5682
5683 // Get 32 bits lba and check
5684 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5685
5686#ifdef VBOX_WITH_SCSI
5687 if (VBOX_IS_SCSI_DEVICE(device))
5688 {
5689 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5690 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5691 goto int13_fail;
5692 }
5693 }
5694 else
5695#endif
5696 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5697 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5698 goto int13_fail;
5699 }
5700
5701
5702 // If verify or seek
5703 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5704 goto int13_success;
5705
5706 // Execute the command
5707 if ( GET_AH() == 0x42 )
5708#ifdef VBOX
5709 {
5710#ifdef VBOX_WITH_SCSI
5711 if (VBOX_IS_SCSI_DEVICE(device))
5712 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5713 else
5714#endif
5715 {
5716 if (count >= 256 || lba + count >= 268435456)
5717 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5718 else
5719 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5720 }
5721 }
5722#else /* !VBOX */
5723 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5724#endif /* VBOX */
5725 else
5726#ifdef VBOX
5727 {
5728#ifdef VBOX_WITH_SCSI
5729 if (VBOX_IS_SCSI_DEVICE(device))
5730 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5731 else
5732#endif
5733 {
5734 if (count >= 256 || lba + count >= 268435456)
5735 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5736 else
5737 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5738 }
5739 }
5740#else /* !VBOX */
5741 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5742#endif /* VBOX */
5743
5744 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5745 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5746
5747 if (status != 0) {
5748 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5749 SET_AH(0x0c);
5750 goto int13_fail_noah;
5751 }
5752
5753 goto int13_success;
5754 break;
5755
5756 case 0x45: // IBM/MS lock/unlock drive
5757 case 0x49: // IBM/MS extended media change
5758 goto int13_success; // Always success for HD
5759 break;
5760
5761 case 0x46: // IBM/MS eject media
5762 SET_AH(0xb2); // Volume Not Removable
5763 goto int13_fail_noah; // Always fail for HD
5764 break;
5765
5766 case 0x48: // IBM/MS get drive parameters
5767 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5768
5769 // Buffer is too small
5770 if(size < 0x1a)
5771 goto int13_fail;
5772
5773 // EDD 1.x
5774 if(size >= 0x1a) {
5775 Bit16u blksize;
5776
5777#ifdef VBOX_WITH_SCSI
5778 if (!VBOX_IS_SCSI_DEVICE(device))
5779#endif
5780 {
5781 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5782 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5783 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5784 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5785 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5786 }
5787#ifdef VBOX_WITH_SCSI
5788 else
5789 {
5790 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5791 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5792 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5793 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5794 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5795 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5796 }
5797#endif
5798
5799 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5800 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5801 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5802 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5803 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5804 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5805 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5806 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5807 }
5808
5809 // EDD 2.x
5810 if(size >= 0x1e) {
5811 Bit8u channel, dev, irq, mode, checksum, i, translation;
5812 Bit16u iobase1, iobase2, options;
5813
5814 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5815
5816 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5817 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5818
5819 // Fill in dpte
5820 channel = device / 2;
5821 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5822 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5823 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5824 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5825 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5826
5827 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5828 options |= (1<<4); // lba translation
5829 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5830 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5831 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5832
5833 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5834 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5835 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5836 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5837 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5838 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5839 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5840 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5841 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5842 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5843 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5844
5845 checksum=0;
5846 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5847 checksum = ~checksum;
5848 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5849 }
5850
5851 // EDD 3.x
5852 if(size >= 0x42) {
5853 Bit8u channel, iface, checksum, i;
5854 Bit16u iobase1;
5855
5856 channel = device / 2;
5857 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5858 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5859
5860 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5861 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5862 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5863 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5864 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5865
5866 if (iface==ATA_IFACE_ISA) {
5867 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5868 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5869 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5870 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5871 }
5872 else {
5873 // FIXME PCI
5874 }
5875 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5876 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5877 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5878 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5879
5880 if (iface==ATA_IFACE_ISA) {
5881 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5882 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5883 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5884 }
5885 else {
5886 // FIXME PCI
5887 }
5888 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5889 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5890 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5891 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5892
5893 checksum=0;
5894 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5895 checksum = ~checksum;
5896 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5897 }
5898
5899 goto int13_success;
5900 break;
5901
5902 case 0x4e: // // IBM/MS set hardware configuration
5903 // DMA, prefetch, PIO maximum not supported
5904 switch (GET_AL()) {
5905 case 0x01:
5906 case 0x03:
5907 case 0x04:
5908 case 0x06:
5909 goto int13_success;
5910 break;
5911 default :
5912 goto int13_fail;
5913 }
5914 break;
5915
5916 case 0x09: /* initialize drive parameters */
5917 case 0x0c: /* seek to specified cylinder */
5918 case 0x0d: /* alternate disk reset */
5919 case 0x11: /* recalibrate */
5920 case 0x14: /* controller internal diagnostic */
5921 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5922 goto int13_success;
5923 break;
5924
5925 case 0x0a: /* read disk sectors with ECC */
5926 case 0x0b: /* write disk sectors with ECC */
5927 case 0x18: // set media type for format
5928 case 0x50: // IBM/MS send packet command
5929 default:
5930 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5931 goto int13_fail;
5932 break;
5933 }
5934
5935int13_fail:
5936 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5937int13_fail_noah:
5938 SET_DISK_RET_STATUS(GET_AH());
5939int13_fail_nostatus:
5940 SET_CF(); // error occurred
5941 return;
5942
5943int13_success:
5944 SET_AH(0x00); // no error
5945int13_success_noah:
5946 SET_DISK_RET_STATUS(0x00);
5947 CLEAR_CF(); // no error
5948 return;
5949}
5950
5951// ---------------------------------------------------------------------------
5952// Start of int13 for cdrom
5953// ---------------------------------------------------------------------------
5954
5955 void
5956int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5957 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5958{
5959 Bit16u ebda_seg=read_word(0x0040,0x000E);
5960 Bit8u device, status, locks;
5961 Bit8u atacmd[12];
5962 Bit32u lba;
5963 Bit16u count, segment, offset, i, size;
5964
5965 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5966
5967 SET_DISK_RET_STATUS(0x00);
5968
5969 /* basic check : device should be 0xE0+ */
5970 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5971 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5972 goto int13_fail;
5973 }
5974
5975 // Get the ata channel
5976 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5977
5978 /* basic check : device has to be valid */
5979 if (device >= BX_MAX_ATA_DEVICES) {
5980 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5981 goto int13_fail;
5982 }
5983
5984 switch (GET_AH()) {
5985
5986 // all those functions return SUCCESS
5987 case 0x00: /* disk controller reset */
5988 case 0x09: /* initialize drive parameters */
5989 case 0x0c: /* seek to specified cylinder */
5990 case 0x0d: /* alternate disk reset */
5991 case 0x10: /* check drive ready */
5992 case 0x11: /* recalibrate */
5993 case 0x14: /* controller internal diagnostic */
5994 case 0x16: /* detect disk change */
5995 goto int13_success;
5996 break;
5997
5998 // all those functions return disk write-protected
5999 case 0x03: /* write disk sectors */
6000 case 0x05: /* format disk track */
6001 case 0x43: // IBM/MS extended write
6002 SET_AH(0x03);
6003 goto int13_fail_noah;
6004 break;
6005
6006 case 0x01: /* read disk status */
6007 status = read_byte(0x0040, 0x0074);
6008 SET_AH(status);
6009 SET_DISK_RET_STATUS(0);
6010
6011 /* set CF if error status read */
6012 if (status) goto int13_fail_nostatus;
6013 else goto int13_success_noah;
6014 break;
6015
6016 case 0x15: /* read disk drive size */
6017 SET_AH(0x02);
6018 goto int13_fail_noah;
6019 break;
6020
6021 case 0x41: // IBM/MS installation check
6022 BX=0xaa55; // install check
6023 SET_AH(0x30); // EDD 2.1
6024 CX=0x0007; // ext disk access, removable and edd
6025 goto int13_success_noah;
6026 break;
6027
6028 case 0x42: // IBM/MS extended read
6029 case 0x44: // IBM/MS verify sectors
6030 case 0x47: // IBM/MS extended seek
6031
6032 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6033 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6034 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6035
6036 // Can't use 64 bits lba
6037 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6038 if (lba != 0L) {
6039 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6040 goto int13_fail;
6041 }
6042
6043 // Get 32 bits lba
6044 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6045
6046 // If verify or seek
6047 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6048 goto int13_success;
6049
6050 memsetb(get_SS(),atacmd,0,12);
6051 atacmd[0]=0x28; // READ command
6052 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6053 atacmd[8]=(count & 0x00ff); // Sectors
6054 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6055 atacmd[3]=(lba & 0x00ff0000) >> 16;
6056 atacmd[4]=(lba & 0x0000ff00) >> 8;
6057 atacmd[5]=(lba & 0x000000ff);
6058 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6059
6060 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6061 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6062
6063 if (status != 0) {
6064 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6065 SET_AH(0x0c);
6066 goto int13_fail_noah;
6067 }
6068
6069 goto int13_success;
6070 break;
6071
6072 case 0x45: // IBM/MS lock/unlock drive
6073 if (GET_AL() > 2) goto int13_fail;
6074
6075 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6076
6077 switch (GET_AL()) {
6078 case 0 : // lock
6079 if (locks == 0xff) {
6080 SET_AH(0xb4);
6081 SET_AL(1);
6082 goto int13_fail_noah;
6083 }
6084 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6085 SET_AL(1);
6086 break;
6087 case 1 : // unlock
6088 if (locks == 0x00) {
6089 SET_AH(0xb0);
6090 SET_AL(0);
6091 goto int13_fail_noah;
6092 }
6093 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6094 SET_AL(locks==0?0:1);
6095 break;
6096 case 2 : // status
6097 SET_AL(locks==0?0:1);
6098 break;
6099 }
6100 goto int13_success;
6101 break;
6102
6103 case 0x46: // IBM/MS eject media
6104 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6105
6106 if (locks != 0) {
6107 SET_AH(0xb1); // media locked
6108 goto int13_fail_noah;
6109 }
6110 // FIXME should handle 0x31 no media in device
6111 // FIXME should handle 0xb5 valid request failed
6112
6113 // Call removable media eject
6114 ASM_START
6115 push bp
6116 mov bp, sp
6117
6118 mov ah, #0x52
6119 int #0x15
6120 mov _int13_cdrom.status + 2[bp], ah
6121 jnc int13_cdrom_rme_end
6122 mov _int13_cdrom.status, #1
6123int13_cdrom_rme_end:
6124 pop bp
6125 ASM_END
6126
6127 if (status != 0) {
6128 SET_AH(0xb1); // media locked
6129 goto int13_fail_noah;
6130 }
6131
6132 goto int13_success;
6133 break;
6134
6135 case 0x48: // IBM/MS get drive parameters
6136 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6137
6138 // Buffer is too small
6139 if(size < 0x1a)
6140 goto int13_fail;
6141
6142 // EDD 1.x
6143 if(size >= 0x1a) {
6144 Bit16u cylinders, heads, spt, blksize;
6145
6146 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6147
6148 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6149 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6150 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6151 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6152 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6153 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6154 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6155 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6156 }
6157
6158 // EDD 2.x
6159 if(size >= 0x1e) {
6160 Bit8u channel, dev, irq, mode, checksum, i;
6161 Bit16u iobase1, iobase2, options;
6162
6163 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6164
6165 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6166 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6167
6168 // Fill in dpte
6169 channel = device / 2;
6170 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6171 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6172 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6173 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6174
6175 // FIXME atapi device
6176 options = (1<<4); // lba translation
6177 options |= (1<<5); // removable device
6178 options |= (1<<6); // atapi device
6179 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6180
6181 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6182 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6183 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6184 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6185 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6186 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6187 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6188 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6189 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6190 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6191 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6192
6193 checksum=0;
6194 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6195 checksum = ~checksum;
6196 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6197 }
6198
6199 // EDD 3.x
6200 if(size >= 0x42) {
6201 Bit8u channel, iface, checksum, i;
6202 Bit16u iobase1;
6203
6204 channel = device / 2;
6205 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6206 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6207
6208 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6209 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6210 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6211 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6212 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6213
6214 if (iface==ATA_IFACE_ISA) {
6215 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6216 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6217 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6218 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6219 }
6220 else {
6221 // FIXME PCI
6222 }
6223 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6224 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6225 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6226 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6227
6228 if (iface==ATA_IFACE_ISA) {
6229 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6230 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6231 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6232 }
6233 else {
6234 // FIXME PCI
6235 }
6236 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6237 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6238 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6239 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6240
6241 checksum=0;
6242 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6243 checksum = ~checksum;
6244 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6245 }
6246
6247 goto int13_success;
6248 break;
6249
6250 case 0x49: // IBM/MS extended media change
6251 // always send changed ??
6252 SET_AH(06);
6253 goto int13_fail_nostatus;
6254 break;
6255
6256 case 0x4e: // // IBM/MS set hardware configuration
6257 // DMA, prefetch, PIO maximum not supported
6258 switch (GET_AL()) {
6259 case 0x01:
6260 case 0x03:
6261 case 0x04:
6262 case 0x06:
6263 goto int13_success;
6264 break;
6265 default :
6266 goto int13_fail;
6267 }
6268 break;
6269
6270 // all those functions return unimplemented
6271 case 0x02: /* read sectors */
6272 case 0x04: /* verify sectors */
6273 case 0x08: /* read disk drive parameters */
6274 case 0x0a: /* read disk sectors with ECC */
6275 case 0x0b: /* write disk sectors with ECC */
6276 case 0x18: /* set media type for format */
6277 case 0x50: // ? - send packet command
6278 default:
6279 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6280 goto int13_fail;
6281 break;
6282 }
6283
6284int13_fail:
6285 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6286int13_fail_noah:
6287 SET_DISK_RET_STATUS(GET_AH());
6288int13_fail_nostatus:
6289 SET_CF(); // error occurred
6290 return;
6291
6292int13_success:
6293 SET_AH(0x00); // no error
6294int13_success_noah:
6295 SET_DISK_RET_STATUS(0x00);
6296 CLEAR_CF(); // no error
6297 return;
6298}
6299
6300// ---------------------------------------------------------------------------
6301// End of int13 for cdrom
6302// ---------------------------------------------------------------------------
6303
6304#if BX_ELTORITO_BOOT
6305// ---------------------------------------------------------------------------
6306// Start of int13 for eltorito functions
6307// ---------------------------------------------------------------------------
6308
6309 void
6310int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6311 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6312{
6313 Bit16u ebda_seg=read_word(0x0040,0x000E);
6314
6315 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6316 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6317
6318 switch (GET_AH()) {
6319
6320 // FIXME ElTorito Various. Should be implemented
6321 case 0x4a: // ElTorito - Initiate disk emu
6322 case 0x4c: // ElTorito - Initiate disk emu and boot
6323 case 0x4d: // ElTorito - Return Boot catalog
6324 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6325 goto int13_fail;
6326 break;
6327
6328 case 0x4b: // ElTorito - Terminate disk emu
6329 // FIXME ElTorito Hardcoded
6330 write_byte(DS,SI+0x00,0x13);
6331 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6332 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6333 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6334 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6335 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6336 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6337 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6338 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6339 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6340 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6341 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6342
6343 // If we have to terminate emulation
6344 if(GET_AL() == 0x00) {
6345 // FIXME ElTorito Various. Should be handled accordingly to spec
6346 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6347 }
6348
6349 goto int13_success;
6350 break;
6351
6352 default:
6353 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6354 goto int13_fail;
6355 break;
6356 }
6357
6358int13_fail:
6359 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6360 SET_DISK_RET_STATUS(GET_AH());
6361 SET_CF(); // error occurred
6362 return;
6363
6364int13_success:
6365 SET_AH(0x00); // no error
6366 SET_DISK_RET_STATUS(0x00);
6367 CLEAR_CF(); // no error
6368 return;
6369}
6370
6371// ---------------------------------------------------------------------------
6372// End of int13 for eltorito functions
6373// ---------------------------------------------------------------------------
6374
6375// ---------------------------------------------------------------------------
6376// Start of int13 when emulating a device from the cd
6377// ---------------------------------------------------------------------------
6378
6379 void
6380int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6381 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6382{
6383 Bit16u ebda_seg=read_word(0x0040,0x000E);
6384 Bit8u device, status;
6385 Bit16u vheads, vspt, vcylinders;
6386 Bit16u head, sector, cylinder, nbsectors;
6387 Bit32u vlba, ilba, slba, elba;
6388 Bit16u before, segment, offset;
6389 Bit8u atacmd[12];
6390
6391 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6392
6393 /* at this point, we are emulating a floppy/harddisk */
6394
6395 // Recompute the device number
6396 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6397 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6398
6399 SET_DISK_RET_STATUS(0x00);
6400
6401 /* basic checks : emulation should be active, dl should equal the emulated drive */
6402 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6403 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6404 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6405 goto int13_fail;
6406 }
6407
6408 switch (GET_AH()) {
6409
6410 // all those functions return SUCCESS
6411 case 0x00: /* disk controller reset */
6412 case 0x09: /* initialize drive parameters */
6413 case 0x0c: /* seek to specified cylinder */
6414 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6415 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6416 case 0x11: /* recalibrate */
6417 case 0x14: /* controller internal diagnostic */
6418 case 0x16: /* detect disk change */
6419 goto int13_success;
6420 break;
6421
6422 // all those functions return disk write-protected
6423 case 0x03: /* write disk sectors */
6424 case 0x05: /* format disk track */
6425 SET_AH(0x03);
6426 goto int13_fail_noah;
6427 break;
6428
6429 case 0x01: /* read disk status */
6430 status=read_byte(0x0040, 0x0074);
6431 SET_AH(status);
6432 SET_DISK_RET_STATUS(0);
6433
6434 /* set CF if error status read */
6435 if (status) goto int13_fail_nostatus;
6436 else goto int13_success_noah;
6437 break;
6438
6439 case 0x02: // read disk sectors
6440 case 0x04: // verify disk sectors
6441 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6442 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6443 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6444
6445 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6446
6447 sector = GET_CL() & 0x003f;
6448 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6449 head = GET_DH();
6450 nbsectors = GET_AL();
6451 segment = ES;
6452 offset = BX;
6453
6454 // no sector to read ?
6455 if(nbsectors==0) goto int13_success;
6456
6457 // sanity checks sco openserver needs this!
6458 if ((sector > vspt)
6459 || (cylinder >= vcylinders)
6460 || (head >= vheads)) {
6461 goto int13_fail;
6462 }
6463
6464 // After controls, verify do nothing
6465 if (GET_AH() == 0x04) goto int13_success;
6466
6467 segment = ES+(BX / 16);
6468 offset = BX % 16;
6469
6470 // calculate the virtual lba inside the image
6471 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6472
6473 // In advance so we don't loose the count
6474 SET_AL(nbsectors);
6475
6476 // start lba on cd
6477 slba = (Bit32u)vlba/4;
6478 before= (Bit16u)vlba%4;
6479
6480 // end lba on cd
6481 elba = (Bit32u)(vlba+nbsectors-1)/4;
6482
6483 memsetb(get_SS(),atacmd,0,12);
6484 atacmd[0]=0x28; // READ command
6485 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6486 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6487 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6488 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6489 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6490 atacmd[5]=(ilba+slba & 0x000000ff);
6491 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6492 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6493 SET_AH(0x02);
6494 SET_AL(0);
6495 goto int13_fail_noah;
6496 }
6497
6498 goto int13_success;
6499 break;
6500
6501 case 0x08: /* read disk drive parameters */
6502 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6503 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6504 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6505
6506 SET_AL( 0x00 );
6507 SET_BL( 0x00 );
6508 SET_CH( vcylinders & 0xff );
6509 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6510 SET_DH( vheads );
6511 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6512 // FIXME ElTorito Harddisk. should send the HD count
6513
6514 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6515 case 0x01: SET_BL( 0x02 ); break;
6516 case 0x02: SET_BL( 0x04 ); break;
6517 case 0x03: SET_BL( 0x06 ); break;
6518 }
6519
6520ASM_START
6521 push bp
6522 mov bp, sp
6523 mov ax, #diskette_param_table2
6524 mov _int13_cdemu.DI+2[bp], ax
6525 mov _int13_cdemu.ES+2[bp], cs
6526 pop bp
6527ASM_END
6528 goto int13_success;
6529 break;
6530
6531 case 0x15: /* read disk drive size */
6532 // FIXME ElTorito Harddisk. What geometry to send ?
6533 SET_AH(0x03);
6534 goto int13_success_noah;
6535 break;
6536
6537 // all those functions return unimplemented
6538 case 0x0a: /* read disk sectors with ECC */
6539 case 0x0b: /* write disk sectors with ECC */
6540 case 0x18: /* set media type for format */
6541 case 0x41: // IBM/MS installation check
6542 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6543 case 0x42: // IBM/MS extended read
6544 case 0x43: // IBM/MS extended write
6545 case 0x44: // IBM/MS verify sectors
6546 case 0x45: // IBM/MS lock/unlock drive
6547 case 0x46: // IBM/MS eject media
6548 case 0x47: // IBM/MS extended seek
6549 case 0x48: // IBM/MS get drive parameters
6550 case 0x49: // IBM/MS extended media change
6551 case 0x4e: // ? - set hardware configuration
6552 case 0x50: // ? - send packet command
6553 default:
6554 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6555 goto int13_fail;
6556 break;
6557 }
6558
6559int13_fail:
6560 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6561int13_fail_noah:
6562 SET_DISK_RET_STATUS(GET_AH());
6563int13_fail_nostatus:
6564 SET_CF(); // error occurred
6565 return;
6566
6567int13_success:
6568 SET_AH(0x00); // no error
6569int13_success_noah:
6570 SET_DISK_RET_STATUS(0x00);
6571 CLEAR_CF(); // no error
6572 return;
6573}
6574
6575// ---------------------------------------------------------------------------
6576// End of int13 when emulating a device from the cd
6577// ---------------------------------------------------------------------------
6578
6579#endif // BX_ELTORITO_BOOT
6580
6581#else //BX_USE_ATADRV
6582
6583 void
6584outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6585 Bit16u cylinder;
6586 Bit16u hd_heads;
6587 Bit16u head;
6588 Bit16u hd_sectors;
6589 Bit16u sector;
6590 Bit16u dl;
6591{
6592ASM_START
6593 push bp
6594 mov bp, sp
6595 push eax
6596 push ebx
6597 push edx
6598 xor eax,eax
6599 mov ax,4[bp] // cylinder
6600 xor ebx,ebx
6601 mov bl,6[bp] // hd_heads
6602 imul ebx
6603
6604 mov bl,8[bp] // head
6605 add eax,ebx
6606 mov bl,10[bp] // hd_sectors
6607 imul ebx
6608 mov bl,12[bp] // sector
6609 add eax,ebx
6610
6611 dec eax
6612 mov dx,#0x1f3
6613 out dx,al
6614 mov dx,#0x1f4
6615 mov al,ah
6616 out dx,al
6617 shr eax,#16
6618 mov dx,#0x1f5
6619 out dx,al
6620 and ah,#0xf
6621 mov bl,14[bp] // dl
6622 and bl,#1
6623 shl bl,#4
6624 or ah,bl
6625 or ah,#0xe0
6626 mov al,ah
6627 mov dx,#0x01f6
6628 out dx,al
6629 pop edx
6630 pop ebx
6631 pop eax
6632 pop bp
6633ASM_END
6634}
6635
6636 void
6637int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6638 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6639{
6640 Bit8u drive, num_sectors, sector, head, status, mod;
6641 Bit8u drive_map;
6642 Bit8u n_drives;
6643 Bit16u cyl_mod, ax;
6644 Bit16u max_cylinder, cylinder, total_sectors;
6645 Bit16u hd_cylinders;
6646 Bit8u hd_heads, hd_sectors;
6647 Bit16u val16;
6648 Bit8u sector_count;
6649 unsigned int i;
6650 Bit16u tempbx;
6651 Bit16u dpsize;
6652
6653 Bit16u count, segment, offset;
6654 Bit32u lba;
6655 Bit16u error;
6656
6657 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6658
6659 write_byte(0x0040, 0x008e, 0); // clear completion flag
6660
6661 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6662 handler code */
6663 /* check how many disks first (cmos reg 0x12), return an error if
6664 drive not present */
6665 drive_map = inb_cmos(0x12);
6666 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6667 (((drive_map & 0x0f)==0) ? 0 : 2);
6668 n_drives = (drive_map==0) ? 0 :
6669 ((drive_map==3) ? 2 : 1);
6670
6671 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6672 SET_AH(0x01);
6673 SET_DISK_RET_STATUS(0x01);
6674 SET_CF(); /* error occurred */
6675 return;
6676 }
6677
6678 switch (GET_AH()) {
6679
6680 case 0x00: /* disk controller reset */
6681BX_DEBUG_INT13_HD("int13_f00\n");
6682
6683 SET_AH(0);
6684 SET_DISK_RET_STATUS(0);
6685 set_diskette_ret_status(0);
6686 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6687 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6688 CLEAR_CF(); /* successful */
6689 return;
6690 break;
6691
6692 case 0x01: /* read disk status */
6693BX_DEBUG_INT13_HD("int13_f01\n");
6694 status = read_byte(0x0040, 0x0074);
6695 SET_AH(status);
6696 SET_DISK_RET_STATUS(0);
6697 /* set CF if error status read */
6698 if (status) SET_CF();
6699 else CLEAR_CF();
6700 return;
6701 break;
6702
6703 case 0x04: // verify disk sectors
6704 case 0x02: // read disk sectors
6705 drive = GET_ELDL();
6706 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6707
6708 num_sectors = GET_AL();
6709 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6710 sector = (GET_CL() & 0x3f);
6711 head = GET_DH();
6712
6713
6714 if (hd_cylinders > 1024) {
6715 if (hd_cylinders <= 2048) {
6716 cylinder <<= 1;
6717 }
6718 else if (hd_cylinders <= 4096) {
6719 cylinder <<= 2;
6720 }
6721 else if (hd_cylinders <= 8192) {
6722 cylinder <<= 3;
6723 }
6724 else { // hd_cylinders <= 16384
6725 cylinder <<= 4;
6726 }
6727
6728 ax = head / hd_heads;
6729 cyl_mod = ax & 0xff;
6730 head = ax >> 8;
6731 cylinder |= cyl_mod;
6732 }
6733
6734 if ( (cylinder >= hd_cylinders) ||
6735 (sector > hd_sectors) ||
6736 (head >= hd_heads) ) {
6737 SET_AH(1);
6738 SET_DISK_RET_STATUS(1);
6739 SET_CF(); /* error occurred */
6740 return;
6741 }
6742
6743 if ( (num_sectors > 128) || (num_sectors == 0) )
6744 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6745
6746 if (head > 15)
6747 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6748
6749 if ( GET_AH() == 0x04 ) {
6750 SET_AH(0);
6751 SET_DISK_RET_STATUS(0);
6752 CLEAR_CF();
6753 return;
6754 }
6755
6756 status = inb(0x1f7);
6757 if (status & 0x80) {
6758 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6759 }
6760 outb(0x01f2, num_sectors);
6761 /* activate LBA? (tomv) */
6762 if (hd_heads > 16) {
6763BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6764 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6765 }
6766 else {
6767 outb(0x01f3, sector);
6768 outb(0x01f4, cylinder & 0x00ff);
6769 outb(0x01f5, cylinder >> 8);
6770 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6771 }
6772 outb(0x01f7, 0x20);
6773
6774 while (1) {
6775 status = inb(0x1f7);
6776 if ( !(status & 0x80) ) break;
6777 }
6778
6779 if (status & 0x01) {
6780 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6781 } else if ( !(status & 0x08) ) {
6782 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6783 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6784 }
6785
6786 sector_count = 0;
6787 tempbx = BX;
6788
6789ASM_START
6790 sti ;; enable higher priority interrupts
6791ASM_END
6792
6793 while (1) {
6794ASM_START
6795 ;; store temp bx in real DI register
6796 push bp
6797 mov bp, sp
6798 mov di, _int13_harddisk.tempbx + 2 [bp]
6799 pop bp
6800
6801 ;; adjust if there will be an overrun
6802 cmp di, #0xfe00
6803 jbe i13_f02_no_adjust
6804i13_f02_adjust:
6805 sub di, #0x0200 ; sub 512 bytes from offset
6806 mov ax, es
6807 add ax, #0x0020 ; add 512 to segment
6808 mov es, ax
6809
6810i13_f02_no_adjust:
6811 mov cx, #0x0100 ;; counter (256 words = 512b)
6812 mov dx, #0x01f0 ;; AT data read port
6813
6814 rep
6815 insw ;; CX words transfered from port(DX) to ES:[DI]
6816
6817i13_f02_done:
6818 ;; store real DI register back to temp bx
6819 push bp
6820 mov bp, sp
6821 mov _int13_harddisk.tempbx + 2 [bp], di
6822 pop bp
6823ASM_END
6824
6825 sector_count++;
6826 num_sectors--;
6827 if (num_sectors == 0) {
6828 status = inb(0x1f7);
6829 if ( (status & 0xc9) != 0x40 )
6830 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6831 break;
6832 }
6833 else {
6834 status = inb(0x1f7);
6835 if ( (status & 0xc9) != 0x48 )
6836 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6837 continue;
6838 }
6839 }
6840
6841 SET_AH(0);
6842 SET_DISK_RET_STATUS(0);
6843 SET_AL(sector_count);
6844 CLEAR_CF(); /* successful */
6845 return;
6846 break;
6847
6848
6849 case 0x03: /* write disk sectors */
6850BX_DEBUG_INT13_HD("int13_f03\n");
6851 drive = GET_ELDL ();
6852 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6853
6854 num_sectors = GET_AL();
6855 cylinder = GET_CH();
6856 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6857 sector = (GET_CL() & 0x3f);
6858 head = GET_DH();
6859
6860 if (hd_cylinders > 1024) {
6861 if (hd_cylinders <= 2048) {
6862 cylinder <<= 1;
6863 }
6864 else if (hd_cylinders <= 4096) {
6865 cylinder <<= 2;
6866 }
6867 else if (hd_cylinders <= 8192) {
6868 cylinder <<= 3;
6869 }
6870 else { // hd_cylinders <= 16384
6871 cylinder <<= 4;
6872 }
6873
6874 ax = head / hd_heads;
6875 cyl_mod = ax & 0xff;
6876 head = ax >> 8;
6877 cylinder |= cyl_mod;
6878 }
6879
6880 if ( (cylinder >= hd_cylinders) ||
6881 (sector > hd_sectors) ||
6882 (head >= hd_heads) ) {
6883 SET_AH( 1);
6884 SET_DISK_RET_STATUS(1);
6885 SET_CF(); /* error occurred */
6886 return;
6887 }
6888
6889 if ( (num_sectors > 128) || (num_sectors == 0) )
6890 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6891
6892 if (head > 15)
6893 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6894
6895 status = inb(0x1f7);
6896 if (status & 0x80) {
6897 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6898 }
6899// should check for Drive Ready Bit also in status reg
6900 outb(0x01f2, num_sectors);
6901
6902 /* activate LBA? (tomv) */
6903 if (hd_heads > 16) {
6904BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6905 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6906 }
6907 else {
6908 outb(0x01f3, sector);
6909 outb(0x01f4, cylinder & 0x00ff);
6910 outb(0x01f5, cylinder >> 8);
6911 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6912 }
6913 outb(0x01f7, 0x30);
6914
6915 // wait for busy bit to turn off after seeking
6916 while (1) {
6917 status = inb(0x1f7);
6918 if ( !(status & 0x80) ) break;
6919 }
6920
6921 if ( !(status & 0x08) ) {
6922 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6923 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6924 }
6925
6926 sector_count = 0;
6927 tempbx = BX;
6928
6929ASM_START
6930 sti ;; enable higher priority interrupts
6931ASM_END
6932
6933 while (1) {
6934ASM_START
6935 ;; store temp bx in real SI register
6936 push bp
6937 mov bp, sp
6938 mov si, _int13_harddisk.tempbx + 2 [bp]
6939 pop bp
6940
6941 ;; adjust if there will be an overrun
6942 cmp si, #0xfe00
6943 jbe i13_f03_no_adjust
6944i13_f03_adjust:
6945 sub si, #0x0200 ; sub 512 bytes from offset
6946 mov ax, es
6947 add ax, #0x0020 ; add 512 to segment
6948 mov es, ax
6949
6950i13_f03_no_adjust:
6951 mov cx, #0x0100 ;; counter (256 words = 512b)
6952 mov dx, #0x01f0 ;; AT data read port
6953
6954 seg ES
6955 rep
6956 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6957
6958 ;; store real SI register back to temp bx
6959 push bp
6960 mov bp, sp
6961 mov _int13_harddisk.tempbx + 2 [bp], si
6962 pop bp
6963ASM_END
6964
6965 sector_count++;
6966 num_sectors--;
6967 if (num_sectors == 0) {
6968 status = inb(0x1f7);
6969 if ( (status & 0xe9) != 0x40 )
6970 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6971 break;
6972 }
6973 else {
6974 status = inb(0x1f7);
6975 if ( (status & 0xc9) != 0x48 )
6976 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6977 continue;
6978 }
6979 }
6980
6981 SET_AH(0);
6982 SET_DISK_RET_STATUS(0);
6983 SET_AL(sector_count);
6984 CLEAR_CF(); /* successful */
6985 return;
6986 break;
6987
6988 case 0x05: /* format disk track */
6989BX_DEBUG_INT13_HD("int13_f05\n");
6990 BX_PANIC("format disk track called\n");
6991 /* nop */
6992 SET_AH(0);
6993 SET_DISK_RET_STATUS(0);
6994 CLEAR_CF(); /* successful */
6995 return;
6996 break;
6997
6998 case 0x08: /* read disk drive parameters */
6999BX_DEBUG_INT13_HD("int13_f08\n");
7000
7001 drive = GET_ELDL ();
7002 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7003
7004 // translate CHS
7005 //
7006 if (hd_cylinders <= 1024) {
7007 // hd_cylinders >>= 0;
7008 // hd_heads <<= 0;
7009 }
7010 else if (hd_cylinders <= 2048) {
7011 hd_cylinders >>= 1;
7012 hd_heads <<= 1;
7013 }
7014 else if (hd_cylinders <= 4096) {
7015 hd_cylinders >>= 2;
7016 hd_heads <<= 2;
7017 }
7018 else if (hd_cylinders <= 8192) {
7019 hd_cylinders >>= 3;
7020 hd_heads <<= 3;
7021 }
7022 else { // hd_cylinders <= 16384
7023 hd_cylinders >>= 4;
7024 hd_heads <<= 4;
7025 }
7026
7027 max_cylinder = hd_cylinders - 2; /* 0 based */
7028 SET_AL(0);
7029 SET_CH(max_cylinder & 0xff);
7030 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7031 SET_DH(hd_heads - 1);
7032 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7033 SET_AH(0);
7034 SET_DISK_RET_STATUS(0);
7035 CLEAR_CF(); /* successful */
7036
7037 return;
7038 break;
7039
7040 case 0x09: /* initialize drive parameters */
7041BX_DEBUG_INT13_HD("int13_f09\n");
7042 SET_AH(0);
7043 SET_DISK_RET_STATUS(0);
7044 CLEAR_CF(); /* successful */
7045 return;
7046 break;
7047
7048 case 0x0a: /* read disk sectors with ECC */
7049BX_DEBUG_INT13_HD("int13_f0a\n");
7050 case 0x0b: /* write disk sectors with ECC */
7051BX_DEBUG_INT13_HD("int13_f0b\n");
7052 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7053 return;
7054 break;
7055
7056 case 0x0c: /* seek to specified cylinder */
7057BX_DEBUG_INT13_HD("int13_f0c\n");
7058 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7059 SET_AH(0);
7060 SET_DISK_RET_STATUS(0);
7061 CLEAR_CF(); /* successful */
7062 return;
7063 break;
7064
7065 case 0x0d: /* alternate disk reset */
7066BX_DEBUG_INT13_HD("int13_f0d\n");
7067 SET_AH(0);
7068 SET_DISK_RET_STATUS(0);
7069 CLEAR_CF(); /* successful */
7070 return;
7071 break;
7072
7073 case 0x10: /* check drive ready */
7074BX_DEBUG_INT13_HD("int13_f10\n");
7075 //SET_AH(0);
7076 //SET_DISK_RET_STATUS(0);
7077 //CLEAR_CF(); /* successful */
7078 //return;
7079 //break;
7080
7081 // should look at 40:8E also???
7082 status = inb(0x01f7);
7083 if ( (status & 0xc0) == 0x40 ) {
7084 SET_AH(0);
7085 SET_DISK_RET_STATUS(0);
7086 CLEAR_CF(); // drive ready
7087 return;
7088 }
7089 else {
7090 SET_AH(0xAA);
7091 SET_DISK_RET_STATUS(0xAA);
7092 SET_CF(); // not ready
7093 return;
7094 }
7095 break;
7096
7097 case 0x11: /* recalibrate */
7098BX_DEBUG_INT13_HD("int13_f11\n");
7099 SET_AH(0);
7100 SET_DISK_RET_STATUS(0);
7101 CLEAR_CF(); /* successful */
7102 return;
7103 break;
7104
7105 case 0x14: /* controller internal diagnostic */
7106BX_DEBUG_INT13_HD("int13_f14\n");
7107 SET_AH(0);
7108 SET_DISK_RET_STATUS(0);
7109 CLEAR_CF(); /* successful */
7110 SET_AL(0);
7111 return;
7112 break;
7113
7114 case 0x15: /* read disk drive size */
7115 drive = GET_ELDL();
7116 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7117ASM_START
7118 push bp
7119 mov bp, sp
7120 mov al, _int13_harddisk.hd_heads + 2 [bp]
7121 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7122 mul al, ah ;; ax = heads * sectors
7123 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7124 dec bx ;; use (cylinders - 1) ???
7125 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7126 ;; now we need to move the 32bit result dx:ax to what the
7127 ;; BIOS wants which is cx:dx.
7128 ;; and then into CX:DX on the stack
7129 mov _int13_harddisk.CX + 2 [bp], dx
7130 mov _int13_harddisk.DX + 2 [bp], ax
7131 pop bp
7132ASM_END
7133 SET_AH(3); // hard disk accessible
7134 SET_DISK_RET_STATUS(0); // ??? should this be 0
7135 CLEAR_CF(); // successful
7136 return;
7137 break;
7138
7139 case 0x18: // set media type for format
7140 case 0x41: // IBM/MS
7141 case 0x42: // IBM/MS
7142 case 0x43: // IBM/MS
7143 case 0x44: // IBM/MS
7144 case 0x45: // IBM/MS lock/unlock drive
7145 case 0x46: // IBM/MS eject media
7146 case 0x47: // IBM/MS extended seek
7147 case 0x49: // IBM/MS extended media change
7148 case 0x50: // IBM/MS send packet command
7149 default:
7150 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7151
7152 SET_AH(1); // code=invalid function in AH or invalid parameter
7153 SET_DISK_RET_STATUS(1);
7154 SET_CF(); /* unsuccessful */
7155 return;
7156 break;
7157 }
7158}
7159
7160static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7161static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7162
7163 void
7164get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7165 Bit8u drive;
7166 Bit16u *hd_cylinders;
7167 Bit8u *hd_heads;
7168 Bit8u *hd_sectors;
7169{
7170 Bit8u hd_type;
7171 Bit16u ss;
7172 Bit16u cylinders;
7173 Bit8u iobase;
7174
7175 ss = get_SS();
7176 if (drive == 0x80) {
7177 hd_type = inb_cmos(0x12) & 0xf0;
7178 if (hd_type != 0xf0)
7179 BX_INFO(panic_msg_reg12h,0);
7180 hd_type = inb_cmos(0x19); // HD0: extended type
7181 if (hd_type != 47)
7182 BX_INFO(panic_msg_reg19h,0,0x19);
7183 iobase = 0x1b;
7184 } else {
7185 hd_type = inb_cmos(0x12) & 0x0f;
7186 if (hd_type != 0x0f)
7187 BX_INFO(panic_msg_reg12h,1);
7188 hd_type = inb_cmos(0x1a); // HD1: extended type
7189 if (hd_type != 47)
7190 BX_INFO(panic_msg_reg19h,0,0x1a);
7191 iobase = 0x24;
7192 }
7193
7194 // cylinders
7195 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7196 write_word(ss, hd_cylinders, cylinders);
7197
7198 // heads
7199 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7200
7201 // sectors per track
7202 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7203}
7204
7205#endif //else BX_USE_ATADRV
7206
7207#if BX_SUPPORT_FLOPPY
7208
7209//////////////////////
7210// FLOPPY functions //
7211//////////////////////
7212
7213void floppy_reset_controller()
7214{
7215 Bit8u val8;
7216
7217 // Reset controller
7218 val8 = inb(0x03f2);
7219 outb(0x03f2, val8 & ~0x04);
7220 outb(0x03f2, val8 | 0x04);
7221
7222 // Wait for controller to come out of reset
7223 do {
7224 val8 = inb(0x3f4);
7225 } while ( (val8 & 0xc0) != 0x80 );
7226}
7227
7228void floppy_prepare_controller(drive)
7229 Bit16u drive;
7230{
7231 Bit8u val8, dor, prev_reset;
7232
7233 // set 40:3e bit 7 to 0
7234 val8 = read_byte(0x0040, 0x003e);
7235 val8 &= 0x7f;
7236 write_byte(0x0040, 0x003e, val8);
7237
7238 // turn on motor of selected drive, DMA & int enabled, normal operation
7239 prev_reset = inb(0x03f2) & 0x04;
7240 if (drive)
7241 dor = 0x20;
7242 else
7243 dor = 0x10;
7244 dor |= 0x0c;
7245 dor |= drive;
7246 outb(0x03f2, dor);
7247
7248 // reset the disk motor timeout value of INT 08
7249 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7250
7251#ifdef VBOX
7252 // program data rate
7253 val8 = read_byte(0x0040, 0x008b);
7254 val8 >>= 6;
7255 outb(0x03f7, val8);
7256#endif
7257
7258 // wait for drive readiness
7259 do {
7260 val8 = inb(0x3f4);
7261 } while ( (val8 & 0xc0) != 0x80 );
7262
7263 if (prev_reset == 0) {
7264 // turn on interrupts
7265ASM_START
7266 sti
7267ASM_END
7268 // wait on 40:3e bit 7 to become 1
7269 do {
7270 val8 = read_byte(0x0040, 0x003e);
7271 } while ( (val8 & 0x80) == 0 );
7272 val8 &= 0x7f;
7273ASM_START
7274 cli
7275ASM_END
7276 write_byte(0x0040, 0x003e, val8);
7277 }
7278}
7279
7280 bx_bool
7281floppy_media_known(drive)
7282 Bit16u drive;
7283{
7284 Bit8u val8;
7285 Bit16u media_state_offset;
7286
7287 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7288 if (drive)
7289 val8 >>= 1;
7290 val8 &= 0x01;
7291 if (val8 == 0)
7292 return(0);
7293
7294 media_state_offset = 0x0090;
7295 if (drive)
7296 media_state_offset += 1;
7297
7298 val8 = read_byte(0x0040, media_state_offset);
7299 val8 = (val8 >> 4) & 0x01;
7300 if (val8 == 0)
7301 return(0);
7302
7303 // check pass, return KNOWN
7304 return(1);
7305}
7306
7307 bx_bool
7308floppy_media_sense(drive)
7309 Bit16u drive;
7310{
7311 bx_bool retval;
7312 Bit16u media_state_offset;
7313 Bit8u drive_type, config_data, media_state;
7314
7315 if (floppy_drive_recal(drive) == 0) {
7316 return(0);
7317 }
7318
7319 // for now cheat and get drive type from CMOS,
7320 // assume media is same as drive type
7321
7322 // ** config_data **
7323 // Bitfields for diskette media control:
7324 // Bit(s) Description (Table M0028)
7325 // 7-6 last data rate set by controller
7326 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7327 // 5-4 last diskette drive step rate selected
7328 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7329 // 3-2 {data rate at start of operation}
7330 // 1-0 reserved
7331
7332 // ** media_state **
7333 // Bitfields for diskette drive media state:
7334 // Bit(s) Description (Table M0030)
7335 // 7-6 data rate
7336 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7337 // 5 double stepping required (e.g. 360kB in 1.2MB)
7338 // 4 media type established
7339 // 3 drive capable of supporting 4MB media
7340 // 2-0 on exit from BIOS, contains
7341 // 000 trying 360kB in 360kB
7342 // 001 trying 360kB in 1.2MB
7343 // 010 trying 1.2MB in 1.2MB
7344 // 011 360kB in 360kB established
7345 // 100 360kB in 1.2MB established
7346 // 101 1.2MB in 1.2MB established
7347 // 110 reserved
7348 // 111 all other formats/drives
7349
7350 drive_type = inb_cmos(0x10);
7351 if (drive == 0)
7352 drive_type >>= 4;
7353 else
7354 drive_type &= 0x0f;
7355 if ( drive_type == 1 ) {
7356 // 360K 5.25" drive
7357 config_data = 0x00; // 0000 0000
7358 media_state = 0x25; // 0010 0101
7359 retval = 1;
7360 }
7361 else if ( drive_type == 2 ) {
7362 // 1.2 MB 5.25" drive
7363 config_data = 0x00; // 0000 0000
7364 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7365 retval = 1;
7366 }
7367 else if ( drive_type == 3 ) {
7368 // 720K 3.5" drive
7369 config_data = 0x00; // 0000 0000 ???
7370 media_state = 0x17; // 0001 0111
7371 retval = 1;
7372 }
7373 else if ( drive_type == 4 ) {
7374 // 1.44 MB 3.5" drive
7375 config_data = 0x00; // 0000 0000
7376 media_state = 0x17; // 0001 0111
7377 retval = 1;
7378 }
7379 else if ( drive_type == 5 ) {
7380 // 2.88 MB 3.5" drive
7381 config_data = 0xCC; // 1100 1100
7382 media_state = 0xD7; // 1101 0111
7383 retval = 1;
7384 }
7385 //
7386 // Extended floppy size uses special cmos setting
7387 else if ( drive_type == 6 ) {
7388 // 160k 5.25" drive
7389 config_data = 0x00; // 0000 0000
7390 media_state = 0x27; // 0010 0111
7391 retval = 1;
7392 }
7393 else if ( drive_type == 7 ) {
7394 // 180k 5.25" drive
7395 config_data = 0x00; // 0000 0000
7396 media_state = 0x27; // 0010 0111
7397 retval = 1;
7398 }
7399 else if ( drive_type == 8 ) {
7400 // 320k 5.25" drive
7401 config_data = 0x00; // 0000 0000
7402 media_state = 0x27; // 0010 0111
7403 retval = 1;
7404 }
7405
7406 else {
7407 // not recognized
7408 config_data = 0x00; // 0000 0000
7409 media_state = 0x00; // 0000 0000
7410 retval = 0;
7411 }
7412
7413 if (drive == 0)
7414 media_state_offset = 0x90;
7415 else
7416 media_state_offset = 0x91;
7417 write_byte(0x0040, 0x008B, config_data);
7418 write_byte(0x0040, media_state_offset, media_state);
7419
7420 return(retval);
7421}
7422
7423 bx_bool
7424floppy_drive_recal(drive)
7425 Bit16u drive;
7426{
7427 Bit8u val8;
7428 Bit16u curr_cyl_offset;
7429
7430 floppy_prepare_controller(drive);
7431
7432 // send Recalibrate command (2 bytes) to controller
7433 outb(0x03f5, 0x07); // 07: Recalibrate
7434 outb(0x03f5, drive); // 0=drive0, 1=drive1
7435
7436 // turn on interrupts
7437ASM_START
7438 sti
7439ASM_END
7440
7441 // wait on 40:3e bit 7 to become 1
7442 do {
7443 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7444 } while ( val8 == 0 );
7445
7446 val8 = 0; // separate asm from while() loop
7447 // turn off interrupts
7448ASM_START
7449 cli
7450ASM_END
7451
7452 // set 40:3e bit 7 to 0, and calibrated bit
7453 val8 = read_byte(0x0040, 0x003e);
7454 val8 &= 0x7f;
7455 if (drive) {
7456 val8 |= 0x02; // Drive 1 calibrated
7457 curr_cyl_offset = 0x0095;
7458 } else {
7459 val8 |= 0x01; // Drive 0 calibrated
7460 curr_cyl_offset = 0x0094;
7461 }
7462 write_byte(0x0040, 0x003e, val8);
7463 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7464
7465 return(1);
7466}
7467
7468
7469
7470 bx_bool
7471floppy_drive_exists(drive)
7472 Bit16u drive;
7473{
7474 Bit8u drive_type;
7475
7476 // check CMOS to see if drive exists
7477 drive_type = inb_cmos(0x10);
7478 if (drive == 0)
7479 drive_type >>= 4;
7480 else
7481 drive_type &= 0x0f;
7482 if ( drive_type == 0 )
7483 return(0);
7484 else
7485 return(1);
7486}
7487
7488 void
7489int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7490 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7491{
7492 Bit8u drive, num_sectors, track, sector, head, status;
7493 Bit16u base_address, base_count, base_es;
7494 Bit8u page, mode_register, val8, dor;
7495 Bit8u return_status[7];
7496 Bit8u drive_type, num_floppies, ah;
7497 Bit16u es, last_addr;
7498
7499 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7500
7501 ah = GET_AH();
7502
7503 switch ( ah ) {
7504 case 0x00: // diskette controller reset
7505BX_DEBUG_INT13_FL("floppy f00\n");
7506 drive = GET_ELDL();
7507 if (drive > 1) {
7508 SET_AH(1); // invalid param
7509 set_diskette_ret_status(1);
7510 SET_CF();
7511 return;
7512 }
7513 drive_type = inb_cmos(0x10);
7514
7515 if (drive == 0)
7516 drive_type >>= 4;
7517 else
7518 drive_type &= 0x0f;
7519 if (drive_type == 0) {
7520 SET_AH(0x80); // drive not responding
7521 set_diskette_ret_status(0x80);
7522 SET_CF();
7523 return;
7524 }
7525 SET_AH(0);
7526 set_diskette_ret_status(0);
7527 CLEAR_CF(); // successful
7528 set_diskette_current_cyl(drive, 0); // current cylinder
7529 return;
7530
7531 case 0x01: // Read Diskette Status
7532 CLEAR_CF();
7533 val8 = read_byte(0x0000, 0x0441);
7534 SET_AH(val8);
7535 if (val8) {
7536 SET_CF();
7537 }
7538 return;
7539
7540 case 0x02: // Read Diskette Sectors
7541 case 0x03: // Write Diskette Sectors
7542 case 0x04: // Verify Diskette Sectors
7543 num_sectors = GET_AL();
7544 track = GET_CH();
7545 sector = GET_CL();
7546 head = GET_DH();
7547 drive = GET_ELDL();
7548
7549 if ( (drive > 1) || (head > 1) ||
7550 (num_sectors == 0) || (num_sectors > 72) ) {
7551BX_INFO("floppy: drive>1 || head>1 ...\n");
7552 SET_AH(1);
7553 set_diskette_ret_status(1);
7554 SET_AL(0); // no sectors read
7555 SET_CF(); // error occurred
7556 return;
7557 }
7558
7559 // see if drive exists
7560 if (floppy_drive_exists(drive) == 0) {
7561 SET_AH(0x80); // not responding
7562 set_diskette_ret_status(0x80);
7563 SET_AL(0); // no sectors read
7564 SET_CF(); // error occurred
7565 return;
7566 }
7567
7568 // see if media in drive, and type is known
7569 if (floppy_media_known(drive) == 0) {
7570 if (floppy_media_sense(drive) == 0) {
7571 SET_AH(0x0C); // Media type not found
7572 set_diskette_ret_status(0x0C);
7573 SET_AL(0); // no sectors read
7574 SET_CF(); // error occurred
7575 return;
7576 }
7577 }
7578
7579 if (ah == 0x02) {
7580 // Read Diskette Sectors
7581
7582 //-----------------------------------
7583 // set up DMA controller for transfer
7584 //-----------------------------------
7585
7586 // es:bx = pointer to where to place information from diskette
7587 // port 04: DMA-1 base and current address, channel 2
7588 // port 05: DMA-1 base and current count, channel 2
7589 page = (ES >> 12); // upper 4 bits
7590 base_es = (ES << 4); // lower 16bits contributed by ES
7591 base_address = base_es + BX; // lower 16 bits of address
7592 // contributed by ES:BX
7593 if ( base_address < base_es ) {
7594 // in case of carry, adjust page by 1
7595 page++;
7596 }
7597 base_count = (num_sectors * 512) - 1;
7598
7599 // check for 64K boundary overrun
7600 last_addr = base_address + base_count;
7601 if (last_addr < base_address) {
7602 SET_AH(0x09);
7603 set_diskette_ret_status(0x09);
7604 SET_AL(0); // no sectors read
7605 SET_CF(); // error occurred
7606 return;
7607 }
7608
7609 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7610 outb(0x000a, 0x06);
7611
7612 BX_DEBUG_INT13_FL("clear flip-flop\n");
7613 outb(0x000c, 0x00); // clear flip-flop
7614 outb(0x0004, base_address);
7615 outb(0x0004, base_address>>8);
7616 BX_DEBUG_INT13_FL("clear flip-flop\n");
7617 outb(0x000c, 0x00); // clear flip-flop
7618 outb(0x0005, base_count);
7619 outb(0x0005, base_count>>8);
7620
7621 // port 0b: DMA-1 Mode Register
7622 mode_register = 0x46; // single mode, increment, autoinit disable,
7623 // transfer type=write, channel 2
7624 BX_DEBUG_INT13_FL("setting mode register\n");
7625 outb(0x000b, mode_register);
7626
7627 BX_DEBUG_INT13_FL("setting page register\n");
7628 // port 81: DMA-1 Page Register, channel 2
7629 outb(0x0081, page);
7630
7631 BX_DEBUG_INT13_FL("unmask chan 2\n");
7632 outb(0x000a, 0x02); // unmask channel 2
7633
7634 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7635 outb(0x000a, 0x02);
7636
7637 //--------------------------------------
7638 // set up floppy controller for transfer
7639 //--------------------------------------
7640 floppy_prepare_controller(drive);
7641
7642 // send read-normal-data command (9 bytes) to controller
7643 outb(0x03f5, 0xe6); // e6: read normal data
7644 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7645 outb(0x03f5, track);
7646 outb(0x03f5, head);
7647 outb(0x03f5, sector);
7648 outb(0x03f5, 2); // 512 byte sector size
7649 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7650 outb(0x03f5, 0); // Gap length
7651 outb(0x03f5, 0xff); // Gap length
7652
7653 // turn on interrupts
7654 ASM_START
7655 sti
7656 ASM_END
7657
7658 // wait on 40:3e bit 7 to become 1
7659 do {
7660 val8 = read_byte(0x0040, 0x0040);
7661 if (val8 == 0) {
7662 floppy_reset_controller();
7663 SET_AH(0x80); // drive not ready (timeout)
7664 set_diskette_ret_status(0x80);
7665 SET_AL(0); // no sectors read
7666 SET_CF(); // error occurred
7667 return;
7668 }
7669 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7670 } while ( val8 == 0 );
7671
7672 val8 = 0; // separate asm from while() loop
7673 // turn off interrupts
7674 ASM_START
7675 cli
7676 ASM_END
7677
7678 // set 40:3e bit 7 to 0
7679 val8 = read_byte(0x0040, 0x003e);
7680 val8 &= 0x7f;
7681 write_byte(0x0040, 0x003e, val8);
7682
7683 // check port 3f4 for accessibility to status bytes
7684 val8 = inb(0x3f4);
7685 if ( (val8 & 0xc0) != 0xc0 )
7686 BX_PANIC("int13_diskette: ctrl not ready\n");
7687
7688 // read 7 return status bytes from controller
7689 // using loop index broken, have to unroll...
7690 return_status[0] = inb(0x3f5);
7691 return_status[1] = inb(0x3f5);
7692 return_status[2] = inb(0x3f5);
7693 return_status[3] = inb(0x3f5);
7694 return_status[4] = inb(0x3f5);
7695 return_status[5] = inb(0x3f5);
7696 return_status[6] = inb(0x3f5);
7697 // record in BIOS Data Area
7698 write_byte(0x0040, 0x0042, return_status[0]);
7699 write_byte(0x0040, 0x0043, return_status[1]);
7700 write_byte(0x0040, 0x0044, return_status[2]);
7701 write_byte(0x0040, 0x0045, return_status[3]);
7702 write_byte(0x0040, 0x0046, return_status[4]);
7703 write_byte(0x0040, 0x0047, return_status[5]);
7704 write_byte(0x0040, 0x0048, return_status[6]);
7705
7706 if ( (return_status[0] & 0xc0) != 0 ) {
7707 SET_AH(0x20);
7708 set_diskette_ret_status(0x20);
7709 SET_AL(0); // no sectors read
7710 SET_CF(); // error occurred
7711 return;
7712 }
7713
7714 // ??? should track be new val from return_status[3] ?
7715 set_diskette_current_cyl(drive, track);
7716 // AL = number of sectors read (same value as passed)
7717 SET_AH(0x00); // success
7718 CLEAR_CF(); // success
7719 return;
7720 } else if (ah == 0x03) {
7721 // Write Diskette Sectors
7722
7723 //-----------------------------------
7724 // set up DMA controller for transfer
7725 //-----------------------------------
7726
7727 // es:bx = pointer to where to place information from diskette
7728 // port 04: DMA-1 base and current address, channel 2
7729 // port 05: DMA-1 base and current count, channel 2
7730 page = (ES >> 12); // upper 4 bits
7731 base_es = (ES << 4); // lower 16bits contributed by ES
7732 base_address = base_es + BX; // lower 16 bits of address
7733 // contributed by ES:BX
7734 if ( base_address < base_es ) {
7735 // in case of carry, adjust page by 1
7736 page++;
7737 }
7738 base_count = (num_sectors * 512) - 1;
7739
7740 // check for 64K boundary overrun
7741 last_addr = base_address + base_count;
7742 if (last_addr < base_address) {
7743 SET_AH(0x09);
7744 set_diskette_ret_status(0x09);
7745 SET_AL(0); // no sectors read
7746 SET_CF(); // error occurred
7747 return;
7748 }
7749
7750 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7751 outb(0x000a, 0x06);
7752
7753 outb(0x000c, 0x00); // clear flip-flop
7754 outb(0x0004, base_address);
7755 outb(0x0004, base_address>>8);
7756 outb(0x000c, 0x00); // clear flip-flop
7757 outb(0x0005, base_count);
7758 outb(0x0005, base_count>>8);
7759
7760 // port 0b: DMA-1 Mode Register
7761 mode_register = 0x4a; // single mode, increment, autoinit disable,
7762 // transfer type=read, channel 2
7763 outb(0x000b, mode_register);
7764
7765 // port 81: DMA-1 Page Register, channel 2
7766 outb(0x0081, page);
7767
7768 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7769 outb(0x000a, 0x02);
7770
7771 //--------------------------------------
7772 // set up floppy controller for transfer
7773 //--------------------------------------
7774 floppy_prepare_controller(drive);
7775
7776 // send write-normal-data command (9 bytes) to controller
7777 outb(0x03f5, 0xc5); // c5: write normal data
7778 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7779 outb(0x03f5, track);
7780 outb(0x03f5, head);
7781 outb(0x03f5, sector);
7782 outb(0x03f5, 2); // 512 byte sector size
7783 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7784 outb(0x03f5, 0); // Gap length
7785 outb(0x03f5, 0xff); // Gap length
7786
7787 // turn on interrupts
7788 ASM_START
7789 sti
7790 ASM_END
7791
7792 // wait on 40:3e bit 7 to become 1
7793 do {
7794 val8 = read_byte(0x0040, 0x0040);
7795 if (val8 == 0) {
7796 floppy_reset_controller();
7797 SET_AH(0x80); // drive not ready (timeout)
7798 set_diskette_ret_status(0x80);
7799 SET_AL(0); // no sectors written
7800 SET_CF(); // error occurred
7801 return;
7802 }
7803 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7804 } while ( val8 == 0 );
7805
7806 val8 = 0; // separate asm from while() loop
7807 // turn off interrupts
7808 ASM_START
7809 cli
7810 ASM_END
7811
7812 // set 40:3e bit 7 to 0
7813 val8 = read_byte(0x0040, 0x003e);
7814 val8 &= 0x7f;
7815 write_byte(0x0040, 0x003e, val8);
7816
7817 // check port 3f4 for accessibility to status bytes
7818 val8 = inb(0x3f4);
7819 if ( (val8 & 0xc0) != 0xc0 )
7820 BX_PANIC("int13_diskette: ctrl not ready\n");
7821
7822 // read 7 return status bytes from controller
7823 // using loop index broken, have to unroll...
7824 return_status[0] = inb(0x3f5);
7825 return_status[1] = inb(0x3f5);
7826 return_status[2] = inb(0x3f5);
7827 return_status[3] = inb(0x3f5);
7828 return_status[4] = inb(0x3f5);
7829 return_status[5] = inb(0x3f5);
7830 return_status[6] = inb(0x3f5);
7831 // record in BIOS Data Area
7832 write_byte(0x0040, 0x0042, return_status[0]);
7833 write_byte(0x0040, 0x0043, return_status[1]);
7834 write_byte(0x0040, 0x0044, return_status[2]);
7835 write_byte(0x0040, 0x0045, return_status[3]);
7836 write_byte(0x0040, 0x0046, return_status[4]);
7837 write_byte(0x0040, 0x0047, return_status[5]);
7838 write_byte(0x0040, 0x0048, return_status[6]);
7839
7840 if ( (return_status[0] & 0xc0) != 0 ) {
7841 if ( (return_status[1] & 0x02) != 0 ) {
7842 // diskette not writable.
7843 // AH=status code=0x03 (tried to write on write-protected disk)
7844 // AL=number of sectors written=0
7845 AX = 0x0300;
7846 SET_CF();
7847 return;
7848 } else {
7849 BX_PANIC("int13_diskette_function: read error\n");
7850 }
7851 }
7852
7853 // ??? should track be new val from return_status[3] ?
7854 set_diskette_current_cyl(drive, track);
7855 // AL = number of sectors read (same value as passed)
7856 SET_AH(0x00); // success
7857 CLEAR_CF(); // success
7858 return;
7859 } else { // if (ah == 0x04)
7860 // Verify Diskette Sectors
7861
7862 // ??? should track be new val from return_status[3] ?
7863 set_diskette_current_cyl(drive, track);
7864 // AL = number of sectors verified (same value as passed)
7865 CLEAR_CF(); // success
7866 SET_AH(0x00); // success
7867 return;
7868 }
7869 break;
7870
7871 case 0x05: // format diskette track
7872BX_DEBUG_INT13_FL("floppy f05\n");
7873
7874 num_sectors = GET_AL();
7875 track = GET_CH();
7876 head = GET_DH();
7877 drive = GET_ELDL();
7878
7879 if ((drive > 1) || (head > 1) || (track > 79) ||
7880 (num_sectors == 0) || (num_sectors > 18)) {
7881 SET_AH(1);
7882 set_diskette_ret_status(1);
7883 SET_CF(); // error occurred
7884 }
7885
7886 // see if drive exists
7887 if (floppy_drive_exists(drive) == 0) {
7888 SET_AH(0x80); // drive not responding
7889 set_diskette_ret_status(0x80);
7890 SET_CF(); // error occurred
7891 return;
7892 }
7893
7894 // see if media in drive, and type is known
7895 if (floppy_media_known(drive) == 0) {
7896 if (floppy_media_sense(drive) == 0) {
7897 SET_AH(0x0C); // Media type not found
7898 set_diskette_ret_status(0x0C);
7899 SET_AL(0); // no sectors read
7900 SET_CF(); // error occurred
7901 return;
7902 }
7903 }
7904
7905 // set up DMA controller for transfer
7906 page = (ES >> 12); // upper 4 bits
7907 base_es = (ES << 4); // lower 16bits contributed by ES
7908 base_address = base_es + BX; // lower 16 bits of address
7909 // contributed by ES:BX
7910 if ( base_address < base_es ) {
7911 // in case of carry, adjust page by 1
7912 page++;
7913 }
7914 base_count = (num_sectors * 4) - 1;
7915
7916 // check for 64K boundary overrun
7917 last_addr = base_address + base_count;
7918 if (last_addr < base_address) {
7919 SET_AH(0x09);
7920 set_diskette_ret_status(0x09);
7921 SET_AL(0); // no sectors read
7922 SET_CF(); // error occurred
7923 return;
7924 }
7925
7926 outb(0x000a, 0x06);
7927 outb(0x000c, 0x00); // clear flip-flop
7928 outb(0x0004, base_address);
7929 outb(0x0004, base_address>>8);
7930 outb(0x000c, 0x00); // clear flip-flop
7931 outb(0x0005, base_count);
7932 outb(0x0005, base_count>>8);
7933 mode_register = 0x4a; // single mode, increment, autoinit disable,
7934 // transfer type=read, channel 2
7935 outb(0x000b, mode_register);
7936 // port 81: DMA-1 Page Register, channel 2
7937 outb(0x0081, page);
7938 outb(0x000a, 0x02);
7939
7940 // set up floppy controller for transfer
7941 floppy_prepare_controller(drive);
7942
7943 // send format-track command (6 bytes) to controller
7944 outb(0x03f5, 0x4d); // 4d: format track
7945 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7946 outb(0x03f5, 2); // 512 byte sector size
7947 outb(0x03f5, num_sectors); // number of sectors per track
7948 outb(0x03f5, 0); // Gap length
7949 outb(0x03f5, 0xf6); // Fill byte
7950 // turn on interrupts
7951 ASM_START
7952 sti
7953 ASM_END
7954
7955 // wait on 40:3e bit 7 to become 1
7956 do {
7957 val8 = read_byte(0x0040, 0x0040);
7958 if (val8 == 0) {
7959 floppy_reset_controller();
7960 SET_AH(0x80); // drive not ready (timeout)
7961 set_diskette_ret_status(0x80);
7962 SET_CF(); // error occurred
7963 return;
7964 }
7965 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7966 } while ( val8 == 0 );
7967
7968 val8 = 0; // separate asm from while() loop
7969 // turn off interrupts
7970 ASM_START
7971 cli
7972 ASM_END
7973 // set 40:3e bit 7 to 0
7974 val8 = read_byte(0x0040, 0x003e);
7975 val8 &= 0x7f;
7976 write_byte(0x0040, 0x003e, val8);
7977 // check port 3f4 for accessibility to status bytes
7978 val8 = inb(0x3f4);
7979 if ( (val8 & 0xc0) != 0xc0 )
7980 BX_PANIC("int13_diskette: ctrl not ready\n");
7981
7982 // read 7 return status bytes from controller
7983 // using loop index broken, have to unroll...
7984 return_status[0] = inb(0x3f5);
7985 return_status[1] = inb(0x3f5);
7986 return_status[2] = inb(0x3f5);
7987 return_status[3] = inb(0x3f5);
7988 return_status[4] = inb(0x3f5);
7989 return_status[5] = inb(0x3f5);
7990 return_status[6] = inb(0x3f5);
7991 // record in BIOS Data Area
7992 write_byte(0x0040, 0x0042, return_status[0]);
7993 write_byte(0x0040, 0x0043, return_status[1]);
7994 write_byte(0x0040, 0x0044, return_status[2]);
7995 write_byte(0x0040, 0x0045, return_status[3]);
7996 write_byte(0x0040, 0x0046, return_status[4]);
7997 write_byte(0x0040, 0x0047, return_status[5]);
7998 write_byte(0x0040, 0x0048, return_status[6]);
7999
8000 if ( (return_status[0] & 0xc0) != 0 ) {
8001 if ( (return_status[1] & 0x02) != 0 ) {
8002 // diskette not writable.
8003 // AH=status code=0x03 (tried to write on write-protected disk)
8004 // AL=number of sectors written=0
8005 AX = 0x0300;
8006 SET_CF();
8007 return;
8008 } else {
8009 BX_PANIC("int13_diskette_function: write error\n");
8010 }
8011 }
8012
8013 SET_AH(0);
8014 set_diskette_ret_status(0);
8015 set_diskette_current_cyl(drive, 0);
8016 CLEAR_CF(); // successful
8017 return;
8018
8019
8020 case 0x08: // read diskette drive parameters
8021BX_DEBUG_INT13_FL("floppy f08\n");
8022 drive = GET_ELDL();
8023
8024 if (drive > 1) {
8025 AX = 0;
8026 BX = 0;
8027 CX = 0;
8028 DX = 0;
8029 ES = 0;
8030 DI = 0;
8031 SET_DL(num_floppies);
8032 SET_CF();
8033 return;
8034 }
8035
8036 drive_type = inb_cmos(0x10);
8037 num_floppies = 0;
8038 if (drive_type & 0xf0)
8039 num_floppies++;
8040 if (drive_type & 0x0f)
8041 num_floppies++;
8042
8043 if (drive == 0)
8044 drive_type >>= 4;
8045 else
8046 drive_type &= 0x0f;
8047
8048 SET_BH(0);
8049 SET_BL(drive_type);
8050 SET_AH(0);
8051 SET_AL(0);
8052 SET_DL(num_floppies);
8053
8054 switch (drive_type) {
8055 case 0: // none
8056 CX = 0;
8057 SET_DH(0); // max head #
8058 break;
8059
8060 case 1: // 360KB, 5.25"
8061 CX = 0x2709; // 40 tracks, 9 sectors
8062 SET_DH(1); // max head #
8063 break;
8064
8065 case 2: // 1.2MB, 5.25"
8066 CX = 0x4f0f; // 80 tracks, 15 sectors
8067 SET_DH(1); // max head #
8068 break;
8069
8070 case 3: // 720KB, 3.5"
8071 CX = 0x4f09; // 80 tracks, 9 sectors
8072 SET_DH(1); // max head #
8073 break;
8074
8075 case 4: // 1.44MB, 3.5"
8076 CX = 0x4f12; // 80 tracks, 18 sectors
8077 SET_DH(1); // max head #
8078 break;
8079
8080 case 5: // 2.88MB, 3.5"
8081 CX = 0x4f24; // 80 tracks, 36 sectors
8082 SET_DH(1); // max head #
8083 break;
8084
8085 case 6: // 160k, 5.25"
8086 CX = 0x2708; // 40 tracks, 8 sectors
8087 SET_DH(0); // max head #
8088 break;
8089
8090 case 7: // 180k, 5.25"
8091 CX = 0x2709; // 40 tracks, 9 sectors
8092 SET_DH(0); // max head #
8093 break;
8094
8095 case 8: // 320k, 5.25"
8096 CX = 0x2708; // 40 tracks, 8 sectors
8097 SET_DH(1); // max head #
8098 break;
8099
8100 default: // ?
8101 BX_PANIC("floppy: int13: bad floppy type\n");
8102 }
8103
8104 /* set es & di to point to 11 byte diskette param table in ROM */
8105ASM_START
8106 push bp
8107 mov bp, sp
8108 mov ax, #diskette_param_table2
8109 mov _int13_diskette_function.DI+2[bp], ax
8110 mov _int13_diskette_function.ES+2[bp], cs
8111 pop bp
8112ASM_END
8113 CLEAR_CF(); // success
8114 /* disk status not changed upon success */
8115 return;
8116
8117
8118 case 0x15: // read diskette drive type
8119BX_DEBUG_INT13_FL("floppy f15\n");
8120 drive = GET_ELDL();
8121 if (drive > 1) {
8122 SET_AH(0); // only 2 drives supported
8123 // set_diskette_ret_status here ???
8124 SET_CF();
8125 return;
8126 }
8127 drive_type = inb_cmos(0x10);
8128
8129 if (drive == 0)
8130 drive_type >>= 4;
8131 else
8132 drive_type &= 0x0f;
8133 CLEAR_CF(); // successful, not present
8134 if (drive_type==0) {
8135 SET_AH(0); // drive not present
8136 }
8137 else {
8138 SET_AH(1); // drive present, does not support change line
8139 }
8140
8141 return;
8142
8143 case 0x16: // get diskette change line status
8144BX_DEBUG_INT13_FL("floppy f16\n");
8145 drive = GET_ELDL();
8146 if (drive > 1) {
8147 SET_AH(0x01); // invalid drive
8148 set_diskette_ret_status(0x01);
8149 SET_CF();
8150 return;
8151 }
8152
8153 SET_AH(0x06); // change line not supported
8154 set_diskette_ret_status(0x06);
8155 SET_CF();
8156 return;
8157
8158 case 0x17: // set diskette type for format(old)
8159BX_DEBUG_INT13_FL("floppy f17\n");
8160 /* not used for 1.44M floppies */
8161 SET_AH(0x01); // not supported
8162 set_diskette_ret_status(1); /* not supported */
8163 SET_CF();
8164 return;
8165
8166 case 0x18: // set diskette type for format(new)
8167BX_DEBUG_INT13_FL("floppy f18\n");
8168 SET_AH(0x01); // do later
8169 set_diskette_ret_status(1);
8170 SET_CF();
8171 return;
8172
8173 default:
8174 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8175
8176 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8177 SET_AH(0x01); // ???
8178 set_diskette_ret_status(1);
8179 SET_CF();
8180 return;
8181 // }
8182 }
8183}
8184#else // #if BX_SUPPORT_FLOPPY
8185 void
8186int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8187 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8188{
8189 Bit8u val8;
8190
8191 switch ( GET_AH() ) {
8192
8193 case 0x01: // Read Diskette Status
8194 CLEAR_CF();
8195 val8 = read_byte(0x0000, 0x0441);
8196 SET_AH(val8);
8197 if (val8) {
8198 SET_CF();
8199 }
8200 return;
8201
8202 default:
8203 SET_CF();
8204 write_byte(0x0000, 0x0441, 0x01);
8205 SET_AH(0x01);
8206 }
8207}
8208#endif // #if BX_SUPPORT_FLOPPY
8209
8210 void
8211set_diskette_ret_status(value)
8212 Bit8u value;
8213{
8214 write_byte(0x0040, 0x0041, value);
8215}
8216
8217 void
8218set_diskette_current_cyl(drive, cyl)
8219 Bit8u drive;
8220 Bit8u cyl;
8221{
8222 if (drive > 1)
8223 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8224 write_byte(0x0040, 0x0094+drive, cyl);
8225}
8226
8227 void
8228determine_floppy_media(drive)
8229 Bit16u drive;
8230{
8231#if 0
8232 Bit8u val8, DOR, ctrl_info;
8233
8234 ctrl_info = read_byte(0x0040, 0x008F);
8235 if (drive==1)
8236 ctrl_info >>= 4;
8237 else
8238 ctrl_info &= 0x0f;
8239
8240#if 0
8241 if (drive == 0) {
8242 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8243 }
8244 else {
8245 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8246 }
8247#endif
8248
8249 if ( (ctrl_info & 0x04) != 0x04 ) {
8250 // Drive not determined means no drive exists, done.
8251 return;
8252 }
8253
8254#if 0
8255 // check Main Status Register for readiness
8256 val8 = inb(0x03f4) & 0x80; // Main Status Register
8257 if (val8 != 0x80)
8258 BX_PANIC("d_f_m: MRQ bit not set\n");
8259
8260 // change line
8261
8262 // existing BDA values
8263
8264 // turn on drive motor
8265 outb(0x03f2, DOR); // Digital Output Register
8266 //
8267#endif
8268 BX_PANIC("d_f_m: OK so far\n");
8269#endif
8270}
8271
8272 void
8273int17_function(regs, ds, iret_addr)
8274 pusha_regs_t regs; // regs pushed from PUSHA instruction
8275 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8276 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8277{
8278 Bit16u addr,timeout;
8279 Bit8u val8;
8280
8281 ASM_START
8282 sti
8283 ASM_END
8284
8285 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8286 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8287 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8288 if (regs.u.r8.ah == 0) {
8289 outb(addr, regs.u.r8.al);
8290 val8 = inb(addr+2);
8291 outb(addr+2, val8 | 0x01); // send strobe
8292 ASM_START
8293 nop
8294 ASM_END
8295 outb(addr+2, val8 & ~0x01);
8296 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8297 timeout--;
8298 }
8299 }
8300 if (regs.u.r8.ah == 1) {
8301 val8 = inb(addr+2);
8302 outb(addr+2, val8 & ~0x04); // send init
8303 ASM_START
8304 nop
8305 ASM_END
8306 outb(addr+2, val8 | 0x04);
8307 }
8308 val8 = inb(addr+1);
8309 regs.u.r8.ah = (val8 ^ 0x48);
8310 if (!timeout) regs.u.r8.ah |= 0x01;
8311 ClearCF(iret_addr.flags);
8312 } else {
8313 SetCF(iret_addr.flags); // Unsupported
8314 }
8315}
8316
8317// returns bootsegment in ax, drive in bl
8318 Bit32u
8319int19_function(bseqnr)
8320Bit8u bseqnr;
8321{
8322 Bit16u ebda_seg=read_word(0x0040,0x000E);
8323 Bit16u bootseq;
8324 Bit8u bootdrv;
8325 Bit8u bootcd;
8326#ifdef VBOX
8327 Bit8u bootlan;
8328#endif /* VBOX */
8329 Bit8u bootchk;
8330 Bit16u bootseg;
8331 Bit16u status;
8332 Bit8u lastdrive=0;
8333
8334 // if BX_ELTORITO_BOOT is not defined, old behavior
8335 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8336 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8337 // 0: system boot sequence, first drive C: then A:
8338 // 1: system boot sequence, first drive A: then C:
8339 // else BX_ELTORITO_BOOT is defined
8340 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8341 // CMOS reg 0x3D & 0x0f : 1st boot device
8342 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8343 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8344#ifdef VBOX
8345 // CMOS reg 0x3C & 0x0f : 4th boot device
8346#endif /* VBOX */
8347 // boot device codes:
8348 // 0x00 : not defined
8349 // 0x01 : first floppy
8350 // 0x02 : first harddrive
8351 // 0x03 : first cdrom
8352#ifdef VBOX
8353 // 0x04 : local area network
8354#endif /* VBOX */
8355 // else : boot failure
8356
8357 // Get the boot sequence
8358#if BX_ELTORITO_BOOT
8359 bootseq=inb_cmos(0x3d);
8360 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8361#ifdef VBOX
8362 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8363 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8364 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8365 /* Boot delay hack. */
8366 if (bseqnr == 1)
8367 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8368#endif /* VBOX */
8369
8370 if (bseqnr==2) bootseq >>= 4;
8371 if (bseqnr==3) bootseq >>= 8;
8372#ifdef VBOX
8373 if (bseqnr==4) bootseq >>= 12;
8374#endif /* VBOX */
8375 if (bootseq<0x10) lastdrive = 1;
8376 bootdrv=0x00; bootcd=0;
8377#ifdef VBOX
8378 bootlan=0;
8379#endif /* VBOX */
8380
8381 switch(bootseq & 0x0f) {
8382 case 0x01:
8383 bootdrv=0x00;
8384 bootcd=0;
8385 break;
8386 case 0x02:
8387 {
8388 // Get the Boot drive.
8389 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8390
8391 bootdrv = boot_drive + 0x80;
8392 bootcd=0;
8393 break;
8394 }
8395 case 0x03:
8396 bootdrv=0x00;
8397 bootcd=1;
8398 break;
8399#ifdef VBOX
8400 case 0x04: bootlan=1; break;
8401#endif /* VBOX */
8402 default: return 0x00000000;
8403 }
8404#else
8405 bootseq=inb_cmos(0x2d);
8406
8407 if (bseqnr==2) {
8408 bootseq ^= 0x20;
8409 lastdrive = 1;
8410 }
8411 bootdrv=0x00; bootcd=0;
8412 if((bootseq&0x20)==0) bootdrv=0x80;
8413#endif // BX_ELTORITO_BOOT
8414
8415#if BX_ELTORITO_BOOT
8416 // We have to boot from cd
8417 if (bootcd != 0) {
8418 status = cdrom_boot();
8419
8420 // If failure
8421 if ( (status & 0x00ff) !=0 ) {
8422 print_cdromboot_failure(status);
8423#ifdef VBOX
8424 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8425#else /* !VBOX */
8426 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8427#endif /* !VBOX */
8428 return 0x00000000;
8429 }
8430
8431 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8432 bootdrv = (Bit8u)(status>>8);
8433 }
8434
8435#endif // BX_ELTORITO_BOOT
8436
8437#ifdef VBOX
8438 // Check for boot from LAN first
8439 if (bootlan == 1) {
8440 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8441 Bit16u pnpoff;
8442 Bit32u manuf;
8443 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8444 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8445 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8446 // Found PnP signature
8447 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8448 if (manuf == 0x65687445) {
8449 // Found Etherboot ROM
8450 print_boot_device(bootcd, bootlan, bootdrv);
8451ASM_START
8452 push ds
8453 push es
8454 pusha
8455 calli 0x0006,VBOX_LANBOOT_SEG
8456 popa
8457 pop es
8458 pop ds
8459ASM_END
8460 } else if (manuf == 0x65746E49) {
8461 // Found Intel PXE ROM
8462 print_boot_device(bootcd, bootlan, bootdrv);
8463ASM_START
8464 push ds
8465 push es
8466 pusha
8467 sti ; Why are interrupts disabled now? Because we were called through an INT!
8468 push #VBOX_LANBOOT_SEG
8469 pop ds
8470 mov bx,#0x1a ; PnP header offset
8471 mov bx,[bx]
8472 add bx,#0x1a ; BEV offset in PnP header
8473 mov ax,[bx]
8474 test ax,ax
8475 jz no_rom
8476bev_jump:
8477 push cs
8478 push #no_rom
8479 push #VBOX_LANBOOT_SEG
8480 push ax
8481 retf ; call Boot Entry Vector
8482no_rom:
8483 popa
8484 pop es
8485 pop ds
8486ASM_END
8487 }
8488 }
8489 }
8490
8491 // boot from LAN will not return if successful.
8492 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8493 return 0x00000000;
8494 }
8495#endif /* VBOX */
8496 // We have to boot from harddisk or floppy
8497#ifdef VBOX
8498 if (bootcd == 0 && bootlan == 0) {
8499#else /* !VBOX */
8500 if (bootcd == 0) {
8501#endif /* !VBOX */
8502 bootseg=0x07c0;
8503
8504ASM_START
8505 push bp
8506 mov bp, sp
8507
8508 xor ax, ax
8509 mov _int19_function.status + 2[bp], ax
8510 mov dl, _int19_function.bootdrv + 2[bp]
8511 mov ax, _int19_function.bootseg + 2[bp]
8512 mov es, ax ;; segment
8513 xor bx, bx ;; offset
8514 mov ah, #0x02 ;; function 2, read diskette sector
8515 mov al, #0x01 ;; read 1 sector
8516 mov ch, #0x00 ;; track 0
8517 mov cl, #0x01 ;; sector 1
8518 mov dh, #0x00 ;; head 0
8519 int #0x13 ;; read sector
8520 jnc int19_load_done
8521 mov ax, #0x0001
8522 mov _int19_function.status + 2[bp], ax
8523
8524int19_load_done:
8525 pop bp
8526ASM_END
8527
8528 if (status != 0) {
8529#ifdef VBOX
8530 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8531#else /* !VBOX */
8532 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8533#endif /* !VBOX */
8534 return 0x00000000;
8535 }
8536 }
8537
8538#ifdef VBOX
8539 // Don't check boot sectors on floppies and don't read CMOS - byte
8540 // 0x38 in CMOS always has the low bit clear.
8541 // There is *no* requirement whatsoever for a valid boot sector to
8542 // have a 55AAh signature. UNIX boot floppies typically have no such
8543 // signature. In general, it is impossible to tell a valid bootsector
8544 // from an invalid one.
8545 // NB: It is somewhat common for failed OS installs to have the
8546 // 0x55AA signature and a valid partition table but zeros in the
8547 // rest of the boot sector. We do a quick check by comparing the first
8548 // two words of boot sector; if identical, the boot sector is
8549 // extremely unlikely to be valid.
8550#endif
8551 // check signature if instructed by cmos reg 0x38, only for floppy
8552 // bootchk = 1 : signature check disabled
8553 // bootchk = 0 : signature check enabled
8554 if (bootdrv != 0) bootchk = 0;
8555#ifdef VBOX
8556 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8557#else
8558 else bootchk = inb_cmos(0x38) & 0x01;
8559#endif
8560
8561#if BX_ELTORITO_BOOT
8562 // if boot from cd, no signature check
8563 if (bootcd != 0)
8564 bootchk = 1;
8565#endif // BX_ELTORITO_BOOT
8566
8567 if (bootchk == 0) {
8568 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8569 read_word(bootseg,0) == read_word(bootseg,2)) {
8570#ifdef VBOX
8571 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8572#else /* !VBOX */
8573 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8574#endif /* VBOX */
8575 return 0x00000000;
8576 }
8577 }
8578
8579#if BX_ELTORITO_BOOT
8580 // Print out the boot string
8581#ifdef VBOX
8582 print_boot_device(bootcd, bootlan, bootdrv);
8583#else /* !VBOX */
8584 print_boot_device(bootcd, bootdrv);
8585#endif /* !VBOX */
8586#else // BX_ELTORITO_BOOT
8587#ifdef VBOX
8588 print_boot_device(0, bootlan, bootdrv);
8589#else /* !VBOX */
8590 print_boot_device(0, bootdrv);
8591#endif /* !VBOX */
8592#endif // BX_ELTORITO_BOOT
8593
8594 // return the boot segment
8595 return (((Bit32u)bootdrv) << 16) + bootseg;
8596}
8597
8598 void
8599int1a_function(regs, ds, iret_addr)
8600 pusha_regs_t regs; // regs pushed from PUSHA instruction
8601 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8602 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8603{
8604 Bit8u val8;
8605
8606 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);
8607
8608 ASM_START
8609 sti
8610 ASM_END
8611
8612 switch (regs.u.r8.ah) {
8613 case 0: // get current clock count
8614 ASM_START
8615 cli
8616 ASM_END
8617 regs.u.r16.cx = BiosData->ticks_high;
8618 regs.u.r16.dx = BiosData->ticks_low;
8619 regs.u.r8.al = BiosData->midnight_flag;
8620 BiosData->midnight_flag = 0; // reset flag
8621 ASM_START
8622 sti
8623 ASM_END
8624 // AH already 0
8625 ClearCF(iret_addr.flags); // OK
8626 break;
8627
8628 case 1: // Set Current Clock Count
8629 ASM_START
8630 cli
8631 ASM_END
8632 BiosData->ticks_high = regs.u.r16.cx;
8633 BiosData->ticks_low = regs.u.r16.dx;
8634 BiosData->midnight_flag = 0; // reset flag
8635 ASM_START
8636 sti
8637 ASM_END
8638 regs.u.r8.ah = 0;
8639 ClearCF(iret_addr.flags); // OK
8640 break;
8641
8642
8643 case 2: // Read CMOS Time
8644 if (rtc_updating()) {
8645 SetCF(iret_addr.flags);
8646 break;
8647 }
8648
8649 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8650 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8651 regs.u.r8.ch = inb_cmos(0x04); // Hours
8652 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8653 regs.u.r8.ah = 0;
8654 regs.u.r8.al = regs.u.r8.ch;
8655 ClearCF(iret_addr.flags); // OK
8656 break;
8657
8658 case 3: // Set CMOS Time
8659 // Using a debugger, I notice the following masking/setting
8660 // of bits in Status Register B, by setting Reg B to
8661 // a few values and getting its value after INT 1A was called.
8662 //
8663 // try#1 try#2 try#3
8664 // before 1111 1101 0111 1101 0000 0000
8665 // after 0110 0010 0110 0010 0000 0010
8666 //
8667 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8668 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8669 if (rtc_updating()) {
8670 init_rtc();
8671 // fall through as if an update were not in progress
8672 }
8673 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8674 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8675 outb_cmos(0x04, regs.u.r8.ch); // Hours
8676 // Set Daylight Savings time enabled bit to requested value
8677 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8678 // (reg B already selected)
8679 outb_cmos(0x0b, val8);
8680 regs.u.r8.ah = 0;
8681 regs.u.r8.al = val8; // val last written to Reg B
8682 ClearCF(iret_addr.flags); // OK
8683 break;
8684
8685 case 4: // Read CMOS Date
8686 regs.u.r8.ah = 0;
8687 if (rtc_updating()) {
8688 SetCF(iret_addr.flags);
8689 break;
8690 }
8691 regs.u.r8.cl = inb_cmos(0x09); // Year
8692 regs.u.r8.dh = inb_cmos(0x08); // Month
8693 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8694 regs.u.r8.ch = inb_cmos(0x32); // Century
8695 regs.u.r8.al = regs.u.r8.ch;
8696 ClearCF(iret_addr.flags); // OK
8697 break;
8698
8699 case 5: // Set CMOS Date
8700 // Using a debugger, I notice the following masking/setting
8701 // of bits in Status Register B, by setting Reg B to
8702 // a few values and getting its value after INT 1A was called.
8703 //
8704 // try#1 try#2 try#3 try#4
8705 // before 1111 1101 0111 1101 0000 0010 0000 0000
8706 // after 0110 1101 0111 1101 0000 0010 0000 0000
8707 //
8708 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8709 // My assumption: RegB = (RegB & 01111111b)
8710 if (rtc_updating()) {
8711 init_rtc();
8712 SetCF(iret_addr.flags);
8713 break;
8714 }
8715 outb_cmos(0x09, regs.u.r8.cl); // Year
8716 outb_cmos(0x08, regs.u.r8.dh); // Month
8717 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8718 outb_cmos(0x32, regs.u.r8.ch); // Century
8719 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8720 outb_cmos(0x0b, val8);
8721 regs.u.r8.ah = 0;
8722 regs.u.r8.al = val8; // AL = val last written to Reg B
8723 ClearCF(iret_addr.flags); // OK
8724 break;
8725
8726 case 6: // Set Alarm Time in CMOS
8727 // Using a debugger, I notice the following masking/setting
8728 // of bits in Status Register B, by setting Reg B to
8729 // a few values and getting its value after INT 1A was called.
8730 //
8731 // try#1 try#2 try#3
8732 // before 1101 1111 0101 1111 0000 0000
8733 // after 0110 1111 0111 1111 0010 0000
8734 //
8735 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8736 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8737 val8 = inb_cmos(0x0b); // Get Status Reg B
8738 regs.u.r16.ax = 0;
8739 if (val8 & 0x20) {
8740 // Alarm interrupt enabled already
8741 SetCF(iret_addr.flags); // Error: alarm in use
8742 break;
8743 }
8744 if (rtc_updating()) {
8745 init_rtc();
8746 // fall through as if an update were not in progress
8747 }
8748 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8749 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8750 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8751 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8752 // enable Status Reg B alarm bit, clear halt clock bit
8753 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8754 ClearCF(iret_addr.flags); // OK
8755 break;
8756
8757 case 7: // Turn off Alarm
8758 // Using a debugger, I notice the following masking/setting
8759 // of bits in Status Register B, by setting Reg B to
8760 // a few values and getting its value after INT 1A was called.
8761 //
8762 // try#1 try#2 try#3 try#4
8763 // before 1111 1101 0111 1101 0010 0000 0010 0010
8764 // after 0100 0101 0101 0101 0000 0000 0000 0010
8765 //
8766 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8767 // My assumption: RegB = (RegB & 01010111b)
8768 val8 = inb_cmos(0x0b); // Get Status Reg B
8769 // clear clock-halt bit, disable alarm bit
8770 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8771 regs.u.r8.ah = 0;
8772 regs.u.r8.al = val8; // val last written to Reg B
8773 ClearCF(iret_addr.flags); // OK
8774 break;
8775#if BX_PCIBIOS
8776 case 0xb1:
8777 // real mode PCI BIOS functions now handled in assembler code
8778 // this C code handles the error code for information only
8779 if (regs.u.r8.bl == 0xff) {
8780 BX_INFO("PCI BIOS: PCI not present\n");
8781 } else if (regs.u.r8.bl == 0x81) {
8782 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8783 } else if (regs.u.r8.bl == 0x83) {
8784 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8785 } else if (regs.u.r8.bl == 0x86) {
8786 if (regs.u.r8.al == 0x02) {
8787 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8788 } else {
8789 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);
8790 }
8791 }
8792 regs.u.r8.ah = regs.u.r8.bl;
8793 SetCF(iret_addr.flags);
8794 break;
8795#endif
8796
8797 default:
8798 SetCF(iret_addr.flags); // Unsupported
8799 }
8800}
8801
8802 void
8803int70_function(regs, ds, iret_addr)
8804 pusha_regs_t regs; // regs pushed from PUSHA instruction
8805 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8806 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8807{
8808 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8809 Bit8u registerB = 0, registerC = 0;
8810
8811 // Check which modes are enabled and have occurred.
8812 registerB = inb_cmos( 0xB );
8813 registerC = inb_cmos( 0xC );
8814
8815 if( ( registerB & 0x60 ) != 0 ) {
8816 if( ( registerC & 0x20 ) != 0 ) {
8817 // Handle Alarm Interrupt.
8818ASM_START
8819 sti
8820 int #0x4a
8821 cli
8822ASM_END
8823 }
8824 if( ( registerC & 0x40 ) != 0 ) {
8825 // Handle Periodic Interrupt.
8826
8827 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8828 // Wait Interval (Int 15, AH=83) active.
8829 Bit32u time, toggle;
8830
8831 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8832 if( time < 0x3D1 ) {
8833 // Done waiting.
8834 Bit16u segment, offset;
8835
8836 segment = read_word( 0x40, 0x98 );
8837 offset = read_word( 0x40, 0x9A );
8838 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8839 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8840 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8841 } else {
8842 // Continue waiting.
8843 time -= 0x3D1;
8844 write_dword( 0x40, 0x9C, time );
8845 }
8846 }
8847 }
8848 }
8849
8850ASM_START
8851 call eoi_both_pics
8852ASM_END
8853}
8854
8855 void
8856dummy_isr_function(regs, ds, iret_addr)
8857 pusha_regs_t regs; // regs pushed from PUSHA instruction
8858 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8859 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8860{
8861 // Interrupt handler for unexpected hardware interrupts. We have to clear
8862 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8863 // and all hell will break loose! This routine also masks the unexpected
8864 // interrupt so it will generally be called only once for each unexpected
8865 // interrupt level.
8866 Bit8u isrA, isrB, imr, last_int = 0xFF;
8867
8868 outb( 0x20, 0x0B );
8869 isrA = inb( 0x20 );
8870 if (isrA) {
8871 outb( 0xA0, 0x0B );
8872 isrB = inb( 0xA0 );
8873 if (isrB) {
8874 imr = inb( 0xA1 );
8875 outb( 0xA1, imr | isrB ); // Mask this interrupt
8876 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8877 } else {
8878 imr = inb( 0x21 );
8879 isrA &= 0xFB; // Never mask the cascade interrupt
8880 outb( 0x21, imr | isrA); // Mask this interrupt
8881 }
8882 outb( 0x20, 0x20 ); // Send EOI on master PIC
8883 last_int = isrA;
8884 }
8885 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8886}
8887
8888ASM_START
8889;------------------------------------------
8890;- INT74h : PS/2 mouse hardware interrupt -
8891;------------------------------------------
8892int74_handler:
8893 sti
8894 pusha
8895 push ds ;; save DS
8896 push #0x00 ;; placeholder for status
8897 push #0x00 ;; placeholder for X
8898 push #0x00 ;; placeholder for Y
8899 push #0x00 ;; placeholder for Z
8900 push #0x00 ;; placeholder for make_far_call boolean
8901 call _int74_function
8902 pop cx ;; remove make_far_call from stack
8903 jcxz int74_done
8904
8905 ;; make far call to EBDA:0022
8906 push #0x00
8907 pop ds
8908 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8909 pop ds
8910 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8911 call far ptr[0x22]
8912int74_done:
8913 cli
8914 call eoi_both_pics
8915 add sp, #8 ;; pop status, x, y, z
8916
8917 pop ds ;; restore DS
8918 popa
8919 iret
8920
8921
8922;; This will perform an IRET, but will retain value of current CF
8923;; by altering flags on stack. Better than RETF #02.
8924iret_modify_cf:
8925 jc carry_set
8926 push bp
8927 mov bp, sp
8928 and BYTE [bp + 0x06], #0xfe
8929 pop bp
8930 iret
8931carry_set:
8932 push bp
8933 mov bp, sp
8934 or BYTE [bp + 0x06], #0x01
8935 pop bp
8936 iret
8937
8938
8939;----------------------
8940;- INT13h (relocated) -
8941;----------------------
8942;
8943; int13_relocated is a little bit messed up since I played with it
8944; I have to rewrite it:
8945; - call a function that detect which function to call
8946; - make all called C function get the same parameters list
8947;
8948int13_relocated:
8949
8950#if BX_ELTORITO_BOOT
8951 ;; check for an eltorito function
8952 cmp ah,#0x4a
8953 jb int13_not_eltorito
8954 cmp ah,#0x4d
8955 ja int13_not_eltorito
8956
8957 pusha
8958 push es
8959 push ds
8960 push ss
8961 pop ds
8962
8963 push #int13_out
8964 jmp _int13_eltorito ;; ELDX not used
8965
8966int13_not_eltorito:
8967 push ax
8968 push bx
8969 push cx
8970 push dx
8971
8972 ;; check if emulation active
8973 call _cdemu_isactive
8974 cmp al,#0x00
8975 je int13_cdemu_inactive
8976
8977 ;; check if access to the emulated drive
8978 call _cdemu_emulated_drive
8979 pop dx
8980 push dx
8981 cmp al,dl ;; int13 on emulated drive
8982 jne int13_nocdemu
8983
8984 pop dx
8985 pop cx
8986 pop bx
8987 pop ax
8988
8989 pusha
8990 push es
8991 push ds
8992 push ss
8993 pop ds
8994
8995 push #int13_out
8996 jmp _int13_cdemu ;; ELDX not used
8997
8998int13_nocdemu:
8999 and dl,#0xE0 ;; mask to get device class, including cdroms
9000 cmp al,dl ;; al is 0x00 or 0x80
9001 jne int13_cdemu_inactive ;; inactive for device class
9002
9003 pop dx
9004 pop cx
9005 pop bx
9006 pop ax
9007
9008 push ax
9009 push cx
9010 push dx
9011 push bx
9012
9013 dec dl ;; real drive is dl - 1
9014 jmp int13_legacy
9015
9016int13_cdemu_inactive:
9017 pop dx
9018 pop cx
9019 pop bx
9020 pop ax
9021
9022#endif // BX_ELTORITO_BOOT
9023
9024int13_noeltorito:
9025
9026 push ax
9027 push cx
9028 push dx
9029 push bx
9030
9031int13_legacy:
9032
9033 push dx ;; push eltorito value of dx instead of sp
9034
9035 push bp
9036 push si
9037 push di
9038
9039 push es
9040 push ds
9041 push ss
9042 pop ds
9043
9044 ;; now the 16-bit registers can be restored with:
9045 ;; pop ds; pop es; popa; iret
9046 ;; arguments passed to functions should be
9047 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9048
9049 test dl, #0x80
9050 jnz int13_notfloppy
9051
9052 push #int13_out
9053 jmp _int13_diskette_function
9054
9055int13_notfloppy:
9056
9057#if BX_USE_ATADRV
9058
9059 cmp dl, #0xE0
9060 jb int13_notcdrom
9061
9062 // ebx is modified: BSD 5.2.1 boot loader problem
9063 // someone should figure out which 32 bit register that actually are used
9064
9065 shr ebx, #16
9066 push bx
9067
9068 call _int13_cdrom
9069
9070 pop bx
9071 shl ebx, #16
9072
9073 jmp int13_out
9074
9075int13_notcdrom:
9076
9077#endif
9078
9079int13_disk:
9080 ;; int13_harddisk modifies high word of EAX
9081 shr eax, #16
9082 push ax
9083 call _int13_harddisk
9084 pop ax
9085 shl eax, #16
9086
9087int13_out:
9088 pop ds
9089 pop es
9090 popa
9091 iret
9092
9093;----------
9094;- INT18h -
9095;----------
9096int18_handler: ;; Boot Failure routing
9097 call _int18_panic_msg
9098 hlt
9099 iret
9100
9101;----------
9102;- INT19h -
9103;----------
9104int19_relocated: ;; Boot function, relocated
9105
9106#ifdef VBOX
9107 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9108 // just to try booting from the configured drives. All BIOS variables and
9109 // interrupt vectors need to be reset, otherwise strange things may happen.
9110 // The approach used is faking a warm reboot (which just skips showing the
9111 // logo), which is a bit more than what we need, but hey, it's fast.
9112 mov bp, sp
9113 mov ax, 2[bp]
9114 cmp ax, #0xf000
9115 jz bios_initiated_boot
9116 xor ax, ax
9117 mov ds, ax
9118 mov ax, #0x1234
9119 mov 0x472, ax
9120 jmp post
9121bios_initiated_boot:
9122#endif /* VBOX */
9123
9124 ;; int19 was beginning to be really complex, so now it
9125 ;; just calls a C function that does the work
9126 ;; it returns in BL the boot drive, and in AX the boot segment
9127 ;; the boot segment will be 0x0000 if something has failed
9128
9129 push bp
9130 mov bp, sp
9131
9132 ;; drop ds
9133 xor ax, ax
9134 mov ds, ax
9135
9136 ;; 1st boot device
9137 mov ax, #0x0001
9138 push ax
9139 call _int19_function
9140 inc sp
9141 inc sp
9142 ;; bl contains the boot drive
9143 ;; ax contains the boot segment or 0 if failure
9144
9145 test ax, ax ;; if ax is 0 try next boot device
9146 jnz boot_setup
9147
9148 ;; 2nd boot device
9149 mov ax, #0x0002
9150 push ax
9151 call _int19_function
9152 inc sp
9153 inc sp
9154 test ax, ax ;; if ax is 0 try next boot device
9155 jnz boot_setup
9156
9157 ;; 3rd boot device
9158 mov ax, #0x0003
9159 push ax
9160 call _int19_function
9161 inc sp
9162 inc sp
9163#ifdef VBOX
9164 test ax, ax ;; if ax is 0 try next boot device
9165 jnz boot_setup
9166
9167 ;; 4th boot device
9168 mov ax, #0x0004
9169 push ax
9170 call _int19_function
9171 inc sp
9172 inc sp
9173#endif /* VBOX */
9174 test ax, ax ;; if ax is 0 call int18
9175 jz int18_handler
9176
9177boot_setup:
9178 mov dl, bl ;; set drive so guest os find it
9179 shl eax, #0x04 ;; convert seg to ip
9180 mov 2[bp], ax ;; set ip
9181
9182 shr eax, #0x04 ;; get cs back
9183 and ax, #0xF000 ;; remove what went in ip
9184 mov 4[bp], ax ;; set cs
9185 xor ax, ax
9186 mov es, ax ;; set es to zero fixes [ 549815 ]
9187 mov [bp], ax ;; set bp to zero
9188 mov ax, #0xaa55 ;; set ok flag
9189
9190 pop bp
9191 iret ;; Beam me up Scotty
9192
9193;----------
9194;- INT1Ch -
9195;----------
9196int1c_handler: ;; User Timer Tick
9197 iret
9198
9199
9200;----------------------
9201;- POST: Floppy Drive -
9202;----------------------
9203floppy_drive_post:
9204 xor ax, ax
9205 mov ds, ax
9206
9207 mov al, #0x00
9208 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9209
9210 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9211
9212 mov 0x0440, al ;; diskette motor timeout counter: not active
9213 mov 0x0441, al ;; diskette controller status return code
9214
9215 mov 0x0442, al ;; disk & diskette controller status register 0
9216 mov 0x0443, al ;; diskette controller status register 1
9217 mov 0x0444, al ;; diskette controller status register 2
9218 mov 0x0445, al ;; diskette controller cylinder number
9219 mov 0x0446, al ;; diskette controller head number
9220 mov 0x0447, al ;; diskette controller sector number
9221 mov 0x0448, al ;; diskette controller bytes written
9222
9223 mov 0x048b, al ;; diskette configuration data
9224
9225 ;; -----------------------------------------------------------------
9226 ;; (048F) diskette controller information
9227 ;;
9228 mov al, #0x10 ;; get CMOS diskette drive type
9229 out 0x70, AL
9230 in AL, 0x71
9231 mov ah, al ;; save byte to AH
9232
9233look_drive0:
9234 shr al, #4 ;; look at top 4 bits for drive 0
9235 jz f0_missing ;; jump if no drive0
9236 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9237 jmp look_drive1
9238f0_missing:
9239 mov bl, #0x00 ;; no drive0
9240
9241look_drive1:
9242 mov al, ah ;; restore from AH
9243 and al, #0x0f ;; look at bottom 4 bits for drive 1
9244 jz f1_missing ;; jump if no drive1
9245 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9246f1_missing:
9247 ;; leave high bits in BL zerod
9248 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9249 ;; -----------------------------------------------------------------
9250
9251 mov al, #0x00
9252 mov 0x0490, al ;; diskette 0 media state
9253 mov 0x0491, al ;; diskette 1 media state
9254
9255 ;; diskette 0,1 operational starting state
9256 ;; drive type has not been determined,
9257 ;; has no changed detection line
9258 mov 0x0492, al
9259 mov 0x0493, al
9260
9261 mov 0x0494, al ;; diskette 0 current cylinder
9262 mov 0x0495, al ;; diskette 1 current cylinder
9263
9264 mov al, #0x02
9265 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9266
9267 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9268 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9269 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9270
9271 ret
9272
9273
9274;--------------------
9275;- POST: HARD DRIVE -
9276;--------------------
9277; relocated here because the primary POST area isnt big enough.
9278hard_drive_post:
9279 // IRQ 14 = INT 76h
9280 // INT 76h calls INT 15h function ax=9100
9281
9282 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9283 mov dx, #0x03f6
9284 out dx, al
9285
9286 xor ax, ax
9287 mov ds, ax
9288 mov 0x0474, al /* hard disk status of last operation */
9289 mov 0x0477, al /* hard disk port offset (XT only ???) */
9290 mov 0x048c, al /* hard disk status register */
9291 mov 0x048d, al /* hard disk error register */
9292 mov 0x048e, al /* hard disk task complete flag */
9293 mov al, #0x01
9294 mov 0x0475, al /* hard disk number attached */
9295 mov al, #0xc0
9296 mov 0x0476, al /* hard disk control byte */
9297 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9298 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9299 ;; INT 41h: hard disk 0 configuration pointer
9300 ;; INT 46h: hard disk 1 configuration pointer
9301 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9302 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9303
9304#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9305 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9306 mov al, #0x12
9307 out #0x70, al
9308 in al, #0x71
9309 and al, #0xf0
9310 cmp al, #0xf0
9311 je post_d0_extended
9312 jmp check_for_hd1
9313post_d0_extended:
9314 mov al, #0x19
9315 out #0x70, al
9316 in al, #0x71
9317 cmp al, #47 ;; decimal 47 - user definable
9318 je post_d0_type47
9319 HALT(__LINE__)
9320post_d0_type47:
9321 ;; CMOS purpose param table offset
9322 ;; 1b cylinders low 0
9323 ;; 1c cylinders high 1
9324 ;; 1d heads 2
9325 ;; 1e write pre-comp low 5
9326 ;; 1f write pre-comp high 6
9327 ;; 20 retries/bad map/heads>8 8
9328 ;; 21 landing zone low C
9329 ;; 22 landing zone high D
9330 ;; 23 sectors/track E
9331
9332 mov ax, #EBDA_SEG
9333 mov ds, ax
9334
9335 ;;; Filling EBDA table for hard disk 0.
9336 mov al, #0x1f
9337 out #0x70, al
9338 in al, #0x71
9339 mov ah, al
9340 mov al, #0x1e
9341 out #0x70, al
9342 in al, #0x71
9343 mov (0x003d + 0x05), ax ;; write precomp word
9344
9345 mov al, #0x20
9346 out #0x70, al
9347 in al, #0x71
9348 mov (0x003d + 0x08), al ;; drive control byte
9349
9350 mov al, #0x22
9351 out #0x70, al
9352 in al, #0x71
9353 mov ah, al
9354 mov al, #0x21
9355 out #0x70, al
9356 in al, #0x71
9357 mov (0x003d + 0x0C), ax ;; landing zone word
9358
9359 mov al, #0x1c ;; get cylinders word in AX
9360 out #0x70, al
9361 in al, #0x71 ;; high byte
9362 mov ah, al
9363 mov al, #0x1b
9364 out #0x70, al
9365 in al, #0x71 ;; low byte
9366 mov bx, ax ;; BX = cylinders
9367
9368 mov al, #0x1d
9369 out #0x70, al
9370 in al, #0x71
9371 mov cl, al ;; CL = heads
9372
9373 mov al, #0x23
9374 out #0x70, al
9375 in al, #0x71
9376 mov dl, al ;; DL = sectors
9377
9378 cmp bx, #1024
9379 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9380
9381hd0_post_physical_chs:
9382 ;; no logical CHS mapping used, just physical CHS
9383 ;; use Standard Fixed Disk Parameter Table (FDPT)
9384 mov (0x003d + 0x00), bx ;; number of physical cylinders
9385 mov (0x003d + 0x02), cl ;; number of physical heads
9386 mov (0x003d + 0x0E), dl ;; number of physical sectors
9387 jmp check_for_hd1
9388
9389hd0_post_logical_chs:
9390 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9391 mov (0x003d + 0x09), bx ;; number of physical cylinders
9392 mov (0x003d + 0x0b), cl ;; number of physical heads
9393 mov (0x003d + 0x04), dl ;; number of physical sectors
9394 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9395 mov al, #0xa0
9396 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9397
9398 cmp bx, #2048
9399 jnbe hd0_post_above_2048
9400 ;; 1024 < c <= 2048 cylinders
9401 shr bx, #0x01
9402 shl cl, #0x01
9403 jmp hd0_post_store_logical
9404
9405hd0_post_above_2048:
9406 cmp bx, #4096
9407 jnbe hd0_post_above_4096
9408 ;; 2048 < c <= 4096 cylinders
9409 shr bx, #0x02
9410 shl cl, #0x02
9411 jmp hd0_post_store_logical
9412
9413hd0_post_above_4096:
9414 cmp bx, #8192
9415 jnbe hd0_post_above_8192
9416 ;; 4096 < c <= 8192 cylinders
9417 shr bx, #0x03
9418 shl cl, #0x03
9419 jmp hd0_post_store_logical
9420
9421hd0_post_above_8192:
9422 ;; 8192 < c <= 16384 cylinders
9423 shr bx, #0x04
9424 shl cl, #0x04
9425
9426hd0_post_store_logical:
9427 mov (0x003d + 0x00), bx ;; number of physical cylinders
9428 mov (0x003d + 0x02), cl ;; number of physical heads
9429 ;; checksum
9430 mov cl, #0x0f ;; repeat count
9431 mov si, #0x003d ;; offset to disk0 FDPT
9432 mov al, #0x00 ;; sum
9433hd0_post_checksum_loop:
9434 add al, [si]
9435 inc si
9436 dec cl
9437 jnz hd0_post_checksum_loop
9438 not al ;; now take 2s complement
9439 inc al
9440 mov [si], al
9441;;; Done filling EBDA table for hard disk 0.
9442
9443
9444check_for_hd1:
9445 ;; is there really a second hard disk? if not, return now
9446 mov al, #0x12
9447 out #0x70, al
9448 in al, #0x71
9449 and al, #0x0f
9450 jnz post_d1_exists
9451 ret
9452post_d1_exists:
9453 ;; check that the hd type is really 0x0f.
9454 cmp al, #0x0f
9455 jz post_d1_extended
9456 HALT(__LINE__)
9457post_d1_extended:
9458 ;; check that the extended type is 47 - user definable
9459 mov al, #0x1a
9460 out #0x70, al
9461 in al, #0x71
9462 cmp al, #47 ;; decimal 47 - user definable
9463 je post_d1_type47
9464 HALT(__LINE__)
9465post_d1_type47:
9466 ;; Table for disk1.
9467 ;; CMOS purpose param table offset
9468 ;; 0x24 cylinders low 0
9469 ;; 0x25 cylinders high 1
9470 ;; 0x26 heads 2
9471 ;; 0x27 write pre-comp low 5
9472 ;; 0x28 write pre-comp high 6
9473 ;; 0x29 heads>8 8
9474 ;; 0x2a landing zone low C
9475 ;; 0x2b landing zone high D
9476 ;; 0x2c sectors/track E
9477;;; Fill EBDA table for hard disk 1.
9478 mov ax, #EBDA_SEG
9479 mov ds, ax
9480 mov al, #0x28
9481 out #0x70, al
9482 in al, #0x71
9483 mov ah, al
9484 mov al, #0x27
9485 out #0x70, al
9486 in al, #0x71
9487 mov (0x004d + 0x05), ax ;; write precomp word
9488
9489 mov al, #0x29
9490 out #0x70, al
9491 in al, #0x71
9492 mov (0x004d + 0x08), al ;; drive control byte
9493
9494 mov al, #0x2b
9495 out #0x70, al
9496 in al, #0x71
9497 mov ah, al
9498 mov al, #0x2a
9499 out #0x70, al
9500 in al, #0x71
9501 mov (0x004d + 0x0C), ax ;; landing zone word
9502
9503 mov al, #0x25 ;; get cylinders word in AX
9504 out #0x70, al
9505 in al, #0x71 ;; high byte
9506 mov ah, al
9507 mov al, #0x24
9508 out #0x70, al
9509 in al, #0x71 ;; low byte
9510 mov bx, ax ;; BX = cylinders
9511
9512 mov al, #0x26
9513 out #0x70, al
9514 in al, #0x71
9515 mov cl, al ;; CL = heads
9516
9517 mov al, #0x2c
9518 out #0x70, al
9519 in al, #0x71
9520 mov dl, al ;; DL = sectors
9521
9522 cmp bx, #1024
9523 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9524
9525hd1_post_physical_chs:
9526 ;; no logical CHS mapping used, just physical CHS
9527 ;; use Standard Fixed Disk Parameter Table (FDPT)
9528 mov (0x004d + 0x00), bx ;; number of physical cylinders
9529 mov (0x004d + 0x02), cl ;; number of physical heads
9530 mov (0x004d + 0x0E), dl ;; number of physical sectors
9531 ret
9532
9533hd1_post_logical_chs:
9534 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9535 mov (0x004d + 0x09), bx ;; number of physical cylinders
9536 mov (0x004d + 0x0b), cl ;; number of physical heads
9537 mov (0x004d + 0x04), dl ;; number of physical sectors
9538 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9539 mov al, #0xa0
9540 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9541
9542 cmp bx, #2048
9543 jnbe hd1_post_above_2048
9544 ;; 1024 < c <= 2048 cylinders
9545 shr bx, #0x01
9546 shl cl, #0x01
9547 jmp hd1_post_store_logical
9548
9549hd1_post_above_2048:
9550 cmp bx, #4096
9551 jnbe hd1_post_above_4096
9552 ;; 2048 < c <= 4096 cylinders
9553 shr bx, #0x02
9554 shl cl, #0x02
9555 jmp hd1_post_store_logical
9556
9557hd1_post_above_4096:
9558 cmp bx, #8192
9559 jnbe hd1_post_above_8192
9560 ;; 4096 < c <= 8192 cylinders
9561 shr bx, #0x03
9562 shl cl, #0x03
9563 jmp hd1_post_store_logical
9564
9565hd1_post_above_8192:
9566 ;; 8192 < c <= 16384 cylinders
9567 shr bx, #0x04
9568 shl cl, #0x04
9569
9570hd1_post_store_logical:
9571 mov (0x004d + 0x00), bx ;; number of physical cylinders
9572 mov (0x004d + 0x02), cl ;; number of physical heads
9573 ;; checksum
9574 mov cl, #0x0f ;; repeat count
9575 mov si, #0x004d ;; offset to disk0 FDPT
9576 mov al, #0x00 ;; sum
9577hd1_post_checksum_loop:
9578 add al, [si]
9579 inc si
9580 dec cl
9581 jnz hd1_post_checksum_loop
9582 not al ;; now take 2s complement
9583 inc al
9584 mov [si], al
9585;;; Done filling EBDA table for hard disk 1.
9586#endif /* !VBOX */
9587
9588 ret
9589
9590;--------------------
9591;- POST: EBDA segment
9592;--------------------
9593; relocated here because the primary POST area isnt big enough.
9594; the SET_INT_VECTORs have nothing to do with EBDA but do not
9595; fit into the primary POST area either
9596ebda_post:
9597 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9598 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9599 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9600 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9601
9602#if BX_USE_EBDA
9603 mov ax, #EBDA_SEG
9604 mov ds, ax
9605 mov byte ptr [0x0], #EBDA_SIZE
9606#endif
9607 xor ax, ax ; mov EBDA seg into 40E
9608 mov ds, ax
9609 mov word ptr [0x40E], #EBDA_SEG
9610 ret;;
9611
9612;--------------------
9613;- POST: EOI + jmp via [0x40:67)
9614;--------------------
9615; relocated here because the primary POST area isnt big enough.
9616eoi_jmp_post:
9617 call eoi_both_pics
9618
9619 xor ax, ax
9620 mov ds, ax
9621
9622 jmp far ptr [0x467]
9623
9624
9625;--------------------
9626eoi_both_pics:
9627 mov al, #0x20
9628 out #0xA0, al ;; slave PIC EOI
9629eoi_master_pic:
9630 mov al, #0x20
9631 out #0x20, al ;; master PIC EOI
9632 ret
9633
9634;--------------------
9635BcdToBin:
9636 ;; in: AL in BCD format
9637 ;; out: AL in binary format, AH will always be 0
9638 ;; trashes BX
9639 mov bl, al
9640 and bl, #0x0f ;; bl has low digit
9641 shr al, #4 ;; al has high digit
9642 mov bh, #10
9643 mul al, bh ;; multiply high digit by 10 (result in AX)
9644 add al, bl ;; then add low digit
9645 ret
9646
9647;--------------------
9648timer_tick_post:
9649 ;; Setup the Timer Ticks Count (0x46C:dword) and
9650 ;; Timer Ticks Roller Flag (0x470:byte)
9651 ;; The Timer Ticks Count needs to be set according to
9652 ;; the current CMOS time, as if ticks have been occurring
9653 ;; at 18.2hz since midnight up to this point. Calculating
9654 ;; this is a little complicated. Here are the factors I gather
9655 ;; regarding this. 14,318,180 hz was the original clock speed,
9656 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9657 ;; at the time, or 4 to drive the CGA video adapter. The div3
9658 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9659 ;; the timer. With a maximum 16bit timer count, this is again
9660 ;; divided down by 65536 to 18.2hz.
9661 ;;
9662 ;; 14,318,180 Hz clock
9663 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9664 ;; /4 = 1,193,181 Hz fed to timer
9665 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9666 ;; 1 second = 18.20650736 ticks
9667 ;; 1 minute = 1092.390442 ticks
9668 ;; 1 hour = 65543.42651 ticks
9669 ;;
9670 ;; Given the values in the CMOS clock, one could calculate
9671 ;; the number of ticks by the following:
9672 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9673 ;; (BcdToBin(minutes) * 1092.3904)
9674 ;; (BcdToBin(hours) * 65543.427)
9675 ;; To get a little more accuracy, since Im using integer
9676 ;; arithmatic, I use:
9677 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9678 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9679 ;; (BcdToBin(hours) * 65543427) / 1000
9680
9681 ;; assuming DS=0000
9682
9683 ;; get CMOS seconds
9684 xor eax, eax ;; clear EAX
9685 mov al, #0x00
9686 out #0x70, al
9687 in al, #0x71 ;; AL has CMOS seconds in BCD
9688 call BcdToBin ;; EAX now has seconds in binary
9689 mov edx, #18206507
9690 mul eax, edx
9691 mov ebx, #1000000
9692 xor edx, edx
9693 div eax, ebx
9694 mov ecx, eax ;; ECX will accumulate total ticks
9695
9696 ;; get CMOS minutes
9697 xor eax, eax ;; clear EAX
9698 mov al, #0x02
9699 out #0x70, al
9700 in al, #0x71 ;; AL has CMOS minutes in BCD
9701 call BcdToBin ;; EAX now has minutes in binary
9702 mov edx, #10923904
9703 mul eax, edx
9704 mov ebx, #10000
9705 xor edx, edx
9706 div eax, ebx
9707 add ecx, eax ;; add to total ticks
9708
9709 ;; get CMOS hours
9710 xor eax, eax ;; clear EAX
9711 mov al, #0x04
9712 out #0x70, al
9713 in al, #0x71 ;; AL has CMOS hours in BCD
9714 call BcdToBin ;; EAX now has hours in binary
9715 mov edx, #65543427
9716 mul eax, edx
9717 mov ebx, #1000
9718 xor edx, edx
9719 div eax, ebx
9720 add ecx, eax ;; add to total ticks
9721
9722 mov 0x46C, ecx ;; Timer Ticks Count
9723 xor al, al
9724 mov 0x470, al ;; Timer Ticks Rollover Flag
9725 ret
9726
9727;--------------------
9728int76_handler:
9729 ;; record completion in BIOS task complete flag
9730 push ax
9731 push ds
9732 mov ax, #0x0040
9733 mov ds, ax
9734 mov 0x008E, #0xff
9735 call eoi_both_pics
9736 pop ds
9737 pop ax
9738 iret
9739
9740
9741;--------------------
9742#ifdef VBOX
9743init_pic:
9744 ;; init PIC
9745 mov al, #0x11 ; send initialisation commands
9746 out 0x20, al
9747 out 0xa0, al
9748 mov al, #0x08
9749 out 0x21, al
9750 mov al, #0x70
9751 out 0xa1, al
9752 mov al, #0x04
9753 out 0x21, al
9754 mov al, #0x02
9755 out 0xa1, al
9756 mov al, #0x01
9757 out 0x21, al
9758 out 0xa1, al
9759 mov al, #0xb8
9760 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9761#if BX_USE_PS2_MOUSE
9762 mov al, #0x8f
9763#else
9764 mov al, #0x9f
9765#endif
9766 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9767 ret
9768#endif /* VBOX */
9769
9770;--------------------
9771#if BX_APM
9772
9773use32 386
9774#define APM_PROT32
9775#include "apmbios.S"
9776
9777use16 386
9778#define APM_PROT16
9779#include "apmbios.S"
9780
9781#define APM_REAL
9782#include "apmbios.S"
9783
9784#endif
9785
9786;--------------------
9787#if BX_PCIBIOS
9788use32 386
9789.align 16
9790bios32_structure:
9791 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9792 dw bios32_entry_point, 0xf ;; 32 bit physical address
9793 db 0 ;; revision level
9794 ;; length in paragraphs and checksum stored in a word to prevent errors
9795 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9796 & 0xff) << 8) + 0x01
9797 db 0,0,0,0,0 ;; reserved
9798
9799.align 16
9800bios32_entry_point:
9801 pushfd
9802 cmp eax, #0x49435024 ;; "$PCI"
9803 jne unknown_service
9804 mov eax, #0x80000000
9805 mov dx, #0x0cf8
9806 out dx, eax
9807 mov dx, #0x0cfc
9808 in eax, dx
9809#ifdef PCI_FIXED_HOST_BRIDGE
9810 cmp eax, #PCI_FIXED_HOST_BRIDGE
9811 jne unknown_service
9812#else
9813 ;; say ok if a device is present
9814 cmp eax, #0xffffffff
9815 je unknown_service
9816#endif
9817 mov ebx, #0x000f0000
9818 mov ecx, #0
9819 mov edx, #pcibios_protected
9820 xor al, al
9821 jmp bios32_end
9822unknown_service:
9823 mov al, #0x80
9824bios32_end:
9825#ifdef BX_QEMU
9826 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9827#endif
9828 popfd
9829 retf
9830
9831.align 16
9832pcibios_protected:
9833 pushfd
9834 cli
9835 push esi
9836 push edi
9837 cmp al, #0x01 ;; installation check
9838 jne pci_pro_f02
9839 mov bx, #0x0210
9840 mov cx, #0
9841 mov edx, #0x20494350 ;; "PCI "
9842 mov al, #0x01
9843 jmp pci_pro_ok
9844pci_pro_f02: ;; find pci device
9845 cmp al, #0x02
9846 jne pci_pro_f03
9847 shl ecx, #16
9848 mov cx, dx
9849 xor ebx, ebx
9850 mov di, #0x00
9851pci_pro_devloop:
9852 call pci_pro_select_reg
9853 mov dx, #0x0cfc
9854 in eax, dx
9855 cmp eax, ecx
9856 jne pci_pro_nextdev
9857 cmp si, #0
9858 je pci_pro_ok
9859 dec si
9860pci_pro_nextdev:
9861 inc ebx
9862 cmp ebx, #0x10000
9863 jne pci_pro_devloop
9864 mov ah, #0x86
9865 jmp pci_pro_fail
9866pci_pro_f03: ;; find class code
9867 cmp al, #0x03
9868 jne pci_pro_f08
9869 xor ebx, ebx
9870 mov di, #0x08
9871pci_pro_devloop2:
9872 call pci_pro_select_reg
9873 mov dx, #0x0cfc
9874 in eax, dx
9875 shr eax, #8
9876 cmp eax, ecx
9877 jne pci_pro_nextdev2
9878 cmp si, #0
9879 je pci_pro_ok
9880 dec si
9881pci_pro_nextdev2:
9882 inc ebx
9883 cmp ebx, #0x10000
9884 jne pci_pro_devloop2
9885 mov ah, #0x86
9886 jmp pci_pro_fail
9887pci_pro_f08: ;; read configuration byte
9888 cmp al, #0x08
9889 jne pci_pro_f09
9890 call pci_pro_select_reg
9891 push edx
9892 mov dx, di
9893 and dx, #0x03
9894 add dx, #0x0cfc
9895 in al, dx
9896 pop edx
9897 mov cl, al
9898 jmp pci_pro_ok
9899pci_pro_f09: ;; read configuration word
9900 cmp al, #0x09
9901 jne pci_pro_f0a
9902 call pci_pro_select_reg
9903 push edx
9904 mov dx, di
9905 and dx, #0x02
9906 add dx, #0x0cfc
9907 in ax, dx
9908 pop edx
9909 mov cx, ax
9910 jmp pci_pro_ok
9911pci_pro_f0a: ;; read configuration dword
9912 cmp al, #0x0a
9913 jne pci_pro_f0b
9914 call pci_pro_select_reg
9915 push edx
9916 mov dx, #0x0cfc
9917 in eax, dx
9918 pop edx
9919 mov ecx, eax
9920 jmp pci_pro_ok
9921pci_pro_f0b: ;; write configuration byte
9922 cmp al, #0x0b
9923 jne pci_pro_f0c
9924 call pci_pro_select_reg
9925 push edx
9926 mov dx, di
9927 and dx, #0x03
9928 add dx, #0x0cfc
9929 mov al, cl
9930 out dx, al
9931 pop edx
9932 jmp pci_pro_ok
9933pci_pro_f0c: ;; write configuration word
9934 cmp al, #0x0c
9935 jne pci_pro_f0d
9936 call pci_pro_select_reg
9937 push edx
9938 mov dx, di
9939 and dx, #0x02
9940 add dx, #0x0cfc
9941 mov ax, cx
9942 out dx, ax
9943 pop edx
9944 jmp pci_pro_ok
9945pci_pro_f0d: ;; write configuration dword
9946 cmp al, #0x0d
9947 jne pci_pro_unknown
9948 call pci_pro_select_reg
9949 push edx
9950 mov dx, #0x0cfc
9951 mov eax, ecx
9952 out dx, eax
9953 pop edx
9954 jmp pci_pro_ok
9955pci_pro_unknown:
9956 mov ah, #0x81
9957pci_pro_fail:
9958 pop edi
9959 pop esi
9960#ifdef BX_QEMU
9961 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9962#endif
9963 popfd
9964 stc
9965 retf
9966pci_pro_ok:
9967 xor ah, ah
9968 pop edi
9969 pop esi
9970#ifdef BX_QEMU
9971 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9972#endif
9973 popfd
9974 clc
9975 retf
9976
9977pci_pro_select_reg:
9978 push edx
9979 mov eax, #0x800000
9980 mov ax, bx
9981 shl eax, #8
9982 and di, #0xff
9983 or ax, di
9984 and al, #0xfc
9985 mov dx, #0x0cf8
9986 out dx, eax
9987 pop edx
9988 ret
9989
9990use16 386
9991
9992pcibios_real:
9993 push eax
9994 push dx
9995 mov eax, #0x80000000
9996 mov dx, #0x0cf8
9997 out dx, eax
9998 mov dx, #0x0cfc
9999 in eax, dx
10000#ifdef PCI_FIXED_HOST_BRIDGE
10001 cmp eax, #PCI_FIXED_HOST_BRIDGE
10002 je pci_present
10003#else
10004 ;; say ok if a device is present
10005 cmp eax, #0xffffffff
10006 jne pci_present
10007#endif
10008 pop dx
10009 pop eax
10010 mov ah, #0xff
10011 stc
10012 ret
10013pci_present:
10014 pop dx
10015 pop eax
10016 cmp al, #0x01 ;; installation check
10017 jne pci_real_f02
10018 mov ax, #0x0001
10019 mov bx, #0x0210
10020 mov cx, #0
10021 mov edx, #0x20494350 ;; "PCI "
10022 mov edi, #0xf0000
10023 mov di, #pcibios_protected
10024 clc
10025 ret
10026pci_real_f02: ;; find pci device
10027 push esi
10028 push edi
10029 cmp al, #0x02
10030 jne pci_real_f03
10031 shl ecx, #16
10032 mov cx, dx
10033 xor ebx, ebx
10034 mov di, #0x00
10035pci_real_devloop:
10036 call pci_real_select_reg
10037 mov dx, #0x0cfc
10038 in eax, dx
10039 cmp eax, ecx
10040 jne pci_real_nextdev
10041 cmp si, #0
10042 je pci_real_ok
10043 dec si
10044pci_real_nextdev:
10045 inc ebx
10046 cmp ebx, #0x10000
10047 jne pci_real_devloop
10048 mov dx, cx
10049 shr ecx, #16
10050 mov ax, #0x8602
10051 jmp pci_real_fail
10052pci_real_f03: ;; find class code
10053 cmp al, #0x03
10054 jne pci_real_f08
10055 xor ebx, ebx
10056 mov di, #0x08
10057pci_real_devloop2:
10058 call pci_real_select_reg
10059 mov dx, #0x0cfc
10060 in eax, dx
10061 shr eax, #8
10062 cmp eax, ecx
10063 jne pci_real_nextdev2
10064 cmp si, #0
10065 je pci_real_ok
10066 dec si
10067pci_real_nextdev2:
10068 inc ebx
10069 cmp ebx, #0x10000
10070 jne pci_real_devloop2
10071 mov dx, cx
10072 shr ecx, #16
10073 mov ax, #0x8603
10074 jmp pci_real_fail
10075pci_real_f08: ;; read configuration byte
10076 cmp al, #0x08
10077 jne pci_real_f09
10078 call pci_real_select_reg
10079 push dx
10080 mov dx, di
10081 and dx, #0x03
10082 add dx, #0x0cfc
10083 in al, dx
10084 pop dx
10085 mov cl, al
10086 jmp pci_real_ok
10087pci_real_f09: ;; read configuration word
10088 cmp al, #0x09
10089 jne pci_real_f0a
10090 call pci_real_select_reg
10091 push dx
10092 mov dx, di
10093 and dx, #0x02
10094 add dx, #0x0cfc
10095 in ax, dx
10096 pop dx
10097 mov cx, ax
10098 jmp pci_real_ok
10099pci_real_f0a: ;; read configuration dword
10100 cmp al, #0x0a
10101 jne pci_real_f0b
10102 call pci_real_select_reg
10103 push dx
10104 mov dx, #0x0cfc
10105 in eax, dx
10106 pop dx
10107 mov ecx, eax
10108 jmp pci_real_ok
10109pci_real_f0b: ;; write configuration byte
10110 cmp al, #0x0b
10111 jne pci_real_f0c
10112 call pci_real_select_reg
10113 push dx
10114 mov dx, di
10115 and dx, #0x03
10116 add dx, #0x0cfc
10117 mov al, cl
10118 out dx, al
10119 pop dx
10120 jmp pci_real_ok
10121pci_real_f0c: ;; write configuration word
10122 cmp al, #0x0c
10123 jne pci_real_f0d
10124 call pci_real_select_reg
10125 push dx
10126 mov dx, di
10127 and dx, #0x02
10128 add dx, #0x0cfc
10129 mov ax, cx
10130 out dx, ax
10131 pop dx
10132 jmp pci_real_ok
10133pci_real_f0d: ;; write configuration dword
10134 cmp al, #0x0d
10135 jne pci_real_f0e
10136 call pci_real_select_reg
10137 push dx
10138 mov dx, #0x0cfc
10139 mov eax, ecx
10140 out dx, eax
10141 pop dx
10142 jmp pci_real_ok
10143pci_real_f0e: ;; get irq routing options
10144 cmp al, #0x0e
10145 jne pci_real_unknown
10146 SEG ES
10147 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10148 jb pci_real_too_small
10149 SEG ES
10150 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10151 pushf
10152 push ds
10153 push es
10154 push cx
10155 push si
10156 push di
10157 cld
10158 mov si, #pci_routing_table_structure_start
10159 push cs
10160 pop ds
10161 SEG ES
10162 mov cx, [di+2]
10163 SEG ES
10164 mov es, [di+4]
10165 mov di, cx
10166 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10167 rep
10168 movsb
10169 pop di
10170 pop si
10171 pop cx
10172 pop es
10173 pop ds
10174 popf
10175 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10176 jmp pci_real_ok
10177pci_real_too_small:
10178 SEG ES
10179 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10180 mov ah, #0x89
10181 jmp pci_real_fail
10182
10183pci_real_unknown:
10184 mov ah, #0x81
10185pci_real_fail:
10186 pop edi
10187 pop esi
10188 stc
10189 ret
10190pci_real_ok:
10191 xor ah, ah
10192 pop edi
10193 pop esi
10194 clc
10195 ret
10196
10197pci_real_select_reg:
10198 push dx
10199 mov eax, #0x800000
10200 mov ax, bx
10201 shl eax, #8
10202 and di, #0xff
10203 or ax, di
10204 and al, #0xfc
10205 mov dx, #0x0cf8
10206 out dx, eax
10207 pop dx
10208 ret
10209
10210.align 16
10211pci_routing_table_structure:
10212 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10213 db 0, 1 ;; version
10214#ifdef VBOX
10215#if 0
10216 dw 32 + (30 * 16) ;; table size
10217#else
10218 dw 32 + (10 * 16) ;; table size
10219#endif
10220#else /* !VBOX */
10221 dw 32 + (6 * 16) ;; table size
10222#endif /* !VBOX */
10223 db 0 ;; PCI interrupt router bus
10224 db 0x08 ;; PCI interrupt router DevFunc
10225 dw 0x0000 ;; PCI exclusive IRQs
10226 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10227 dw 0x7000 ;; compatible PCI interrupt router device ID
10228 dw 0,0 ;; Miniport data
10229 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10230#ifdef VBOX
10231 db 0x00 ;; checksum (set by biossums)
10232#else /* !VBOX */
10233 db 0x07 ;; checksum
10234#endif /* !VBOX */
10235pci_routing_table_structure_start:
10236 ;; first slot entry PCI-to-ISA (embedded)
10237 db 0 ;; pci bus number
10238 db 0x08 ;; pci device number (bit 7-3)
10239 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10240 dw 0xdef8 ;; IRQ bitmap INTA#
10241 db 0x61 ;; link value INTB#
10242 dw 0xdef8 ;; IRQ bitmap INTB#
10243 db 0x62 ;; link value INTC#
10244 dw 0xdef8 ;; IRQ bitmap INTC#
10245 db 0x63 ;; link value INTD#
10246 dw 0xdef8 ;; IRQ bitmap INTD#
10247 db 0 ;; physical slot (0 = embedded)
10248 db 0 ;; reserved
10249 ;; second slot entry: 1st PCI slot
10250 db 0 ;; pci bus number
10251 db 0x10 ;; pci device number (bit 7-3)
10252 db 0x61 ;; link value INTA#
10253 dw 0xdef8 ;; IRQ bitmap INTA#
10254 db 0x62 ;; link value INTB#
10255 dw 0xdef8 ;; IRQ bitmap INTB#
10256 db 0x63 ;; link value INTC#
10257 dw 0xdef8 ;; IRQ bitmap INTC#
10258 db 0x60 ;; link value INTD#
10259 dw 0xdef8 ;; IRQ bitmap INTD#
10260 db 1 ;; physical slot (0 = embedded)
10261 db 0 ;; reserved
10262 ;; third slot entry: 2nd PCI slot
10263 db 0 ;; pci bus number
10264 db 0x18 ;; pci device number (bit 7-3)
10265 db 0x62 ;; link value INTA#
10266 dw 0xdef8 ;; IRQ bitmap INTA#
10267 db 0x63 ;; link value INTB#
10268 dw 0xdef8 ;; IRQ bitmap INTB#
10269 db 0x60 ;; link value INTC#
10270 dw 0xdef8 ;; IRQ bitmap INTC#
10271 db 0x61 ;; link value INTD#
10272 dw 0xdef8 ;; IRQ bitmap INTD#
10273 db 2 ;; physical slot (0 = embedded)
10274 db 0 ;; reserved
10275 ;; 4th slot entry: 3rd PCI slot
10276 db 0 ;; pci bus number
10277 db 0x20 ;; pci device number (bit 7-3)
10278 db 0x63 ;; link value INTA#
10279 dw 0xdef8 ;; IRQ bitmap INTA#
10280 db 0x60 ;; link value INTB#
10281 dw 0xdef8 ;; IRQ bitmap INTB#
10282 db 0x61 ;; link value INTC#
10283 dw 0xdef8 ;; IRQ bitmap INTC#
10284 db 0x62 ;; link value INTD#
10285 dw 0xdef8 ;; IRQ bitmap INTD#
10286 db 3 ;; physical slot (0 = embedded)
10287 db 0 ;; reserved
10288 ;; 5th slot entry: 4rd PCI slot
10289 db 0 ;; pci bus number
10290 db 0x28 ;; pci device number (bit 7-3)
10291 db 0x60 ;; link value INTA#
10292 dw 0xdef8 ;; IRQ bitmap INTA#
10293 db 0x61 ;; link value INTB#
10294 dw 0xdef8 ;; IRQ bitmap INTB#
10295 db 0x62 ;; link value INTC#
10296 dw 0xdef8 ;; IRQ bitmap INTC#
10297 db 0x63 ;; link value INTD#
10298 dw 0xdef8 ;; IRQ bitmap INTD#
10299 db 4 ;; physical slot (0 = embedded)
10300 db 0 ;; reserved
10301 ;; 6th slot entry: 5rd PCI slot
10302 db 0 ;; pci bus number
10303 db 0x30 ;; pci device number (bit 7-3)
10304 db 0x61 ;; link value INTA#
10305 dw 0xdef8 ;; IRQ bitmap INTA#
10306 db 0x62 ;; link value INTB#
10307 dw 0xdef8 ;; IRQ bitmap INTB#
10308 db 0x63 ;; link value INTC#
10309 dw 0xdef8 ;; IRQ bitmap INTC#
10310 db 0x60 ;; link value INTD#
10311 dw 0xdef8 ;; IRQ bitmap INTD#
10312 db 5 ;; physical slot (0 = embedded)
10313 db 0 ;; reserved
10314#ifdef VBOX
10315 ;; 7th slot entry: 6th PCI slot
10316 db 0 ;; pci bus number
10317 db 0x38 ;; pci device number (bit 7-3)
10318 db 0x62 ;; link value INTA#
10319 dw 0xdef8 ;; IRQ bitmap INTA#
10320 db 0x63 ;; link value INTB#
10321 dw 0xdef8 ;; IRQ bitmap INTB#
10322 db 0x60 ;; link value INTC#
10323 dw 0xdef8 ;; IRQ bitmap INTC#
10324 db 0x61 ;; link value INTD#
10325 dw 0xdef8 ;; IRQ bitmap INTD#
10326 db 6 ;; physical slot (0 = embedded)
10327 db 0 ;; reserved
10328 ;; 8th slot entry: 7th PCI slot
10329 db 0 ;; pci bus number
10330 db 0x40 ;; pci device number (bit 7-3)
10331 db 0x63 ;; link value INTA#
10332 dw 0xdef8 ;; IRQ bitmap INTA#
10333 db 0x60 ;; link value INTB#
10334 dw 0xdef8 ;; IRQ bitmap INTB#
10335 db 0x61 ;; link value INTC#
10336 dw 0xdef8 ;; IRQ bitmap INTC#
10337 db 0x62 ;; link value INTD#
10338 dw 0xdef8 ;; IRQ bitmap INTD#
10339 db 7 ;; physical slot (0 = embedded)
10340 db 0 ;; reserved
10341 ;; 9th slot entry: 8th PCI slot
10342 db 0 ;; pci bus number
10343 db 0x48 ;; pci device number (bit 7-3)
10344 db 0x60 ;; link value INTA#
10345 dw 0xdef8 ;; IRQ bitmap INTA#
10346 db 0x61 ;; link value INTB#
10347 dw 0xdef8 ;; IRQ bitmap INTB#
10348 db 0x62 ;; link value INTC#
10349 dw 0xdef8 ;; IRQ bitmap INTC#
10350 db 0x63 ;; link value INTD#
10351 dw 0xdef8 ;; IRQ bitmap INTD#
10352 db 8 ;; physical slot (0 = embedded)
10353 db 0 ;; reserved
10354 ;; 10th slot entry: 9th PCI slot
10355 db 0 ;; pci bus number
10356 db 0x50 ;; pci device number (bit 7-3)
10357 db 0x61 ;; link value INTA#
10358 dw 0xdef8 ;; IRQ bitmap INTA#
10359 db 0x62 ;; link value INTB#
10360 dw 0xdef8 ;; IRQ bitmap INTB#
10361 db 0x63 ;; link value INTC#
10362 dw 0xdef8 ;; IRQ bitmap INTC#
10363 db 0x60 ;; link value INTD#
10364 dw 0xdef8 ;; IRQ bitmap INTD#
10365 db 9 ;; physical slot (0 = embedded)
10366 db 0 ;; reserved
10367 ;; 11th slot entry: 10th PCI slot
10368 db 0 ;; pci bus number
10369 db 0x58 ;; pci device number (bit 7-3)
10370 db 0x61 ;; link value INTA#
10371 dw 0xdef8 ;; IRQ bitmap INTA#
10372 db 0x62 ;; link value INTB#
10373 dw 0xdef8 ;; IRQ bitmap INTB#
10374 db 0x63 ;; link value INTC#
10375 dw 0xdef8 ;; IRQ bitmap INTC#
10376 db 0x60 ;; link value INTD#
10377 dw 0xdef8 ;; IRQ bitmap INTD#
10378 db 10 ;; physical slot (0 = embedded)
10379 db 0 ;; reserved
10380 ;; 12th slot entry: 11th PCI slot
10381 db 0 ;; pci bus number
10382 db 0x60 ;; pci device number (bit 7-3)
10383 db 0x61 ;; link value INTA#
10384 dw 0xdef8 ;; IRQ bitmap INTA#
10385 db 0x62 ;; link value INTB#
10386 dw 0xdef8 ;; IRQ bitmap INTB#
10387 db 0x63 ;; link value INTC#
10388 dw 0xdef8 ;; IRQ bitmap INTC#
10389 db 0x60 ;; link value INTD#
10390 dw 0xdef8 ;; IRQ bitmap INTD#
10391 db 11 ;; physical slot (0 = embedded)
10392 db 0 ;; reserved
10393 ;; 13th slot entry: 12th PCI slot
10394 db 0 ;; pci bus number
10395 db 0x68 ;; pci device number (bit 7-3)
10396 db 0x61 ;; link value INTA#
10397 dw 0xdef8 ;; IRQ bitmap INTA#
10398 db 0x62 ;; link value INTB#
10399 dw 0xdef8 ;; IRQ bitmap INTB#
10400 db 0x63 ;; link value INTC#
10401 dw 0xdef8 ;; IRQ bitmap INTC#
10402 db 0x60 ;; link value INTD#
10403 dw 0xdef8 ;; IRQ bitmap INTD#
10404 db 12 ;; physical slot (0 = embedded)
10405 db 0 ;; reserved
10406 ;; 14th slot entry: 13th PCI slot
10407 db 0 ;; pci bus number
10408 db 0x70 ;; pci device number (bit 7-3)
10409 db 0x61 ;; link value INTA#
10410 dw 0xdef8 ;; IRQ bitmap INTA#
10411 db 0x62 ;; link value INTB#
10412 dw 0xdef8 ;; IRQ bitmap INTB#
10413 db 0x63 ;; link value INTC#
10414 dw 0xdef8 ;; IRQ bitmap INTC#
10415 db 0x60 ;; link value INTD#
10416 dw 0xdef8 ;; IRQ bitmap INTD#
10417 db 13 ;; physical slot (0 = embedded)
10418 db 0 ;; reserved
10419 ;; 15th slot entry: 14th PCI slot
10420 db 0 ;; pci bus number
10421 db 0x78 ;; pci device number (bit 7-3)
10422 db 0x61 ;; link value INTA#
10423 dw 0xdef8 ;; IRQ bitmap INTA#
10424 db 0x62 ;; link value INTB#
10425 dw 0xdef8 ;; IRQ bitmap INTB#
10426 db 0x63 ;; link value INTC#
10427 dw 0xdef8 ;; IRQ bitmap INTC#
10428 db 0x60 ;; link value INTD#
10429 dw 0xdef8 ;; IRQ bitmap INTD#
10430 db 14 ;; physical slot (0 = embedded)
10431 db 0 ;; reserved
10432 ;; 16th slot entry: 15th PCI slot
10433 db 0 ;; pci bus number
10434 db 0x80 ;; pci device number (bit 7-3)
10435 db 0x61 ;; link value INTA#
10436 dw 0xdef8 ;; IRQ bitmap INTA#
10437 db 0x62 ;; link value INTB#
10438 dw 0xdef8 ;; IRQ bitmap INTB#
10439 db 0x63 ;; link value INTC#
10440 dw 0xdef8 ;; IRQ bitmap INTC#
10441 db 0x60 ;; link value INTD#
10442 dw 0xdef8 ;; IRQ bitmap INTD#
10443 db 15 ;; physical slot (0 = embedded)
10444 db 0 ;; reserved
10445 ;; 17th slot entry: 16th PCI slot
10446 db 0 ;; pci bus number
10447 db 0x88 ;; pci device number (bit 7-3)
10448 db 0x61 ;; link value INTA#
10449 dw 0xdef8 ;; IRQ bitmap INTA#
10450 db 0x62 ;; link value INTB#
10451 dw 0xdef8 ;; IRQ bitmap INTB#
10452 db 0x63 ;; link value INTC#
10453 dw 0xdef8 ;; IRQ bitmap INTC#
10454 db 0x60 ;; link value INTD#
10455 dw 0xdef8 ;; IRQ bitmap INTD#
10456 db 16 ;; physical slot (0 = embedded)
10457 db 0 ;; reserved
10458 ;; 18th slot entry: 17th PCI slot
10459 db 0 ;; pci bus number
10460 db 0x90 ;; pci device number (bit 7-3)
10461 db 0x61 ;; link value INTA#
10462 dw 0xdef8 ;; IRQ bitmap INTA#
10463 db 0x62 ;; link value INTB#
10464 dw 0xdef8 ;; IRQ bitmap INTB#
10465 db 0x63 ;; link value INTC#
10466 dw 0xdef8 ;; IRQ bitmap INTC#
10467 db 0x60 ;; link value INTD#
10468 dw 0xdef8 ;; IRQ bitmap INTD#
10469 db 17 ;; physical slot (0 = embedded)
10470 db 0 ;; reserved
10471 ;; 19th slot entry: 18th PCI slot
10472 db 0 ;; pci bus number
10473 db 0x98 ;; pci device number (bit 7-3)
10474 db 0x61 ;; link value INTA#
10475 dw 0xdef8 ;; IRQ bitmap INTA#
10476 db 0x62 ;; link value INTB#
10477 dw 0xdef8 ;; IRQ bitmap INTB#
10478 db 0x63 ;; link value INTC#
10479 dw 0xdef8 ;; IRQ bitmap INTC#
10480 db 0x60 ;; link value INTD#
10481 dw 0xdef8 ;; IRQ bitmap INTD#
10482 db 18 ;; physical slot (0 = embedded)
10483 db 0 ;; reserved
10484 ;; 20th slot entry: 19th PCI slot
10485 db 0 ;; pci bus number
10486 db 0xa0 ;; pci device number (bit 7-3)
10487 db 0x61 ;; link value INTA#
10488 dw 0xdef8 ;; IRQ bitmap INTA#
10489 db 0x62 ;; link value INTB#
10490 dw 0xdef8 ;; IRQ bitmap INTB#
10491 db 0x63 ;; link value INTC#
10492 dw 0xdef8 ;; IRQ bitmap INTC#
10493 db 0x60 ;; link value INTD#
10494 dw 0xdef8 ;; IRQ bitmap INTD#
10495 db 19 ;; physical slot (0 = embedded)
10496 db 0 ;; reserved
10497 ;; 21th slot entry: 20th PCI slot
10498 db 0 ;; pci bus number
10499 db 0xa8 ;; pci device number (bit 7-3)
10500 db 0x61 ;; link value INTA#
10501 dw 0xdef8 ;; IRQ bitmap INTA#
10502 db 0x62 ;; link value INTB#
10503 dw 0xdef8 ;; IRQ bitmap INTB#
10504 db 0x63 ;; link value INTC#
10505 dw 0xdef8 ;; IRQ bitmap INTC#
10506 db 0x60 ;; link value INTD#
10507 dw 0xdef8 ;; IRQ bitmap INTD#
10508 db 20 ;; physical slot (0 = embedded)
10509 db 0 ;; reserved
10510 ;; 21th slot entry: 20th PCI slot
10511 db 0 ;; pci bus number
10512 db 0xb0 ;; pci device number (bit 7-3)
10513 db 0x61 ;; link value INTA#
10514 dw 0xdef8 ;; IRQ bitmap INTA#
10515 db 0x62 ;; link value INTB#
10516 dw 0xdef8 ;; IRQ bitmap INTB#
10517 db 0x63 ;; link value INTC#
10518 dw 0xdef8 ;; IRQ bitmap INTC#
10519 db 0x60 ;; link value INTD#
10520 dw 0xdef8 ;; IRQ bitmap INTD#
10521 db 20 ;; physical slot (0 = embedded)
10522 db 0 ;; reserved
10523 ;; 22th slot entry: 21th PCI slot
10524 db 0 ;; pci bus number
10525 db 0xb8 ;; pci device number (bit 7-3)
10526 db 0x61 ;; link value INTA#
10527 dw 0xdef8 ;; IRQ bitmap INTA#
10528 db 0x62 ;; link value INTB#
10529 dw 0xdef8 ;; IRQ bitmap INTB#
10530 db 0x63 ;; link value INTC#
10531 dw 0xdef8 ;; IRQ bitmap INTC#
10532 db 0x60 ;; link value INTD#
10533 dw 0xdef8 ;; IRQ bitmap INTD#
10534 db 21 ;; physical slot (0 = embedded)
10535 db 0 ;; reserved
10536 ;; 23th slot entry: 22th PCI slot
10537 db 0 ;; pci bus number
10538 db 0xc0 ;; pci device number (bit 7-3)
10539 db 0x61 ;; link value INTA#
10540 dw 0xdef8 ;; IRQ bitmap INTA#
10541 db 0x62 ;; link value INTB#
10542 dw 0xdef8 ;; IRQ bitmap INTB#
10543 db 0x63 ;; link value INTC#
10544 dw 0xdef8 ;; IRQ bitmap INTC#
10545 db 0x60 ;; link value INTD#
10546 dw 0xdef8 ;; IRQ bitmap INTD#
10547 db 22 ;; physical slot (0 = embedded)
10548 db 0 ;; reserved
10549 ;; 24th slot entry: 23th PCI slot
10550 db 0 ;; pci bus number
10551 db 0xc8 ;; pci device number (bit 7-3)
10552 db 0x61 ;; link value INTA#
10553 dw 0xdef8 ;; IRQ bitmap INTA#
10554 db 0x62 ;; link value INTB#
10555 dw 0xdef8 ;; IRQ bitmap INTB#
10556 db 0x63 ;; link value INTC#
10557 dw 0xdef8 ;; IRQ bitmap INTC#
10558 db 0x60 ;; link value INTD#
10559 dw 0xdef8 ;; IRQ bitmap INTD#
10560 db 23 ;; physical slot (0 = embedded)
10561 db 0 ;; reserved
10562 ;; 25th slot entry: 24th PCI slot
10563 db 0 ;; pci bus number
10564 db 0xd0 ;; pci device number (bit 7-3)
10565 db 0x61 ;; link value INTA#
10566 dw 0xdef8 ;; IRQ bitmap INTA#
10567 db 0x62 ;; link value INTB#
10568 dw 0xdef8 ;; IRQ bitmap INTB#
10569 db 0x63 ;; link value INTC#
10570 dw 0xdef8 ;; IRQ bitmap INTC#
10571 db 0x60 ;; link value INTD#
10572 dw 0xdef8 ;; IRQ bitmap INTD#
10573 db 24 ;; physical slot (0 = embedded)
10574 db 0 ;; reserved
10575 ;; 26th slot entry: 25th PCI slot
10576 db 0 ;; pci bus number
10577 db 0xd8 ;; pci device number (bit 7-3)
10578 db 0x61 ;; link value INTA#
10579 dw 0xdef8 ;; IRQ bitmap INTA#
10580 db 0x62 ;; link value INTB#
10581 dw 0xdef8 ;; IRQ bitmap INTB#
10582 db 0x63 ;; link value INTC#
10583 dw 0xdef8 ;; IRQ bitmap INTC#
10584 db 0x60 ;; link value INTD#
10585 dw 0xdef8 ;; IRQ bitmap INTD#
10586 db 25 ;; physical slot (0 = embedded)
10587 db 0 ;; reserved
10588 ;; 27th slot entry: 26th PCI slot
10589 db 0 ;; pci bus number
10590 db 0xe0 ;; pci device number (bit 7-3)
10591 db 0x61 ;; link value INTA#
10592 dw 0xdef8 ;; IRQ bitmap INTA#
10593 db 0x62 ;; link value INTB#
10594 dw 0xdef8 ;; IRQ bitmap INTB#
10595 db 0x63 ;; link value INTC#
10596 dw 0xdef8 ;; IRQ bitmap INTC#
10597 db 0x60 ;; link value INTD#
10598 dw 0xdef8 ;; IRQ bitmap INTD#
10599 db 26 ;; physical slot (0 = embedded)
10600 db 0 ;; reserved
10601 ;; 28th slot entry: 27th PCI slot
10602 db 0 ;; pci bus number
10603 db 0xe8 ;; pci device number (bit 7-3)
10604 db 0x61 ;; link value INTA#
10605 dw 0xdef8 ;; IRQ bitmap INTA#
10606 db 0x62 ;; link value INTB#
10607 dw 0xdef8 ;; IRQ bitmap INTB#
10608 db 0x63 ;; link value INTC#
10609 dw 0xdef8 ;; IRQ bitmap INTC#
10610 db 0x60 ;; link value INTD#
10611 dw 0xdef8 ;; IRQ bitmap INTD#
10612 db 27 ;; physical slot (0 = embedded)
10613 db 0 ;; reserved
10614 ;; 29th slot entry: 28th PCI slot
10615 db 0 ;; pci bus number
10616 db 0xf0 ;; pci device number (bit 7-3)
10617 db 0x61 ;; link value INTA#
10618 dw 0xdef8 ;; IRQ bitmap INTA#
10619 db 0x62 ;; link value INTB#
10620 dw 0xdef8 ;; IRQ bitmap INTB#
10621 db 0x63 ;; link value INTC#
10622 dw 0xdef8 ;; IRQ bitmap INTC#
10623 db 0x60 ;; link value INTD#
10624 dw 0xdef8 ;; IRQ bitmap INTD#
10625 db 28 ;; physical slot (0 = embedded)
10626 db 0 ;; reserved
10627 ;; 30th slot entry: 29th PCI slot
10628 db 0 ;; pci bus number
10629 db 0xf8 ;; pci device number (bit 7-3)
10630 db 0x61 ;; link value INTA#
10631 dw 0xdef8 ;; IRQ bitmap INTA#
10632 db 0x62 ;; link value INTB#
10633 dw 0xdef8 ;; IRQ bitmap INTB#
10634 db 0x63 ;; link value INTC#
10635 dw 0xdef8 ;; IRQ bitmap INTC#
10636 db 0x60 ;; link value INTD#
10637 dw 0xdef8 ;; IRQ bitmap INTD#
10638 db 29 ;; physical slot (0 = embedded)
10639 db 0 ;; reserved
10640#endif /* VBOX */
10641pci_routing_table_structure_end:
10642
10643#if !BX_ROMBIOS32
10644pci_irq_list:
10645 db 11, 10, 9, 5;
10646
10647pcibios_init_sel_reg:
10648 push eax
10649 mov eax, #0x800000
10650 mov ax, bx
10651 shl eax, #8
10652 and dl, #0xfc
10653 or al, dl
10654 mov dx, #0x0cf8
10655 out dx, eax
10656 pop eax
10657 ret
10658
10659pcibios_init_iomem_bases:
10660 push bp
10661 mov bp, sp
10662 mov eax, #0xe0000000 ;; base for memory init
10663 push eax
10664 mov ax, #0xc000 ;; base for i/o init
10665 push ax
10666 mov ax, #0x0010 ;; start at base address #0
10667 push ax
10668 mov bx, #0x0008
10669pci_init_io_loop1:
10670 mov dl, #0x00
10671 call pcibios_init_sel_reg
10672 mov dx, #0x0cfc
10673 in ax, dx
10674 cmp ax, #0xffff
10675 jz next_pci_dev
10676#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10677 mov dl, #0x04 ;; disable i/o and memory space access
10678 call pcibios_init_sel_reg
10679 mov dx, #0x0cfc
10680 in al, dx
10681 and al, #0xfc
10682 out dx, al
10683pci_init_io_loop2:
10684 mov dl, [bp-8]
10685 call pcibios_init_sel_reg
10686 mov dx, #0x0cfc
10687 in eax, dx
10688 test al, #0x01
10689 jnz init_io_base
10690 mov ecx, eax
10691 mov eax, #0xffffffff
10692 out dx, eax
10693 in eax, dx
10694 cmp eax, ecx
10695 je next_pci_base
10696 xor eax, #0xffffffff
10697 mov ecx, eax
10698 mov eax, [bp-4]
10699 out dx, eax
10700 add eax, ecx ;; calculate next free mem base
10701 add eax, #0x01000000
10702 and eax, #0xff000000
10703 mov [bp-4], eax
10704 jmp next_pci_base
10705init_io_base:
10706 mov cx, ax
10707 mov ax, #0xffff
10708 out dx, ax
10709 in ax, dx
10710 cmp ax, cx
10711 je next_pci_base
10712 xor ax, #0xfffe
10713 mov cx, ax
10714 mov ax, [bp-6]
10715 out dx, ax
10716 add ax, cx ;; calculate next free i/o base
10717 add ax, #0x0100
10718 and ax, #0xff00
10719 mov [bp-6], ax
10720next_pci_base:
10721 mov al, [bp-8]
10722 add al, #0x04
10723 cmp al, #0x28
10724 je enable_iomem_space
10725 mov byte ptr[bp-8], al
10726 jmp pci_init_io_loop2
10727#endif /* !VBOX */
10728enable_iomem_space:
10729 mov dl, #0x04 ;; enable i/o and memory space access if available
10730 call pcibios_init_sel_reg
10731 mov dx, #0x0cfc
10732 in al, dx
10733 or al, #0x07
10734 out dx, al
10735#ifdef VBOX
10736 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10737 call pcibios_init_sel_reg
10738 mov dx, #0x0cfc
10739 in eax, dx
10740 cmp eax, #0x20001022
10741 jne next_pci_dev
10742 mov dl, #0x10 ;; get I/O address
10743 call pcibios_init_sel_reg
10744 mov dx, #0x0cfc
10745 in ax, dx
10746 and ax, #0xfffc
10747 mov cx, ax
10748 mov dx, cx
10749 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10750 in ax, dx ;; reset is performed by reading the reset register
10751 mov dx, cx
10752 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10753 in eax, dx ;; reset is performed by reading the reset register
10754#endif /* VBOX */
10755next_pci_dev:
10756 mov byte ptr[bp-8], #0x10
10757 inc bx
10758 cmp bx, #0x0100
10759 jne pci_init_io_loop1
10760 mov sp, bp
10761 pop bp
10762 ret
10763
10764pcibios_init_set_elcr:
10765 push ax
10766 push cx
10767 mov dx, #0x04d0
10768 test al, #0x08
10769 jz is_master_pic
10770 inc dx
10771 and al, #0x07
10772is_master_pic:
10773 mov cl, al
10774 mov bl, #0x01
10775 shl bl, cl
10776 in al, dx
10777 or al, bl
10778 out dx, al
10779 pop cx
10780 pop ax
10781 ret
10782
10783pcibios_init_irqs:
10784 push ds
10785 push bp
10786 mov ax, #0xf000
10787 mov ds, ax
10788 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10789 mov al, #0x00
10790 out dx, al
10791 inc dx
10792 out dx, al
10793 mov si, #pci_routing_table_structure
10794 mov bh, [si+8]
10795 mov bl, [si+9]
10796 mov dl, #0x00
10797 call pcibios_init_sel_reg
10798 mov dx, #0x0cfc
10799 in eax, dx
10800 cmp eax, [si+12] ;; check irq router
10801 jne pci_init_end
10802 mov dl, [si+34]
10803 call pcibios_init_sel_reg
10804 push bx ;; save irq router bus + devfunc
10805 mov dx, #0x0cfc
10806 mov ax, #0x8080
10807 out dx, ax ;; reset PIRQ route control
10808 add dx, #2
10809 out dx, ax
10810 mov ax, [si+6]
10811 sub ax, #0x20
10812 shr ax, #4
10813 mov cx, ax
10814 add si, #0x20 ;; set pointer to 1st entry
10815 mov bp, sp
10816 mov ax, #pci_irq_list
10817 push ax
10818 xor ax, ax
10819 push ax
10820pci_init_irq_loop1:
10821 mov bh, [si]
10822 mov bl, [si+1]
10823pci_init_irq_loop2:
10824 mov dl, #0x00
10825 call pcibios_init_sel_reg
10826 mov dx, #0x0cfc
10827 in ax, dx
10828 cmp ax, #0xffff
10829 jnz pci_test_int_pin
10830 test bl, #0x07
10831 jz next_pir_entry
10832 jmp next_pci_func
10833pci_test_int_pin:
10834 mov dl, #0x3c
10835 call pcibios_init_sel_reg
10836 mov dx, #0x0cfd
10837 in al, dx
10838 and al, #0x07
10839 jz next_pci_func
10840 dec al ;; determine pirq reg
10841 mov dl, #0x03
10842 mul al, dl
10843 add al, #0x02
10844 xor ah, ah
10845 mov bx, ax
10846 mov al, [si+bx]
10847 mov dl, al
10848 mov bx, [bp]
10849 call pcibios_init_sel_reg
10850 mov dx, #0x0cfc
10851 and al, #0x03
10852 add dl, al
10853 in al, dx
10854 cmp al, #0x80
10855 jb pirq_found
10856 mov bx, [bp-2] ;; pci irq list pointer
10857 mov al, [bx]
10858 out dx, al
10859 inc bx
10860 mov [bp-2], bx
10861 call pcibios_init_set_elcr
10862pirq_found:
10863 mov bh, [si]
10864 mov bl, [si+1]
10865 add bl, [bp-3] ;; pci function number
10866 mov dl, #0x3c
10867 call pcibios_init_sel_reg
10868 mov dx, #0x0cfc
10869 out dx, al
10870next_pci_func:
10871 inc byte ptr[bp-3]
10872 inc bl
10873 test bl, #0x07
10874 jnz pci_init_irq_loop2
10875next_pir_entry:
10876 add si, #0x10
10877 mov byte ptr[bp-3], #0x00
10878 loop pci_init_irq_loop1
10879 mov sp, bp
10880 pop bx
10881pci_init_end:
10882 pop bp
10883 pop ds
10884 ret
10885#endif // !BX_ROMBIOS32
10886#endif // BX_PCIBIOS
10887
10888#if BX_ROMBIOS32
10889rombios32_init:
10890 ;; save a20 and enable it
10891 in al, 0x92
10892 push ax
10893 or al, #0x02
10894 out 0x92, al
10895
10896 ;; save SS:SP to the BDA
10897 xor ax, ax
10898 mov ds, ax
10899 mov 0x0469, ss
10900 mov 0x0467, sp
10901
10902 SEG CS
10903 lidt [pmode_IDT_info]
10904 SEG CS
10905 lgdt [rombios32_gdt_48]
10906 ;; set PE bit in CR0
10907 mov eax, cr0
10908 or al, #0x01
10909 mov cr0, eax
10910 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10911 db 0x66, 0xea
10912 dw rombios32_05
10913 dw 0x000f ;; high 16 bit address
10914 dw 0x0010
10915
10916use32 386
10917rombios32_05:
10918 ;; init data segments
10919 mov eax, #0x18
10920 mov ds, ax
10921 mov es, ax
10922 mov ss, ax
10923 xor eax, eax
10924 mov fs, ax
10925 mov gs, ax
10926 cld
10927
10928 ;; copy rombios32 code to ram (ram offset = 1MB)
10929 mov esi, #0xfffe0000
10930 mov edi, #0x00040000
10931 mov ecx, #0x10000 / 4
10932 rep
10933 movsd
10934
10935 ;; init the stack pointer
10936 mov esp, #0x00080000
10937
10938 ;; call rombios32 code
10939 mov eax, #0x00040000
10940 call eax
10941
10942 ;; return to 16 bit protected mode first
10943 db 0xea
10944 dd rombios32_10
10945 dw 0x20
10946
10947use16 386
10948rombios32_10:
10949 ;; restore data segment limits to 0xffff
10950 mov ax, #0x28
10951 mov ds, ax
10952 mov es, ax
10953 mov ss, ax
10954 mov fs, ax
10955 mov gs, ax
10956
10957 ;; reset PE bit in CR0
10958 mov eax, cr0
10959 and al, #0xFE
10960 mov cr0, eax
10961
10962 ;; far jump to flush CPU queue after transition to real mode
10963 JMP_AP(0xf000, rombios32_real_mode)
10964
10965rombios32_real_mode:
10966 ;; restore IDT to normal real-mode defaults
10967 SEG CS
10968 lidt [rmode_IDT_info]
10969
10970 xor ax, ax
10971 mov ds, ax
10972 mov es, ax
10973 mov fs, ax
10974 mov gs, ax
10975
10976 ;; restore SS:SP from the BDA
10977 mov ss, 0x0469
10978 xor esp, esp
10979 mov sp, 0x0467
10980 ;; restore a20
10981 pop ax
10982 out 0x92, al
10983 ret
10984
10985rombios32_gdt_48:
10986 dw 0x30
10987 dw rombios32_gdt
10988 dw 0x000f
10989
10990rombios32_gdt:
10991 dw 0, 0, 0, 0
10992 dw 0, 0, 0, 0
10993 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
10994 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
10995 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
10996 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
10997#endif // BX_ROMBIOS32
10998
10999
11000; parallel port detection: base address in DX, index in BX, timeout in CL
11001detect_parport:
11002 push dx
11003 add dx, #2
11004 in al, dx
11005 and al, #0xdf ; clear input mode
11006 out dx, al
11007 pop dx
11008 mov al, #0xaa
11009 out dx, al
11010 in al, dx
11011 cmp al, #0xaa
11012 jne no_parport
11013 push bx
11014 shl bx, #1
11015 mov [bx+0x408], dx ; Parallel I/O address
11016 pop bx
11017 mov [bx+0x478], cl ; Parallel printer timeout
11018 inc bx
11019no_parport:
11020 ret
11021
11022; serial port detection: base address in DX, index in BX, timeout in CL
11023detect_serial:
11024 push dx
11025 inc dx
11026 mov al, #0x02
11027 out dx, al
11028 in al, dx
11029 cmp al, #0x02
11030 jne no_serial
11031 inc dx
11032 in al, dx
11033 cmp al, #0x02
11034 jne no_serial
11035 dec dx
11036 xor al, al
11037 out dx, al
11038 pop dx
11039 push bx
11040 shl bx, #1
11041 mov [bx+0x400], dx ; Serial I/O address
11042 pop bx
11043 mov [bx+0x47c], cl ; Serial timeout
11044 inc bx
11045 ret
11046no_serial:
11047 pop dx
11048 ret
11049
11050rom_checksum:
11051 push ax
11052 push bx
11053 push cx
11054 xor ax, ax
11055 xor bx, bx
11056 xor cx, cx
11057 mov ch, [2]
11058 shl cx, #1
11059checksum_loop:
11060 add al, [bx]
11061 inc bx
11062 loop checksum_loop
11063 and al, #0xff
11064 pop cx
11065 pop bx
11066 pop ax
11067 ret
11068
11069rom_scan:
11070 ;; Scan for existence of valid expansion ROMS.
11071 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11072 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11073 ;; System ROM: only 0xE0000
11074 ;;
11075 ;; Header:
11076 ;; Offset Value
11077 ;; 0 0x55
11078 ;; 1 0xAA
11079 ;; 2 ROM length in 512-byte blocks
11080 ;; 3 ROM initialization entry point (FAR CALL)
11081
11082 mov cx, #0xc000
11083rom_scan_loop:
11084 mov ds, cx
11085 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11086 cmp [0], #0xAA55 ;; look for signature
11087 jne rom_scan_increment
11088 call rom_checksum
11089 jnz rom_scan_increment
11090 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11091
11092 ;; We want our increment in 512-byte quantities, rounded to
11093 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11094 test al, #0x03
11095 jz block_count_rounded
11096 and al, #0xfc ;; needs rounding up
11097 add al, #0x04
11098block_count_rounded:
11099
11100 xor bx, bx ;; Restore DS back to 0000:
11101 mov ds, bx
11102 push ax ;; Save AX
11103 ;; Push addr of ROM entry point
11104 push cx ;; Push seg
11105 push #0x0003 ;; Push offset
11106 mov bp, sp ;; Call ROM init routine using seg:off on stack
11107 db 0xff ;; call_far ss:[bp+0]
11108 db 0x5e
11109 db 0
11110 cli ;; In case expansion ROM BIOS turns IF on
11111 add sp, #2 ;; Pop offset value
11112 pop cx ;; Pop seg value (restore CX)
11113 pop ax ;; Restore AX
11114rom_scan_increment:
11115 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11116 ;; because the segment selector is shifted left 4 bits.
11117 add cx, ax
11118 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11119 jbe rom_scan_loop
11120
11121 xor ax, ax ;; Restore DS back to 0000:
11122 mov ds, ax
11123 ret
11124
11125;; for 'C' strings and other data, insert them here with
11126;; a the following hack:
11127;; DATA_SEG_DEFS_HERE
11128
11129
11130;; the following area can be used to write dynamically generated tables
11131 .align 16
11132bios_table_area_start:
11133 dd 0xaafb4442
11134 dd bios_table_area_end - bios_table_area_start - 8;
11135
11136;--------
11137;- POST -
11138;--------
11139.org 0xe05b ; POST Entry Point
11140bios_table_area_end:
11141post:
11142
11143 xor ax, ax
11144
11145 ;; first reset the DMA controllers
11146 out 0x0d,al
11147 out 0xda,al
11148
11149 ;; then initialize the DMA controllers
11150 mov al, #0xC0
11151 out 0xD6, al ; cascade mode of channel 4 enabled
11152 mov al, #0x00
11153 out 0xD4, al ; unmask channel 4
11154
11155 ;; Examine CMOS shutdown status.
11156 mov AL, #0x0f
11157 out 0x70, AL
11158 in AL, 0x71
11159
11160 ;; backup status
11161 mov bl, al
11162
11163 ;; Reset CMOS shutdown status.
11164 mov AL, #0x0f
11165 out 0x70, AL ; select CMOS register Fh
11166 mov AL, #0x00
11167 out 0x71, AL ; set shutdown action to normal
11168
11169 ;; Examine CMOS shutdown status.
11170 mov al, bl
11171
11172 ;; 0x00, 0x09, 0x0D+ = normal startup
11173 cmp AL, #0x00
11174 jz normal_post
11175 cmp AL, #0x0d
11176 jae normal_post
11177 cmp AL, #0x09
11178 je normal_post
11179
11180 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11181 cmp al, #0x05
11182 je eoi_jmp_post
11183
11184 ;; Examine CMOS shutdown status.
11185 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11186 push bx
11187 call _shutdown_status_panic
11188
11189#if 0
11190 HALT(__LINE__)
11191 ;
11192 ;#if 0
11193 ; 0xb0, 0x20, /* mov al, #0x20 */
11194 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11195 ;#endif
11196 ;
11197 pop es
11198 pop ds
11199 popa
11200 iret
11201#endif
11202
11203normal_post:
11204 ; case 0: normal startup
11205
11206 cli
11207 mov ax, #0xfffe
11208 mov sp, ax
11209 xor ax, ax
11210 mov ds, ax
11211 mov ss, ax
11212
11213#ifndef VBOX
11214 ;; zero out BIOS data area (40:00..40:ff)
11215 mov es, ax
11216 mov cx, #0x0080 ;; 128 words
11217 mov di, #0x0400
11218 cld
11219 rep
11220 stosw
11221#else /* VBOX */
11222 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11223 mov es, ax
11224 xor di, di
11225 cld
11226 mov cx, #0x0239 ;; 569 words
11227 rep
11228 stosw
11229 inc di
11230 inc di
11231 mov cx, #0x7dc6 ;; 32198 words
11232 rep
11233 stosw
11234 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11235 ;; because we store the MP table there
11236 xor eax, eax
11237 xor bx, bx
11238memory_zero_loop:
11239 add bx, #0x1000
11240 cmp bx, #0x9000
11241 jae memory_cleared
11242 mov es, bx
11243 xor di, di
11244 mov cx, #0x4000
11245 rep
11246 stosd
11247 jmp memory_zero_loop
11248memory_cleared:
11249 mov es, bx
11250 xor di, di
11251 mov cx, #0x3f00
11252 rep
11253 stosd
11254 xor bx, bx
11255#endif
11256
11257 call _log_bios_start
11258
11259 ;; set all interrupts to default handler
11260 xor bx, bx ;; offset index
11261 mov cx, #0x0100 ;; counter (256 interrupts)
11262 mov ax, #dummy_iret_handler
11263 mov dx, #0xF000
11264
11265post_default_ints:
11266 mov [bx], ax
11267 add bx, #2
11268 mov [bx], dx
11269 add bx, #2
11270 loop post_default_ints
11271
11272 ;; set vector 0x79 to zero
11273 ;; this is used by 'gardian angel' protection system
11274 SET_INT_VECTOR(0x79, #0, #0)
11275
11276 ;; base memory in K 40:13 (word)
11277 mov ax, #BASE_MEM_IN_K
11278 mov 0x0413, ax
11279
11280
11281 ;; Manufacturing Test 40:12
11282 ;; zerod out above
11283
11284#ifndef VBOX
11285 ;; Warm Boot Flag 0040:0072
11286 ;; value of 1234h = skip memory checks
11287 ;; zerod out above
11288#endif /* !VBOX */
11289
11290
11291 ;; Printer Services vector
11292 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11293
11294 ;; Bootstrap failure vector
11295 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11296
11297 ;; Bootstrap Loader vector
11298 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11299
11300 ;; User Timer Tick vector
11301 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11302
11303 ;; Memory Size Check vector
11304 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11305
11306 ;; Equipment Configuration Check vector
11307 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11308
11309 ;; System Services
11310 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11311
11312 ;; EBDA setup
11313 call ebda_post
11314
11315 ;; PIT setup
11316 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11317 ;; int 1C already points at dummy_iret_handler (above)
11318 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11319 out 0x43, al
11320 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11321 out 0x40, al
11322 out 0x40, al
11323
11324 ;; Keyboard
11325 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11326 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11327
11328 xor ax, ax
11329 mov ds, ax
11330 mov 0x0417, al /* keyboard shift flags, set 1 */
11331 mov 0x0418, al /* keyboard shift flags, set 2 */
11332 mov 0x0419, al /* keyboard alt-numpad work area */
11333 mov 0x0471, al /* keyboard ctrl-break flag */
11334 mov 0x0497, al /* keyboard status flags 4 */
11335 mov al, #0x10
11336 mov 0x0496, al /* keyboard status flags 3 */
11337
11338
11339 /* keyboard head of buffer pointer */
11340 mov bx, #0x001E
11341 mov 0x041A, bx
11342
11343 /* keyboard end of buffer pointer */
11344 mov 0x041C, bx
11345
11346 /* keyboard pointer to start of buffer */
11347 mov bx, #0x001E
11348 mov 0x0480, bx
11349
11350 /* keyboard pointer to end of buffer */
11351 mov bx, #0x003E
11352 mov 0x0482, bx
11353
11354 /* init the keyboard */
11355 call _keyboard_init
11356
11357 ;; mov CMOS Equipment Byte to BDA Equipment Word
11358 mov ax, 0x0410
11359 mov al, #0x14
11360 out 0x70, al
11361 in al, 0x71
11362 mov 0x0410, ax
11363
11364
11365 ;; Parallel setup
11366 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11367 xor ax, ax
11368 mov ds, ax
11369 xor bx, bx
11370 mov cl, #0x14 ; timeout value
11371 mov dx, #0x378 ; Parallel I/O address, port 1
11372 call detect_parport
11373 mov dx, #0x278 ; Parallel I/O address, port 2
11374 call detect_parport
11375 shl bx, #0x0e
11376 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
11377 and ax, #0x3fff
11378 or ax, bx ; set number of parallel ports
11379 mov 0x410, ax
11380
11381 ;; Serial setup
11382 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11383 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11384 xor bx, bx
11385 mov cl, #0x0a ; timeout value
11386 mov dx, #0x03f8 ; Serial I/O address, port 1
11387 call detect_serial
11388 mov dx, #0x02f8 ; Serial I/O address, port 2
11389 call detect_serial
11390 mov dx, #0x03e8 ; Serial I/O address, port 3
11391 call detect_serial
11392 mov dx, #0x02e8 ; Serial I/O address, port 4
11393 call detect_serial
11394 shl bx, #0x09
11395 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11396 and ax, #0xf1ff
11397 or ax, bx ; set number of serial port
11398 mov 0x410, ax
11399
11400 ;; CMOS RTC
11401 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11402 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11403 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11404 ;; BIOS DATA AREA 0x4CE ???
11405 call timer_tick_post
11406
11407 ;; PS/2 mouse setup
11408 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11409
11410 ;; IRQ13 (FPU exception) setup
11411 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11412
11413 ;; Video setup
11414 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11415
11416#ifdef VBOX
11417 ;; moved the PIC initialization to another place as we need
11418 ;; some space for additions init calls. Otherwise this code
11419 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11420 call init_pic
11421#else /* !VBOX */
11422 ;; PIC
11423 mov al, #0x11 ; send initialisation commands
11424 out 0x20, al
11425 out 0xa0, al
11426 mov al, #0x08
11427 out 0x21, al
11428 mov al, #0x70
11429 out 0xa1, al
11430 mov al, #0x04
11431 out 0x21, al
11432 mov al, #0x02
11433 out 0xa1, al
11434 mov al, #0x01
11435 out 0x21, al
11436 out 0xa1, al
11437 mov al, #0xb8
11438 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11439#if BX_USE_PS2_MOUSE
11440 mov al, #0x8f
11441#else
11442 mov al, #0x9f
11443#endif
11444 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11445#endif /* !VBOX */
11446
11447#if BX_ROMBIOS32
11448 call rombios32_init
11449#else
11450 call pcibios_init_iomem_bases
11451 call pcibios_init_irqs
11452#endif
11453 call rom_scan
11454
11455#if BX_USE_ATADRV
11456 ;;
11457 ;; ATA/ATAPI driver setup
11458 ;;
11459 call _ata_init
11460 call _ata_detect
11461 ;;
11462#endif
11463
11464#ifdef VBOX_WITH_SCSI
11465 ;;
11466 ;; SCSI driver setup
11467 ;;
11468 call _scsi_init
11469 ;;
11470#endif
11471
11472 call _print_bios_banner
11473
11474 ;;
11475 ;; Floppy setup
11476 ;;
11477 call floppy_drive_post
11478
11479 ;;
11480 ;; Hard Drive setup
11481 ;;
11482 call hard_drive_post
11483
11484#if BX_ELTORITO_BOOT
11485 ;;
11486 ;; eltorito floppy/harddisk emulation from cd
11487 ;;
11488 call _cdemu_init
11489 ;;
11490#endif // BX_ELTORITO_BOOT
11491
11492 sti ;; enable interrupts
11493 int #0x19
11494
11495.org 0xe2c3 ; NMI Handler Entry Point
11496nmi:
11497 ;; FIXME the NMI handler should not panic
11498 ;; but iret when called from int75 (fpu exception)
11499 call _nmi_handler_msg
11500 iret
11501
11502int75_handler:
11503 out 0xf0, al // clear irq13
11504 call eoi_both_pics // clear interrupt
11505 int 2 // legacy nmi call
11506 iret
11507
11508;-------------------------------------------
11509;- INT 13h Fixed Disk Services Entry Point -
11510;-------------------------------------------
11511.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11512int13_handler:
11513 //JMPL(int13_relocated)
11514 jmp int13_relocated
11515
11516.org 0xe401 ; Fixed Disk Parameter Table
11517
11518;----------
11519;- INT19h -
11520;----------
11521.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11522int19_handler:
11523
11524 jmp int19_relocated
11525;-------------------------------------------
11526;- System BIOS Configuration Data Table
11527;-------------------------------------------
11528.org BIOS_CONFIG_TABLE
11529db 0x08 ; Table size (bytes) -Lo
11530db 0x00 ; Table size (bytes) -Hi
11531db SYS_MODEL_ID
11532db SYS_SUBMODEL_ID
11533db BIOS_REVISION
11534; Feature byte 1
11535; b7: 1=DMA channel 3 used by hard disk
11536; b6: 1=2 interrupt controllers present
11537; b5: 1=RTC present
11538; b4: 1=BIOS calls int 15h/4Fh every key
11539; b3: 1=wait for extern event supported (Int 15h/41h)
11540; b2: 1=extended BIOS data area used
11541; b1: 0=AT or ESDI bus, 1=MicroChannel
11542; b0: 1=Dual bus (MicroChannel + ISA)
11543db (0 << 7) | \
11544 (1 << 6) | \
11545 (1 << 5) | \
11546 (BX_CALL_INT15_4F << 4) | \
11547 (0 << 3) | \
11548 (BX_USE_EBDA << 2) | \
11549 (0 << 1) | \
11550 (0 << 0)
11551; Feature byte 2
11552; b7: 1=32-bit DMA supported
11553; b6: 1=int16h, function 9 supported
11554; b5: 1=int15h/C6h (get POS data) supported
11555; b4: 1=int15h/C7h (get mem map info) supported
11556; b3: 1=int15h/C8h (en/dis CPU) supported
11557; b2: 1=non-8042 kb controller
11558; b1: 1=data streaming supported
11559; b0: reserved
11560db (0 << 7) | \
11561 (1 << 6) | \
11562 (0 << 5) | \
11563 (0 << 4) | \
11564 (0 << 3) | \
11565 (0 << 2) | \
11566 (0 << 1) | \
11567 (0 << 0)
11568; Feature byte 3
11569; b7: not used
11570; b6: reserved
11571; b5: reserved
11572; b4: POST supports ROM-to-RAM enable/disable
11573; b3: SCSI on system board
11574; b2: info panel installed
11575; b1: Initial Machine Load (IML) system - BIOS on disk
11576; b0: SCSI supported in IML
11577db 0x00
11578; Feature byte 4
11579; b7: IBM private
11580; b6: EEPROM present
11581; b5-3: ABIOS presence (011 = not supported)
11582; b2: private
11583; b1: memory split above 16Mb supported
11584; b0: POSTEXT directly supported by POST
11585db 0x00
11586; Feature byte 5 (IBM)
11587; b1: enhanced mouse
11588; b0: flash EPROM
11589db 0x00
11590
11591
11592
11593.org 0xe729 ; Baud Rate Generator Table
11594
11595;----------
11596;- INT14h -
11597;----------
11598.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11599int14_handler:
11600 push ds
11601 pusha
11602 xor ax, ax
11603 mov ds, ax
11604 call _int14_function
11605 popa
11606 pop ds
11607 iret
11608
11609
11610;----------------------------------------
11611;- INT 16h Keyboard Service Entry Point -
11612;----------------------------------------
11613.org 0xe82e
11614int16_handler:
11615
11616 sti
11617 push ds
11618 pushf
11619 pusha
11620
11621 cmp ah, #0x00
11622 je int16_F00
11623 cmp ah, #0x10
11624 je int16_F00
11625
11626 mov bx, #0xf000
11627 mov ds, bx
11628 call _int16_function
11629 popa
11630 popf
11631 pop ds
11632 jz int16_zero_set
11633
11634int16_zero_clear:
11635 push bp
11636 mov bp, sp
11637 //SEG SS
11638 and BYTE [bp + 0x06], #0xbf
11639 pop bp
11640 iret
11641
11642int16_zero_set:
11643 push bp
11644 mov bp, sp
11645 //SEG SS
11646 or BYTE [bp + 0x06], #0x40
11647 pop bp
11648 iret
11649
11650int16_F00:
11651 mov bx, #0x0040
11652 mov ds, bx
11653
11654int16_wait_for_key:
11655 cli
11656 mov bx, 0x001a
11657 cmp bx, 0x001c
11658 jne int16_key_found
11659 sti
11660 nop
11661#if 0
11662 /* no key yet, call int 15h, function AX=9002 */
11663 0x50, /* push AX */
11664 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11665 0xcd, 0x15, /* int 15h */
11666 0x58, /* pop AX */
11667 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11668#endif
11669 jmp int16_wait_for_key
11670
11671int16_key_found:
11672 mov bx, #0xf000
11673 mov ds, bx
11674 call _int16_function
11675 popa
11676 popf
11677 pop ds
11678#if 0
11679 /* notify int16 complete w/ int 15h, function AX=9102 */
11680 0x50, /* push AX */
11681 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11682 0xcd, 0x15, /* int 15h */
11683 0x58, /* pop AX */
11684#endif
11685 iret
11686
11687
11688
11689;-------------------------------------------------
11690;- INT09h : Keyboard Hardware Service Entry Point -
11691;-------------------------------------------------
11692.org 0xe987
11693int09_handler:
11694 cli
11695 push ax
11696
11697 mov al, #0xAD ;;disable keyboard
11698 out #0x64, al
11699
11700 mov al, #0x0B
11701 out #0x20, al
11702 in al, #0x20
11703 and al, #0x02
11704 jz int09_finish
11705
11706 in al, #0x60 ;;read key from keyboard controller
11707 sti
11708 push ds
11709 pusha
11710#ifdef BX_CALL_INT15_4F
11711 mov ah, #0x4f ;; allow for keyboard intercept
11712 stc
11713 int #0x15
11714 jnc int09_done
11715#endif
11716
11717 ;; check for extended key
11718 cmp al, #0xe0
11719 jne int09_check_pause
11720 xor ax, ax
11721 mov ds, ax
11722 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11723 or al, #0x02
11724 mov BYTE [0x496], al
11725 jmp int09_done
11726
11727int09_check_pause: ;; check for pause key
11728 cmp al, #0xe1
11729 jne int09_process_key
11730 xor ax, ax
11731 mov ds, ax
11732 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11733 or al, #0x01
11734 mov BYTE [0x496], al
11735 jmp int09_done
11736
11737int09_process_key:
11738 mov bx, #0xf000
11739 mov ds, bx
11740 call _int09_function
11741
11742int09_done:
11743 popa
11744 pop ds
11745 cli
11746 call eoi_master_pic
11747
11748int09_finish:
11749 mov al, #0xAE ;;enable keyboard
11750 out #0x64, al
11751 pop ax
11752 iret
11753
11754
11755;----------------------------------------
11756;- INT 13h Diskette Service Entry Point -
11757;----------------------------------------
11758.org 0xec59
11759int13_diskette:
11760 jmp int13_noeltorito
11761
11762;---------------------------------------------
11763;- INT 0Eh Diskette Hardware ISR Entry Point -
11764;---------------------------------------------
11765.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11766int0e_handler:
11767 push ax
11768 push dx
11769 mov dx, #0x03f4
11770 in al, dx
11771 and al, #0xc0
11772 cmp al, #0xc0
11773 je int0e_normal
11774 mov dx, #0x03f5
11775 mov al, #0x08 ; sense interrupt status
11776 out dx, al
11777int0e_loop1:
11778 mov dx, #0x03f4
11779 in al, dx
11780 and al, #0xc0
11781 cmp al, #0xc0
11782 jne int0e_loop1
11783int0e_loop2:
11784 mov dx, #0x03f5
11785 in al, dx
11786 mov dx, #0x03f4
11787 in al, dx
11788 and al, #0xc0
11789 cmp al, #0xc0
11790 je int0e_loop2
11791int0e_normal:
11792 push ds
11793 xor ax, ax ;; segment 0000
11794 mov ds, ax
11795 call eoi_master_pic
11796 mov al, 0x043e
11797 or al, #0x80 ;; diskette interrupt has occurred
11798 mov 0x043e, al
11799 pop ds
11800 pop dx
11801 pop ax
11802 iret
11803
11804
11805.org 0xefc7 ; Diskette Controller Parameter Table
11806diskette_param_table:
11807;; Since no provisions are made for multiple drive types, most
11808;; values in this table are ignored. I set parameters for 1.44M
11809;; floppy here
11810db 0xAF
11811db 0x02 ;; head load time 0000001, DMA used
11812db 0x25
11813db 0x02
11814db 18
11815db 0x1B
11816db 0xFF
11817db 0x6C
11818db 0xF6
11819db 0x0F
11820db 0x08
11821
11822
11823;----------------------------------------
11824;- INT17h : Printer Service Entry Point -
11825;----------------------------------------
11826.org 0xefd2
11827int17_handler:
11828 push ds
11829 pusha
11830 xor ax, ax
11831 mov ds, ax
11832 call _int17_function
11833 popa
11834 pop ds
11835 iret
11836
11837diskette_param_table2:
11838;; New diskette parameter table adding 3 parameters from IBM
11839;; Since no provisions are made for multiple drive types, most
11840;; values in this table are ignored. I set parameters for 1.44M
11841;; floppy here
11842db 0xAF
11843db 0x02 ;; head load time 0000001, DMA used
11844db 0x25
11845db 0x02
11846db 18
11847db 0x1B
11848db 0xFF
11849db 0x6C
11850db 0xF6
11851db 0x0F
11852db 0x08
11853db 79 ;; maximum track
11854db 0 ;; data transfer rate
11855db 4 ;; drive type in cmos
11856
11857.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11858 HALT(__LINE__)
11859 iret
11860
11861;----------
11862;- INT10h -
11863;----------
11864.org 0xf065 ; INT 10h Video Support Service Entry Point
11865int10_handler:
11866 ;; dont do anything, since the VGA BIOS handles int10h requests
11867 iret
11868
11869.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11870
11871;----------
11872;- INT12h -
11873;----------
11874.org 0xf841 ; INT 12h Memory Size Service Entry Point
11875; ??? different for Pentium (machine check)?
11876int12_handler:
11877 push ds
11878 mov ax, #0x0040
11879 mov ds, ax
11880 mov ax, 0x0013
11881 pop ds
11882 iret
11883
11884;----------
11885;- INT11h -
11886;----------
11887.org 0xf84d ; INT 11h Equipment List Service Entry Point
11888int11_handler:
11889 push ds
11890 mov ax, #0x0040
11891 mov ds, ax
11892 mov ax, 0x0010
11893 pop ds
11894 iret
11895
11896;----------
11897;- INT15h -
11898;----------
11899.org 0xf859 ; INT 15h System Services Entry Point
11900int15_handler:
11901 pushf
11902#if BX_APM
11903 cmp ah, #0x53
11904 je apm_call
11905#endif
11906 push ds
11907 push es
11908 cmp ah, #0x86
11909 je int15_handler32
11910 cmp ah, #0xE8
11911 je int15_handler32
11912 pusha
11913#if BX_USE_PS2_MOUSE
11914 cmp ah, #0xC2
11915 je int15_handler_mouse
11916#endif
11917 call _int15_function
11918int15_handler_mouse_ret:
11919 popa
11920int15_handler32_ret:
11921 pop es
11922 pop ds
11923 popf
11924 jmp iret_modify_cf
11925#if BX_APM
11926apm_call:
11927 jmp _apmreal_entry
11928#endif
11929
11930#if BX_USE_PS2_MOUSE
11931int15_handler_mouse:
11932 call _int15_function_mouse
11933 jmp int15_handler_mouse_ret
11934#endif
11935
11936int15_handler32:
11937 pushad
11938 call _int15_function32
11939 popad
11940 jmp int15_handler32_ret
11941
11942;; Protected mode IDT descriptor
11943;;
11944;; I just make the limit 0, so the machine will shutdown
11945;; if an exception occurs during protected mode memory
11946;; transfers.
11947;;
11948;; Set base to f0000 to correspond to beginning of BIOS,
11949;; in case I actually define an IDT later
11950;; Set limit to 0
11951
11952pmode_IDT_info:
11953dw 0x0000 ;; limit 15:00
11954dw 0x0000 ;; base 15:00
11955db 0x0f ;; base 23:16
11956
11957;; Real mode IDT descriptor
11958;;
11959;; Set to typical real-mode values.
11960;; base = 000000
11961;; limit = 03ff
11962
11963rmode_IDT_info:
11964dw 0x03ff ;; limit 15:00
11965dw 0x0000 ;; base 15:00
11966db 0x00 ;; base 23:16
11967
11968;;
11969;; Handler for unexpected hardware interrupts
11970;;
11971dummy_isr:
11972 push ds
11973 pushad
11974 xor ax, ax
11975 mov ds, ax
11976 call _dummy_isr_function
11977 popad
11978 pop ds
11979 iret
11980
11981;----------
11982;- INT1Ah -
11983;----------
11984.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
11985int1a_handler:
11986#if BX_PCIBIOS
11987 cmp ah, #0xb1
11988 jne int1a_normal
11989 call pcibios_real
11990 jc pcibios_error
11991 retf 2
11992pcibios_error:
11993 mov bl, ah
11994 mov ah, #0xb1
11995 push ds
11996 pusha
11997 mov ax, ss ; set readable descriptor to ds, for calling pcibios
11998 mov ds, ax ; on 16bit protected mode.
11999 jmp int1a_callfunction
12000int1a_normal:
12001#endif
12002 push ds
12003 pusha
12004 xor ax, ax
12005 mov ds, ax
12006int1a_callfunction:
12007 call _int1a_function
12008 popa
12009 pop ds
12010 iret
12011
12012;;
12013;; int70h: IRQ8 - CMOS RTC
12014;;
12015int70_handler:
12016 push ds
12017 pushad
12018 xor ax, ax
12019 mov ds, ax
12020 call _int70_function
12021 popad
12022 pop ds
12023 iret
12024
12025;---------
12026;- INT08 -
12027;---------
12028.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12029int08_handler:
12030 sti
12031 push eax
12032 push ds
12033 xor ax, ax
12034 mov ds, ax
12035
12036 ;; time to turn off drive(s)?
12037 mov al,0x0440
12038 or al,al
12039 jz int08_floppy_off
12040 dec al
12041 mov 0x0440,al
12042 jnz int08_floppy_off
12043 ;; turn motor(s) off
12044 push dx
12045 mov dx,#0x03f2
12046 in al,dx
12047 and al,#0xcf
12048 out dx,al
12049 pop dx
12050int08_floppy_off:
12051
12052 mov eax, 0x046c ;; get ticks dword
12053 inc eax
12054
12055 ;; compare eax to one days worth of timer ticks at 18.2 hz
12056 cmp eax, #0x001800B0
12057 jb int08_store_ticks
12058 ;; there has been a midnight rollover at this point
12059 xor eax, eax ;; zero out counter
12060 inc BYTE 0x0470 ;; increment rollover flag
12061
12062int08_store_ticks:
12063 mov 0x046c, eax ;; store new ticks dword
12064 ;; chain to user timer tick INT #0x1c
12065 //pushf
12066 //;; call_ep [ds:loc]
12067 //CALL_EP( 0x1c << 2 )
12068 int #0x1c
12069 cli
12070 call eoi_master_pic
12071 pop ds
12072 pop eax
12073 iret
12074
12075.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12076
12077
12078.org 0xff00
12079.ascii BIOS_COPYRIGHT_STRING
12080
12081#ifdef VBOX
12082// The SMBIOS header
12083.org 0xff30
12084.align 16
12085 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12086 db 0x00 ; checksum (set by biossums)
12087 db 0x1f ; EPS length, defined by standard
12088 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12089 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12090 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12091 db 0x00 ; Entry point revision
12092 db 0x00, 0x00, 0x00, 0x00, 0x00
12093
12094// The DMI header
12095 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12096 db 0x00 ; checksum (set by biossums)
12097 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12098 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12099 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12100 db VBOX_DMI_TABLE_VER ; DMI version
12101 db 0x00 ; Just for alignment
12102#endif
12103
12104;------------------------------------------------
12105;- IRET Instruction for Dummy Interrupt Handler -
12106;------------------------------------------------
12107.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12108dummy_iret_handler:
12109 iret
12110
12111.org 0xff54 ; INT 05h Print Screen Service Entry Point
12112 HALT(__LINE__)
12113 iret
12114
12115.org 0xfff0 ; Power-up Entry Point
12116 jmp 0xf000:post
12117
12118.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12119.ascii BIOS_BUILD_DATE
12120
12121.org 0xfffe ; System Model ID
12122db SYS_MODEL_ID
12123db 0x00 ; filler
12124
12125.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12126ASM_END
12127/*
12128 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12129 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12130 * This font is public domain
12131 */
12132static Bit8u vgafont8[128*8]=
12133{
12134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12135 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12136 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12137 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12138 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12139 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12140 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12141 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12142 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12143 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12144 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12145 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12146 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12147 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12148 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12149 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12150 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12151 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12152 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12153 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12154 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12155 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12156 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12157 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12158 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12159 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12160 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12161 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12162 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12163 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12164 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12165 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12167 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12168 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12169 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12170 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12171 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12172 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12173 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12174 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12175 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12176 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12177 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12178 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12179 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12180 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12181 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12182 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12183 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12184 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12185 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12186 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12187 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12188 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12189 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12190 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12191 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12192 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12193 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12194 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12195 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12196 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12197 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12198 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12199 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12200 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12201 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12202 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12203 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12204 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12205 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12206 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12207 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12208 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12209 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12210 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12211 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12212 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12213 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12214 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12215 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12216 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12217 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12218 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12219 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12220 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12221 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12222 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12223 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12224 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12225 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12226 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12227 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12228 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12230 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12231 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12232 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12233 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12234 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12235 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12236 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12237 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12238 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12239 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12240 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12241 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12242 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12243 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12244 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12245 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12246 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12247 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12248 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12249 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12250 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12251 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12252 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12253 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12254 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12255 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12256 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12257 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12258 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12259 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12260 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12261 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12262};
12263
12264ASM_START
12265.org 0xcc00
12266// bcc-generated data will be placed here
12267ASM_END
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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