VirtualBox

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

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

BIOS: Implement Ctrl+Alt+Del for real mode

  • Property svn:eol-style set to native
File size: 332.3 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
37
38
39// ROM BIOS compatability entry points:
40// ===================================
41// $e05b ; POST Entry Point
42// $e2c3 ; NMI Handler Entry Point
43// $e3fe ; INT 13h Fixed Disk Services Entry Point
44// $e401 ; Fixed Disk Parameter Table
45// $e6f2 ; INT 19h Boot Load Service Entry Point
46// $e6f5 ; Configuration Data Table
47// $e729 ; Baud Rate Generator Table
48// $e739 ; INT 14h Serial Communications Service Entry Point
49// $e82e ; INT 16h Keyboard Service Entry Point
50// $e987 ; INT 09h Keyboard Service Entry Point
51// $ec59 ; INT 13h Diskette Service Entry Point
52// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
53// $efc7 ; Diskette Controller Parameter Table
54// $efd2 ; INT 17h Printer Service Entry Point
55// $f045 ; INT 10 Functions 0-Fh Entry Point
56// $f065 ; INT 10h Video Support Service Entry Point
57// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
58// $f841 ; INT 12h Memory Size Service Entry Point
59// $f84d ; INT 11h Equipment List Service Entry Point
60// $f859 ; INT 15h System Services Entry Point
61// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
62// $fe6e ; INT 1Ah Time-of-day Service Entry Point
63// $fea5 ; INT 08h System Timer ISR Entry Point
64// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
65// $ff53 ; IRET Instruction for Dummy Interrupt Handler
66// $ff54 ; INT 05h Print Screen Service Entry Point
67// $fff0 ; Power-up Entry Point
68// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
69// $fffe ; System Model ID
70
71// NOTES for ATA/ATAPI driver (cbbochs@free.fr)
72// Features
73// - supports up to 4 ATA interfaces
74// - device/geometry detection
75// - 16bits/32bits device access
76// - pchs/lba access
77// - datain/dataout/packet command support
78//
79// NOTES for El-Torito Boot (cbbochs@free.fr)
80// - CD-ROM booting is only available if ATA/ATAPI Driver is available
81// - Current code is only able to boot mono-session cds
82// - Current code can not boot and emulate a hard-disk
83// the bios will panic otherwise
84// - Current code also use memory in EBDA segement.
85// - I used cmos byte 0x3D to store extended information on boot-device
86// - Code has to be modified modified to handle multiple cdrom drives
87// - Here are the cdrom boot failure codes:
88// 1 : no atapi device found
89// 2 : no atapi cdrom found
90// 3 : can not read cd - BRVD
91// 4 : cd is not eltorito (BRVD)
92// 5 : cd is not eltorito (ISO TAG)
93// 6 : cd is not eltorito (ELTORITO TAG)
94// 7 : can not read cd - boot catalog
95// 8 : boot catalog : bad header
96// 9 : boot catalog : bad platform
97// 10 : boot catalog : bad signature
98// 11 : boot catalog : bootable flag not set
99// 12 : can not read cd - boot image
100//
101// ATA driver
102// - EBDA segment.
103// I used memory starting at 0x121 in the segment
104#ifndef VBOX
105// - the translation policy is defined in cmos regs 0x39 & 0x3a
106#endif /* !VBOX */
107//
108// TODO :
109//
110// int74
111// - needs to be reworked. Uses direct [bp] offsets. (?)
112//
113// int13:
114// - f04 (verify sectors) isn't complete (?)
115// - f02/03/04 should set current cyl,etc in BDA (?)
116// - rewrite int13_relocated & clean up int13 entry code
117//
118// NOTES:
119// - NMI access (bit7 of addr written to 70h)
120//
121// ATA driver
122// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
123// - could send the multiple-sector read/write commands
124//
125// El-Torito
126// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
127// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
128// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
129// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
130// This is ok. But DL should be reincremented afterwards.
131// - Fix all "FIXME ElTorito Various"
132// - should be able to boot any cdrom instead of the first one
133//
134// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
135
136#ifdef VBOX
137#include "DevPcBios.h"
138#include <VBox/version.h>
139#endif
140
141#define BX_ROMBIOS32 0
142#define DEBUG_ROMBIOS 0
143
144#define DEBUG_ATA 0
145#define DEBUG_INT13_HD 0
146#define DEBUG_INT13_CD 0
147#define DEBUG_INT13_ET 0
148#define DEBUG_INT13_FL 0
149#define DEBUG_INT15 0
150#define DEBUG_INT16 0
151#define DEBUG_INT1A 0
152#define DEBUG_INT74 0
153#define DEBUG_APM 0
154
155#define BX_CPU 3
156#define BX_USE_PS2_MOUSE 1
157#define BX_CALL_INT15_4F 1
158#define BX_USE_EBDA 1
159#define BX_SUPPORT_FLOPPY 1
160#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
161#define BX_PCIBIOS 1
162#define BX_APM 1
163
164#define BX_USE_ATADRV 1
165#define BX_ELTORITO_BOOT 1
166
167#define BX_MAX_ATA_INTERFACES 4
168#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
169
170#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
171#define BX_DEBUG_SERIAL 0 /* output to COM1 */
172
173 /* model byte 0xFC = AT */
174#define SYS_MODEL_ID 0xFC
175#define SYS_SUBMODEL_ID 0x00
176#define BIOS_REVISION 1
177#define BIOS_CONFIG_TABLE 0xe6f5
178
179#ifndef BIOS_BUILD_DATE
180# define BIOS_BUILD_DATE "06/23/99"
181#endif
182
183 // 1K of base memory used for Extended Bios Data Area (EBDA)
184 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
185#define EBDA_SEG 0x9FC0
186#define EBDA_SIZE 1 // In KiB
187#define BASE_MEM_IN_K (640 - EBDA_SIZE)
188
189#define ACPI_DATA_SIZE 0x00010000L
190
191 // Define the application NAME
192#if defined(BX_QEMU)
193# define BX_APPNAME "QEMU"
194#elif defined(PLEX86)
195# define BX_APPNAME "Plex86"
196#else
197# define BX_APPNAME "Bochs"
198#endif
199
200 // Sanity Checks
201#if BX_USE_ATADRV && BX_CPU<3
202# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
203#endif
204#if BX_USE_ATADRV && !BX_USE_EBDA
205# error ATA/ATAPI Driver can only be used if EBDA is available
206#endif
207#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
208# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
209#endif
210#if BX_PCIBIOS && BX_CPU<3
211# error PCI BIOS can only be used with 386+ cpu
212#endif
213#if BX_APM && BX_CPU<3
214# error APM BIOS can only be used with 386+ cpu
215#endif
216
217#if defined(VBOX) && !BX_USE_ATADRV
218# error VBOX requires enabling the ATA/ATAPI driver
219#endif
220
221#ifdef VBOX_WITH_SCSI
222/* Enough for now */
223# define BX_MAX_SCSI_DEVICES 4
224
225/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
226# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
227# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
228#endif
229
230#ifndef VBOX
231#define PANIC_PORT 0x400
232#define PANIC_PORT2 0x401
233#define INFO_PORT 0x402
234#define DEBUG_PORT 0x403
235#else /* VBOX */
236/* Redirect INFO output to backdoor logging port. */
237#define PANIC_PORT 0x400
238#define PANIC_PORT2 0x401
239#define INFO_PORT 0x504
240#define DEBUG_PORT 0x403
241#endif /* VBOX */
242
243// define this if you want to make PCIBIOS working on a specific bridge only
244// undef enables PCIBIOS when at least one PCI device is found
245// i440FX is emulated by Bochs and QEMU
246#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
247
248// #20 is dec 20
249// #$20 is hex 20 = 32
250// #0x20 is hex 20 = 32
251// LDA #$20
252// JSR $E820
253// LDD .i,S
254// JSR $C682
255// mov al, #$20
256
257// all hex literals should be prefixed with '0x'
258// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
259// no mov SEG-REG, #value, must mov register into seg-reg
260// grep -i "mov[ ]*.s" rombios.c
261
262// This is for compiling with gcc2 and gcc3
263#define ASM_START #asm
264#define ASM_END #endasm
265
266ASM_START
267.rom
268
269.org 0x0000
270
271#if BX_CPU >= 3
272use16 386
273#else
274use16 286
275#endif
276
277MACRO HALT
278 ;; the HALT macro is called with the line number of the HALT call.
279 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
280 ;; to print a BX_PANIC message. This will normally halt the simulation
281 ;; with a message such as "BIOS panic at rombios.c, line 4091".
282 ;; However, users can choose to make panics non-fatal and continue.
283#if BX_VIRTUAL_PORTS
284 mov dx,#PANIC_PORT
285 mov ax,#?1
286 out dx,ax
287#else
288 mov dx,#0x80
289 mov ax,#?1
290 out dx,al
291#endif
292MEND
293
294MACRO JMP_AP
295 db 0xea
296 dw ?2
297 dw ?1
298MEND
299
300MACRO SET_INT_VECTOR
301 mov ax, ?3
302 mov ?1*4, ax
303 mov ax, ?2
304 mov ?1*4+2, ax
305MEND
306
307ASM_END
308
309typedef unsigned char Bit8u;
310typedef unsigned short Bit16u;
311typedef unsigned short bx_bool;
312typedef unsigned long Bit32u;
313
314#if BX_USE_ATADRV
315
316 void memsetb(seg,offset,value,count);
317 void memcpyb(dseg,doffset,sseg,soffset,count);
318 void memcpyd(dseg,doffset,sseg,soffset,count);
319
320 // memset of count bytes
321 void
322 memsetb(seg,offset,value,count)
323 Bit16u seg;
324 Bit16u offset;
325 Bit16u value;
326 Bit16u count;
327 {
328 ASM_START
329 push bp
330 mov bp, sp
331
332 push ax
333 push cx
334 push es
335 push di
336
337 mov cx, 10[bp] ; count
338 test cx, cx
339 je memsetb_end
340 mov ax, 4[bp] ; segment
341 mov es, ax
342 mov ax, 6[bp] ; offset
343 mov di, ax
344 mov al, 8[bp] ; value
345 cld
346 rep
347 stosb
348
349 memsetb_end:
350 pop di
351 pop es
352 pop cx
353 pop ax
354
355 pop bp
356 ASM_END
357 }
358
359#if 0
360 // memcpy of count bytes
361 void
362 memcpyb(dseg,doffset,sseg,soffset,count)
363 Bit16u dseg;
364 Bit16u doffset;
365 Bit16u sseg;
366 Bit16u soffset;
367 Bit16u count;
368 {
369 ASM_START
370 push bp
371 mov bp, sp
372
373 push ax
374 push cx
375 push es
376 push di
377 push ds
378 push si
379
380 mov cx, 12[bp] ; count
381 cmp cx, #0x0000
382 je memcpyb_end
383 mov ax, 4[bp] ; dsegment
384 mov es, ax
385 mov ax, 6[bp] ; doffset
386 mov di, ax
387 mov ax, 8[bp] ; ssegment
388 mov ds, ax
389 mov ax, 10[bp] ; soffset
390 mov si, ax
391 cld
392 rep
393 movsb
394
395 memcpyb_end:
396 pop si
397 pop ds
398 pop di
399 pop es
400 pop cx
401 pop ax
402
403 pop bp
404 ASM_END
405 }
406
407 // memcpy of count dword
408 void
409 memcpyd(dseg,doffset,sseg,soffset,count)
410 Bit16u dseg;
411 Bit16u doffset;
412 Bit16u sseg;
413 Bit16u soffset;
414 Bit16u count;
415 {
416 ASM_START
417 push bp
418 mov bp, sp
419
420 push ax
421 push cx
422 push es
423 push di
424 push ds
425 push si
426
427 mov cx, 12[bp] ; count
428 test cx, cx
429 je memcpyd_end
430 mov ax, 4[bp] ; dsegment
431 mov es, ax
432 mov ax, 6[bp] ; doffset
433 mov di, ax
434 mov ax, 8[bp] ; ssegment
435 mov ds, ax
436 mov ax, 10[bp] ; soffset
437 mov si, ax
438 cld
439 rep
440 movsd
441
442 memcpyd_end:
443 pop si
444 pop ds
445 pop di
446 pop es
447 pop cx
448 pop ax
449
450 pop bp
451 ASM_END
452 }
453#endif
454#endif //BX_USE_ATADRV
455
456 // read_dword and write_dword functions
457 static Bit32u read_dword();
458 static void write_dword();
459
460 Bit32u
461 read_dword(seg, offset)
462 Bit16u seg;
463 Bit16u offset;
464 {
465 ASM_START
466 push bp
467 mov bp, sp
468
469 push bx
470 push ds
471 mov ax, 4[bp] ; segment
472 mov ds, ax
473 mov bx, 6[bp] ; offset
474 mov ax, [bx]
475 add bx, #2
476 mov dx, [bx]
477 ;; ax = return value (word)
478 ;; dx = return value (word)
479 pop ds
480 pop bx
481
482 pop bp
483 ASM_END
484 }
485
486 void
487 write_dword(seg, offset, data)
488 Bit16u seg;
489 Bit16u offset;
490 Bit32u data;
491 {
492 ASM_START
493 push bp
494 mov bp, sp
495
496 push ax
497 push bx
498 push ds
499 mov ax, 4[bp] ; segment
500 mov ds, ax
501 mov bx, 6[bp] ; offset
502 mov ax, 8[bp] ; data word
503 mov [bx], ax ; write data word
504 add bx, #2
505 mov ax, 10[bp] ; data word
506 mov [bx], ax ; write data word
507 pop ds
508 pop bx
509 pop ax
510
511 pop bp
512 ASM_END
513 }
514
515 // Bit32u (unsigned long) and long helper functions
516 ASM_START
517
518 ;; and function
519 landl:
520 landul:
521 SEG SS
522 and ax,[di]
523 SEG SS
524 and bx,2[di]
525 ret
526
527 ;; add function
528 laddl:
529 laddul:
530 SEG SS
531 add ax,[di]
532 SEG SS
533 adc bx,2[di]
534 ret
535
536 ;; cmp function
537 lcmpl:
538 lcmpul:
539 and eax, #0x0000FFFF
540 shl ebx, #16
541 or eax, ebx
542 shr ebx, #16
543 SEG SS
544 cmp eax, dword ptr [di]
545 ret
546
547 ;; sub function
548 lsubl:
549 lsubul:
550 SEG SS
551 sub ax,[di]
552 SEG SS
553 sbb bx,2[di]
554 ret
555
556 ;; mul function
557 lmull:
558 lmulul:
559 and eax, #0x0000FFFF
560 shl ebx, #16
561 or eax, ebx
562 SEG SS
563 mul eax, dword ptr [di]
564 mov ebx, eax
565 shr ebx, #16
566 ret
567
568 ;; dec function
569 ldecl:
570 ldecul:
571 SEG SS
572 dec dword ptr [bx]
573 ret
574
575 ;; or function
576 lorl:
577 lorul:
578 SEG SS
579 or ax,[di]
580 SEG SS
581 or bx,2[di]
582 ret
583
584 ;; inc function
585 lincl:
586 lincul:
587 SEG SS
588 inc dword ptr [bx]
589 ret
590
591 ;; tst function
592 ltstl:
593 ltstul:
594 and eax, #0x0000FFFF
595 shl ebx, #16
596 or eax, ebx
597 shr ebx, #16
598 test eax, eax
599 ret
600
601 ;; sr function
602 lsrul:
603 mov cx,di
604 jcxz lsr_exit
605 and eax, #0x0000FFFF
606 shl ebx, #16
607 or eax, ebx
608 lsr_loop:
609 shr eax, #1
610 loop lsr_loop
611 mov ebx, eax
612 shr ebx, #16
613 lsr_exit:
614 ret
615
616 ;; sl function
617 lsll:
618 lslul:
619 mov cx,di
620 jcxz lsl_exit
621 and eax, #0x0000FFFF
622 shl ebx, #16
623 or eax, ebx
624 lsl_loop:
625 shl eax, #1
626 loop lsl_loop
627 mov ebx, eax
628 shr ebx, #16
629 lsl_exit:
630 ret
631
632 idiv_:
633 cwd
634 idiv bx
635 ret
636
637 idiv_u:
638 xor dx,dx
639 div bx
640 ret
641
642 ldivul:
643 and eax, #0x0000FFFF
644 shl ebx, #16
645 or eax, ebx
646 xor edx, edx
647 SEG SS
648 mov bx, 2[di]
649 shl ebx, #16
650 SEG SS
651 mov bx, [di]
652 div ebx
653 mov ebx, eax
654 shr ebx, #16
655 ret
656
657 ASM_END
658
659// for access to RAM area which is used by interrupt vectors
660// and BIOS Data Area
661
662typedef struct {
663 unsigned char filler1[0x400];
664 unsigned char filler2[0x6c];
665 Bit16u ticks_low;
666 Bit16u ticks_high;
667 Bit8u midnight_flag;
668 } bios_data_t;
669
670#define BiosData ((bios_data_t *) 0)
671
672#if BX_USE_ATADRV
673 typedef struct {
674 Bit16u heads; // # heads
675 Bit16u cylinders; // # cylinders
676 Bit16u spt; // # sectors / track
677 } chs_t;
678
679 // DPTE definition
680 typedef struct {
681 Bit16u iobase1;
682 Bit16u iobase2;
683 Bit8u prefix;
684 Bit8u unused;
685 Bit8u irq;
686 Bit8u blkcount;
687 Bit8u dma;
688 Bit8u pio;
689 Bit16u options;
690 Bit16u reserved;
691 Bit8u revision;
692 Bit8u checksum;
693 } dpte_t;
694
695 typedef struct {
696 Bit8u iface; // ISA or PCI
697 Bit16u iobase1; // IO Base 1
698 Bit16u iobase2; // IO Base 2
699 Bit8u irq; // IRQ
700 } ata_channel_t;
701
702 typedef struct {
703 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
704 Bit8u device; // Detected type of attached devices (hd/cd/none)
705 Bit8u removable; // Removable device flag
706 Bit8u lock; // Locks for removable devices
707 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
708 Bit16u blksize; // block size
709
710 Bit8u translation; // type of translation
711 chs_t lchs; // Logical CHS
712 chs_t pchs; // Physical CHS
713
714 Bit32u sectors; // Total sectors count
715 } ata_device_t;
716
717 typedef struct {
718 // ATA channels info
719 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
720
721 // ATA devices info
722 ata_device_t devices[BX_MAX_ATA_DEVICES];
723 //
724 // map between (bios hd id - 0x80) and ata channels and scsi disks.
725#ifdef VBOX_WITH_SCSI
726 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
727#else
728 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
729#endif
730
731 // map between (bios cd id - 0xE0) and ata channels
732 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
733
734 // Buffer for DPTE table
735 dpte_t dpte;
736
737 // Count of transferred sectors and bytes
738 Bit16u trsfsectors;
739 Bit32u trsfbytes;
740
741 } ata_t;
742
743#if BX_ELTORITO_BOOT
744 // ElTorito Device Emulation data
745 typedef struct {
746 Bit8u active;
747 Bit8u media;
748 Bit8u emulated_drive;
749 Bit8u controller_index;
750 Bit16u device_spec;
751 Bit32u ilba;
752 Bit16u buffer_segment;
753 Bit16u load_segment;
754 Bit16u sector_count;
755
756 // Virtual device
757 chs_t vdevice;
758 } cdemu_t;
759#endif // BX_ELTORITO_BOOT
760
761#ifdef VBOX_WITH_SCSI
762 typedef struct {
763 // I/O port this device is attached to.
764 Bit16u io_base;
765 // Target Id.
766 Bit8u target_id;
767 // SCSI devices info
768 ata_device_t device_info;
769 } scsi_device_t;
770
771 typedef struct {
772 // SCSi device info
773 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
774 // Number of scsi disks.
775 Bit8u hdcount;
776 } scsi_t;
777#endif
778
779 // for access to EBDA area
780 // The EBDA structure should conform to
781 // http://www.frontiernet.net/~fys/rombios.htm document
782 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
783 typedef struct {
784 unsigned char filler1[0x3D];
785
786 // FDPT - Can be splitted in data members if needed
787 unsigned char fdpt0[0x10];
788 unsigned char fdpt1[0x10];
789
790 unsigned char filler2[0xC4];
791
792 // ATA Driver data
793 ata_t ata;
794
795#if BX_ELTORITO_BOOT
796 // El Torito Emulation data
797 cdemu_t cdemu;
798#endif // BX_ELTORITO_BOOT
799
800#ifdef VBOX
801
802#ifdef VBOX_WITH_SCSI
803 // SCSI Driver data
804 scsi_t scsi;
805# endif
806
807 unsigned char uForceBootDrive;
808 unsigned char uForceBootDevice;
809#endif /* VBOX */
810
811 } ebda_data_t;
812
813#ifdef VBOX
814 // the last 16 bytes of the EBDA segment are used for the MPS floating
815 // pointer structure (only if an IOAPIC is present)
816#endif
817
818 #define EbdaData ((ebda_data_t *) 0)
819
820 // for access to the int13ext structure
821 typedef struct {
822 Bit8u size;
823 Bit8u reserved;
824 Bit16u count;
825 Bit16u offset;
826 Bit16u segment;
827 Bit32u lba1;
828 Bit32u lba2;
829 } int13ext_t;
830
831 #define Int13Ext ((int13ext_t *) 0)
832
833 // Disk Physical Table definition
834 typedef struct {
835 Bit16u size;
836 Bit16u infos;
837 Bit32u cylinders;
838 Bit32u heads;
839 Bit32u spt;
840 Bit32u sector_count1;
841 Bit32u sector_count2;
842 Bit16u blksize;
843 Bit16u dpte_offset;
844 Bit16u dpte_segment;
845 Bit16u key;
846 Bit8u dpi_length;
847 Bit8u reserved1;
848 Bit16u reserved2;
849 Bit8u host_bus[4];
850 Bit8u iface_type[8];
851 Bit8u iface_path[8];
852 Bit8u device_path[8];
853 Bit8u reserved3;
854 Bit8u checksum;
855 } dpt_t;
856
857 #define Int13DPT ((dpt_t *) 0)
858
859#endif // BX_USE_ATADRV
860
861typedef struct {
862 union {
863 struct {
864 Bit16u di, si, bp, sp;
865 Bit16u bx, dx, cx, ax;
866 } r16;
867 struct {
868 Bit16u filler[4];
869 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
870 } r8;
871 } u;
872 } pusha_regs_t;
873
874typedef struct {
875 union {
876 struct {
877 Bit32u edi, esi, ebp, esp;
878 Bit32u ebx, edx, ecx, eax;
879 } r32;
880 struct {
881 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
882 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
883 } r16;
884 struct {
885 Bit32u filler[4];
886 Bit8u bl, bh;
887 Bit16u filler1;
888 Bit8u dl, dh;
889 Bit16u filler2;
890 Bit8u cl, ch;
891 Bit16u filler3;
892 Bit8u al, ah;
893 Bit16u filler4;
894 } r8;
895 } u;
896} pushad_regs_t;
897
898typedef struct {
899 union {
900 struct {
901 Bit16u flags;
902 } r16;
903 struct {
904 Bit8u flagsl;
905 Bit8u flagsh;
906 } r8;
907 } u;
908 } flags_t;
909
910#define SetCF(x) x.u.r8.flagsl |= 0x01
911#define SetZF(x) x.u.r8.flagsl |= 0x40
912#define ClearCF(x) x.u.r8.flagsl &= 0xfe
913#define ClearZF(x) x.u.r8.flagsl &= 0xbf
914#define GetCF(x) (x.u.r8.flagsl & 0x01)
915
916typedef struct {
917 Bit16u ip;
918 Bit16u cs;
919 flags_t flags;
920 } iret_addr_t;
921
922
923
924static Bit8u inb();
925static Bit8u inb_cmos();
926static void outb();
927static void outb_cmos();
928static Bit16u inw();
929static void outw();
930static void init_rtc();
931static bx_bool rtc_updating();
932
933static Bit8u read_byte();
934static Bit16u read_word();
935static void write_byte();
936static void write_word();
937static void bios_printf();
938
939static Bit8u send_to_mouse_ctrl();
940static Bit8u get_mouse_data();
941static void set_kbd_command_byte();
942
943static void int09_function();
944static void int13_harddisk();
945static void int13_cdrom();
946static void int13_cdemu();
947static void int13_eltorito();
948static void int13_diskette_function();
949static void int14_function();
950static void int15_function();
951static void int16_function();
952static void int17_function();
953static Bit32u int19_function();
954static void int1a_function();
955static void int70_function();
956static void int74_function();
957static void dummy_isr_function();
958static Bit16u get_CS();
959static Bit16u get_SS();
960static unsigned int enqueue_key();
961static unsigned int dequeue_key();
962static void get_hd_geometry();
963static void set_diskette_ret_status();
964static void set_diskette_current_cyl();
965static void determine_floppy_media();
966static bx_bool floppy_drive_exists();
967static bx_bool floppy_drive_recal();
968static bx_bool floppy_media_known();
969static bx_bool floppy_media_sense();
970static bx_bool set_enable_a20();
971static void debugger_on();
972static void debugger_off();
973static void keyboard_init();
974static void keyboard_panic();
975static void shutdown_status_panic();
976static void nmi_handler_msg();
977
978static void print_bios_banner();
979static void print_boot_device();
980static void print_boot_failure();
981static void print_cdromboot_failure();
982
983# if BX_USE_ATADRV
984
985// ATA / ATAPI driver
986void ata_init();
987void ata_detect();
988void ata_reset();
989
990Bit16u ata_cmd_non_data();
991Bit16u ata_cmd_data_in();
992Bit16u ata_cmd_data_out();
993Bit16u ata_cmd_packet();
994
995Bit16u atapi_get_sense();
996Bit16u atapi_is_ready();
997Bit16u atapi_is_cdrom();
998
999#endif // BX_USE_ATADRV
1000
1001#if BX_ELTORITO_BOOT
1002
1003void cdemu_init();
1004Bit8u cdemu_isactive();
1005Bit8u cdemu_emulated_drive();
1006
1007Bit16u cdrom_boot();
1008
1009#endif // BX_ELTORITO_BOOT
1010
1011#ifdef VBOX
1012static char bios_prefix_string[] = "BIOS: ";
1013/* Do not use build timestamps in this string. Otherwise even rebuilding the
1014 * very same code will lead to compare errors when restoring saved state. */
1015static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1016#define BIOS_COPYRIGHT_STRING "Sun VirtualBox BIOS"
1017#else /* !VBOX */
1018static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1019
1020#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1021#endif /* !VBOX */
1022
1023#define BIOS_PRINTF_HALT 1
1024#define BIOS_PRINTF_SCREEN 2
1025#define BIOS_PRINTF_INFO 4
1026#define BIOS_PRINTF_DEBUG 8
1027#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1028#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1029
1030#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1031
1032// Defines the output macros.
1033// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1034// per-device basis. Debug info are sent only in debug mode
1035#if DEBUG_ROMBIOS
1036# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1037#else
1038# define BX_DEBUG(format, p...)
1039#endif
1040#ifdef VBOX
1041#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, get_CS(), bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
1042#else /* !VBOX */
1043#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1044#endif /* !VBOX */
1045#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1046
1047#if DEBUG_ATA
1048# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1049#else
1050# define BX_DEBUG_ATA(a...)
1051#endif
1052#if DEBUG_INT13_HD
1053# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1054#else
1055# define BX_DEBUG_INT13_HD(a...)
1056#endif
1057#if DEBUG_INT13_CD
1058# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1059#else
1060# define BX_DEBUG_INT13_CD(a...)
1061#endif
1062#if DEBUG_INT13_ET
1063# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1064#else
1065# define BX_DEBUG_INT13_ET(a...)
1066#endif
1067#if DEBUG_INT13_FL
1068# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1069#else
1070# define BX_DEBUG_INT13_FL(a...)
1071#endif
1072#if DEBUG_INT15
1073# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1074#else
1075# define BX_DEBUG_INT15(a...)
1076#endif
1077#if DEBUG_INT16
1078# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1079#else
1080# define BX_DEBUG_INT16(a...)
1081#endif
1082#if DEBUG_INT1A
1083# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1084#else
1085# define BX_DEBUG_INT1A(a...)
1086#endif
1087#if DEBUG_INT74
1088# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1089#else
1090# define BX_DEBUG_INT74(a...)
1091#endif
1092
1093#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1094#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1095#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1096#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1097#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1098#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1099#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1100#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1101
1102#define GET_AL() ( AX & 0x00ff )
1103#define GET_BL() ( BX & 0x00ff )
1104#define GET_CL() ( CX & 0x00ff )
1105#define GET_DL() ( DX & 0x00ff )
1106#define GET_AH() ( AX >> 8 )
1107#define GET_BH() ( BX >> 8 )
1108#define GET_CH() ( CX >> 8 )
1109#define GET_DH() ( DX >> 8 )
1110
1111#define GET_ELDL() ( ELDX & 0x00ff )
1112#define GET_ELDH() ( ELDX >> 8 )
1113
1114#define SET_CF() FLAGS |= 0x0001
1115#define CLEAR_CF() FLAGS &= 0xfffe
1116#define GET_CF() (FLAGS & 0x0001)
1117
1118#define SET_ZF() FLAGS |= 0x0040
1119#define CLEAR_ZF() FLAGS &= 0xffbf
1120#define GET_ZF() (FLAGS & 0x0040)
1121
1122#define UNSUPPORTED_FUNCTION 0x86
1123
1124#define none 0
1125#define MAX_SCAN_CODE 0x58
1126
1127static struct {
1128 Bit16u normal;
1129 Bit16u shift;
1130 Bit16u control;
1131 Bit16u alt;
1132 Bit8u lock_flags;
1133 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1134 { none, none, none, none, none },
1135 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1136 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1137 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1138 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1139 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1140 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1141 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1142 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1143 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1144 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1145 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1146 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1147 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1148 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1149 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1150 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1151 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1152 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1153 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1154 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1155 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1156 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1157 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1158 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1159 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1160 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1161 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1162 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1163 { none, none, none, none, none }, /* L Ctrl */
1164 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1165 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1166 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1167 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1168 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1169 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1170 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1171 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1172 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1173 { 0x273b, 0x273a, none, none, none }, /* ;: */
1174 { 0x2827, 0x2822, none, none, none }, /* '" */
1175 { 0x2960, 0x297e, none, none, none }, /* `~ */
1176 { none, none, none, none, none }, /* L shift */
1177 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1178 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1179 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1180 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1181 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1182 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1183 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1184 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1185 { 0x332c, 0x333c, none, none, none }, /* ,< */
1186 { 0x342e, 0x343e, none, none, none }, /* .> */
1187 { 0x352f, 0x353f, none, none, none }, /* /? */
1188 { none, none, none, none, none }, /* R Shift */
1189 { 0x372a, 0x372a, none, none, none }, /* * */
1190 { none, none, none, none, none }, /* L Alt */
1191 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1192 { none, none, none, none, none }, /* caps lock */
1193 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1194 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1195 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1196 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1197 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1198 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1199 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1200 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1201 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1202 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1203 { none, none, none, none, none }, /* Num Lock */
1204 { none, none, none, none, none }, /* Scroll Lock */
1205 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1206 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1207 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1208 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1209 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1210 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1211 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1212 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1213 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1214 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1215 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1216 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1217 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1218 { none, none, none, none, none },
1219 { none, none, none, none, none },
1220 { 0x565c, 0x567c, none, none, none }, /* \| */
1221#ifndef VBOX
1222 { 0x5700, 0x5700, none, none, none }, /* F11 */
1223 { 0x5800, 0x5800, none, none, none } /* F12 */
1224#else
1225 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1226 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1227#endif
1228 };
1229
1230 Bit8u
1231inb(port)
1232 Bit16u port;
1233{
1234ASM_START
1235 push bp
1236 mov bp, sp
1237
1238 push dx
1239 mov dx, 4[bp]
1240 in al, dx
1241 pop dx
1242
1243 pop bp
1244ASM_END
1245}
1246
1247#if BX_USE_ATADRV
1248 Bit16u
1249inw(port)
1250 Bit16u port;
1251{
1252ASM_START
1253 push bp
1254 mov bp, sp
1255
1256 push dx
1257 mov dx, 4[bp]
1258 in ax, dx
1259 pop dx
1260
1261 pop bp
1262ASM_END
1263}
1264#endif
1265
1266 void
1267outb(port, val)
1268 Bit16u port;
1269 Bit8u val;
1270{
1271ASM_START
1272 push bp
1273 mov bp, sp
1274
1275 push ax
1276 push dx
1277 mov dx, 4[bp]
1278 mov al, 6[bp]
1279 out dx, al
1280 pop dx
1281 pop ax
1282
1283 pop bp
1284ASM_END
1285}
1286
1287#if BX_USE_ATADRV
1288 void
1289outw(port, val)
1290 Bit16u port;
1291 Bit16u val;
1292{
1293ASM_START
1294 push bp
1295 mov bp, sp
1296
1297 push ax
1298 push dx
1299 mov dx, 4[bp]
1300 mov ax, 6[bp]
1301 out dx, ax
1302 pop dx
1303 pop ax
1304
1305 pop bp
1306ASM_END
1307}
1308#endif
1309
1310 void
1311outb_cmos(cmos_reg, val)
1312 Bit8u cmos_reg;
1313 Bit8u val;
1314{
1315ASM_START
1316 push bp
1317 mov bp, sp
1318
1319 mov al, 4[bp] ;; cmos_reg
1320 out 0x70, al
1321 mov al, 6[bp] ;; val
1322 out 0x71, al
1323
1324 pop bp
1325ASM_END
1326}
1327
1328 Bit8u
1329inb_cmos(cmos_reg)
1330 Bit8u cmos_reg;
1331{
1332ASM_START
1333 push bp
1334 mov bp, sp
1335
1336 mov al, 4[bp] ;; cmos_reg
1337 out 0x70, al
1338 in al, 0x71
1339
1340 pop bp
1341ASM_END
1342}
1343
1344 void
1345init_rtc()
1346{
1347 outb_cmos(0x0a, 0x26);
1348 outb_cmos(0x0b, 0x02);
1349 inb_cmos(0x0c);
1350 inb_cmos(0x0d);
1351}
1352
1353 bx_bool
1354rtc_updating()
1355{
1356 // This function checks to see if the update-in-progress bit
1357 // is set in CMOS Status Register A. If not, it returns 0.
1358 // If it is set, it tries to wait until there is a transition
1359 // to 0, and will return 0 if such a transition occurs. A 1
1360 // is returned only after timing out. The maximum period
1361 // that this bit should be set is constrained to 244useconds.
1362 // The count I use below guarantees coverage or more than
1363 // this time, with any reasonable IPS setting.
1364
1365 Bit16u count;
1366
1367 count = 25000;
1368 while (--count != 0) {
1369 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1370 return(0);
1371 }
1372 return(1); // update-in-progress never transitioned to 0
1373}
1374
1375
1376 Bit8u
1377read_byte(seg, offset)
1378 Bit16u seg;
1379 Bit16u offset;
1380{
1381ASM_START
1382 push bp
1383 mov bp, sp
1384
1385 push bx
1386 push ds
1387 mov ax, 4[bp] ; segment
1388 mov ds, ax
1389 mov bx, 6[bp] ; offset
1390 mov al, [bx]
1391 ;; al = return value (byte)
1392 pop ds
1393 pop bx
1394
1395 pop bp
1396ASM_END
1397}
1398
1399 Bit16u
1400read_word(seg, offset)
1401 Bit16u seg;
1402 Bit16u offset;
1403{
1404ASM_START
1405 push bp
1406 mov bp, sp
1407
1408 push bx
1409 push ds
1410 mov ax, 4[bp] ; segment
1411 mov ds, ax
1412 mov bx, 6[bp] ; offset
1413 mov ax, [bx]
1414 ;; ax = return value (word)
1415 pop ds
1416 pop bx
1417
1418 pop bp
1419ASM_END
1420}
1421
1422 void
1423write_byte(seg, offset, data)
1424 Bit16u seg;
1425 Bit16u offset;
1426 Bit8u data;
1427{
1428ASM_START
1429 push bp
1430 mov bp, sp
1431
1432 push ax
1433 push bx
1434 push ds
1435 mov ax, 4[bp] ; segment
1436 mov ds, ax
1437 mov bx, 6[bp] ; offset
1438 mov al, 8[bp] ; data byte
1439 mov [bx], al ; write data byte
1440 pop ds
1441 pop bx
1442 pop ax
1443
1444 pop bp
1445ASM_END
1446}
1447
1448 void
1449write_word(seg, offset, data)
1450 Bit16u seg;
1451 Bit16u offset;
1452 Bit16u data;
1453{
1454ASM_START
1455 push bp
1456 mov bp, sp
1457
1458 push ax
1459 push bx
1460 push ds
1461 mov ax, 4[bp] ; segment
1462 mov ds, ax
1463 mov bx, 6[bp] ; offset
1464 mov ax, 8[bp] ; data word
1465 mov [bx], ax ; write data word
1466 pop ds
1467 pop bx
1468 pop ax
1469
1470 pop bp
1471ASM_END
1472}
1473
1474 Bit16u
1475get_CS()
1476{
1477ASM_START
1478 mov ax, cs
1479ASM_END
1480}
1481
1482 Bit16u
1483get_SS()
1484{
1485ASM_START
1486 mov ax, ss
1487ASM_END
1488}
1489
1490#if BX_DEBUG_SERIAL
1491/* serial debug port*/
1492#define BX_DEBUG_PORT 0x03f8
1493
1494/* data */
1495#define UART_RBR 0x00
1496#define UART_THR 0x00
1497
1498/* control */
1499#define UART_IER 0x01
1500#define UART_IIR 0x02
1501#define UART_FCR 0x02
1502#define UART_LCR 0x03
1503#define UART_MCR 0x04
1504#define UART_DLL 0x00
1505#define UART_DLM 0x01
1506
1507/* status */
1508#define UART_LSR 0x05
1509#define UART_MSR 0x06
1510#define UART_SCR 0x07
1511
1512int uart_can_tx_byte(base_port)
1513 Bit16u base_port;
1514{
1515 return inb(base_port + UART_LSR) & 0x20;
1516}
1517
1518void uart_wait_to_tx_byte(base_port)
1519 Bit16u base_port;
1520{
1521 while (!uart_can_tx_byte(base_port));
1522}
1523
1524void uart_wait_until_sent(base_port)
1525 Bit16u base_port;
1526{
1527 while (!(inb(base_port + UART_LSR) & 0x40));
1528}
1529
1530void uart_tx_byte(base_port, data)
1531 Bit16u base_port;
1532 Bit8u data;
1533{
1534 uart_wait_to_tx_byte(base_port);
1535 outb(base_port + UART_THR, data);
1536 uart_wait_until_sent(base_port);
1537}
1538#endif
1539
1540 void
1541wrch(c)
1542 Bit8u c;
1543{
1544 ASM_START
1545 push bp
1546 mov bp, sp
1547
1548 push bx
1549 mov ah, #0x0e
1550 mov al, 4[bp]
1551 xor bx,bx
1552 int #0x10
1553 pop bx
1554
1555 pop bp
1556 ASM_END
1557}
1558
1559 void
1560send(action, c)
1561 Bit16u action;
1562 Bit8u c;
1563{
1564#if BX_DEBUG_SERIAL
1565 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1566 uart_tx_byte(BX_DEBUG_PORT, c);
1567#endif
1568#if BX_VIRTUAL_PORTS
1569 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1570 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1571#endif
1572 if (action & BIOS_PRINTF_SCREEN) {
1573 if (c == '\n') wrch('\r');
1574 wrch(c);
1575 }
1576}
1577
1578 void
1579put_int(action, val, width, neg)
1580 Bit16u action;
1581 short val, width;
1582 bx_bool neg;
1583{
1584 short nval = val / 10;
1585 if (nval)
1586 put_int(action, nval, width - 1, neg);
1587 else {
1588 while (--width > 0) send(action, ' ');
1589 if (neg) send(action, '-');
1590 }
1591 send(action, val - (nval * 10) + '0');
1592}
1593
1594 void
1595put_uint(action, val, width, neg)
1596 Bit16u action;
1597 unsigned short val;
1598 short width;
1599 bx_bool neg;
1600{
1601 unsigned short nval = val / 10;
1602 if (nval)
1603 put_uint(action, nval, width - 1, neg);
1604 else {
1605 while (--width > 0) send(action, ' ');
1606 if (neg) send(action, '-');
1607 }
1608 send(action, val - (nval * 10) + '0');
1609}
1610
1611 void
1612put_luint(action, val, width, neg)
1613 Bit16u action;
1614 unsigned long val;
1615 short width;
1616 bx_bool neg;
1617{
1618 unsigned long nval = val / 10;
1619 if (nval)
1620 put_luint(action, nval, width - 1, neg);
1621 else {
1622 while (--width > 0) send(action, ' ');
1623 if (neg) send(action, '-');
1624 }
1625 send(action, val - (nval * 10) + '0');
1626}
1627
1628void put_str(action, segment, offset)
1629 Bit16u action;
1630 Bit16u segment;
1631 Bit16u offset;
1632{
1633 Bit8u c;
1634
1635 while (c = read_byte(segment, offset)) {
1636 send(action, c);
1637 offset++;
1638 }
1639}
1640
1641
1642//--------------------------------------------------------------------------
1643// bios_printf()
1644// A compact variable argument printf function.
1645//
1646// Supports %[format_width][length]format
1647// where format can be x,X,u,d,s,S,c
1648// and the optional length modifier is l (ell)
1649//--------------------------------------------------------------------------
1650 void
1651bios_printf(action, s)
1652 Bit16u action;
1653 Bit8u *s;
1654{
1655 Bit8u c, format_char;
1656 bx_bool in_format;
1657 short i;
1658 Bit16u *arg_ptr;
1659 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1660
1661 arg_ptr = &s;
1662 arg_seg = get_SS();
1663
1664 in_format = 0;
1665 format_width = 0;
1666
1667 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1668#if BX_VIRTUAL_PORTS
1669 outb(PANIC_PORT2, 0x00);
1670#endif
1671 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1672 }
1673
1674 while (c = read_byte(get_CS(), s)) {
1675 if ( c == '%' ) {
1676 in_format = 1;
1677 format_width = 0;
1678 }
1679 else if (in_format) {
1680 if ( (c>='0') && (c<='9') ) {
1681 format_width = (format_width * 10) + (c - '0');
1682 }
1683 else {
1684 arg_ptr++; // increment to next arg
1685 arg = read_word(arg_seg, arg_ptr);
1686 if (c == 'x' || c == 'X') {
1687 if (format_width == 0)
1688 format_width = 4;
1689 if (c == 'x')
1690 hexadd = 'a';
1691 else
1692 hexadd = 'A';
1693 for (i=format_width-1; i>=0; i--) {
1694 nibble = (arg >> (4 * i)) & 0x000f;
1695 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1696 }
1697 }
1698 else if (c == 'u') {
1699 put_uint(action, arg, format_width, 0);
1700 }
1701 else if (c == 'l') {
1702 s++;
1703 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1704 arg_ptr++; /* increment to next arg */
1705 hibyte = read_word(arg_seg, arg_ptr);
1706 if (c == 'd') {
1707 if (hibyte & 0x8000)
1708 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1709 else
1710 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1711 }
1712 else if (c == 'u') {
1713 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1714 }
1715 else if (c == 'x' || c == 'X')
1716 {
1717 if (format_width == 0)
1718 format_width = 8;
1719 if (c == 'x')
1720 hexadd = 'a';
1721 else
1722 hexadd = 'A';
1723 for (i=format_width-1; i>=0; i--) {
1724 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1725 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1726 }
1727 }
1728 }
1729 else if (c == 'd') {
1730 if (arg & 0x8000)
1731 put_int(action, -arg, format_width - 1, 1);
1732 else
1733 put_int(action, arg, format_width, 0);
1734 }
1735 else if (c == 's') {
1736 put_str(action, get_CS(), arg);
1737 }
1738 else if (c == 'S') {
1739 hibyte = arg;
1740 arg_ptr++;
1741 arg = read_word(arg_seg, arg_ptr);
1742 put_str(action, hibyte, arg);
1743 }
1744 else if (c == 'c') {
1745 send(action, arg);
1746 }
1747 else
1748 BX_PANIC("bios_printf: unknown format\n");
1749 in_format = 0;
1750 }
1751 }
1752 else {
1753 send(action, c);
1754 }
1755 s ++;
1756 }
1757
1758 if (action & BIOS_PRINTF_HALT) {
1759 // freeze in a busy loop.
1760ASM_START
1761 cli
1762 halt2_loop:
1763 hlt
1764 jmp halt2_loop
1765ASM_END
1766 }
1767}
1768
1769//--------------------------------------------------------------------------
1770// keyboard_init
1771//--------------------------------------------------------------------------
1772// this file is based on LinuxBIOS implementation of keyboard.c
1773// could convert to #asm to gain space
1774 void
1775keyboard_init()
1776{
1777 Bit16u max;
1778
1779 /* ------------------- Flush buffers ------------------------*/
1780 /* Wait until buffer is empty */
1781 max=0xffff;
1782 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1783
1784 /* flush incoming keys */
1785 max=0x2000;
1786 while (--max > 0) {
1787 outb(0x80, 0x00);
1788 if (inb(0x64) & 0x01) {
1789 inb(0x60);
1790 max = 0x2000;
1791 }
1792 }
1793
1794 // Due to timer issues, and if the IPS setting is > 15000000,
1795 // the incoming keys might not be flushed here. That will
1796 // cause a panic a few lines below. See sourceforge bug report :
1797 // [ 642031 ] FATAL: Keyboard RESET error:993
1798
1799 /* ------------------- controller side ----------------------*/
1800 /* send cmd = 0xAA, self test 8042 */
1801 outb(0x64, 0xaa);
1802
1803 /* Wait until buffer is empty */
1804 max=0xffff;
1805 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1806 if (max==0x0) keyboard_panic(00);
1807
1808 /* Wait for data */
1809 max=0xffff;
1810 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1811 if (max==0x0) keyboard_panic(01);
1812
1813 /* read self-test result, 0x55 should be returned from 0x60 */
1814 if ((inb(0x60) != 0x55)){
1815 keyboard_panic(991);
1816 }
1817
1818 /* send cmd = 0xAB, keyboard interface test */
1819 outb(0x64,0xab);
1820
1821 /* Wait until buffer is empty */
1822 max=0xffff;
1823 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1824 if (max==0x0) keyboard_panic(10);
1825
1826 /* Wait for data */
1827 max=0xffff;
1828 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1829 if (max==0x0) keyboard_panic(11);
1830
1831 /* read keyboard interface test result, */
1832 /* 0x00 should be returned form 0x60 */
1833 if ((inb(0x60) != 0x00)) {
1834 keyboard_panic(992);
1835 }
1836
1837 /* Enable Keyboard clock */
1838 outb(0x64,0xae);
1839 outb(0x64,0xa8);
1840
1841 /* ------------------- keyboard side ------------------------*/
1842 /* reset kerboard and self test (keyboard side) */
1843 outb(0x60, 0xff);
1844
1845 /* Wait until buffer is empty */
1846 max=0xffff;
1847 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1848 if (max==0x0) keyboard_panic(20);
1849
1850 /* Wait for data */
1851 max=0xffff;
1852 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1853 if (max==0x0) keyboard_panic(21);
1854
1855 /* keyboard should return ACK */
1856 if ((inb(0x60) != 0xfa)) {
1857 keyboard_panic(993);
1858 }
1859
1860 /* Wait for data */
1861 max=0xffff;
1862 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1863 if (max==0x0) keyboard_panic(31);
1864
1865 if ((inb(0x60) != 0xaa)) {
1866 keyboard_panic(994);
1867 }
1868
1869 /* Disable keyboard */
1870 outb(0x60, 0xf5);
1871
1872 /* Wait until buffer is empty */
1873 max=0xffff;
1874 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1875 if (max==0x0) keyboard_panic(40);
1876
1877 /* Wait for data */
1878 max=0xffff;
1879 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1880 if (max==0x0) keyboard_panic(41);
1881
1882 /* keyboard should return ACK */
1883 if ((inb(0x60) != 0xfa)) {
1884 keyboard_panic(995);
1885 }
1886
1887 /* Write Keyboard Mode */
1888 outb(0x64, 0x60);
1889
1890 /* Wait until buffer is empty */
1891 max=0xffff;
1892 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1893 if (max==0x0) keyboard_panic(50);
1894
1895 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1896 outb(0x60, 0x65);
1897
1898 /* Wait until buffer is empty */
1899 max=0xffff;
1900 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1901 if (max==0x0) keyboard_panic(60);
1902
1903 /* Enable keyboard */
1904 outb(0x60, 0xf4);
1905
1906 /* Wait until buffer is empty */
1907 max=0xffff;
1908 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1909 if (max==0x0) keyboard_panic(70);
1910
1911 /* Wait for data */
1912 max=0xffff;
1913 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1914 if (max==0x0) keyboard_panic(70);
1915
1916 /* keyboard should return ACK */
1917 if ((inb(0x60) != 0xfa)) {
1918 keyboard_panic(996);
1919 }
1920
1921 outb(0x80, 0x77);
1922}
1923
1924//--------------------------------------------------------------------------
1925// keyboard_panic
1926//--------------------------------------------------------------------------
1927 void
1928keyboard_panic(status)
1929 Bit16u status;
1930{
1931 // If you're getting a 993 keyboard panic here,
1932 // please see the comment in keyboard_init
1933
1934 BX_PANIC("Keyboard error:%u\n",status);
1935}
1936
1937//--------------------------------------------------------------------------
1938// shutdown_status_panic
1939// called when the shutdown statsu is not implemented, displays the status
1940//--------------------------------------------------------------------------
1941 void
1942shutdown_status_panic(status)
1943 Bit16u status;
1944{
1945 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1946}
1947
1948#ifdef VBOX
1949#include "logo.c"
1950#endif /* VBOX */
1951
1952//--------------------------------------------------------------------------
1953// print_bios_banner
1954// displays a the bios version
1955//--------------------------------------------------------------------------
1956void
1957print_bios_banner()
1958{
1959#ifdef VBOX
1960 // Skip the logo if a warm boot is requested.
1961 Bit16u warm_boot = read_word(0x0040,0x0072);
1962 write_word(0x0040,0x0072, 0);
1963 if (warm_boot == 0x1234)
1964 return;
1965#if !defined(DEBUG) || defined(DEBUG_sunlover)
1966 /* show graphical logo */
1967 show_logo();
1968#else
1969 /* set text mode */
1970 ASM_START
1971 mov ax, #0x0003
1972 int #0x10
1973 ASM_END
1974#endif /* !DEBUG */
1975#else /* !VBOX */
1976 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1977 BIOS_BUILD_DATE, bios_cvs_version_string);
1978 printf(
1979#if BX_APM
1980 "apmbios "
1981#endif
1982#if BX_PCIBIOS
1983 "pcibios "
1984#endif
1985#if BX_ELTORITO_BOOT
1986 "eltorito "
1987#endif
1988#if BX_ROMBIOS32
1989 "rombios32 "
1990#endif
1991 "\n\n");
1992#endif /* VBOX */
1993}
1994
1995//--------------------------------------------------------------------------
1996// print_boot_device
1997// displays the boot device
1998//--------------------------------------------------------------------------
1999
2000#ifdef VBOX
2001static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
2002#else /* !VBOX */
2003static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
2004#endif /* !VBOX */
2005
2006#ifdef VBOX
2007void
2008print_boot_device(cdboot, lanboot, drive)
2009 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2010#else /* !VBOX */
2011void
2012print_boot_device(cdboot, drive)
2013 Bit8u cdboot; Bit16u drive;
2014#endif /* !VBOX */
2015{
2016 Bit8u i;
2017
2018#ifdef VBOX
2019 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2020 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2021#else /* !VBOX */
2022 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2023#endif /* !VBOX */
2024 // drive contains real/emulated boot drive
2025
2026 if(cdboot)i=2; // CD-Rom
2027#ifdef VBOX
2028 else if(lanboot)i=3; // LAN
2029#endif /* VBOX */
2030 else if((drive&0x0080)==0x00)i=0; // Floppy
2031 else if((drive&0x0080)==0x80)i=1; // Hard drive
2032 else return;
2033
2034#ifdef VBOX
2035 BX_INFO("Booting from %s...\n",drivetypes[i]);
2036#else /* !VBOX */
2037 printf("Booting from %s...\n",drivetypes[i]);
2038#endif /* !VBOX */
2039}
2040
2041//--------------------------------------------------------------------------
2042// print_boot_failure
2043// displays the reason why boot failed
2044//--------------------------------------------------------------------------
2045#ifdef VBOX
2046 void
2047print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2048 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2049#else /* !VBOX */
2050 void
2051print_boot_failure(cdboot, drive, reason, lastdrive)
2052 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2053#endif /* !VBOX */
2054{
2055 Bit16u drivenum = drive&0x7f;
2056
2057 // cdboot: 1 if boot from cd, 0 otherwise
2058#ifdef VBOX
2059 // lanboot: 1 if boot from lan, 0 otherwise
2060#endif /* VBOX */
2061 // drive : drive number
2062 // reason: 0 signature check failed, 1 read error
2063 // lastdrive: 1 boot drive is the last one in boot sequence
2064
2065 if (cdboot)
2066#ifndef VBOX
2067 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2068#else /* VBOX */
2069 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2070 else if (lanboot)
2071 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2072#endif /* VBOX */
2073 else if (drive & 0x80)
2074#ifndef VBOX
2075 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2076#else /* VBOX */
2077 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2078#endif /* VBOX */
2079 else
2080#ifndef VBOX
2081 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2082#else /* VBOX */
2083 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2084#endif /* VBOX */
2085
2086 if (lastdrive==1) {
2087 if (reason==0)
2088#ifndef VBOX
2089 BX_PANIC("Not a bootable disk\n");
2090#else /* VBOX */
2091 BX_PANIC("No bootable medium found! System halted.\n");
2092#endif /* VBOX */
2093 else
2094#ifndef VBOX
2095 BX_PANIC("Could not read the boot disk\n");
2096#else /* VBOX */
2097 BX_PANIC("Could not read from the boot medium! System halted.\n");
2098#endif /* VBOX */
2099 }
2100}
2101
2102//--------------------------------------------------------------------------
2103// print_cdromboot_failure
2104// displays the reason why boot failed
2105//--------------------------------------------------------------------------
2106 void
2107print_cdromboot_failure( code )
2108 Bit16u code;
2109{
2110#ifndef VBOX
2111 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2112#else /* VBOX */
2113 BX_INFO("CDROM boot failure code : %04x\n",code);
2114#endif /* VBOX */
2115
2116 return;
2117}
2118
2119void
2120nmi_handler_msg()
2121{
2122 BX_PANIC("NMI Handler called\n");
2123}
2124
2125void
2126int18_panic_msg()
2127{
2128 BX_PANIC("INT18: BOOT FAILURE\n");
2129}
2130
2131void
2132log_bios_start()
2133{
2134#if BX_DEBUG_SERIAL
2135 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2136#endif
2137 BX_INFO("%s\n", bios_cvs_version_string);
2138}
2139
2140 bx_bool
2141set_enable_a20(val)
2142 bx_bool val;
2143{
2144 Bit8u oldval;
2145
2146 // Use PS2 System Control port A to set A20 enable
2147
2148 // get current setting first
2149 oldval = inb(0x92);
2150
2151 // change A20 status
2152 if (val)
2153 outb(0x92, oldval | 0x02);
2154 else
2155 outb(0x92, oldval & 0xfd);
2156
2157 return((oldval & 0x02) != 0);
2158}
2159
2160 void
2161debugger_on()
2162{
2163 outb(0xfedc, 0x01);
2164}
2165
2166 void
2167debugger_off()
2168{
2169 outb(0xfedc, 0x00);
2170}
2171
2172#if BX_USE_ATADRV
2173
2174// ---------------------------------------------------------------------------
2175// Start of ATA/ATAPI Driver
2176// ---------------------------------------------------------------------------
2177
2178// Global defines -- ATA register and register bits.
2179// command block & control block regs
2180#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2181#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2182#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2183#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2184#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2185#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2186#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2187#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2188#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2189#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2190#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2191#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2192#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2193
2194#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2195#define ATA_CB_ER_BBK 0x80 // ATA bad block
2196#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2197#define ATA_CB_ER_MC 0x20 // ATA media change
2198#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2199#define ATA_CB_ER_MCR 0x08 // ATA media change request
2200#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2201#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2202#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2203
2204#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2205#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2206#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2207#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2208#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2209
2210// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2211#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2212#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2213#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2214#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2215
2216// bits 7-4 of the device/head (CB_DH) reg
2217#define ATA_CB_DH_DEV0 0xa0 // select device 0
2218#define ATA_CB_DH_DEV1 0xb0 // select device 1
2219
2220// status reg (CB_STAT and CB_ASTAT) bits
2221#define ATA_CB_STAT_BSY 0x80 // busy
2222#define ATA_CB_STAT_RDY 0x40 // ready
2223#define ATA_CB_STAT_DF 0x20 // device fault
2224#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2225#define ATA_CB_STAT_SKC 0x10 // seek complete
2226#define ATA_CB_STAT_SERV 0x10 // service
2227#define ATA_CB_STAT_DRQ 0x08 // data request
2228#define ATA_CB_STAT_CORR 0x04 // corrected
2229#define ATA_CB_STAT_IDX 0x02 // index
2230#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2231#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2232
2233// device control reg (CB_DC) bits
2234#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2235#define ATA_CB_DC_SRST 0x04 // soft reset
2236#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2237
2238// Most mandtory and optional ATA commands (from ATA-3),
2239#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2240#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2241#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2242#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2243#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2244#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2245#define ATA_CMD_CHECK_POWER_MODE2 0x98
2246#define ATA_CMD_DEVICE_RESET 0x08
2247#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2248#define ATA_CMD_FLUSH_CACHE 0xE7
2249#define ATA_CMD_FORMAT_TRACK 0x50
2250#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2251#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2252#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2253#define ATA_CMD_IDLE1 0xE3
2254#define ATA_CMD_IDLE2 0x97
2255#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2256#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2257#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2258#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2259#define ATA_CMD_NOP 0x00
2260#define ATA_CMD_PACKET 0xA0
2261#define ATA_CMD_READ_BUFFER 0xE4
2262#define ATA_CMD_READ_DMA 0xC8
2263#define ATA_CMD_READ_DMA_QUEUED 0xC7
2264#define ATA_CMD_READ_MULTIPLE 0xC4
2265#define ATA_CMD_READ_SECTORS 0x20
2266#ifdef VBOX
2267#define ATA_CMD_READ_SECTORS_EXT 0x24
2268#endif /* VBOX */
2269#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2270#define ATA_CMD_RECALIBRATE 0x10
2271#define ATA_CMD_SEEK 0x70
2272#define ATA_CMD_SET_FEATURES 0xEF
2273#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2274#define ATA_CMD_SLEEP1 0xE6
2275#define ATA_CMD_SLEEP2 0x99
2276#define ATA_CMD_STANDBY1 0xE2
2277#define ATA_CMD_STANDBY2 0x96
2278#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2279#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2280#define ATA_CMD_WRITE_BUFFER 0xE8
2281#define ATA_CMD_WRITE_DMA 0xCA
2282#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2283#define ATA_CMD_WRITE_MULTIPLE 0xC5
2284#define ATA_CMD_WRITE_SECTORS 0x30
2285#ifdef VBOX
2286#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2287#endif /* VBOX */
2288#define ATA_CMD_WRITE_VERIFY 0x3C
2289
2290#define ATA_IFACE_NONE 0x00
2291#define ATA_IFACE_ISA 0x00
2292#define ATA_IFACE_PCI 0x01
2293
2294#define ATA_TYPE_NONE 0x00
2295#define ATA_TYPE_UNKNOWN 0x01
2296#define ATA_TYPE_ATA 0x02
2297#define ATA_TYPE_ATAPI 0x03
2298#ifdef VBOX
2299#define ATA_TYPE_SCSI 0x04 // SCSI disk
2300#endif
2301
2302#define ATA_DEVICE_NONE 0x00
2303#define ATA_DEVICE_HD 0xFF
2304#define ATA_DEVICE_CDROM 0x05
2305
2306#define ATA_MODE_NONE 0x00
2307#define ATA_MODE_PIO16 0x00
2308#define ATA_MODE_PIO32 0x01
2309#define ATA_MODE_ISADMA 0x02
2310#define ATA_MODE_PCIDMA 0x03
2311#define ATA_MODE_USEIRQ 0x10
2312
2313#define ATA_TRANSLATION_NONE 0
2314#define ATA_TRANSLATION_LBA 1
2315#define ATA_TRANSLATION_LARGE 2
2316#define ATA_TRANSLATION_RECHS 3
2317
2318#define ATA_DATA_NO 0x00
2319#define ATA_DATA_IN 0x01
2320#define ATA_DATA_OUT 0x02
2321
2322// ---------------------------------------------------------------------------
2323// ATA/ATAPI driver : initialization
2324// ---------------------------------------------------------------------------
2325void ata_init( )
2326{
2327 Bit16u ebda_seg=read_word(0x0040,0x000E);
2328 Bit8u channel, device;
2329
2330 // Channels info init.
2331 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2332 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2333 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2334 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2335 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2336 }
2337
2338 // Devices info init.
2339 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2340 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2341 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2342 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2343 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2344 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2345 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2346 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2347 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2348 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2349 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2350 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2351 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2352 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2353
2354 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2355 }
2356
2357 // hdidmap and cdidmap init.
2358 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2359 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2360 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2361 }
2362
2363 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2364 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2365}
2366
2367// ---------------------------------------------------------------------------
2368// ATA/ATAPI driver : device detection
2369// ---------------------------------------------------------------------------
2370
2371void ata_detect( )
2372{
2373 Bit16u ebda_seg=read_word(0x0040,0x000E);
2374 Bit8u hdcount, cdcount, device, type;
2375 Bit8u buffer[0x0200];
2376
2377#if BX_MAX_ATA_INTERFACES > 0
2378 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2379 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2380 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2381 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2382#endif
2383#if BX_MAX_ATA_INTERFACES > 1
2384 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2385 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2386 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2387 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2388#endif
2389#if BX_MAX_ATA_INTERFACES > 2
2390 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2391 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2392 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2393 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2394#endif
2395#if BX_MAX_ATA_INTERFACES > 3
2396 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2397 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2398 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2399 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2400#endif
2401#if BX_MAX_ATA_INTERFACES > 4
2402#error Please fill the ATA interface informations
2403#endif
2404
2405 // Device detection
2406 hdcount=cdcount=0;
2407
2408 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2409 Bit16u iobase1, iobase2;
2410 Bit8u channel, slave, shift;
2411 Bit8u sc, sn, cl, ch, st;
2412
2413 channel = device / 2;
2414 slave = device % 2;
2415
2416 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2417 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2418
2419 // Disable interrupts
2420 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2421
2422 // Look for device
2423 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2424 outb(iobase1+ATA_CB_SC, 0x55);
2425 outb(iobase1+ATA_CB_SN, 0xaa);
2426 outb(iobase1+ATA_CB_SC, 0xaa);
2427 outb(iobase1+ATA_CB_SN, 0x55);
2428 outb(iobase1+ATA_CB_SC, 0x55);
2429 outb(iobase1+ATA_CB_SN, 0xaa);
2430
2431 // If we found something
2432 sc = inb(iobase1+ATA_CB_SC);
2433 sn = inb(iobase1+ATA_CB_SN);
2434
2435 if ( (sc == 0x55) && (sn == 0xaa) ) {
2436 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2437
2438 // reset the channel
2439 ata_reset(device);
2440
2441 // check for ATA or ATAPI
2442 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2443 sc = inb(iobase1+ATA_CB_SC);
2444 sn = inb(iobase1+ATA_CB_SN);
2445 if ((sc==0x01) && (sn==0x01)) {
2446 cl = inb(iobase1+ATA_CB_CL);
2447 ch = inb(iobase1+ATA_CB_CH);
2448 st = inb(iobase1+ATA_CB_STAT);
2449
2450 if ((cl==0x14) && (ch==0xeb)) {
2451 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2452 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2453 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2454 } else if ((cl==0xff) && (ch==0xff)) {
2455 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2456 }
2457 }
2458 }
2459
2460#ifdef VBOX
2461 // Enable interrupts
2462 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2463#endif /* VBOX */
2464
2465 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2466
2467 // Now we send a IDENTIFY command to ATA device
2468 if(type == ATA_TYPE_ATA) {
2469 Bit32u sectors;
2470 Bit16u cylinders, heads, spt, blksize;
2471#ifdef VBOX
2472 Bit16u lcylinders, lheads, lspt;
2473 Bit8u chsgeo_base;
2474#endif /* VBOX */
2475 Bit8u translation, removable, mode;
2476
2477 //Temporary values to do the transfer
2478 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2479 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2480
2481 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2482 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2483
2484 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2485 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2486#ifdef VBOX
2487 blksize = 512; /* There is no sector size field any more. */
2488#else /* !VBOX */
2489 blksize = read_word(get_SS(),buffer+10);
2490#endif /* !VBOX */
2491
2492 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2493 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2494 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2495
2496 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2497#ifdef VBOX
2498 /** @todo update sectors to be a 64 bit number (also lba...). */
2499 if (sectors == 268435455)
2500 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2501 switch (device)
2502 {
2503 case 0:
2504 chsgeo_base = 0x1e;
2505 break;
2506 case 1:
2507 chsgeo_base = 0x26;
2508 break;
2509 case 2:
2510 chsgeo_base = 0x67;
2511 break;
2512 case 3:
2513 chsgeo_base = 0x70;
2514 break;
2515 case 4:
2516 chsgeo_base = 0x40;
2517 break;
2518 case 5:
2519 chsgeo_base = 0x48;
2520 break;
2521 case 6:
2522 chsgeo_base = 0x50;
2523 break;
2524 case 7:
2525 chsgeo_base = 0x58;
2526 break;
2527 default:
2528 chsgeo_base = 0;
2529 }
2530 if (chsgeo_base != 0)
2531 {
2532 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2533 lheads = inb_cmos(chsgeo_base+2);
2534 lspt = inb_cmos(chsgeo_base+7);
2535 }
2536 else
2537 {
2538 lcylinders = 0;
2539 lheads = 0;
2540 lspt = 0;
2541 }
2542 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2543#endif /* VBOX */
2544
2545 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2546 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2547 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2548 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2551 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2552 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2553#ifdef VBOX
2554 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2555 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2556 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2557 if (device < 2)
2558 {
2559 Bit8u sum, i;
2560 unsigned char *fdpt;
2561 if (device == 0)
2562 fdpt = &EbdaData->fdpt0;
2563 else
2564 fdpt = &EbdaData->fdpt1;
2565
2566 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2567 * to be done at POST time with lots of ugly assembler code, which
2568 * isn't worth the effort of converting from AMI to Award CMOS
2569 * format. Just do it here. */
2570 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2571 write_byte(ebda_seg, fdpt + 0x02, lheads);
2572 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2573 write_word(ebda_seg, fdpt + 0x09, cylinders);
2574 write_byte(ebda_seg, fdpt + 0x0b, heads);
2575 write_byte(ebda_seg, fdpt + 0x04, spt);
2576 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2577 sum = 0;
2578 for (i = 0; i < 0xf; i++)
2579 sum += read_byte(ebda_seg, fdpt + i);
2580 sum = 1 - sum;
2581 write_byte(ebda_seg, fdpt + 0x0f, sum);
2582 }
2583#else /* !VBOX */
2584 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2585
2586 translation = inb_cmos(0x39 + channel/2);
2587 for (shift=device%4; shift>0; shift--) translation >>= 2;
2588 translation &= 0x03;
2589
2590 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2591
2592 switch (translation) {
2593 case ATA_TRANSLATION_NONE:
2594 BX_INFO("none");
2595 break;
2596 case ATA_TRANSLATION_LBA:
2597 BX_INFO("lba");
2598 break;
2599 case ATA_TRANSLATION_LARGE:
2600 BX_INFO("large");
2601 break;
2602 case ATA_TRANSLATION_RECHS:
2603 BX_INFO("r-echs");
2604 break;
2605 }
2606 switch (translation) {
2607 case ATA_TRANSLATION_NONE:
2608 break;
2609 case ATA_TRANSLATION_LBA:
2610 spt = 63;
2611 sectors /= 63;
2612 heads = sectors / 1024;
2613 if (heads>128) heads = 255;
2614 else if (heads>64) heads = 128;
2615 else if (heads>32) heads = 64;
2616 else if (heads>16) heads = 32;
2617 else heads=16;
2618 cylinders = sectors / heads;
2619 break;
2620 case ATA_TRANSLATION_RECHS:
2621 // Take care not to overflow
2622 if (heads==16) {
2623 if(cylinders>61439) cylinders=61439;
2624 heads=15;
2625 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2626 }
2627 // then go through the large bitshift process
2628 case ATA_TRANSLATION_LARGE:
2629 while(cylinders > 1024) {
2630 cylinders >>= 1;
2631 heads <<= 1;
2632
2633 // If we max out the head count
2634 if (heads > 127) break;
2635 }
2636 break;
2637 }
2638 // clip to 1024 cylinders in lchs
2639 if (cylinders > 1024) cylinders=1024;
2640 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2641
2642 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2643 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2644 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2645#endif /* VBOX */
2646
2647 // fill hdidmap
2648 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2649 hdcount++;
2650 }
2651
2652 // Now we send a IDENTIFY command to ATAPI device
2653 if(type == ATA_TYPE_ATAPI) {
2654
2655 Bit8u type, removable, mode;
2656 Bit16u blksize;
2657
2658 //Temporary values to do the transfer
2659 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2660 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2661
2662 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2663 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2664
2665 type = read_byte(get_SS(),buffer+1) & 0x1f;
2666 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2667 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2668 blksize = 2048;
2669
2670 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2671 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2672 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2673 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2674
2675 // fill cdidmap
2676 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2677 cdcount++;
2678 }
2679
2680 {
2681 Bit32u sizeinmb;
2682 Bit16u ataversion;
2683 Bit8u c, i, version, model[41];
2684
2685 switch (type) {
2686 case ATA_TYPE_ATA:
2687 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2688 sizeinmb >>= 11;
2689 case ATA_TYPE_ATAPI:
2690 // Read ATA/ATAPI version
2691 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2692 for(version=15;version>0;version--) {
2693 if((ataversion&(1<<version))!=0)
2694 break;
2695 }
2696
2697 // Read model name
2698 for(i=0;i<20;i++){
2699 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2700 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2701 }
2702
2703 // Reformat
2704 write_byte(get_SS(),model+40,0x00);
2705 for(i=39;i>0;i--){
2706 if(read_byte(get_SS(),model+i)==0x20)
2707 write_byte(get_SS(),model+i,0x00);
2708 else break;
2709 }
2710 break;
2711 }
2712
2713#ifdef VBOX
2714 // we don't want any noisy output for now
2715#else /* !VBOX */
2716 switch (type) {
2717 case ATA_TYPE_ATA:
2718 printf("ata%d %s: ",channel,slave?" slave":"master");
2719 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2720 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2721 break;
2722 case ATA_TYPE_ATAPI:
2723 printf("ata%d %s: ",channel,slave?" slave":"master");
2724 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2725 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2726 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2727 else
2728 printf(" ATAPI-%d Device\n",version);
2729 break;
2730 case ATA_TYPE_UNKNOWN:
2731 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2732 break;
2733 }
2734#endif /* !VBOX */
2735 }
2736 }
2737
2738 // Store the devices counts
2739 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2740 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2741 write_byte(0x40,0x75, hdcount);
2742
2743#ifdef VBOX
2744 // we don't want any noisy output for now
2745#else /* !VBOX */
2746 printf("\n");
2747#endif /* !VBOX */
2748
2749 // FIXME : should use bios=cmos|auto|disable bits
2750 // FIXME : should know about translation bits
2751 // FIXME : move hard_drive_post here
2752
2753}
2754
2755// ---------------------------------------------------------------------------
2756// ATA/ATAPI driver : software reset
2757// ---------------------------------------------------------------------------
2758// ATA-3
2759// 8.2.1 Software reset - Device 0
2760
2761void ata_reset(device)
2762Bit16u device;
2763{
2764 Bit16u ebda_seg=read_word(0x0040,0x000E);
2765 Bit16u iobase1, iobase2;
2766 Bit8u channel, slave, sn, sc;
2767 Bit16u max;
2768#ifdef VBOX
2769 Bit16u pdelay;
2770#endif /* VBOX */
2771
2772 channel = device / 2;
2773 slave = device % 2;
2774
2775 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2776 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2777
2778 // Reset
2779
2780// 8.2.1 (a) -- set SRST in DC
2781 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2782
2783// 8.2.1 (b) -- wait for BSY
2784 max=0xff;
2785 while(--max>0) {
2786 Bit8u status = inb(iobase1+ATA_CB_STAT);
2787 if ((status & ATA_CB_STAT_BSY) != 0) break;
2788 }
2789
2790// 8.2.1 (f) -- clear SRST
2791 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2792
2793 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2794
2795// 8.2.1 (g) -- check for sc==sn==0x01
2796 // select device
2797 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2798 sc = inb(iobase1+ATA_CB_SC);
2799 sn = inb(iobase1+ATA_CB_SN);
2800
2801 if ( (sc==0x01) && (sn==0x01) ) {
2802
2803// 8.2.1 (h) -- wait for not BSY
2804#ifdef VBOX
2805 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2806#else /* !VBOX */
2807 max=0xff;
2808#endif /* !VBOX */
2809 while(--max>0) {
2810 Bit8u status = inb(iobase1+ATA_CB_STAT);
2811 if ((status & ATA_CB_STAT_BSY) == 0) break;
2812#ifdef VBOX
2813 pdelay=0xffff;
2814 while (--pdelay>0) {
2815 /* nothing */
2816 }
2817#endif /* VBOX */
2818 }
2819 }
2820 }
2821
2822// 8.2.1 (i) -- wait for DRDY
2823#ifdef VBOX
2824 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2825#else /* !VBOX */
2826 max=0xfff;
2827#endif /* !VBOX */
2828 while(--max>0) {
2829 Bit8u status = inb(iobase1+ATA_CB_STAT);
2830 if ((status & ATA_CB_STAT_RDY) != 0) break;
2831 }
2832
2833 // Enable interrupts
2834 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2835}
2836
2837// ---------------------------------------------------------------------------
2838// ATA/ATAPI driver : execute a non data command
2839// ---------------------------------------------------------------------------
2840
2841Bit16u ata_cmd_non_data()
2842{return 0;}
2843
2844// ---------------------------------------------------------------------------
2845// ATA/ATAPI driver : execute a data-in command
2846// ---------------------------------------------------------------------------
2847 // returns
2848 // 0 : no error
2849 // 1 : BUSY bit set
2850 // 2 : read error
2851 // 3 : expected DRQ=1
2852 // 4 : no sectors left to read/verify
2853 // 5 : more sectors to read/verify
2854 // 6 : no sectors left to write
2855 // 7 : more sectors to write
2856Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2857Bit16u device, command, count, cylinder, head, sector, segment, offset;
2858Bit32u lba;
2859{
2860 Bit16u ebda_seg=read_word(0x0040,0x000E);
2861 Bit16u iobase1, iobase2, blksize;
2862 Bit8u channel, slave;
2863 Bit8u status, current, mode;
2864
2865 channel = device / 2;
2866 slave = device % 2;
2867
2868 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2869 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2870 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2871 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2872 if (mode == ATA_MODE_PIO32) blksize>>=2;
2873 else blksize>>=1;
2874
2875#ifdef VBOX
2876 status = inb(iobase1 + ATA_CB_STAT);
2877 if (status & ATA_CB_STAT_BSY)
2878 {
2879 // Enable interrupts
2880 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2881 return 1;
2882 }
2883#endif /* VBOX */
2884
2885 // sector will be 0 only on lba access. Convert to lba-chs
2886 if (sector == 0) {
2887#ifdef VBOX
2888 if (count >= 256 || lba + count >= 268435456)
2889 {
2890 sector = (lba & 0xff000000L) >> 24;
2891 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2892 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2893 outb(iobase1 + ATA_CB_SN, sector);
2894 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2895 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2896 /* Leave the bottom 24 bits as is, they are treated correctly by the
2897 * LBA28 code path. */
2898 lba &= 0xffffff;
2899 }
2900#endif /* VBOX */
2901 sector = (Bit16u) (lba & 0x000000ffL);
2902 lba >>= 8;
2903 cylinder = (Bit16u) (lba & 0x0000ffffL);
2904 lba >>= 16;
2905 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2906 }
2907
2908 // Reset count of transferred data
2909 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2910 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2911 current = 0;
2912
2913#ifndef VBOX
2914 status = inb(iobase1 + ATA_CB_STAT);
2915 if (status & ATA_CB_STAT_BSY) return 1;
2916#endif /* !VBOX */
2917
2918 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2919 outb(iobase1 + ATA_CB_FR, 0x00);
2920 outb(iobase1 + ATA_CB_SC, count);
2921 outb(iobase1 + ATA_CB_SN, sector);
2922 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2923 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2924 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2925 outb(iobase1 + ATA_CB_CMD, command);
2926
2927 while (1) {
2928 status = inb(iobase1 + ATA_CB_STAT);
2929 if ( !(status & ATA_CB_STAT_BSY) ) break;
2930 }
2931
2932 if (status & ATA_CB_STAT_ERR) {
2933 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2934#ifdef VBOX
2935 // Enable interrupts
2936 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2937#endif /* VBOX */
2938 return 2;
2939 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2940 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2941#ifdef VBOX
2942 // Enable interrupts
2943 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2944#endif /* VBOX */
2945 return 3;
2946 }
2947
2948 // FIXME : move seg/off translation here
2949
2950ASM_START
2951 sti ;; enable higher priority interrupts
2952ASM_END
2953
2954 while (1) {
2955
2956ASM_START
2957 push bp
2958 mov bp, sp
2959 mov di, _ata_cmd_data_in.offset + 2[bp]
2960 mov ax, _ata_cmd_data_in.segment + 2[bp]
2961 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2962
2963 ;; adjust if there will be an overrun. 2K max sector size
2964 cmp di, #0xf800 ;;
2965 jbe ata_in_no_adjust
2966
2967ata_in_adjust:
2968 sub di, #0x0800 ;; sub 2 kbytes from offset
2969 add ax, #0x0080 ;; add 2 Kbytes to segment
2970
2971ata_in_no_adjust:
2972 mov es, ax ;; segment in es
2973
2974 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2975
2976 mov ah, _ata_cmd_data_in.mode + 2[bp]
2977 cmp ah, #ATA_MODE_PIO32
2978 je ata_in_32
2979
2980ata_in_16:
2981 rep
2982 insw ;; CX words transfered from port(DX) to ES:[DI]
2983 jmp ata_in_done
2984
2985ata_in_32:
2986 rep
2987 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2988
2989ata_in_done:
2990 mov _ata_cmd_data_in.offset + 2[bp], di
2991 mov _ata_cmd_data_in.segment + 2[bp], es
2992 pop bp
2993ASM_END
2994
2995 current++;
2996 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2997 count--;
2998#ifdef VBOX
2999 while (1) {
3000 status = inb(iobase1 + ATA_CB_STAT);
3001 if ( !(status & ATA_CB_STAT_BSY) ) break;
3002 }
3003#else /* !VBOX */
3004 status = inb(iobase1 + ATA_CB_STAT);
3005#endif /* !VBOX */
3006 if (count == 0) {
3007 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3008 != ATA_CB_STAT_RDY ) {
3009 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3010#ifdef VBOX
3011 // Enable interrupts
3012 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3013#endif /* VBOX */
3014 return 4;
3015 }
3016 break;
3017 }
3018 else {
3019 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3020 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3021 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3022#ifdef VBOX
3023 // Enable interrupts
3024 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3025#endif /* VBOX */
3026 return 5;
3027 }
3028 continue;
3029 }
3030 }
3031 // Enable interrupts
3032 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3033 return 0;
3034}
3035
3036// ---------------------------------------------------------------------------
3037// ATA/ATAPI driver : execute a data-out command
3038// ---------------------------------------------------------------------------
3039 // returns
3040 // 0 : no error
3041 // 1 : BUSY bit set
3042 // 2 : read error
3043 // 3 : expected DRQ=1
3044 // 4 : no sectors left to read/verify
3045 // 5 : more sectors to read/verify
3046 // 6 : no sectors left to write
3047 // 7 : more sectors to write
3048Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3049Bit16u device, command, count, cylinder, head, sector, segment, offset;
3050Bit32u lba;
3051{
3052 Bit16u ebda_seg=read_word(0x0040,0x000E);
3053 Bit16u iobase1, iobase2, blksize;
3054 Bit8u channel, slave;
3055 Bit8u status, current, mode;
3056
3057 channel = device / 2;
3058 slave = device % 2;
3059
3060 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3061 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3062 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3063 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3064 if (mode == ATA_MODE_PIO32) blksize>>=2;
3065 else blksize>>=1;
3066
3067#ifdef VBOX
3068 status = inb(iobase1 + ATA_CB_STAT);
3069 if (status & ATA_CB_STAT_BSY)
3070 {
3071 // Enable interrupts
3072 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3073 return 1;
3074 }
3075#endif /* VBOX */
3076
3077 // sector will be 0 only on lba access. Convert to lba-chs
3078 if (sector == 0) {
3079#ifdef VBOX
3080 if (count >= 256 || lba + count >= 268435456)
3081 {
3082 sector = (lba & 0xff000000L) >> 24;
3083 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3084 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3085 outb(iobase1 + ATA_CB_SN, sector);
3086 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3087 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3088 /* Leave the bottom 24 bits as is, they are treated correctly by the
3089 * LBA28 code path. */
3090 lba &= 0xffffff;
3091 }
3092#endif /* VBOX */
3093 sector = (Bit16u) (lba & 0x000000ffL);
3094 lba >>= 8;
3095 cylinder = (Bit16u) (lba & 0x0000ffffL);
3096 lba >>= 16;
3097 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3098 }
3099
3100 // Reset count of transferred data
3101 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3102 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3103 current = 0;
3104
3105#ifndef VBOX
3106 status = inb(iobase1 + ATA_CB_STAT);
3107 if (status & ATA_CB_STAT_BSY) return 1;
3108#endif /* !VBOX */
3109
3110 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3111 outb(iobase1 + ATA_CB_FR, 0x00);
3112 outb(iobase1 + ATA_CB_SC, count);
3113 outb(iobase1 + ATA_CB_SN, sector);
3114 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3115 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3116 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3117 outb(iobase1 + ATA_CB_CMD, command);
3118
3119 while (1) {
3120 status = inb(iobase1 + ATA_CB_STAT);
3121 if ( !(status & ATA_CB_STAT_BSY) ) break;
3122 }
3123
3124 if (status & ATA_CB_STAT_ERR) {
3125 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3126#ifdef VBOX
3127 // Enable interrupts
3128 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3129#endif /* VBOX */
3130 return 2;
3131 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3132 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3133#ifdef VBOX
3134 // Enable interrupts
3135 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3136#endif /* VBOX */
3137 return 3;
3138 }
3139
3140 // FIXME : move seg/off translation here
3141
3142ASM_START
3143 sti ;; enable higher priority interrupts
3144ASM_END
3145
3146 while (1) {
3147
3148ASM_START
3149 push bp
3150 mov bp, sp
3151 mov si, _ata_cmd_data_out.offset + 2[bp]
3152 mov ax, _ata_cmd_data_out.segment + 2[bp]
3153 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3154
3155 ;; adjust if there will be an overrun. 2K max sector size
3156 cmp si, #0xf800 ;;
3157 jbe ata_out_no_adjust
3158
3159ata_out_adjust:
3160 sub si, #0x0800 ;; sub 2 kbytes from offset
3161 add ax, #0x0080 ;; add 2 Kbytes to segment
3162
3163ata_out_no_adjust:
3164 mov es, ax ;; segment in es
3165
3166 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3167
3168 mov ah, _ata_cmd_data_out.mode + 2[bp]
3169 cmp ah, #ATA_MODE_PIO32
3170 je ata_out_32
3171
3172ata_out_16:
3173 seg ES
3174 rep
3175 outsw ;; CX words transfered from port(DX) to ES:[SI]
3176 jmp ata_out_done
3177
3178ata_out_32:
3179 seg ES
3180 rep
3181 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3182
3183ata_out_done:
3184 mov _ata_cmd_data_out.offset + 2[bp], si
3185 mov _ata_cmd_data_out.segment + 2[bp], es
3186 pop bp
3187ASM_END
3188
3189 current++;
3190 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3191 count--;
3192#ifdef VBOX
3193 while (1) {
3194 status = inb(iobase1 + ATA_CB_STAT);
3195 if ( !(status & ATA_CB_STAT_BSY) ) break;
3196 }
3197#else /* !VBOX */
3198 status = inb(iobase1 + ATA_CB_STAT);
3199#endif /* VBOX */
3200 if (count == 0) {
3201 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3202 != ATA_CB_STAT_RDY ) {
3203 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3204#ifdef VBOX
3205 // Enable interrupts
3206 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3207#endif /* VBOX */
3208 return 6;
3209 }
3210 break;
3211 }
3212 else {
3213 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3214 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3215 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3216#ifdef VBOX
3217 // Enable interrupts
3218 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3219#endif /* VBOX */
3220 return 7;
3221 }
3222 continue;
3223 }
3224 }
3225 // Enable interrupts
3226 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3227 return 0;
3228}
3229
3230// ---------------------------------------------------------------------------
3231// ATA/ATAPI driver : execute a packet command
3232// ---------------------------------------------------------------------------
3233 // returns
3234 // 0 : no error
3235 // 1 : error in parameters
3236 // 2 : BUSY bit set
3237 // 3 : error
3238 // 4 : not ready
3239Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3240Bit8u cmdlen,inout;
3241Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3242Bit16u header;
3243Bit32u length;
3244{
3245 Bit16u ebda_seg=read_word(0x0040,0x000E);
3246 Bit16u iobase1, iobase2;
3247 Bit16u lcount, lbefore, lafter, count;
3248 Bit8u channel, slave;
3249 Bit8u status, mode, lmode;
3250 Bit32u total, transfer;
3251
3252 channel = device / 2;
3253 slave = device % 2;
3254
3255 // Data out is not supported yet
3256 if (inout == ATA_DATA_OUT) {
3257 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3258 return 1;
3259 }
3260
3261 // The header length must be even
3262 if (header & 1) {
3263 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3264 return 1;
3265 }
3266
3267 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3268 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3269 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3270 transfer= 0L;
3271
3272 if (cmdlen < 12) cmdlen=12;
3273 if (cmdlen > 12) cmdlen=16;
3274 cmdlen>>=1;
3275
3276 // Reset count of transferred data
3277 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3278 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3279
3280 status = inb(iobase1 + ATA_CB_STAT);
3281 if (status & ATA_CB_STAT_BSY) return 2;
3282
3283 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3284 // outb(iobase1 + ATA_CB_FR, 0x00);
3285 // outb(iobase1 + ATA_CB_SC, 0x00);
3286 // outb(iobase1 + ATA_CB_SN, 0x00);
3287 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3288 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3289 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3290 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3291
3292 // Device should ok to receive command
3293 while (1) {
3294 status = inb(iobase1 + ATA_CB_STAT);
3295 if ( !(status & ATA_CB_STAT_BSY) ) break;
3296 }
3297
3298 if (status & ATA_CB_STAT_ERR) {
3299 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3300#ifdef VBOX
3301 // Enable interrupts
3302 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3303#endif /* VBOX */
3304 return 3;
3305 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3306 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3307#ifdef VBOX
3308 // Enable interrupts
3309 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3310#endif /* VBOX */
3311 return 4;
3312 }
3313
3314 // Normalize address
3315 cmdseg += (cmdoff / 16);
3316 cmdoff %= 16;
3317
3318 // Send command to device
3319ASM_START
3320 sti ;; enable higher priority interrupts
3321
3322 push bp
3323 mov bp, sp
3324
3325 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3326 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3327 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3328 mov es, ax ;; segment in es
3329
3330 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3331
3332 seg ES
3333 rep
3334 outsw ;; CX words transfered from port(DX) to ES:[SI]
3335
3336 pop bp
3337ASM_END
3338
3339 if (inout == ATA_DATA_NO) {
3340 status = inb(iobase1 + ATA_CB_STAT);
3341 }
3342 else {
3343 while (1) {
3344
3345#ifdef VBOX
3346 while (1) {
3347 status = inb(iobase1 + ATA_CB_STAT);
3348 if ( !(status & ATA_CB_STAT_BSY) ) break;
3349 }
3350#else /* VBOX */
3351 status = inb(iobase1 + ATA_CB_STAT);
3352#endif /* VBOX */
3353
3354 // Check if command completed
3355 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3356
3357 if (status & ATA_CB_STAT_ERR) {
3358 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3359#ifdef VBOX
3360 // Enable interrupts
3361 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3362#endif /* VBOX */
3363 return 3;
3364 }
3365
3366 // Device must be ready to send data
3367 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3368 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3369 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3370#ifdef VBOX
3371 // Enable interrupts
3372 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3373#endif /* VBOX */
3374 return 4;
3375 }
3376
3377 // Normalize address
3378 bufseg += (bufoff / 16);
3379 bufoff %= 16;
3380
3381 // Get the byte count
3382 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3383
3384 // adjust to read what we want
3385 if(header>lcount) {
3386 lbefore=lcount;
3387 header-=lcount;
3388 lcount=0;
3389 }
3390 else {
3391 lbefore=header;
3392 header=0;
3393 lcount-=lbefore;
3394 }
3395
3396 if(lcount>length) {
3397 lafter=lcount-length;
3398 lcount=length;
3399 length=0;
3400 }
3401 else {
3402 lafter=0;
3403 length-=lcount;
3404 }
3405
3406 // Save byte count
3407 count = lcount;
3408
3409 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3410 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3411
3412 // If counts not dividable by 4, use 16bits mode
3413 lmode = mode;
3414 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3415 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3416 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3417
3418 // adds an extra byte if count are odd. before is always even
3419 if (lcount & 0x01) {
3420 lcount+=1;
3421 if ((lafter > 0) && (lafter & 0x01)) {
3422 lafter-=1;
3423 }
3424 }
3425
3426 if (lmode == ATA_MODE_PIO32) {
3427 lcount>>=2; lbefore>>=2; lafter>>=2;
3428 }
3429 else {
3430 lcount>>=1; lbefore>>=1; lafter>>=1;
3431 }
3432
3433 ; // FIXME bcc bug
3434
3435ASM_START
3436 push bp
3437 mov bp, sp
3438
3439 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3440
3441 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3442 jcxz ata_packet_no_before
3443
3444 mov ah, _ata_cmd_packet.lmode + 2[bp]
3445 cmp ah, #ATA_MODE_PIO32
3446 je ata_packet_in_before_32
3447
3448ata_packet_in_before_16:
3449 in ax, dx
3450 loop ata_packet_in_before_16
3451 jmp ata_packet_no_before
3452
3453ata_packet_in_before_32:
3454 push eax
3455ata_packet_in_before_32_loop:
3456 in eax, dx
3457 loop ata_packet_in_before_32_loop
3458 pop eax
3459
3460ata_packet_no_before:
3461 mov cx, _ata_cmd_packet.lcount + 2[bp]
3462 jcxz ata_packet_after
3463
3464 mov di, _ata_cmd_packet.bufoff + 2[bp]
3465 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3466 mov es, ax
3467
3468 mov ah, _ata_cmd_packet.lmode + 2[bp]
3469 cmp ah, #ATA_MODE_PIO32
3470 je ata_packet_in_32
3471
3472ata_packet_in_16:
3473 rep
3474 insw ;; CX words transfered tp port(DX) to ES:[DI]
3475 jmp ata_packet_after
3476
3477ata_packet_in_32:
3478 rep
3479 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3480
3481ata_packet_after:
3482 mov cx, _ata_cmd_packet.lafter + 2[bp]
3483 jcxz ata_packet_done
3484
3485 mov ah, _ata_cmd_packet.lmode + 2[bp]
3486 cmp ah, #ATA_MODE_PIO32
3487 je ata_packet_in_after_32
3488
3489ata_packet_in_after_16:
3490 in ax, dx
3491 loop ata_packet_in_after_16
3492 jmp ata_packet_done
3493
3494ata_packet_in_after_32:
3495 push eax
3496ata_packet_in_after_32_loop:
3497 in eax, dx
3498 loop ata_packet_in_after_32_loop
3499 pop eax
3500
3501ata_packet_done:
3502 pop bp
3503ASM_END
3504
3505 // Compute new buffer address
3506 bufoff += count;
3507
3508 // Save transferred bytes count
3509 transfer += count;
3510 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3511 }
3512 }
3513
3514 // Final check, device must be ready
3515 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3516 != ATA_CB_STAT_RDY ) {
3517 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3518#ifdef VBOX
3519 // Enable interrupts
3520 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3521#endif /* VBOX */
3522 return 4;
3523 }
3524
3525 // Enable interrupts
3526 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3527 return 0;
3528}
3529
3530// ---------------------------------------------------------------------------
3531// End of ATA/ATAPI Driver
3532// ---------------------------------------------------------------------------
3533
3534// ---------------------------------------------------------------------------
3535// Start of ATA/ATAPI generic functions
3536// ---------------------------------------------------------------------------
3537
3538 Bit16u
3539atapi_get_sense(device)
3540 Bit16u device;
3541{
3542 Bit8u atacmd[12];
3543 Bit8u buffer[16];
3544 Bit8u i;
3545
3546 memsetb(get_SS(),atacmd,0,12);
3547
3548 // Request SENSE
3549 atacmd[0]=0x03;
3550 atacmd[4]=0x20;
3551 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3552 return 0x0002;
3553
3554 if ((buffer[0] & 0x7e) == 0x70) {
3555 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3556 }
3557
3558 return 0;
3559}
3560
3561 Bit16u
3562atapi_is_ready(device)
3563 Bit16u device;
3564{
3565 Bit8u atacmd[12];
3566 Bit8u buffer[];
3567
3568 memsetb(get_SS(),atacmd,0,12);
3569
3570 // Test Unit Ready
3571 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3572 return 0x000f;
3573
3574 if (atapi_get_sense(device) !=0 ) {
3575 memsetb(get_SS(),atacmd,0,12);
3576
3577 // try to send Test Unit Ready again
3578 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3579 return 0x000f;
3580
3581 return atapi_get_sense(device);
3582 }
3583 return 0;
3584}
3585
3586 Bit16u
3587atapi_is_cdrom(device)
3588 Bit8u device;
3589{
3590 Bit16u ebda_seg=read_word(0x0040,0x000E);
3591
3592 if (device >= BX_MAX_ATA_DEVICES)
3593 return 0;
3594
3595 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3596 return 0;
3597
3598 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3599 return 0;
3600
3601 return 1;
3602}
3603
3604// ---------------------------------------------------------------------------
3605// End of ATA/ATAPI generic functions
3606// ---------------------------------------------------------------------------
3607
3608#endif // BX_USE_ATADRV
3609
3610#if BX_ELTORITO_BOOT
3611
3612// ---------------------------------------------------------------------------
3613// Start of El-Torito boot functions
3614// ---------------------------------------------------------------------------
3615
3616 void
3617cdemu_init()
3618{
3619 Bit16u ebda_seg=read_word(0x0040,0x000E);
3620
3621 // the only important data is this one for now
3622 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3623}
3624
3625 Bit8u
3626cdemu_isactive()
3627{
3628 Bit16u ebda_seg=read_word(0x0040,0x000E);
3629
3630 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3631}
3632
3633 Bit8u
3634cdemu_emulated_drive()
3635{
3636 Bit16u ebda_seg=read_word(0x0040,0x000E);
3637
3638 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3639}
3640
3641static char isotag[6]="CD001";
3642static char eltorito[24]="EL TORITO SPECIFICATION";
3643//
3644// Returns ah: emulated drive, al: error code
3645//
3646 Bit16u
3647cdrom_boot()
3648{
3649 Bit16u ebda_seg=read_word(0x0040,0x000E);
3650 Bit8u atacmd[12], buffer[2048];
3651 Bit32u lba;
3652 Bit16u boot_segment, nbsectors, i, error;
3653 Bit8u device;
3654#ifdef VBOX
3655 Bit8u read_try;
3656#endif /* VBOX */
3657
3658 // Find out the first cdrom
3659 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3660 if (atapi_is_cdrom(device)) break;
3661 }
3662
3663 // if not found
3664 if(device >= BX_MAX_ATA_DEVICES) return 2;
3665
3666 // Read the Boot Record Volume Descriptor
3667 memsetb(get_SS(),atacmd,0,12);
3668 atacmd[0]=0x28; // READ command
3669 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3670 atacmd[8]=(0x01 & 0x00ff); // Sectors
3671 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3672 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3673 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3674 atacmd[5]=(0x11 & 0x000000ff);
3675#ifdef VBOX
3676 for (read_try = 0; read_try <= 4; read_try++)
3677 {
3678 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3679 if (!error)
3680 break;
3681 }
3682 if (error)
3683 return 3;
3684#else /* !VBOX */
3685 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3686 return 3;
3687#endif /* !VBOX */
3688
3689 // Validity checks
3690 if(buffer[0]!=0)return 4;
3691 for(i=0;i<5;i++){
3692 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3693 }
3694 for(i=0;i<23;i++)
3695 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3696
3697 // ok, now we calculate the Boot catalog address
3698 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3699
3700 // And we read the Boot Catalog
3701 memsetb(get_SS(),atacmd,0,12);
3702 atacmd[0]=0x28; // READ command
3703 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3704 atacmd[8]=(0x01 & 0x00ff); // Sectors
3705 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3706 atacmd[3]=(lba & 0x00ff0000) >> 16;
3707 atacmd[4]=(lba & 0x0000ff00) >> 8;
3708 atacmd[5]=(lba & 0x000000ff);
3709 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3710 return 7;
3711
3712 // Validation entry
3713 if(buffer[0x00]!=0x01)return 8; // Header
3714 if(buffer[0x01]!=0x00)return 9; // Platform
3715 if(buffer[0x1E]!=0x55)return 10; // key 1
3716 if(buffer[0x1F]!=0xAA)return 10; // key 2
3717
3718 // Initial/Default Entry
3719 if(buffer[0x20]!=0x88)return 11; // Bootable
3720
3721 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3722 if(buffer[0x21]==0){
3723 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3724 // Win2000 cd boot needs to know it booted from cd
3725 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3726 }
3727 else if(buffer[0x21]<4)
3728 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3729 else
3730 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3731
3732 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3733 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3734
3735 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3736 if(boot_segment==0x0000)boot_segment=0x07C0;
3737
3738 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3739 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3740
3741 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3742 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3743
3744 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3745 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3746
3747 // And we read the image in memory
3748 memsetb(get_SS(),atacmd,0,12);
3749 atacmd[0]=0x28; // READ command
3750 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3751 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3752 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3753 atacmd[3]=(lba & 0x00ff0000) >> 16;
3754 atacmd[4]=(lba & 0x0000ff00) >> 8;
3755 atacmd[5]=(lba & 0x000000ff);
3756 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3757 return 12;
3758
3759 // Remember the media type
3760 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3761 case 0x01: // 1.2M floppy
3762 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3763 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3764 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3765 break;
3766 case 0x02: // 1.44M floppy
3767 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3768 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3769 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3770 break;
3771 case 0x03: // 2.88M floppy
3772 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3773 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3775 break;
3776 case 0x04: // Harddrive
3777 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3778 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3779 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3780 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3781 break;
3782 }
3783
3784 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3785 // Increase bios installed hardware number of devices
3786 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3787 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3788 else
3789 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3790 }
3791
3792
3793 // everything is ok, so from now on, the emulation is active
3794 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3795 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3796
3797 // return the boot drive + no error
3798 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3799}
3800
3801// ---------------------------------------------------------------------------
3802// End of El-Torito boot functions
3803// ---------------------------------------------------------------------------
3804#endif // BX_ELTORITO_BOOT
3805
3806#ifdef VBOX_WITH_SCSI
3807# include "scsi.c"
3808#endif
3809
3810 void
3811int14_function(regs, ds, iret_addr)
3812 pusha_regs_t regs; // regs pushed from PUSHA instruction
3813 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3814 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3815{
3816 Bit16u addr,timer,val16;
3817 Bit8u timeout;
3818
3819 ASM_START
3820 sti
3821 ASM_END
3822
3823 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3824 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3825 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3826 switch (regs.u.r8.ah) {
3827 case 0:
3828 outb(addr+3, inb(addr+3) | 0x80);
3829 if (regs.u.r8.al & 0xE0 == 0) {
3830 outb(addr, 0x17);
3831 outb(addr+1, 0x04);
3832 } else {
3833 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3834 outb(addr, val16 & 0xFF);
3835 outb(addr+1, val16 >> 8);
3836 }
3837 outb(addr+3, regs.u.r8.al & 0x1F);
3838 regs.u.r8.ah = inb(addr+5);
3839 regs.u.r8.al = inb(addr+6);
3840 ClearCF(iret_addr.flags);
3841 break;
3842 case 1:
3843 timer = read_word(0x0040, 0x006C);
3844 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3845 val16 = read_word(0x0040, 0x006C);
3846 if (val16 != timer) {
3847 timer = val16;
3848 timeout--;
3849 }
3850 }
3851 if (timeout) outb(addr, regs.u.r8.al);
3852 regs.u.r8.ah = inb(addr+5);
3853 if (!timeout) regs.u.r8.ah |= 0x80;
3854 ClearCF(iret_addr.flags);
3855 break;
3856 case 2:
3857 timer = read_word(0x0040, 0x006C);
3858 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3859 val16 = read_word(0x0040, 0x006C);
3860 if (val16 != timer) {
3861 timer = val16;
3862 timeout--;
3863 }
3864 }
3865 if (timeout) {
3866 regs.u.r8.ah = 0;
3867 regs.u.r8.al = inb(addr);
3868 } else {
3869 regs.u.r8.ah = inb(addr+5);
3870 }
3871 ClearCF(iret_addr.flags);
3872 break;
3873 case 3:
3874 regs.u.r8.ah = inb(addr+5);
3875 regs.u.r8.al = inb(addr+6);
3876 ClearCF(iret_addr.flags);
3877 break;
3878 default:
3879 SetCF(iret_addr.flags); // Unsupported
3880 }
3881 } else {
3882 SetCF(iret_addr.flags); // Unsupported
3883 }
3884}
3885
3886 void
3887int15_function(regs, ES, DS, FLAGS)
3888 pusha_regs_t regs; // REGS pushed via pusha
3889 Bit16u ES, DS, FLAGS;
3890{
3891 Bit16u ebda_seg=read_word(0x0040,0x000E);
3892 bx_bool prev_a20_enable;
3893 Bit16u base15_00;
3894 Bit8u base23_16;
3895 Bit16u ss;
3896 Bit16u BX,CX,DX;
3897
3898 Bit16u bRegister;
3899 Bit8u irqDisable;
3900
3901BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3902
3903 switch (regs.u.r8.ah) {
3904#ifdef VBOX
3905 case 0x00: /* assorted functions */
3906 if (regs.u.r8.al != 0xc0)
3907 goto undecoded;
3908 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3909 * which we don't support, but logging that event is annoying. In fact
3910 * it is likely that they just misread some specs, because there is a
3911 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3912 * wants to achieve. */
3913 SET_CF();
3914 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3915 break;
3916#endif
3917 case 0x24: /* A20 Control */
3918 switch (regs.u.r8.al) {
3919 case 0x00:
3920 set_enable_a20(0);
3921 CLEAR_CF();
3922 regs.u.r8.ah = 0;
3923 break;
3924 case 0x01:
3925 set_enable_a20(1);
3926 CLEAR_CF();
3927 regs.u.r8.ah = 0;
3928 break;
3929 case 0x02:
3930 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3931 CLEAR_CF();
3932 regs.u.r8.ah = 0;
3933 break;
3934 case 0x03:
3935 CLEAR_CF();
3936 regs.u.r8.ah = 0;
3937 regs.u.r16.bx = 3;
3938 break;
3939 default:
3940 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3941 SET_CF();
3942 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3943 }
3944 break;
3945
3946 case 0x41:
3947 SET_CF();
3948 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3949 break;
3950
3951 case 0x4f:
3952 /* keyboard intercept */
3953#if BX_CPU < 2
3954 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3955#else
3956 // nop
3957#endif
3958 SET_CF();
3959 break;
3960
3961 case 0x52: // removable media eject
3962 CLEAR_CF();
3963 regs.u.r8.ah = 0; // "ok ejection may proceed"
3964 break;
3965
3966 case 0x83: {
3967 if( regs.u.r8.al == 0 ) {
3968 // Set Interval requested.
3969 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3970 // Interval not already set.
3971 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3972 write_word( 0x40, 0x98, ES ); // Byte location, segment
3973 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3974 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3975 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3976 CLEAR_CF( );
3977 irqDisable = inb( 0xA1 );
3978 outb( 0xA1, irqDisable & 0xFE );
3979 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3980 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3981 } else {
3982 // Interval already set.
3983 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3984 SET_CF();
3985 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3986 }
3987 } else if( regs.u.r8.al == 1 ) {
3988 // Clear Interval requested
3989 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3990 CLEAR_CF( );
3991 bRegister = inb_cmos( 0xB );
3992 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3993 } else {
3994 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3995 SET_CF();
3996 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3997 regs.u.r8.al--;
3998 }
3999
4000 break;
4001 }
4002
4003 case 0x87:
4004#if BX_CPU < 3
4005# error "Int15 function 87h not supported on < 80386"
4006#endif
4007 // +++ should probably have descriptor checks
4008 // +++ should have exception handlers
4009
4010 // turn off interrupts
4011ASM_START
4012 cli
4013ASM_END
4014
4015 prev_a20_enable = set_enable_a20(1); // enable A20 line
4016
4017 // 128K max of transfer on 386+ ???
4018 // source == destination ???
4019
4020 // ES:SI points to descriptor table
4021 // offset use initially comments
4022 // ==============================================
4023 // 00..07 Unused zeros Null descriptor
4024 // 08..0f GDT zeros filled in by BIOS
4025 // 10..17 source ssssssss source of data
4026 // 18..1f dest dddddddd destination of data
4027 // 20..27 CS zeros filled in by BIOS
4028 // 28..2f SS zeros filled in by BIOS
4029
4030 //es:si
4031 //eeee0
4032 //0ssss
4033 //-----
4034
4035// check for access rights of source & dest here
4036
4037 // Initialize GDT descriptor
4038 base15_00 = (ES << 4) + regs.u.r16.si;
4039 base23_16 = ES >> 12;
4040 if (base15_00 < (ES<<4))
4041 base23_16++;
4042 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4043 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4044 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4045 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4046 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4047
4048 // Initialize CS descriptor
4049 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4050 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4051 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4052 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4053 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4054
4055 // Initialize SS descriptor
4056 ss = get_SS();
4057 base15_00 = ss << 4;
4058 base23_16 = ss >> 12;
4059 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4060 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4061 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4062 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4063 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4064
4065 CX = regs.u.r16.cx;
4066ASM_START
4067 // Compile generates locals offset info relative to SP.
4068 // Get CX (word count) from stack.
4069 mov bx, sp
4070 SEG SS
4071 mov cx, _int15_function.CX [bx]
4072
4073 // since we need to set SS:SP, save them to the BDA
4074 // for future restore
4075 push eax
4076 xor eax, eax
4077 mov ds, ax
4078 mov 0x0469, ss
4079 mov 0x0467, sp
4080
4081 SEG ES
4082 lgdt [si + 0x08]
4083 SEG CS
4084 lidt [pmode_IDT_info]
4085 ;; perhaps do something with IDT here
4086
4087 ;; set PE bit in CR0
4088 mov eax, cr0
4089 or al, #0x01
4090 mov cr0, eax
4091 ;; far jump to flush CPU queue after transition to protected mode
4092 JMP_AP(0x0020, protected_mode)
4093
4094protected_mode:
4095 ;; GDT points to valid descriptor table, now load SS, DS, ES
4096 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4097 mov ss, ax
4098 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4099 mov ds, ax
4100 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4101 mov es, ax
4102 xor si, si
4103 xor di, di
4104 cld
4105 rep
4106 movsw ;; move CX words from DS:SI to ES:DI
4107
4108 ;; make sure DS and ES limits are 64KB
4109 mov ax, #0x28
4110 mov ds, ax
4111 mov es, ax
4112
4113 ;; reset PG bit in CR0 ???
4114 mov eax, cr0
4115 and al, #0xFE
4116 mov cr0, eax
4117
4118 ;; far jump to flush CPU queue after transition to real mode
4119 JMP_AP(0xf000, real_mode)
4120
4121real_mode:
4122 ;; restore IDT to normal real-mode defaults
4123 SEG CS
4124 lidt [rmode_IDT_info]
4125
4126 // restore SS:SP from the BDA
4127 xor ax, ax
4128 mov ds, ax
4129 mov ss, 0x0469
4130 mov sp, 0x0467
4131 pop eax
4132ASM_END
4133
4134 set_enable_a20(prev_a20_enable);
4135
4136 // turn back on interrupts
4137ASM_START
4138 sti
4139ASM_END
4140
4141 regs.u.r8.ah = 0;
4142 CLEAR_CF();
4143 break;
4144
4145
4146 case 0x88:
4147 // Get the amount of extended memory (above 1M)
4148#if BX_CPU < 2
4149 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4150 SET_CF();
4151#else
4152 regs.u.r8.al = inb_cmos(0x30);
4153 regs.u.r8.ah = inb_cmos(0x31);
4154
4155 // According to Ralf Brown's interrupt the limit should be 15M,
4156 // but real machines mostly return max. 63M.
4157 if(regs.u.r16.ax > 0xffc0)
4158 regs.u.r16.ax = 0xffc0;
4159
4160 CLEAR_CF();
4161#endif
4162 break;
4163
4164#ifdef VBOX
4165 case 0x89:
4166 // Switch to Protected Mode.
4167 // ES:DI points to user-supplied GDT
4168 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4169 // This subfunction does not return!
4170
4171// turn off interrupts
4172ASM_START
4173 cli
4174ASM_END
4175
4176 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4177
4178 // Initialize CS descriptor for BIOS
4179 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4180 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4181 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4182 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4183 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4184
4185 BX = regs.u.r16.bx;
4186ASM_START
4187 // Compiler generates locals offset info relative to SP.
4188 // Get BX (PIC offsets) from stack.
4189 mov bx, sp
4190 SEG SS
4191 mov bx, _int15_function.BX [bx]
4192
4193 // Program PICs
4194 mov al, #0x11 ; send initialisation commands
4195 out 0x20, al
4196 out 0xa0, al
4197 mov al, bh
4198 out 0x21, al
4199 mov al, bl
4200 out 0xa1, al
4201 mov al, #0x04
4202 out 0x21, al
4203 mov al, #0x02
4204 out 0xa1, al
4205 mov al, #0x01
4206 out 0x21, al
4207 out 0xa1, al
4208 mov al, #0xff ; mask all IRQs, user must re-enable
4209 out 0x21, al
4210 out 0xa1, al
4211
4212 // Load GDT and IDT from supplied data
4213 SEG ES
4214 lgdt [si + 0x08]
4215 SEG ES
4216 lidt [si + 0x10]
4217
4218 // set PE bit in CR0
4219 mov eax, cr0
4220 or al, #0x01
4221 mov cr0, eax
4222 // far jump to flush CPU queue after transition to protected mode
4223 JMP_AP(0x0038, protmode_switch)
4224
4225protmode_switch:
4226 ;; GDT points to valid descriptor table, now load SS, DS, ES
4227 mov ax, #0x28
4228 mov ss, ax
4229 mov ax, #0x18
4230 mov ds, ax
4231 mov ax, #0x20
4232 mov es, ax
4233
4234 // unwind the stack - this will break if calling sequence changes!
4235 mov sp,bp
4236 add sp,#4 ; skip return address
4237 popa ; restore regs
4238 pop ax ; skip saved es
4239 pop ax ; skip saved ds
4240 pop ax ; skip saved flags
4241
4242 // return to caller - note that we do not use IRET because
4243 // we cannot enable interrupts
4244 pop cx ; get return offset
4245 pop ax ; skip return segment
4246 pop ax ; skip flags
4247 mov ax, #0x30 ; ah must be 0 on successful exit
4248 push ax
4249 push cx ; re-create modified ret address on stack
4250 retf
4251
4252ASM_END
4253
4254 break;
4255#endif /* VBOX */
4256
4257 case 0x90:
4258 /* Device busy interrupt. Called by Int 16h when no key available */
4259 break;
4260
4261 case 0x91:
4262 /* Interrupt complete. Called by Int 16h when key becomes available */
4263 break;
4264
4265 case 0xbf:
4266 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4267 SET_CF();
4268 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4269 break;
4270
4271 case 0xC0:
4272#if 0
4273 SET_CF();
4274 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4275 break;
4276#endif
4277 CLEAR_CF();
4278 regs.u.r8.ah = 0;
4279 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4280 ES = 0xF000;
4281 break;
4282
4283 case 0xc1:
4284 ES = ebda_seg;
4285 CLEAR_CF();
4286 break;
4287
4288 case 0xd8:
4289 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4290 SET_CF();
4291 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4292 break;
4293
4294#ifdef VBOX
4295 /* Make the BIOS warning for pretty much every Linux kernel start
4296 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4297 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4298 SET_CF();
4299 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4300 break;
4301undecoded:
4302#endif /* VBOX */
4303 default:
4304 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4305 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4306 SET_CF();
4307 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4308 break;
4309 }
4310}
4311
4312#if BX_USE_PS2_MOUSE
4313 void
4314int15_function_mouse(regs, ES, DS, FLAGS)
4315 pusha_regs_t regs; // REGS pushed via pusha
4316 Bit16u ES, DS, FLAGS;
4317{
4318 Bit16u ebda_seg=read_word(0x0040,0x000E);
4319 Bit8u mouse_flags_1, mouse_flags_2;
4320 Bit16u mouse_driver_seg;
4321 Bit16u mouse_driver_offset;
4322 Bit8u mouse_cmd;
4323 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4324
4325BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4326
4327 switch (regs.u.r8.ah) {
4328 case 0xC2:
4329 // Return Codes status in AH
4330 // =========================
4331 // 00: success
4332 // 01: invalid subfunction (AL > 7)
4333 // 02: invalid input value (out of allowable range)
4334 // 03: interface error
4335 // 04: resend command received from mouse controller,
4336 // device driver should attempt command again
4337 // 05: cannot enable mouse, since no far call has been installed
4338 // 80/86: mouse service not implemented
4339
4340 if (regs.u.r8.al > 7) {
4341BX_DEBUG_INT15("unsupported subfn\n");
4342 // invalid function
4343 SET_CF();
4344 regs.u.r8.ah = 1;
4345 break;
4346 }
4347
4348 // Valid subfn; disable AUX input and IRQ12, assume no error
4349 set_kbd_command_byte(0x65);
4350 CLEAR_CF();
4351 regs.u.r8.ah = 0;
4352
4353 switch (regs.u.r8.al) {
4354 case 0: // Disable/Enable Mouse
4355BX_DEBUG_INT15("case 0: ");
4356 if (regs.u.r8.bh > 1) {
4357 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4358 // invalid subfunction
4359 SET_CF();
4360 regs.u.r8.ah = 1;
4361 break;
4362 }
4363 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4364 if ( (mouse_flags_2 & 0x80) == 0 ) {
4365 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4366 SET_CF();
4367 regs.u.r8.ah = 5; // no far call installed
4368 break;
4369 }
4370 if (regs.u.r8.bh == 0) {
4371BX_DEBUG_INT15("Disable Mouse\n");
4372 mouse_cmd = 0xF5; // disable mouse command
4373 } else {
4374BX_DEBUG_INT15("Enable Mouse\n");
4375 mouse_cmd = 0xF4; // enable mouse command
4376 }
4377
4378 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4379 if (ret == 0) {
4380 ret = get_mouse_data(&mouse_data1);
4381 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4382 // success
4383 break;
4384 }
4385 }
4386
4387 // interface error
4388 SET_CF();
4389 regs.u.r8.ah = 3;
4390 break;
4391
4392 case 5: // Initialize Mouse
4393 // Valid package sizes are 1 to 8
4394 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4395 SET_CF();
4396 regs.u.r8.ah = 2; // invalid input
4397 break;
4398 }
4399 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4400 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4401 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4402 // fall through!
4403
4404 case 1: // Reset Mouse
4405BX_DEBUG_INT15("case 1 or 5:\n");
4406 // clear current package byte index
4407 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4408 mouse_flags_1 = mouse_flags_1 & 0xf8;
4409 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4410 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4411 if (ret == 0) {
4412 ret = get_mouse_data(&mouse_data3);
4413 // if no mouse attached, it will return RESEND
4414 if (mouse_data3 == 0xfe) {
4415 SET_CF();
4416 regs.u.r8.ah = 4; // resend
4417 break;
4418 }
4419 if (mouse_data3 != 0xfa)
4420 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4421 if ( ret == 0 ) {
4422 ret = get_mouse_data(&mouse_data1);
4423 if ( ret == 0 ) {
4424 ret = get_mouse_data(&mouse_data2);
4425 if ( ret == 0 ) {
4426 // success
4427 regs.u.r8.bl = mouse_data1;
4428 regs.u.r8.bh = mouse_data2;
4429 break;
4430 }
4431 }
4432 }
4433 }
4434
4435 // interface error
4436 SET_CF();
4437 regs.u.r8.ah = 3;
4438 break;
4439
4440 case 2: // Set Sample Rate
4441BX_DEBUG_INT15("case 2:\n");
4442 switch (regs.u.r8.bh) {
4443 case 0: mouse_data1 = 10; break; // 10 reports/sec
4444 case 1: mouse_data1 = 20; break; // 20 reports/sec
4445 case 2: mouse_data1 = 40; break; // 40 reports/sec
4446 case 3: mouse_data1 = 60; break; // 60 reports/sec
4447 case 4: mouse_data1 = 80; break; // 80 reports/sec
4448 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4449 case 6: mouse_data1 = 200; break; // 200 reports/sec
4450 default: mouse_data1 = 0;
4451 }
4452 if (mouse_data1 > 0) {
4453 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4454 if (ret == 0) {
4455 ret = get_mouse_data(&mouse_data2);
4456 ret = send_to_mouse_ctrl(mouse_data1);
4457 ret = get_mouse_data(&mouse_data2);
4458 // success
4459 } else {
4460 // interface error
4461 SET_CF();
4462 regs.u.r8.ah = 3;
4463 }
4464 } else {
4465 // invalid input
4466 SET_CF();
4467 regs.u.r8.ah = 2;
4468 }
4469 break;
4470
4471 case 3: // Set Resolution
4472BX_DEBUG_INT15("case 3:\n");
4473 // BX:
4474 // 0 = 25 dpi, 1 count per millimeter
4475 // 1 = 50 dpi, 2 counts per millimeter
4476 // 2 = 100 dpi, 4 counts per millimeter
4477 // 3 = 200 dpi, 8 counts per millimeter
4478 if (regs.u.r8.bh < 4) {
4479 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4480 if (ret == 0) {
4481 ret = get_mouse_data(&mouse_data1);
4482 if (mouse_data1 != 0xfa)
4483 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4484 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4485 ret = get_mouse_data(&mouse_data1);
4486 if (mouse_data1 != 0xfa)
4487 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4488 // success
4489 } else {
4490 // interface error
4491 SET_CF();
4492 regs.u.r8.ah = 3;
4493 }
4494 } else {
4495 // invalid input
4496 SET_CF();
4497 regs.u.r8.ah = 2;
4498 }
4499 break;
4500
4501 case 4: // Get Device ID
4502BX_DEBUG_INT15("case 4:\n");
4503 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4504 if (ret == 0) {
4505 ret = get_mouse_data(&mouse_data1);
4506 ret = get_mouse_data(&mouse_data2);
4507 regs.u.r8.bh = mouse_data2;
4508 // success
4509 } else {
4510 // interface error
4511 SET_CF();
4512 regs.u.r8.ah = 3;
4513 }
4514 break;
4515
4516 case 6: // Return Status & Set Scaling Factor...
4517BX_DEBUG_INT15("case 6:\n");
4518 switch (regs.u.r8.bh) {
4519 case 0: // Return Status
4520 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4521 if (ret == 0) {
4522 ret = get_mouse_data(&mouse_data1);
4523 if (mouse_data1 != 0xfa)
4524 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4525 if (ret == 0) {
4526 ret = get_mouse_data(&mouse_data1);
4527 if ( ret == 0 ) {
4528 ret = get_mouse_data(&mouse_data2);
4529 if ( ret == 0 ) {
4530 ret = get_mouse_data(&mouse_data3);
4531 if ( ret == 0 ) {
4532 regs.u.r8.bl = mouse_data1;
4533 regs.u.r8.cl = mouse_data2;
4534 regs.u.r8.dl = mouse_data3;
4535 // success
4536 break;
4537 }
4538 }
4539 }
4540 }
4541 }
4542
4543 // interface error
4544 SET_CF();
4545 regs.u.r8.ah = 3;
4546 break;
4547
4548 case 1: // Set Scaling Factor to 1:1
4549 case 2: // Set Scaling Factor to 2:1
4550 if (regs.u.r8.bh == 1) {
4551 ret = send_to_mouse_ctrl(0xE6);
4552 } else {
4553 ret = send_to_mouse_ctrl(0xE7);
4554 }
4555 if (ret == 0) {
4556 get_mouse_data(&mouse_data1);
4557 ret = (mouse_data1 != 0xFA);
4558 }
4559 if (ret != 0) {
4560 // interface error
4561 SET_CF();
4562 regs.u.r8.ah = 3;
4563 }
4564 break;
4565
4566 default:
4567 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4568 // invalid subfunction
4569 SET_CF();
4570 regs.u.r8.ah = 1;
4571 }
4572 break;
4573
4574 case 7: // Set Mouse Handler Address
4575BX_DEBUG_INT15("case 7:\n");
4576 mouse_driver_seg = ES;
4577 mouse_driver_offset = regs.u.r16.bx;
4578 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4579 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4580 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4581 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4582 /* remove handler */
4583 if ( (mouse_flags_2 & 0x80) != 0 ) {
4584 mouse_flags_2 &= ~0x80;
4585 }
4586 }
4587 else {
4588 /* install handler */
4589 mouse_flags_2 |= 0x80;
4590 }
4591 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4592 break;
4593
4594 default:
4595 BX_PANIC("INT 15h C2 default case entered\n");
4596 // invalid subfunction
4597 SET_CF();
4598 regs.u.r8.ah = 1;
4599 }
4600BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4601 // Re-enable AUX input and IRQ12
4602 set_kbd_command_byte(0x47);
4603 break;
4604
4605 default:
4606 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4607 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4608 SET_CF();
4609 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4610 break;
4611 }
4612}
4613#endif // BX_USE_PS2_MOUSE
4614
4615
4616void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4617 Bit16u ES;
4618 Bit16u DI;
4619 Bit32u start;
4620 Bit32u end;
4621 Bit8u extra_start;
4622 Bit8u extra_end;
4623 Bit16u type;
4624{
4625 write_word(ES, DI, start);
4626 write_word(ES, DI+2, start >> 16);
4627 write_word(ES, DI+4, extra_start);
4628 write_word(ES, DI+6, 0x00);
4629
4630 end -= start;
4631 extra_end -= extra_start;
4632 write_word(ES, DI+8, end);
4633 write_word(ES, DI+10, end >> 16);
4634 write_word(ES, DI+12, extra_end);
4635 write_word(ES, DI+14, 0x0000);
4636
4637 write_word(ES, DI+16, type);
4638 write_word(ES, DI+18, 0x0);
4639}
4640
4641 void
4642int15_function32(regs, ES, DS, FLAGS)
4643 pushad_regs_t regs; // REGS pushed via pushad
4644 Bit16u ES, DS, FLAGS;
4645{
4646 Bit32u extended_memory_size=0; // 64bits long
4647 Bit32u extra_lowbits_memory_size=0;
4648 Bit16u CX,DX;
4649 Bit8u extra_highbits_memory_size=0;
4650
4651BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4652
4653 switch (regs.u.r8.ah) {
4654 case 0x86:
4655 // Wait for CX:DX microseconds. currently using the
4656 // refresh request port 0x61 bit4, toggling every 15usec
4657
4658 CX = regs.u.r16.cx;
4659 DX = regs.u.r16.dx;
4660
4661ASM_START
4662 sti
4663
4664 ;; Get the count in eax
4665 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4666 mov bx, sp
4667 SEG SS
4668 mov ax, _int15_function32.CX [bx]
4669 shl eax, #16
4670 SEG SS
4671 mov ax, _int15_function32.DX [bx]
4672
4673 ;; convert to numbers of 15usec ticks
4674 mov ebx, #15
4675 xor edx, edx
4676 div eax, ebx
4677 mov ecx, eax
4678
4679 ;; wait for ecx number of refresh requests
4680 in al, #0x61
4681 and al,#0x10
4682 mov ah, al
4683
4684 or ecx, ecx
4685 je int1586_tick_end
4686int1586_tick:
4687 in al, #0x61
4688 and al,#0x10
4689 cmp al, ah
4690 je int1586_tick
4691 mov ah, al
4692 dec ecx
4693 jnz int1586_tick
4694int1586_tick_end:
4695ASM_END
4696
4697 break;
4698
4699 case 0xe8:
4700 switch(regs.u.r8.al)
4701 {
4702 case 0x20: // coded by osmaker aka K.J.
4703 if(regs.u.r32.edx == 0x534D4150)
4704 {
4705 extended_memory_size = inb_cmos(0x35);
4706 extended_memory_size <<= 8;
4707 extended_memory_size |= inb_cmos(0x34);
4708 extended_memory_size *= 64;
4709#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4710 // greater than EFF00000???
4711 if(extended_memory_size > 0x3bc000) {
4712 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4713 }
4714#endif /* !VBOX */
4715 extended_memory_size *= 1024;
4716 extended_memory_size += (16L * 1024 * 1024);
4717
4718 if(extended_memory_size <= (16L * 1024 * 1024)) {
4719 extended_memory_size = inb_cmos(0x31);
4720 extended_memory_size <<= 8;
4721 extended_memory_size |= inb_cmos(0x30);
4722 extended_memory_size *= 1024;
4723 extended_memory_size += (1L * 1024 * 1024);
4724 }
4725
4726#ifdef VBOX /* We've already used the CMOS entries for SATA.
4727 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4728 extra_lowbits_memory_size = inb_cmos(0x62);
4729 extra_lowbits_memory_size <<= 8;
4730 extra_lowbits_memory_size |= inb_cmos(0x61);
4731 extra_lowbits_memory_size <<= 16;
4732 extra_highbits_memory_size = inb_cmos(0x63);
4733 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4734#else
4735 extra_lowbits_memory_size = inb_cmos(0x5c);
4736 extra_lowbits_memory_size <<= 8;
4737 extra_lowbits_memory_size |= inb_cmos(0x5b);
4738 extra_lowbits_memory_size *= 64;
4739 extra_lowbits_memory_size *= 1024;
4740 extra_highbits_memory_size = inb_cmos(0x5d);
4741#endif /* !VBOX */
4742
4743 switch(regs.u.r16.bx)
4744 {
4745 case 0:
4746 set_e820_range(ES, regs.u.r16.di,
4747#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4748 0x0000000L, 0x0009f000L, 0, 0, 1);
4749#else
4750 0x0000000L, 0x0009fc00L, 0, 0, 1);
4751#endif
4752 regs.u.r32.ebx = 1;
4753 break;
4754 case 1:
4755 set_e820_range(ES, regs.u.r16.di,
4756#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4757 0x0009f000L, 0x000a0000L, 0, 0, 2);
4758#else
4759 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4760#endif
4761 regs.u.r32.ebx = 2;
4762 break;
4763 case 2:
4764#ifdef VBOX
4765 /* Mark the BIOS as reserved. VBox doesn't currently
4766 * use the 0xe0000-0xeffff area. It does use the
4767 * 0xd0000-0xdffff area for the BIOS logo, but it's
4768 * not worth marking it as reserved. Note that various
4769 * Windows versions don't accept (read: in debug builds
4770 * they trigger the "Too many similar traps" assertion)
4771 * a single reserved range from 0xd0000 to 0xffffff.
4772 * A 128K area starting from 0xd0000 works. */
4773 set_e820_range(ES, regs.u.r16.di,
4774 0x000f0000L, 0x00100000L, 0, 0, 2);
4775#else /* !VBOX */
4776 set_e820_range(ES, regs.u.r16.di,
4777 0x000e8000L, 0x00100000L, 0, 0, 2);
4778#endif /* !VBOX */
4779 regs.u.r32.ebx = 3;
4780 break;
4781 case 3:
4782#if BX_ROMBIOS32 || defined(VBOX)
4783 set_e820_range(ES, regs.u.r16.di,
4784 0x00100000L,
4785 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4786 regs.u.r32.ebx = 4;
4787#else
4788 set_e820_range(ES, regs.u.r16.di,
4789 0x00100000L,
4790 extended_memory_size, 1);
4791 regs.u.r32.ebx = 5;
4792#endif
4793 break;
4794 case 4:
4795 set_e820_range(ES, regs.u.r16.di,
4796 extended_memory_size - ACPI_DATA_SIZE,
4797 extended_memory_size, 0, 0, 3); // ACPI RAM
4798 regs.u.r32.ebx = 5;
4799 break;
4800 case 5:
4801 /* 256KB BIOS area at the end of 4 GB */
4802#ifdef VBOX
4803 /* We don't set the end to 1GB here and rely on the 32-bit
4804 unsigned wrap around effect (0-0xfffc0000L). */
4805#endif
4806 set_e820_range(ES, regs.u.r16.di,
4807 0xfffc0000L, 0x00000000L, 0, 0, 2);
4808 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4809 regs.u.r32.ebx = 6;
4810 else
4811 regs.u.r32.ebx = 0;
4812 break;
4813 case 6:
4814#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4815 /* Mapping of memory above 4 GB if present.
4816 Note: set_e820_range needs do no borrowing in the
4817 subtraction because of the nice numbers. */
4818 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4819 {
4820 set_e820_range(ES, regs.u.r16.di,
4821 0x00000000L, extra_lowbits_memory_size,
4822 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4823 regs.u.r32.ebx = 0;
4824 break;
4825 }
4826 /* fall thru */
4827#else /* !VBOX */
4828 /* Maping of memory above 4 GB */
4829 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4830 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4831 + 1, 1);
4832 regs.u.r32.ebx = 0;
4833 break;
4834#endif /* !VBOX */
4835 default: /* AX=E820, DX=534D4150, BX unrecognized */
4836 goto int15_unimplemented;
4837 break;
4838 }
4839 regs.u.r32.eax = 0x534D4150;
4840 regs.u.r32.ecx = 0x14;
4841 CLEAR_CF();
4842 } else {
4843 // if DX != 0x534D4150)
4844 goto int15_unimplemented;
4845 }
4846 break;
4847
4848 case 0x01:
4849 // do we have any reason to fail here ?
4850 CLEAR_CF();
4851
4852 // my real system sets ax and bx to 0
4853 // this is confirmed by Ralph Brown list
4854 // but syslinux v1.48 is known to behave
4855 // strangely if ax is set to 0
4856 // regs.u.r16.ax = 0;
4857 // regs.u.r16.bx = 0;
4858
4859 // Get the amount of extended memory (above 1M)
4860 regs.u.r8.cl = inb_cmos(0x30);
4861 regs.u.r8.ch = inb_cmos(0x31);
4862
4863 // limit to 15M
4864 if(regs.u.r16.cx > 0x3c00)
4865 {
4866 regs.u.r16.cx = 0x3c00;
4867 }
4868
4869 // Get the amount of extended memory above 16M in 64k blocs
4870 regs.u.r8.dl = inb_cmos(0x34);
4871 regs.u.r8.dh = inb_cmos(0x35);
4872
4873 // Set configured memory equal to extended memory
4874 regs.u.r16.ax = regs.u.r16.cx;
4875 regs.u.r16.bx = regs.u.r16.dx;
4876 break;
4877 default: /* AH=0xE8?? but not implemented */
4878 goto int15_unimplemented;
4879 }
4880 break;
4881 int15_unimplemented:
4882 // fall into the default
4883 default:
4884 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4885 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4886 SET_CF();
4887 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4888 break;
4889 }
4890}
4891
4892 void
4893int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4894 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4895{
4896 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4897 Bit16u kbd_code, max;
4898
4899 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4900
4901 shift_flags = read_byte(0x0040, 0x17);
4902 led_flags = read_byte(0x0040, 0x97);
4903 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4904ASM_START
4905 cli
4906ASM_END
4907 outb(0x60, 0xed);
4908 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4909 if ((inb(0x60) == 0xfa)) {
4910 led_flags &= 0xf8;
4911 led_flags |= ((shift_flags >> 4) & 0x07);
4912 outb(0x60, led_flags & 0x07);
4913 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4914 inb(0x60);
4915 write_byte(0x0040, 0x97, led_flags);
4916 }
4917ASM_START
4918 sti
4919ASM_END
4920 }
4921
4922 switch (GET_AH()) {
4923 case 0x00: /* read keyboard input */
4924
4925 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4926 BX_PANIC("KBD: int16h: out of keyboard input\n");
4927 }
4928 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4929 else if (ascii_code == 0xE0) ascii_code = 0;
4930 AX = (scan_code << 8) | ascii_code;
4931 break;
4932
4933 case 0x01: /* check keyboard status */
4934 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4935 SET_ZF();
4936 return;
4937 }
4938 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4939 else if (ascii_code == 0xE0) ascii_code = 0;
4940 AX = (scan_code << 8) | ascii_code;
4941 CLEAR_ZF();
4942 break;
4943
4944 case 0x02: /* get shift flag status */
4945 shift_flags = read_byte(0x0040, 0x17);
4946 SET_AL(shift_flags);
4947 break;
4948
4949 case 0x05: /* store key-stroke into buffer */
4950 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4951 SET_AL(1);
4952 }
4953 else {
4954 SET_AL(0);
4955 }
4956 break;
4957
4958 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4959 // bit Bochs Description
4960 // 7 0 reserved
4961 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4962 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4963 // 4 1 INT 16/AH=0Ah supported
4964 // 3 0 INT 16/AX=0306h supported
4965 // 2 0 INT 16/AX=0305h supported
4966 // 1 0 INT 16/AX=0304h supported
4967 // 0 0 INT 16/AX=0300h supported
4968 //
4969 SET_AL(0x30);
4970 break;
4971
4972 case 0x0A: /* GET KEYBOARD ID */
4973 count = 2;
4974 kbd_code = 0x0;
4975 outb(0x60, 0xf2);
4976 /* Wait for data */
4977 max=0xffff;
4978 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4979 if (max>0x0) {
4980 if ((inb(0x60) == 0xfa)) {
4981 do {
4982 max=0xffff;
4983 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4984 if (max>0x0) {
4985 kbd_code >>= 8;
4986 kbd_code |= (inb(0x60) << 8);
4987 }
4988 } while (--count>0);
4989 }
4990 }
4991 BX=kbd_code;
4992 break;
4993
4994 case 0x10: /* read MF-II keyboard input */
4995
4996 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4997 BX_PANIC("KBD: int16h: out of keyboard input\n");
4998 }
4999 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5000 AX = (scan_code << 8) | ascii_code;
5001 break;
5002
5003 case 0x11: /* check MF-II keyboard status */
5004 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5005 SET_ZF();
5006 return;
5007 }
5008 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5009 AX = (scan_code << 8) | ascii_code;
5010 CLEAR_ZF();
5011 break;
5012
5013 case 0x12: /* get extended keyboard status */
5014 shift_flags = read_byte(0x0040, 0x17);
5015 SET_AL(shift_flags);
5016 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5017 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5018 SET_AH(shift_flags);
5019 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5020 break;
5021
5022 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5023 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5024 break;
5025
5026 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5027 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5028 break;
5029
5030 case 0x6F:
5031 if (GET_AL() == 0x08)
5032 SET_AH(0x02); // unsupported, aka normal keyboard
5033
5034 default:
5035 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5036 }
5037}
5038
5039 unsigned int
5040dequeue_key(scan_code, ascii_code, incr)
5041 Bit8u *scan_code;
5042 Bit8u *ascii_code;
5043 unsigned int incr;
5044{
5045 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5046 Bit16u ss;
5047 Bit8u acode, scode;
5048
5049#if BX_CPU < 2
5050 buffer_start = 0x001E;
5051 buffer_end = 0x003E;
5052#else
5053 buffer_start = read_word(0x0040, 0x0080);
5054 buffer_end = read_word(0x0040, 0x0082);
5055#endif
5056
5057 buffer_head = read_word(0x0040, 0x001a);
5058 buffer_tail = read_word(0x0040, 0x001c);
5059
5060 if (buffer_head != buffer_tail) {
5061 ss = get_SS();
5062 acode = read_byte(0x0040, buffer_head);
5063 scode = read_byte(0x0040, buffer_head+1);
5064 write_byte(ss, ascii_code, acode);
5065 write_byte(ss, scan_code, scode);
5066
5067 if (incr) {
5068 buffer_head += 2;
5069 if (buffer_head >= buffer_end)
5070 buffer_head = buffer_start;
5071 write_word(0x0040, 0x001a, buffer_head);
5072 }
5073 return(1);
5074 }
5075 else {
5076 return(0);
5077 }
5078}
5079
5080static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5081
5082 Bit8u
5083send_to_mouse_ctrl(sendbyte)
5084 Bit8u sendbyte;
5085{
5086 Bit8u response;
5087
5088 // wait for chance to write to ctrl
5089 if ( inb(0x64) & 0x02 )
5090 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5091 outb(0x64, 0xD4);
5092 outb(0x60, sendbyte);
5093 return(0);
5094}
5095
5096
5097 Bit8u
5098get_mouse_data(data)
5099 Bit8u *data;
5100{
5101 Bit8u response;
5102 Bit16u ss;
5103
5104 while ( (inb(0x64) & 0x21) != 0x21 ) {
5105 }
5106
5107 response = inb(0x60);
5108
5109 ss = get_SS();
5110 write_byte(ss, data, response);
5111 return(0);
5112}
5113
5114 void
5115set_kbd_command_byte(command_byte)
5116 Bit8u command_byte;
5117{
5118 if ( inb(0x64) & 0x02 )
5119 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5120
5121 outb(0x64, 0x60); // write command byte
5122 outb(0x60, command_byte);
5123}
5124
5125 void
5126int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5127 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5128{
5129 Bit8u scancode, asciicode, shift_flags;
5130 Bit8u mf2_flags, mf2_state;
5131
5132 //
5133 // DS has been set to F000 before call
5134 //
5135
5136
5137 scancode = GET_AL();
5138
5139 if (scancode == 0) {
5140 BX_INFO("KBD: int09 handler: AL=0\n");
5141 return;
5142 }
5143
5144
5145 shift_flags = read_byte(0x0040, 0x17);
5146 mf2_flags = read_byte(0x0040, 0x18);
5147 mf2_state = read_byte(0x0040, 0x96);
5148 asciicode = 0;
5149
5150 switch (scancode) {
5151 case 0x3a: /* Caps Lock press */
5152 shift_flags ^= 0x40;
5153 write_byte(0x0040, 0x17, shift_flags);
5154 mf2_flags |= 0x40;
5155 write_byte(0x0040, 0x18, mf2_flags);
5156 break;
5157 case 0xba: /* Caps Lock release */
5158 mf2_flags &= ~0x40;
5159 write_byte(0x0040, 0x18, mf2_flags);
5160 break;
5161
5162 case 0x2a: /* L Shift press */
5163 shift_flags |= 0x02;
5164 write_byte(0x0040, 0x17, shift_flags);
5165 break;
5166 case 0xaa: /* L Shift release */
5167 shift_flags &= ~0x02;
5168 write_byte(0x0040, 0x17, shift_flags);
5169 break;
5170
5171 case 0x36: /* R Shift press */
5172 shift_flags |= 0x01;
5173 write_byte(0x0040, 0x17, shift_flags);
5174 break;
5175 case 0xb6: /* R Shift release */
5176 shift_flags &= ~0x01;
5177 write_byte(0x0040, 0x17, shift_flags);
5178 break;
5179
5180 case 0x1d: /* Ctrl press */
5181 if ((mf2_state & 0x01) == 0) {
5182 shift_flags |= 0x04;
5183 write_byte(0x0040, 0x17, shift_flags);
5184 if (mf2_state & 0x02) {
5185 mf2_state |= 0x04;
5186 write_byte(0x0040, 0x96, mf2_state);
5187 } else {
5188 mf2_flags |= 0x01;
5189 write_byte(0x0040, 0x18, mf2_flags);
5190 }
5191 }
5192 break;
5193 case 0x9d: /* Ctrl release */
5194 if ((mf2_state & 0x01) == 0) {
5195 shift_flags &= ~0x04;
5196 write_byte(0x0040, 0x17, shift_flags);
5197 if (mf2_state & 0x02) {
5198 mf2_state &= ~0x04;
5199 write_byte(0x0040, 0x96, mf2_state);
5200 } else {
5201 mf2_flags &= ~0x01;
5202 write_byte(0x0040, 0x18, mf2_flags);
5203 }
5204 }
5205 break;
5206
5207 case 0x38: /* Alt press */
5208 shift_flags |= 0x08;
5209 write_byte(0x0040, 0x17, shift_flags);
5210 if (mf2_state & 0x02) {
5211 mf2_state |= 0x08;
5212 write_byte(0x0040, 0x96, mf2_state);
5213 } else {
5214 mf2_flags |= 0x02;
5215 write_byte(0x0040, 0x18, mf2_flags);
5216 }
5217 break;
5218 case 0xb8: /* Alt release */
5219 shift_flags &= ~0x08;
5220 write_byte(0x0040, 0x17, shift_flags);
5221 if (mf2_state & 0x02) {
5222 mf2_state &= ~0x08;
5223 write_byte(0x0040, 0x96, mf2_state);
5224 } else {
5225 mf2_flags &= ~0x02;
5226 write_byte(0x0040, 0x18, mf2_flags);
5227 }
5228 break;
5229
5230 case 0x45: /* Num Lock press */
5231 if ((mf2_state & 0x03) == 0) {
5232 mf2_flags |= 0x20;
5233 write_byte(0x0040, 0x18, mf2_flags);
5234 shift_flags ^= 0x20;
5235 write_byte(0x0040, 0x17, shift_flags);
5236 }
5237 break;
5238 case 0xc5: /* Num Lock release */
5239 if ((mf2_state & 0x03) == 0) {
5240 mf2_flags &= ~0x20;
5241 write_byte(0x0040, 0x18, mf2_flags);
5242 }
5243 break;
5244
5245 case 0x46: /* Scroll Lock press */
5246 mf2_flags |= 0x10;
5247 write_byte(0x0040, 0x18, mf2_flags);
5248 shift_flags ^= 0x10;
5249 write_byte(0x0040, 0x17, shift_flags);
5250 break;
5251
5252 case 0xc6: /* Scroll Lock release */
5253 mf2_flags &= ~0x10;
5254 write_byte(0x0040, 0x18, mf2_flags);
5255 break;
5256
5257 case 0x53: /* Del press */
5258 if ((shift_flags & 0x0f) == 0x0c)
5259 {
5260ASM_START
5261 /* Ctrl+Alt+Del => Reboot */
5262 jmp 0xf000:post
5263ASM_END
5264 }
5265 /* fall through */
5266
5267 default:
5268 if (scancode & 0x80) {
5269 break; /* toss key releases ... */
5270 }
5271 if (scancode > MAX_SCAN_CODE) {
5272 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5273 return;
5274 }
5275 if (shift_flags & 0x08) { /* ALT */
5276 asciicode = scan_to_scanascii[scancode].alt;
5277 scancode = scan_to_scanascii[scancode].alt >> 8;
5278 } else if (shift_flags & 0x04) { /* CONTROL */
5279 asciicode = scan_to_scanascii[scancode].control;
5280 scancode = scan_to_scanascii[scancode].control >> 8;
5281 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5282 /* extended keys handling */
5283 asciicode = 0xe0;
5284 scancode = scan_to_scanascii[scancode].normal >> 8;
5285 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5286 /* check if lock state should be ignored
5287 * because a SHIFT key are pressed */
5288
5289 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5290 asciicode = scan_to_scanascii[scancode].normal;
5291 scancode = scan_to_scanascii[scancode].normal >> 8;
5292 } else {
5293 asciicode = scan_to_scanascii[scancode].shift;
5294 scancode = scan_to_scanascii[scancode].shift >> 8;
5295 }
5296 } else {
5297 /* check if lock is on */
5298 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5299 asciicode = scan_to_scanascii[scancode].shift;
5300 scancode = scan_to_scanascii[scancode].shift >> 8;
5301 } else {
5302 asciicode = scan_to_scanascii[scancode].normal;
5303 scancode = scan_to_scanascii[scancode].normal >> 8;
5304 }
5305 }
5306 if (scancode==0 && asciicode==0) {
5307 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5308 }
5309 enqueue_key(scancode, asciicode);
5310 break;
5311 }
5312 if ((scancode & 0x7f) != 0x1d) {
5313 mf2_state &= ~0x01;
5314 }
5315 mf2_state &= ~0x02;
5316 write_byte(0x0040, 0x96, mf2_state);
5317}
5318
5319 unsigned int
5320enqueue_key(scan_code, ascii_code)
5321 Bit8u scan_code, ascii_code;
5322{
5323 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5324
5325#if BX_CPU < 2
5326 buffer_start = 0x001E;
5327 buffer_end = 0x003E;
5328#else
5329 buffer_start = read_word(0x0040, 0x0080);
5330 buffer_end = read_word(0x0040, 0x0082);
5331#endif
5332
5333 buffer_head = read_word(0x0040, 0x001A);
5334 buffer_tail = read_word(0x0040, 0x001C);
5335
5336 temp_tail = buffer_tail;
5337 buffer_tail += 2;
5338 if (buffer_tail >= buffer_end)
5339 buffer_tail = buffer_start;
5340
5341 if (buffer_tail == buffer_head) {
5342 return(0);
5343 }
5344
5345 write_byte(0x0040, temp_tail, ascii_code);
5346 write_byte(0x0040, temp_tail+1, scan_code);
5347 write_word(0x0040, 0x001C, buffer_tail);
5348 return(1);
5349}
5350
5351
5352 void
5353int74_function(make_farcall, Z, Y, X, status)
5354 Bit16u make_farcall, Z, Y, X, status;
5355{
5356 Bit16u ebda_seg=read_word(0x0040,0x000E);
5357 Bit8u in_byte, index, package_count;
5358 Bit8u mouse_flags_1, mouse_flags_2;
5359
5360BX_DEBUG_INT74("entering int74_function\n");
5361 make_farcall = 0;
5362
5363 in_byte = inb(0x64);
5364 if ( (in_byte & 0x21) != 0x21 ) {
5365 return;
5366 }
5367 in_byte = inb(0x60);
5368BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5369
5370 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5371 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5372
5373 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5374 return;
5375 }
5376
5377 package_count = mouse_flags_2 & 0x07;
5378 index = mouse_flags_1 & 0x07;
5379 write_byte(ebda_seg, 0x28 + index, in_byte);
5380
5381 if ( index >= package_count ) {
5382BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5383 status = read_byte(ebda_seg, 0x0028 + 0);
5384 X = read_byte(ebda_seg, 0x0028 + 1);
5385 Y = read_byte(ebda_seg, 0x0028 + 2);
5386 Z = 0;
5387 mouse_flags_1 = 0;
5388 // check if far call handler installed
5389 if (mouse_flags_2 & 0x80)
5390 make_farcall = 1;
5391 }
5392 else {
5393 mouse_flags_1++;
5394 }
5395 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5396}
5397
5398#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5399
5400#if BX_USE_ATADRV
5401
5402 void
5403int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5404 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5405{
5406 Bit32u lba;
5407 Bit16u ebda_seg=read_word(0x0040,0x000E);
5408 Bit16u cylinder, head, sector;
5409 Bit16u segment, offset;
5410 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5411 Bit16u size, count;
5412 Bit8u device, status;
5413
5414 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5415
5416 write_byte(0x0040, 0x008e, 0); // clear completion flag
5417
5418#ifdef VBOX_WITH_SCSI
5419 // basic check : device has to be defined
5420 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) ) {
5421 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5422 goto int13_fail;
5423 }
5424#else
5425 // basic check : device has to be defined
5426 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5427 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5428 goto int13_fail;
5429 }
5430#endif
5431
5432 // Get the ata channel
5433 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5434
5435#ifdef VBOX_WITH_SCSI
5436 // basic check : device has to be valid
5437 if (device >= BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) {
5438 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5439 goto int13_fail;
5440 }
5441#else
5442 // basic check : device has to be valid
5443 if (device >= BX_MAX_ATA_DEVICES) {
5444 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5445 goto int13_fail;
5446 }
5447#endif
5448
5449 switch (GET_AH()) {
5450
5451 case 0x00: /* disk controller reset */
5452#ifdef VBOX_WITH_SCSI
5453 /* SCSI controller does not need a reset. */
5454 if (!VBOX_IS_SCSI_DEVICE(device))
5455#endif
5456 ata_reset (device);
5457 goto int13_success;
5458 break;
5459
5460 case 0x01: /* read disk status */
5461 status = read_byte(0x0040, 0x0074);
5462 SET_AH(status);
5463 SET_DISK_RET_STATUS(0);
5464 /* set CF if error status read */
5465 if (status) goto int13_fail_nostatus;
5466 else goto int13_success_noah;
5467 break;
5468
5469 case 0x02: // read disk sectors
5470 case 0x03: // write disk sectors
5471 case 0x04: // verify disk sectors
5472
5473 count = GET_AL();
5474 cylinder = GET_CH();
5475 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5476 sector = (GET_CL() & 0x3f);
5477 head = GET_DH();
5478
5479 segment = ES;
5480 offset = BX;
5481
5482 if ( (count > 128) || (count == 0) ) {
5483 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5484 goto int13_fail;
5485 }
5486
5487#ifdef VBOX_WITH_SCSI
5488 if (!VBOX_IS_SCSI_DEVICE(device))
5489#endif
5490 {
5491 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5492 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5493 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5494 }
5495#ifdef VBOX_WITH_SCSI
5496 else
5497 {
5498 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5499
5500 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5501 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5502 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5503 }
5504#endif
5505
5506 // sanity check on cyl heads, sec
5507 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5508 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5509 goto int13_fail;
5510 }
5511
5512 // FIXME verify
5513 if ( GET_AH() == 0x04 ) goto int13_success;
5514
5515#ifdef VBOX_WITH_SCSI
5516 if (!VBOX_IS_SCSI_DEVICE(device))
5517#endif
5518 {
5519 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5520 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5521 }
5522#ifdef VBOX_WITH_SCSI
5523 else
5524 {
5525 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5526 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5527 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5528 }
5529#endif
5530
5531 // if needed, translate lchs to lba, and execute command
5532#ifdef VBOX_WITH_SCSI
5533 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5534 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5535 sector = 0; // this forces the command to be lba
5536 }
5537#else
5538 if (( (nph != nlh) || (npspt != nlspt)) ) {
5539 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5540 sector = 0; // this forces the command to be lba
5541 }
5542#endif
5543
5544 if ( GET_AH() == 0x02 )
5545 {
5546#ifdef VBOX_WITH_SCSI
5547 if (VBOX_IS_SCSI_DEVICE(device))
5548 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5549 else
5550#endif
5551 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5552 }
5553 else
5554 {
5555#ifdef VBOX_WITH_SCSI
5556 if (VBOX_IS_SCSI_DEVICE(device))
5557 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5558 else
5559#endif
5560 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5561 }
5562
5563 // Set nb of sector transferred
5564 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5565
5566 if (status != 0) {
5567 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5568 SET_AH(0x0c);
5569 goto int13_fail_noah;
5570 }
5571
5572 goto int13_success;
5573 break;
5574
5575 case 0x05: /* format disk track */
5576 BX_INFO("format disk track called\n");
5577 goto int13_success;
5578 return;
5579 break;
5580
5581 case 0x08: /* read disk drive parameters */
5582
5583 // Get logical geometry from table
5584#ifdef VBOX_WITH_SCSI
5585 if (!VBOX_IS_SCSI_DEVICE(device))
5586#endif
5587 {
5588 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5589 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5590 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5591 }
5592#ifdef VBOX_WITH_SCSI
5593 else
5594 {
5595 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5596 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5597 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5598 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5599 }
5600#endif
5601
5602 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5603#ifndef VBOX
5604 nlc = nlc - 2; /* 0 based , last sector not used */
5605#else /* VBOX */
5606 /* Maximum cylinder number is just one less than the number of cylinders. */
5607 nlc = nlc - 1; /* 0 based , last sector not used */
5608#endif /* VBOX */
5609 SET_AL(0);
5610 SET_CH(nlc & 0xff);
5611 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5612 SET_DH(nlh - 1);
5613 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5614
5615 // FIXME should set ES & DI
5616
5617 goto int13_success;
5618 break;
5619
5620 case 0x10: /* check drive ready */
5621 // should look at 40:8E also???
5622
5623 // Read the status from controller
5624 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5625 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5626 goto int13_success;
5627 }
5628 else {
5629 SET_AH(0xAA);
5630 goto int13_fail_noah;
5631 }
5632 break;
5633
5634 case 0x15: /* read disk drive size */
5635
5636 // Get physical geometry from table
5637#ifdef VBOX_WITH_SCSI
5638 if (!VBOX_IS_SCSI_DEVICE(device))
5639#endif
5640 {
5641 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5642 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5643 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5644 }
5645#ifdef VBOX_WITH_SCSI
5646 else
5647 {
5648 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5649 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5650 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5651 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5652 }
5653#endif
5654
5655 // Compute sector count seen by int13
5656#ifndef VBOX
5657 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5658#else /* VBOX */
5659 /* Is it so hard to multiply a couple of counts (without introducing
5660 * arbitrary off by one errors)? */
5661 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5662#endif /* VBOX */
5663 CX = lba >> 16;
5664 DX = lba & 0xffff;
5665
5666 SET_AH(3); // hard disk accessible
5667 goto int13_success_noah;
5668 break;
5669
5670 case 0x41: // IBM/MS installation check
5671 BX=0xaa55; // install check
5672 SET_AH(0x30); // EDD 3.0
5673 CX=0x0007; // ext disk access and edd, removable supported
5674 goto int13_success_noah;
5675 break;
5676
5677 case 0x42: // IBM/MS extended read
5678 case 0x43: // IBM/MS extended write
5679 case 0x44: // IBM/MS verify
5680 case 0x47: // IBM/MS extended seek
5681
5682 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5683 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5684 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5685
5686 // Can't use 64 bits lba
5687 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5688 if (lba != 0L) {
5689 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5690 goto int13_fail;
5691 }
5692
5693 // Get 32 bits lba and check
5694 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5695
5696#ifdef VBOX_WITH_SCSI
5697 if (VBOX_IS_SCSI_DEVICE(device))
5698 {
5699 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5700 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5701 goto int13_fail;
5702 }
5703 }
5704 else
5705#endif
5706 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5707 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5708 goto int13_fail;
5709 }
5710
5711
5712 // If verify or seek
5713 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5714 goto int13_success;
5715
5716 // Execute the command
5717 if ( GET_AH() == 0x42 )
5718#ifdef VBOX
5719 {
5720#ifdef VBOX_WITH_SCSI
5721 if (VBOX_IS_SCSI_DEVICE(device))
5722 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5723 else
5724#endif
5725 {
5726 if (count >= 256 || lba + count >= 268435456)
5727 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5728 else
5729 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5730 }
5731 }
5732#else /* !VBOX */
5733 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5734#endif /* VBOX */
5735 else
5736#ifdef VBOX
5737 {
5738#ifdef VBOX_WITH_SCSI
5739 if (VBOX_IS_SCSI_DEVICE(device))
5740 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5741 else
5742#endif
5743 {
5744 if (count >= 256 || lba + count >= 268435456)
5745 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5746 else
5747 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5748 }
5749 }
5750#else /* !VBOX */
5751 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5752#endif /* VBOX */
5753
5754 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5755 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5756
5757 if (status != 0) {
5758 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5759 SET_AH(0x0c);
5760 goto int13_fail_noah;
5761 }
5762
5763 goto int13_success;
5764 break;
5765
5766 case 0x45: // IBM/MS lock/unlock drive
5767 case 0x49: // IBM/MS extended media change
5768 goto int13_success; // Always success for HD
5769 break;
5770
5771 case 0x46: // IBM/MS eject media
5772 SET_AH(0xb2); // Volume Not Removable
5773 goto int13_fail_noah; // Always fail for HD
5774 break;
5775
5776 case 0x48: // IBM/MS get drive parameters
5777 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5778
5779 // Buffer is too small
5780 if(size < 0x1a)
5781 goto int13_fail;
5782
5783 // EDD 1.x
5784 if(size >= 0x1a) {
5785 Bit16u blksize;
5786
5787#ifdef VBOX_WITH_SCSI
5788 if (!VBOX_IS_SCSI_DEVICE(device))
5789#endif
5790 {
5791 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5792 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5793 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5794 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5795 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5796 }
5797#ifdef VBOX_WITH_SCSI
5798 else
5799 {
5800 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5801 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5802 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5803 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5804 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5805 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5806 }
5807#endif
5808
5809 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5810 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5811 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5812 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5813 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5814 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5815 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5816 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5817 }
5818
5819 // EDD 2.x
5820 if(size >= 0x1e) {
5821 Bit8u channel, dev, irq, mode, checksum, i, translation;
5822 Bit16u iobase1, iobase2, options;
5823
5824 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5825
5826 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5827 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5828
5829 // Fill in dpte
5830 channel = device / 2;
5831 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5832 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5833 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5834 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5835 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5836
5837 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5838 options |= (1<<4); // lba translation
5839 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5840 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5841 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5842
5843 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5844 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5845 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5846 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5847 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5848 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5849 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5850 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5851 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5852 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5853 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5854
5855 checksum=0;
5856 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5857 checksum = ~checksum;
5858 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5859 }
5860
5861 // EDD 3.x
5862 if(size >= 0x42) {
5863 Bit8u channel, iface, checksum, i;
5864 Bit16u iobase1;
5865
5866 channel = device / 2;
5867 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5868 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5869
5870 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5871 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5872 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5873 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5874 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5875
5876 if (iface==ATA_IFACE_ISA) {
5877 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5878 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5879 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5880 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5881 }
5882 else {
5883 // FIXME PCI
5884 }
5885 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5886 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5887 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5888 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5889
5890 if (iface==ATA_IFACE_ISA) {
5891 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5892 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5893 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5894 }
5895 else {
5896 // FIXME PCI
5897 }
5898 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5899 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5900 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5901 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5902
5903 checksum=0;
5904 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5905 checksum = ~checksum;
5906 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5907 }
5908
5909 goto int13_success;
5910 break;
5911
5912 case 0x4e: // // IBM/MS set hardware configuration
5913 // DMA, prefetch, PIO maximum not supported
5914 switch (GET_AL()) {
5915 case 0x01:
5916 case 0x03:
5917 case 0x04:
5918 case 0x06:
5919 goto int13_success;
5920 break;
5921 default :
5922 goto int13_fail;
5923 }
5924 break;
5925
5926 case 0x09: /* initialize drive parameters */
5927 case 0x0c: /* seek to specified cylinder */
5928 case 0x0d: /* alternate disk reset */
5929 case 0x11: /* recalibrate */
5930 case 0x14: /* controller internal diagnostic */
5931 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5932 goto int13_success;
5933 break;
5934
5935 case 0x0a: /* read disk sectors with ECC */
5936 case 0x0b: /* write disk sectors with ECC */
5937 case 0x18: // set media type for format
5938 case 0x50: // IBM/MS send packet command
5939 default:
5940 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5941 goto int13_fail;
5942 break;
5943 }
5944
5945int13_fail:
5946 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5947int13_fail_noah:
5948 SET_DISK_RET_STATUS(GET_AH());
5949int13_fail_nostatus:
5950 SET_CF(); // error occurred
5951 return;
5952
5953int13_success:
5954 SET_AH(0x00); // no error
5955int13_success_noah:
5956 SET_DISK_RET_STATUS(0x00);
5957 CLEAR_CF(); // no error
5958 return;
5959}
5960
5961// ---------------------------------------------------------------------------
5962// Start of int13 for cdrom
5963// ---------------------------------------------------------------------------
5964
5965 void
5966int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5967 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5968{
5969 Bit16u ebda_seg=read_word(0x0040,0x000E);
5970 Bit8u device, status, locks;
5971 Bit8u atacmd[12];
5972 Bit32u lba;
5973 Bit16u count, segment, offset, i, size;
5974
5975 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5976
5977 SET_DISK_RET_STATUS(0x00);
5978
5979 /* basic check : device should be 0xE0+ */
5980 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5981 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5982 goto int13_fail;
5983 }
5984
5985 // Get the ata channel
5986 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5987
5988 /* basic check : device has to be valid */
5989 if (device >= BX_MAX_ATA_DEVICES) {
5990 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5991 goto int13_fail;
5992 }
5993
5994 switch (GET_AH()) {
5995
5996 // all those functions return SUCCESS
5997 case 0x00: /* disk controller reset */
5998 case 0x09: /* initialize drive parameters */
5999 case 0x0c: /* seek to specified cylinder */
6000 case 0x0d: /* alternate disk reset */
6001 case 0x10: /* check drive ready */
6002 case 0x11: /* recalibrate */
6003 case 0x14: /* controller internal diagnostic */
6004 case 0x16: /* detect disk change */
6005 goto int13_success;
6006 break;
6007
6008 // all those functions return disk write-protected
6009 case 0x03: /* write disk sectors */
6010 case 0x05: /* format disk track */
6011 case 0x43: // IBM/MS extended write
6012 SET_AH(0x03);
6013 goto int13_fail_noah;
6014 break;
6015
6016 case 0x01: /* read disk status */
6017 status = read_byte(0x0040, 0x0074);
6018 SET_AH(status);
6019 SET_DISK_RET_STATUS(0);
6020
6021 /* set CF if error status read */
6022 if (status) goto int13_fail_nostatus;
6023 else goto int13_success_noah;
6024 break;
6025
6026 case 0x15: /* read disk drive size */
6027 SET_AH(0x02);
6028 goto int13_fail_noah;
6029 break;
6030
6031 case 0x41: // IBM/MS installation check
6032 BX=0xaa55; // install check
6033 SET_AH(0x30); // EDD 2.1
6034 CX=0x0007; // ext disk access, removable and edd
6035 goto int13_success_noah;
6036 break;
6037
6038 case 0x42: // IBM/MS extended read
6039 case 0x44: // IBM/MS verify sectors
6040 case 0x47: // IBM/MS extended seek
6041
6042 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6043 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6044 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6045
6046 // Can't use 64 bits lba
6047 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6048 if (lba != 0L) {
6049 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6050 goto int13_fail;
6051 }
6052
6053 // Get 32 bits lba
6054 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6055
6056 // If verify or seek
6057 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6058 goto int13_success;
6059
6060 memsetb(get_SS(),atacmd,0,12);
6061 atacmd[0]=0x28; // READ command
6062 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6063 atacmd[8]=(count & 0x00ff); // Sectors
6064 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6065 atacmd[3]=(lba & 0x00ff0000) >> 16;
6066 atacmd[4]=(lba & 0x0000ff00) >> 8;
6067 atacmd[5]=(lba & 0x000000ff);
6068 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6069
6070 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6071 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6072
6073 if (status != 0) {
6074 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6075 SET_AH(0x0c);
6076 goto int13_fail_noah;
6077 }
6078
6079 goto int13_success;
6080 break;
6081
6082 case 0x45: // IBM/MS lock/unlock drive
6083 if (GET_AL() > 2) goto int13_fail;
6084
6085 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6086
6087 switch (GET_AL()) {
6088 case 0 : // lock
6089 if (locks == 0xff) {
6090 SET_AH(0xb4);
6091 SET_AL(1);
6092 goto int13_fail_noah;
6093 }
6094 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6095 SET_AL(1);
6096 break;
6097 case 1 : // unlock
6098 if (locks == 0x00) {
6099 SET_AH(0xb0);
6100 SET_AL(0);
6101 goto int13_fail_noah;
6102 }
6103 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6104 SET_AL(locks==0?0:1);
6105 break;
6106 case 2 : // status
6107 SET_AL(locks==0?0:1);
6108 break;
6109 }
6110 goto int13_success;
6111 break;
6112
6113 case 0x46: // IBM/MS eject media
6114 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6115
6116 if (locks != 0) {
6117 SET_AH(0xb1); // media locked
6118 goto int13_fail_noah;
6119 }
6120 // FIXME should handle 0x31 no media in device
6121 // FIXME should handle 0xb5 valid request failed
6122
6123 // Call removable media eject
6124 ASM_START
6125 push bp
6126 mov bp, sp
6127
6128 mov ah, #0x52
6129 int #0x15
6130 mov _int13_cdrom.status + 2[bp], ah
6131 jnc int13_cdrom_rme_end
6132 mov _int13_cdrom.status, #1
6133int13_cdrom_rme_end:
6134 pop bp
6135 ASM_END
6136
6137 if (status != 0) {
6138 SET_AH(0xb1); // media locked
6139 goto int13_fail_noah;
6140 }
6141
6142 goto int13_success;
6143 break;
6144
6145 case 0x48: // IBM/MS get drive parameters
6146 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6147
6148 // Buffer is too small
6149 if(size < 0x1a)
6150 goto int13_fail;
6151
6152 // EDD 1.x
6153 if(size >= 0x1a) {
6154 Bit16u cylinders, heads, spt, blksize;
6155
6156 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6157
6158 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6159 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6160 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6161 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6162 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6163 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6164 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6165 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6166 }
6167
6168 // EDD 2.x
6169 if(size >= 0x1e) {
6170 Bit8u channel, dev, irq, mode, checksum, i;
6171 Bit16u iobase1, iobase2, options;
6172
6173 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6174
6175 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6176 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6177
6178 // Fill in dpte
6179 channel = device / 2;
6180 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6181 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6182 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6183 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6184
6185 // FIXME atapi device
6186 options = (1<<4); // lba translation
6187 options |= (1<<5); // removable device
6188 options |= (1<<6); // atapi device
6189 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6190
6191 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6192 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6193 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6194 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6195 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6196 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6197 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6198 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6199 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6200 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6201 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6202
6203 checksum=0;
6204 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6205 checksum = ~checksum;
6206 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6207 }
6208
6209 // EDD 3.x
6210 if(size >= 0x42) {
6211 Bit8u channel, iface, checksum, i;
6212 Bit16u iobase1;
6213
6214 channel = device / 2;
6215 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6216 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6217
6218 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6219 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6220 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6221 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6222 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6223
6224 if (iface==ATA_IFACE_ISA) {
6225 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6226 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6227 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6228 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6229 }
6230 else {
6231 // FIXME PCI
6232 }
6233 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6234 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6235 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6236 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6237
6238 if (iface==ATA_IFACE_ISA) {
6239 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6240 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6241 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6242 }
6243 else {
6244 // FIXME PCI
6245 }
6246 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6247 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6248 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6249 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6250
6251 checksum=0;
6252 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6253 checksum = ~checksum;
6254 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6255 }
6256
6257 goto int13_success;
6258 break;
6259
6260 case 0x49: // IBM/MS extended media change
6261 // always send changed ??
6262 SET_AH(06);
6263 goto int13_fail_nostatus;
6264 break;
6265
6266 case 0x4e: // // IBM/MS set hardware configuration
6267 // DMA, prefetch, PIO maximum not supported
6268 switch (GET_AL()) {
6269 case 0x01:
6270 case 0x03:
6271 case 0x04:
6272 case 0x06:
6273 goto int13_success;
6274 break;
6275 default :
6276 goto int13_fail;
6277 }
6278 break;
6279
6280 // all those functions return unimplemented
6281 case 0x02: /* read sectors */
6282 case 0x04: /* verify sectors */
6283 case 0x08: /* read disk drive parameters */
6284 case 0x0a: /* read disk sectors with ECC */
6285 case 0x0b: /* write disk sectors with ECC */
6286 case 0x18: /* set media type for format */
6287 case 0x50: // ? - send packet command
6288 default:
6289 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6290 goto int13_fail;
6291 break;
6292 }
6293
6294int13_fail:
6295 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6296int13_fail_noah:
6297 SET_DISK_RET_STATUS(GET_AH());
6298int13_fail_nostatus:
6299 SET_CF(); // error occurred
6300 return;
6301
6302int13_success:
6303 SET_AH(0x00); // no error
6304int13_success_noah:
6305 SET_DISK_RET_STATUS(0x00);
6306 CLEAR_CF(); // no error
6307 return;
6308}
6309
6310// ---------------------------------------------------------------------------
6311// End of int13 for cdrom
6312// ---------------------------------------------------------------------------
6313
6314#if BX_ELTORITO_BOOT
6315// ---------------------------------------------------------------------------
6316// Start of int13 for eltorito functions
6317// ---------------------------------------------------------------------------
6318
6319 void
6320int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6321 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6322{
6323 Bit16u ebda_seg=read_word(0x0040,0x000E);
6324
6325 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6326 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6327
6328 switch (GET_AH()) {
6329
6330 // FIXME ElTorito Various. Should be implemented
6331 case 0x4a: // ElTorito - Initiate disk emu
6332 case 0x4c: // ElTorito - Initiate disk emu and boot
6333 case 0x4d: // ElTorito - Return Boot catalog
6334 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6335 goto int13_fail;
6336 break;
6337
6338 case 0x4b: // ElTorito - Terminate disk emu
6339 // FIXME ElTorito Hardcoded
6340 write_byte(DS,SI+0x00,0x13);
6341 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6342 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6343 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6344 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6345 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6346 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6347 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6348 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6349 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6350 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6351 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6352
6353 // If we have to terminate emulation
6354 if(GET_AL() == 0x00) {
6355 // FIXME ElTorito Various. Should be handled accordingly to spec
6356 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6357 }
6358
6359 goto int13_success;
6360 break;
6361
6362 default:
6363 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6364 goto int13_fail;
6365 break;
6366 }
6367
6368int13_fail:
6369 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6370 SET_DISK_RET_STATUS(GET_AH());
6371 SET_CF(); // error occurred
6372 return;
6373
6374int13_success:
6375 SET_AH(0x00); // no error
6376 SET_DISK_RET_STATUS(0x00);
6377 CLEAR_CF(); // no error
6378 return;
6379}
6380
6381// ---------------------------------------------------------------------------
6382// End of int13 for eltorito functions
6383// ---------------------------------------------------------------------------
6384
6385// ---------------------------------------------------------------------------
6386// Start of int13 when emulating a device from the cd
6387// ---------------------------------------------------------------------------
6388
6389 void
6390int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6391 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6392{
6393 Bit16u ebda_seg=read_word(0x0040,0x000E);
6394 Bit8u device, status;
6395 Bit16u vheads, vspt, vcylinders;
6396 Bit16u head, sector, cylinder, nbsectors;
6397 Bit32u vlba, ilba, slba, elba;
6398 Bit16u before, segment, offset;
6399 Bit8u atacmd[12];
6400
6401 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6402
6403 /* at this point, we are emulating a floppy/harddisk */
6404
6405 // Recompute the device number
6406 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6407 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6408
6409 SET_DISK_RET_STATUS(0x00);
6410
6411 /* basic checks : emulation should be active, dl should equal the emulated drive */
6412 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6413 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6414 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6415 goto int13_fail;
6416 }
6417
6418 switch (GET_AH()) {
6419
6420 // all those functions return SUCCESS
6421 case 0x00: /* disk controller reset */
6422 case 0x09: /* initialize drive parameters */
6423 case 0x0c: /* seek to specified cylinder */
6424 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6425 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6426 case 0x11: /* recalibrate */
6427 case 0x14: /* controller internal diagnostic */
6428 case 0x16: /* detect disk change */
6429 goto int13_success;
6430 break;
6431
6432 // all those functions return disk write-protected
6433 case 0x03: /* write disk sectors */
6434 case 0x05: /* format disk track */
6435 SET_AH(0x03);
6436 goto int13_fail_noah;
6437 break;
6438
6439 case 0x01: /* read disk status */
6440 status=read_byte(0x0040, 0x0074);
6441 SET_AH(status);
6442 SET_DISK_RET_STATUS(0);
6443
6444 /* set CF if error status read */
6445 if (status) goto int13_fail_nostatus;
6446 else goto int13_success_noah;
6447 break;
6448
6449 case 0x02: // read disk sectors
6450 case 0x04: // verify disk sectors
6451 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6452 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6453 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6454
6455 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6456
6457 sector = GET_CL() & 0x003f;
6458 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6459 head = GET_DH();
6460 nbsectors = GET_AL();
6461 segment = ES;
6462 offset = BX;
6463
6464 // no sector to read ?
6465 if(nbsectors==0) goto int13_success;
6466
6467 // sanity checks sco openserver needs this!
6468 if ((sector > vspt)
6469 || (cylinder >= vcylinders)
6470 || (head >= vheads)) {
6471 goto int13_fail;
6472 }
6473
6474 // After controls, verify do nothing
6475 if (GET_AH() == 0x04) goto int13_success;
6476
6477 segment = ES+(BX / 16);
6478 offset = BX % 16;
6479
6480 // calculate the virtual lba inside the image
6481 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6482
6483 // In advance so we don't loose the count
6484 SET_AL(nbsectors);
6485
6486 // start lba on cd
6487 slba = (Bit32u)vlba/4;
6488 before= (Bit16u)vlba%4;
6489
6490 // end lba on cd
6491 elba = (Bit32u)(vlba+nbsectors-1)/4;
6492
6493 memsetb(get_SS(),atacmd,0,12);
6494 atacmd[0]=0x28; // READ command
6495 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6496 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6497 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6498 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6499 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6500 atacmd[5]=(ilba+slba & 0x000000ff);
6501 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6502 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6503 SET_AH(0x02);
6504 SET_AL(0);
6505 goto int13_fail_noah;
6506 }
6507
6508 goto int13_success;
6509 break;
6510
6511 case 0x08: /* read disk drive parameters */
6512 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6513 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6514 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6515
6516 SET_AL( 0x00 );
6517 SET_BL( 0x00 );
6518 SET_CH( vcylinders & 0xff );
6519 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6520 SET_DH( vheads );
6521 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6522 // FIXME ElTorito Harddisk. should send the HD count
6523
6524 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6525 case 0x01: SET_BL( 0x02 ); break;
6526 case 0x02: SET_BL( 0x04 ); break;
6527 case 0x03: SET_BL( 0x06 ); break;
6528 }
6529
6530ASM_START
6531 push bp
6532 mov bp, sp
6533 mov ax, #diskette_param_table2
6534 mov _int13_cdemu.DI+2[bp], ax
6535 mov _int13_cdemu.ES+2[bp], cs
6536 pop bp
6537ASM_END
6538 goto int13_success;
6539 break;
6540
6541 case 0x15: /* read disk drive size */
6542 // FIXME ElTorito Harddisk. What geometry to send ?
6543 SET_AH(0x03);
6544 goto int13_success_noah;
6545 break;
6546
6547 // all those functions return unimplemented
6548 case 0x0a: /* read disk sectors with ECC */
6549 case 0x0b: /* write disk sectors with ECC */
6550 case 0x18: /* set media type for format */
6551 case 0x41: // IBM/MS installation check
6552 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6553 case 0x42: // IBM/MS extended read
6554 case 0x43: // IBM/MS extended write
6555 case 0x44: // IBM/MS verify sectors
6556 case 0x45: // IBM/MS lock/unlock drive
6557 case 0x46: // IBM/MS eject media
6558 case 0x47: // IBM/MS extended seek
6559 case 0x48: // IBM/MS get drive parameters
6560 case 0x49: // IBM/MS extended media change
6561 case 0x4e: // ? - set hardware configuration
6562 case 0x50: // ? - send packet command
6563 default:
6564 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6565 goto int13_fail;
6566 break;
6567 }
6568
6569int13_fail:
6570 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6571int13_fail_noah:
6572 SET_DISK_RET_STATUS(GET_AH());
6573int13_fail_nostatus:
6574 SET_CF(); // error occurred
6575 return;
6576
6577int13_success:
6578 SET_AH(0x00); // no error
6579int13_success_noah:
6580 SET_DISK_RET_STATUS(0x00);
6581 CLEAR_CF(); // no error
6582 return;
6583}
6584
6585// ---------------------------------------------------------------------------
6586// End of int13 when emulating a device from the cd
6587// ---------------------------------------------------------------------------
6588
6589#endif // BX_ELTORITO_BOOT
6590
6591#else //BX_USE_ATADRV
6592
6593 void
6594outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6595 Bit16u cylinder;
6596 Bit16u hd_heads;
6597 Bit16u head;
6598 Bit16u hd_sectors;
6599 Bit16u sector;
6600 Bit16u dl;
6601{
6602ASM_START
6603 push bp
6604 mov bp, sp
6605 push eax
6606 push ebx
6607 push edx
6608 xor eax,eax
6609 mov ax,4[bp] // cylinder
6610 xor ebx,ebx
6611 mov bl,6[bp] // hd_heads
6612 imul ebx
6613
6614 mov bl,8[bp] // head
6615 add eax,ebx
6616 mov bl,10[bp] // hd_sectors
6617 imul ebx
6618 mov bl,12[bp] // sector
6619 add eax,ebx
6620
6621 dec eax
6622 mov dx,#0x1f3
6623 out dx,al
6624 mov dx,#0x1f4
6625 mov al,ah
6626 out dx,al
6627 shr eax,#16
6628 mov dx,#0x1f5
6629 out dx,al
6630 and ah,#0xf
6631 mov bl,14[bp] // dl
6632 and bl,#1
6633 shl bl,#4
6634 or ah,bl
6635 or ah,#0xe0
6636 mov al,ah
6637 mov dx,#0x01f6
6638 out dx,al
6639 pop edx
6640 pop ebx
6641 pop eax
6642 pop bp
6643ASM_END
6644}
6645
6646 void
6647int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6648 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6649{
6650 Bit8u drive, num_sectors, sector, head, status, mod;
6651 Bit8u drive_map;
6652 Bit8u n_drives;
6653 Bit16u cyl_mod, ax;
6654 Bit16u max_cylinder, cylinder, total_sectors;
6655 Bit16u hd_cylinders;
6656 Bit8u hd_heads, hd_sectors;
6657 Bit16u val16;
6658 Bit8u sector_count;
6659 unsigned int i;
6660 Bit16u tempbx;
6661 Bit16u dpsize;
6662
6663 Bit16u count, segment, offset;
6664 Bit32u lba;
6665 Bit16u error;
6666
6667 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6668
6669 write_byte(0x0040, 0x008e, 0); // clear completion flag
6670
6671 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6672 handler code */
6673 /* check how many disks first (cmos reg 0x12), return an error if
6674 drive not present */
6675 drive_map = inb_cmos(0x12);
6676 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6677 (((drive_map & 0x0f)==0) ? 0 : 2);
6678 n_drives = (drive_map==0) ? 0 :
6679 ((drive_map==3) ? 2 : 1);
6680
6681 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6682 SET_AH(0x01);
6683 SET_DISK_RET_STATUS(0x01);
6684 SET_CF(); /* error occurred */
6685 return;
6686 }
6687
6688 switch (GET_AH()) {
6689
6690 case 0x00: /* disk controller reset */
6691BX_DEBUG_INT13_HD("int13_f00\n");
6692
6693 SET_AH(0);
6694 SET_DISK_RET_STATUS(0);
6695 set_diskette_ret_status(0);
6696 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6697 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6698 CLEAR_CF(); /* successful */
6699 return;
6700 break;
6701
6702 case 0x01: /* read disk status */
6703BX_DEBUG_INT13_HD("int13_f01\n");
6704 status = read_byte(0x0040, 0x0074);
6705 SET_AH(status);
6706 SET_DISK_RET_STATUS(0);
6707 /* set CF if error status read */
6708 if (status) SET_CF();
6709 else CLEAR_CF();
6710 return;
6711 break;
6712
6713 case 0x04: // verify disk sectors
6714 case 0x02: // read disk sectors
6715 drive = GET_ELDL();
6716 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6717
6718 num_sectors = GET_AL();
6719 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6720 sector = (GET_CL() & 0x3f);
6721 head = GET_DH();
6722
6723
6724 if (hd_cylinders > 1024) {
6725 if (hd_cylinders <= 2048) {
6726 cylinder <<= 1;
6727 }
6728 else if (hd_cylinders <= 4096) {
6729 cylinder <<= 2;
6730 }
6731 else if (hd_cylinders <= 8192) {
6732 cylinder <<= 3;
6733 }
6734 else { // hd_cylinders <= 16384
6735 cylinder <<= 4;
6736 }
6737
6738 ax = head / hd_heads;
6739 cyl_mod = ax & 0xff;
6740 head = ax >> 8;
6741 cylinder |= cyl_mod;
6742 }
6743
6744 if ( (cylinder >= hd_cylinders) ||
6745 (sector > hd_sectors) ||
6746 (head >= hd_heads) ) {
6747 SET_AH(1);
6748 SET_DISK_RET_STATUS(1);
6749 SET_CF(); /* error occurred */
6750 return;
6751 }
6752
6753 if ( (num_sectors > 128) || (num_sectors == 0) )
6754 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6755
6756 if (head > 15)
6757 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6758
6759 if ( GET_AH() == 0x04 ) {
6760 SET_AH(0);
6761 SET_DISK_RET_STATUS(0);
6762 CLEAR_CF();
6763 return;
6764 }
6765
6766 status = inb(0x1f7);
6767 if (status & 0x80) {
6768 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6769 }
6770 outb(0x01f2, num_sectors);
6771 /* activate LBA? (tomv) */
6772 if (hd_heads > 16) {
6773BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6774 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6775 }
6776 else {
6777 outb(0x01f3, sector);
6778 outb(0x01f4, cylinder & 0x00ff);
6779 outb(0x01f5, cylinder >> 8);
6780 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6781 }
6782 outb(0x01f7, 0x20);
6783
6784 while (1) {
6785 status = inb(0x1f7);
6786 if ( !(status & 0x80) ) break;
6787 }
6788
6789 if (status & 0x01) {
6790 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6791 } else if ( !(status & 0x08) ) {
6792 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6793 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6794 }
6795
6796 sector_count = 0;
6797 tempbx = BX;
6798
6799ASM_START
6800 sti ;; enable higher priority interrupts
6801ASM_END
6802
6803 while (1) {
6804ASM_START
6805 ;; store temp bx in real DI register
6806 push bp
6807 mov bp, sp
6808 mov di, _int13_harddisk.tempbx + 2 [bp]
6809 pop bp
6810
6811 ;; adjust if there will be an overrun
6812 cmp di, #0xfe00
6813 jbe i13_f02_no_adjust
6814i13_f02_adjust:
6815 sub di, #0x0200 ; sub 512 bytes from offset
6816 mov ax, es
6817 add ax, #0x0020 ; add 512 to segment
6818 mov es, ax
6819
6820i13_f02_no_adjust:
6821 mov cx, #0x0100 ;; counter (256 words = 512b)
6822 mov dx, #0x01f0 ;; AT data read port
6823
6824 rep
6825 insw ;; CX words transfered from port(DX) to ES:[DI]
6826
6827i13_f02_done:
6828 ;; store real DI register back to temp bx
6829 push bp
6830 mov bp, sp
6831 mov _int13_harddisk.tempbx + 2 [bp], di
6832 pop bp
6833ASM_END
6834
6835 sector_count++;
6836 num_sectors--;
6837 if (num_sectors == 0) {
6838 status = inb(0x1f7);
6839 if ( (status & 0xc9) != 0x40 )
6840 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6841 break;
6842 }
6843 else {
6844 status = inb(0x1f7);
6845 if ( (status & 0xc9) != 0x48 )
6846 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6847 continue;
6848 }
6849 }
6850
6851 SET_AH(0);
6852 SET_DISK_RET_STATUS(0);
6853 SET_AL(sector_count);
6854 CLEAR_CF(); /* successful */
6855 return;
6856 break;
6857
6858
6859 case 0x03: /* write disk sectors */
6860BX_DEBUG_INT13_HD("int13_f03\n");
6861 drive = GET_ELDL ();
6862 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6863
6864 num_sectors = GET_AL();
6865 cylinder = GET_CH();
6866 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6867 sector = (GET_CL() & 0x3f);
6868 head = GET_DH();
6869
6870 if (hd_cylinders > 1024) {
6871 if (hd_cylinders <= 2048) {
6872 cylinder <<= 1;
6873 }
6874 else if (hd_cylinders <= 4096) {
6875 cylinder <<= 2;
6876 }
6877 else if (hd_cylinders <= 8192) {
6878 cylinder <<= 3;
6879 }
6880 else { // hd_cylinders <= 16384
6881 cylinder <<= 4;
6882 }
6883
6884 ax = head / hd_heads;
6885 cyl_mod = ax & 0xff;
6886 head = ax >> 8;
6887 cylinder |= cyl_mod;
6888 }
6889
6890 if ( (cylinder >= hd_cylinders) ||
6891 (sector > hd_sectors) ||
6892 (head >= hd_heads) ) {
6893 SET_AH( 1);
6894 SET_DISK_RET_STATUS(1);
6895 SET_CF(); /* error occurred */
6896 return;
6897 }
6898
6899 if ( (num_sectors > 128) || (num_sectors == 0) )
6900 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6901
6902 if (head > 15)
6903 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6904
6905 status = inb(0x1f7);
6906 if (status & 0x80) {
6907 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6908 }
6909// should check for Drive Ready Bit also in status reg
6910 outb(0x01f2, num_sectors);
6911
6912 /* activate LBA? (tomv) */
6913 if (hd_heads > 16) {
6914BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6915 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6916 }
6917 else {
6918 outb(0x01f3, sector);
6919 outb(0x01f4, cylinder & 0x00ff);
6920 outb(0x01f5, cylinder >> 8);
6921 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6922 }
6923 outb(0x01f7, 0x30);
6924
6925 // wait for busy bit to turn off after seeking
6926 while (1) {
6927 status = inb(0x1f7);
6928 if ( !(status & 0x80) ) break;
6929 }
6930
6931 if ( !(status & 0x08) ) {
6932 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6933 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6934 }
6935
6936 sector_count = 0;
6937 tempbx = BX;
6938
6939ASM_START
6940 sti ;; enable higher priority interrupts
6941ASM_END
6942
6943 while (1) {
6944ASM_START
6945 ;; store temp bx in real SI register
6946 push bp
6947 mov bp, sp
6948 mov si, _int13_harddisk.tempbx + 2 [bp]
6949 pop bp
6950
6951 ;; adjust if there will be an overrun
6952 cmp si, #0xfe00
6953 jbe i13_f03_no_adjust
6954i13_f03_adjust:
6955 sub si, #0x0200 ; sub 512 bytes from offset
6956 mov ax, es
6957 add ax, #0x0020 ; add 512 to segment
6958 mov es, ax
6959
6960i13_f03_no_adjust:
6961 mov cx, #0x0100 ;; counter (256 words = 512b)
6962 mov dx, #0x01f0 ;; AT data read port
6963
6964 seg ES
6965 rep
6966 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6967
6968 ;; store real SI register back to temp bx
6969 push bp
6970 mov bp, sp
6971 mov _int13_harddisk.tempbx + 2 [bp], si
6972 pop bp
6973ASM_END
6974
6975 sector_count++;
6976 num_sectors--;
6977 if (num_sectors == 0) {
6978 status = inb(0x1f7);
6979 if ( (status & 0xe9) != 0x40 )
6980 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6981 break;
6982 }
6983 else {
6984 status = inb(0x1f7);
6985 if ( (status & 0xc9) != 0x48 )
6986 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6987 continue;
6988 }
6989 }
6990
6991 SET_AH(0);
6992 SET_DISK_RET_STATUS(0);
6993 SET_AL(sector_count);
6994 CLEAR_CF(); /* successful */
6995 return;
6996 break;
6997
6998 case 0x05: /* format disk track */
6999BX_DEBUG_INT13_HD("int13_f05\n");
7000 BX_PANIC("format disk track called\n");
7001 /* nop */
7002 SET_AH(0);
7003 SET_DISK_RET_STATUS(0);
7004 CLEAR_CF(); /* successful */
7005 return;
7006 break;
7007
7008 case 0x08: /* read disk drive parameters */
7009BX_DEBUG_INT13_HD("int13_f08\n");
7010
7011 drive = GET_ELDL ();
7012 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7013
7014 // translate CHS
7015 //
7016 if (hd_cylinders <= 1024) {
7017 // hd_cylinders >>= 0;
7018 // hd_heads <<= 0;
7019 }
7020 else if (hd_cylinders <= 2048) {
7021 hd_cylinders >>= 1;
7022 hd_heads <<= 1;
7023 }
7024 else if (hd_cylinders <= 4096) {
7025 hd_cylinders >>= 2;
7026 hd_heads <<= 2;
7027 }
7028 else if (hd_cylinders <= 8192) {
7029 hd_cylinders >>= 3;
7030 hd_heads <<= 3;
7031 }
7032 else { // hd_cylinders <= 16384
7033 hd_cylinders >>= 4;
7034 hd_heads <<= 4;
7035 }
7036
7037 max_cylinder = hd_cylinders - 2; /* 0 based */
7038 SET_AL(0);
7039 SET_CH(max_cylinder & 0xff);
7040 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7041 SET_DH(hd_heads - 1);
7042 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7043 SET_AH(0);
7044 SET_DISK_RET_STATUS(0);
7045 CLEAR_CF(); /* successful */
7046
7047 return;
7048 break;
7049
7050 case 0x09: /* initialize drive parameters */
7051BX_DEBUG_INT13_HD("int13_f09\n");
7052 SET_AH(0);
7053 SET_DISK_RET_STATUS(0);
7054 CLEAR_CF(); /* successful */
7055 return;
7056 break;
7057
7058 case 0x0a: /* read disk sectors with ECC */
7059BX_DEBUG_INT13_HD("int13_f0a\n");
7060 case 0x0b: /* write disk sectors with ECC */
7061BX_DEBUG_INT13_HD("int13_f0b\n");
7062 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7063 return;
7064 break;
7065
7066 case 0x0c: /* seek to specified cylinder */
7067BX_DEBUG_INT13_HD("int13_f0c\n");
7068 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7069 SET_AH(0);
7070 SET_DISK_RET_STATUS(0);
7071 CLEAR_CF(); /* successful */
7072 return;
7073 break;
7074
7075 case 0x0d: /* alternate disk reset */
7076BX_DEBUG_INT13_HD("int13_f0d\n");
7077 SET_AH(0);
7078 SET_DISK_RET_STATUS(0);
7079 CLEAR_CF(); /* successful */
7080 return;
7081 break;
7082
7083 case 0x10: /* check drive ready */
7084BX_DEBUG_INT13_HD("int13_f10\n");
7085 //SET_AH(0);
7086 //SET_DISK_RET_STATUS(0);
7087 //CLEAR_CF(); /* successful */
7088 //return;
7089 //break;
7090
7091 // should look at 40:8E also???
7092 status = inb(0x01f7);
7093 if ( (status & 0xc0) == 0x40 ) {
7094 SET_AH(0);
7095 SET_DISK_RET_STATUS(0);
7096 CLEAR_CF(); // drive ready
7097 return;
7098 }
7099 else {
7100 SET_AH(0xAA);
7101 SET_DISK_RET_STATUS(0xAA);
7102 SET_CF(); // not ready
7103 return;
7104 }
7105 break;
7106
7107 case 0x11: /* recalibrate */
7108BX_DEBUG_INT13_HD("int13_f11\n");
7109 SET_AH(0);
7110 SET_DISK_RET_STATUS(0);
7111 CLEAR_CF(); /* successful */
7112 return;
7113 break;
7114
7115 case 0x14: /* controller internal diagnostic */
7116BX_DEBUG_INT13_HD("int13_f14\n");
7117 SET_AH(0);
7118 SET_DISK_RET_STATUS(0);
7119 CLEAR_CF(); /* successful */
7120 SET_AL(0);
7121 return;
7122 break;
7123
7124 case 0x15: /* read disk drive size */
7125 drive = GET_ELDL();
7126 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7127ASM_START
7128 push bp
7129 mov bp, sp
7130 mov al, _int13_harddisk.hd_heads + 2 [bp]
7131 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7132 mul al, ah ;; ax = heads * sectors
7133 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7134 dec bx ;; use (cylinders - 1) ???
7135 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7136 ;; now we need to move the 32bit result dx:ax to what the
7137 ;; BIOS wants which is cx:dx.
7138 ;; and then into CX:DX on the stack
7139 mov _int13_harddisk.CX + 2 [bp], dx
7140 mov _int13_harddisk.DX + 2 [bp], ax
7141 pop bp
7142ASM_END
7143 SET_AH(3); // hard disk accessible
7144 SET_DISK_RET_STATUS(0); // ??? should this be 0
7145 CLEAR_CF(); // successful
7146 return;
7147 break;
7148
7149 case 0x18: // set media type for format
7150 case 0x41: // IBM/MS
7151 case 0x42: // IBM/MS
7152 case 0x43: // IBM/MS
7153 case 0x44: // IBM/MS
7154 case 0x45: // IBM/MS lock/unlock drive
7155 case 0x46: // IBM/MS eject media
7156 case 0x47: // IBM/MS extended seek
7157 case 0x49: // IBM/MS extended media change
7158 case 0x50: // IBM/MS send packet command
7159 default:
7160 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7161
7162 SET_AH(1); // code=invalid function in AH or invalid parameter
7163 SET_DISK_RET_STATUS(1);
7164 SET_CF(); /* unsuccessful */
7165 return;
7166 break;
7167 }
7168}
7169
7170static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7171static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7172
7173 void
7174get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7175 Bit8u drive;
7176 Bit16u *hd_cylinders;
7177 Bit8u *hd_heads;
7178 Bit8u *hd_sectors;
7179{
7180 Bit8u hd_type;
7181 Bit16u ss;
7182 Bit16u cylinders;
7183 Bit8u iobase;
7184
7185 ss = get_SS();
7186 if (drive == 0x80) {
7187 hd_type = inb_cmos(0x12) & 0xf0;
7188 if (hd_type != 0xf0)
7189 BX_INFO(panic_msg_reg12h,0);
7190 hd_type = inb_cmos(0x19); // HD0: extended type
7191 if (hd_type != 47)
7192 BX_INFO(panic_msg_reg19h,0,0x19);
7193 iobase = 0x1b;
7194 } else {
7195 hd_type = inb_cmos(0x12) & 0x0f;
7196 if (hd_type != 0x0f)
7197 BX_INFO(panic_msg_reg12h,1);
7198 hd_type = inb_cmos(0x1a); // HD1: extended type
7199 if (hd_type != 47)
7200 BX_INFO(panic_msg_reg19h,0,0x1a);
7201 iobase = 0x24;
7202 }
7203
7204 // cylinders
7205 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7206 write_word(ss, hd_cylinders, cylinders);
7207
7208 // heads
7209 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7210
7211 // sectors per track
7212 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7213}
7214
7215#endif //else BX_USE_ATADRV
7216
7217#if BX_SUPPORT_FLOPPY
7218
7219//////////////////////
7220// FLOPPY functions //
7221//////////////////////
7222
7223void floppy_reset_controller()
7224{
7225 Bit8u val8;
7226
7227 // Reset controller
7228 val8 = inb(0x03f2);
7229 outb(0x03f2, val8 & ~0x04);
7230 outb(0x03f2, val8 | 0x04);
7231
7232 // Wait for controller to come out of reset
7233 do {
7234 val8 = inb(0x3f4);
7235 } while ( (val8 & 0xc0) != 0x80 );
7236}
7237
7238void floppy_prepare_controller(drive)
7239 Bit16u drive;
7240{
7241 Bit8u val8, dor, prev_reset;
7242
7243 // set 40:3e bit 7 to 0
7244 val8 = read_byte(0x0040, 0x003e);
7245 val8 &= 0x7f;
7246 write_byte(0x0040, 0x003e, val8);
7247
7248 // turn on motor of selected drive, DMA & int enabled, normal operation
7249 prev_reset = inb(0x03f2) & 0x04;
7250 if (drive)
7251 dor = 0x20;
7252 else
7253 dor = 0x10;
7254 dor |= 0x0c;
7255 dor |= drive;
7256 outb(0x03f2, dor);
7257
7258 // reset the disk motor timeout value of INT 08
7259 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7260
7261#ifdef VBOX
7262 // program data rate
7263 val8 = read_byte(0x0040, 0x008b);
7264 val8 >>= 6;
7265 outb(0x03f7, val8);
7266#endif
7267
7268 // wait for drive readiness
7269 do {
7270 val8 = inb(0x3f4);
7271 } while ( (val8 & 0xc0) != 0x80 );
7272
7273 if (prev_reset == 0) {
7274 // turn on interrupts
7275ASM_START
7276 sti
7277ASM_END
7278 // wait on 40:3e bit 7 to become 1
7279 do {
7280 val8 = read_byte(0x0040, 0x003e);
7281 } while ( (val8 & 0x80) == 0 );
7282 val8 &= 0x7f;
7283ASM_START
7284 cli
7285ASM_END
7286 write_byte(0x0040, 0x003e, val8);
7287 }
7288}
7289
7290 bx_bool
7291floppy_media_known(drive)
7292 Bit16u drive;
7293{
7294 Bit8u val8;
7295 Bit16u media_state_offset;
7296
7297 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7298 if (drive)
7299 val8 >>= 1;
7300 val8 &= 0x01;
7301 if (val8 == 0)
7302 return(0);
7303
7304 media_state_offset = 0x0090;
7305 if (drive)
7306 media_state_offset += 1;
7307
7308 val8 = read_byte(0x0040, media_state_offset);
7309 val8 = (val8 >> 4) & 0x01;
7310 if (val8 == 0)
7311 return(0);
7312
7313 // check pass, return KNOWN
7314 return(1);
7315}
7316
7317 bx_bool
7318floppy_media_sense(drive)
7319 Bit16u drive;
7320{
7321 bx_bool retval;
7322 Bit16u media_state_offset;
7323 Bit8u drive_type, config_data, media_state;
7324
7325 if (floppy_drive_recal(drive) == 0) {
7326 return(0);
7327 }
7328
7329 // for now cheat and get drive type from CMOS,
7330 // assume media is same as drive type
7331
7332 // ** config_data **
7333 // Bitfields for diskette media control:
7334 // Bit(s) Description (Table M0028)
7335 // 7-6 last data rate set by controller
7336 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7337 // 5-4 last diskette drive step rate selected
7338 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7339 // 3-2 {data rate at start of operation}
7340 // 1-0 reserved
7341
7342 // ** media_state **
7343 // Bitfields for diskette drive media state:
7344 // Bit(s) Description (Table M0030)
7345 // 7-6 data rate
7346 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7347 // 5 double stepping required (e.g. 360kB in 1.2MB)
7348 // 4 media type established
7349 // 3 drive capable of supporting 4MB media
7350 // 2-0 on exit from BIOS, contains
7351 // 000 trying 360kB in 360kB
7352 // 001 trying 360kB in 1.2MB
7353 // 010 trying 1.2MB in 1.2MB
7354 // 011 360kB in 360kB established
7355 // 100 360kB in 1.2MB established
7356 // 101 1.2MB in 1.2MB established
7357 // 110 reserved
7358 // 111 all other formats/drives
7359
7360 drive_type = inb_cmos(0x10);
7361 if (drive == 0)
7362 drive_type >>= 4;
7363 else
7364 drive_type &= 0x0f;
7365 if ( drive_type == 1 ) {
7366 // 360K 5.25" drive
7367 config_data = 0x00; // 0000 0000
7368 media_state = 0x25; // 0010 0101
7369 retval = 1;
7370 }
7371 else if ( drive_type == 2 ) {
7372 // 1.2 MB 5.25" drive
7373 config_data = 0x00; // 0000 0000
7374 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7375 retval = 1;
7376 }
7377 else if ( drive_type == 3 ) {
7378 // 720K 3.5" drive
7379 config_data = 0x00; // 0000 0000 ???
7380 media_state = 0x17; // 0001 0111
7381 retval = 1;
7382 }
7383 else if ( drive_type == 4 ) {
7384 // 1.44 MB 3.5" drive
7385 config_data = 0x00; // 0000 0000
7386 media_state = 0x17; // 0001 0111
7387 retval = 1;
7388 }
7389 else if ( drive_type == 5 ) {
7390 // 2.88 MB 3.5" drive
7391 config_data = 0xCC; // 1100 1100
7392 media_state = 0xD7; // 1101 0111
7393 retval = 1;
7394 }
7395 //
7396 // Extended floppy size uses special cmos setting
7397 else if ( drive_type == 6 ) {
7398 // 160k 5.25" drive
7399 config_data = 0x00; // 0000 0000
7400 media_state = 0x27; // 0010 0111
7401 retval = 1;
7402 }
7403 else if ( drive_type == 7 ) {
7404 // 180k 5.25" drive
7405 config_data = 0x00; // 0000 0000
7406 media_state = 0x27; // 0010 0111
7407 retval = 1;
7408 }
7409 else if ( drive_type == 8 ) {
7410 // 320k 5.25" drive
7411 config_data = 0x00; // 0000 0000
7412 media_state = 0x27; // 0010 0111
7413 retval = 1;
7414 }
7415
7416 else {
7417 // not recognized
7418 config_data = 0x00; // 0000 0000
7419 media_state = 0x00; // 0000 0000
7420 retval = 0;
7421 }
7422
7423 if (drive == 0)
7424 media_state_offset = 0x90;
7425 else
7426 media_state_offset = 0x91;
7427 write_byte(0x0040, 0x008B, config_data);
7428 write_byte(0x0040, media_state_offset, media_state);
7429
7430 return(retval);
7431}
7432
7433 bx_bool
7434floppy_drive_recal(drive)
7435 Bit16u drive;
7436{
7437 Bit8u val8;
7438 Bit16u curr_cyl_offset;
7439
7440 floppy_prepare_controller(drive);
7441
7442 // send Recalibrate command (2 bytes) to controller
7443 outb(0x03f5, 0x07); // 07: Recalibrate
7444 outb(0x03f5, drive); // 0=drive0, 1=drive1
7445
7446 // turn on interrupts
7447ASM_START
7448 sti
7449ASM_END
7450
7451 // wait on 40:3e bit 7 to become 1
7452 do {
7453 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7454 } while ( val8 == 0 );
7455
7456 val8 = 0; // separate asm from while() loop
7457 // turn off interrupts
7458ASM_START
7459 cli
7460ASM_END
7461
7462 // set 40:3e bit 7 to 0, and calibrated bit
7463 val8 = read_byte(0x0040, 0x003e);
7464 val8 &= 0x7f;
7465 if (drive) {
7466 val8 |= 0x02; // Drive 1 calibrated
7467 curr_cyl_offset = 0x0095;
7468 } else {
7469 val8 |= 0x01; // Drive 0 calibrated
7470 curr_cyl_offset = 0x0094;
7471 }
7472 write_byte(0x0040, 0x003e, val8);
7473 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7474
7475 return(1);
7476}
7477
7478
7479
7480 bx_bool
7481floppy_drive_exists(drive)
7482 Bit16u drive;
7483{
7484 Bit8u drive_type;
7485
7486 // check CMOS to see if drive exists
7487 drive_type = inb_cmos(0x10);
7488 if (drive == 0)
7489 drive_type >>= 4;
7490 else
7491 drive_type &= 0x0f;
7492 if ( drive_type == 0 )
7493 return(0);
7494 else
7495 return(1);
7496}
7497
7498 void
7499int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7500 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7501{
7502 Bit8u drive, num_sectors, track, sector, head, status;
7503 Bit16u base_address, base_count, base_es;
7504 Bit8u page, mode_register, val8, dor;
7505 Bit8u return_status[7];
7506 Bit8u drive_type, num_floppies, ah;
7507 Bit16u es, last_addr;
7508
7509 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7510
7511 ah = GET_AH();
7512
7513 switch ( ah ) {
7514 case 0x00: // diskette controller reset
7515BX_DEBUG_INT13_FL("floppy f00\n");
7516 drive = GET_ELDL();
7517 if (drive > 1) {
7518 SET_AH(1); // invalid param
7519 set_diskette_ret_status(1);
7520 SET_CF();
7521 return;
7522 }
7523 drive_type = inb_cmos(0x10);
7524
7525 if (drive == 0)
7526 drive_type >>= 4;
7527 else
7528 drive_type &= 0x0f;
7529 if (drive_type == 0) {
7530 SET_AH(0x80); // drive not responding
7531 set_diskette_ret_status(0x80);
7532 SET_CF();
7533 return;
7534 }
7535 SET_AH(0);
7536 set_diskette_ret_status(0);
7537 CLEAR_CF(); // successful
7538 set_diskette_current_cyl(drive, 0); // current cylinder
7539 return;
7540
7541 case 0x01: // Read Diskette Status
7542 CLEAR_CF();
7543 val8 = read_byte(0x0000, 0x0441);
7544 SET_AH(val8);
7545 if (val8) {
7546 SET_CF();
7547 }
7548 return;
7549
7550 case 0x02: // Read Diskette Sectors
7551 case 0x03: // Write Diskette Sectors
7552 case 0x04: // Verify Diskette Sectors
7553 num_sectors = GET_AL();
7554 track = GET_CH();
7555 sector = GET_CL();
7556 head = GET_DH();
7557 drive = GET_ELDL();
7558
7559 if ( (drive > 1) || (head > 1) ||
7560 (num_sectors == 0) || (num_sectors > 72) ) {
7561BX_INFO("floppy: drive>1 || head>1 ...\n");
7562 SET_AH(1);
7563 set_diskette_ret_status(1);
7564 SET_AL(0); // no sectors read
7565 SET_CF(); // error occurred
7566 return;
7567 }
7568
7569 // see if drive exists
7570 if (floppy_drive_exists(drive) == 0) {
7571 SET_AH(0x80); // not responding
7572 set_diskette_ret_status(0x80);
7573 SET_AL(0); // no sectors read
7574 SET_CF(); // error occurred
7575 return;
7576 }
7577
7578 // see if media in drive, and type is known
7579 if (floppy_media_known(drive) == 0) {
7580 if (floppy_media_sense(drive) == 0) {
7581 SET_AH(0x0C); // Media type not found
7582 set_diskette_ret_status(0x0C);
7583 SET_AL(0); // no sectors read
7584 SET_CF(); // error occurred
7585 return;
7586 }
7587 }
7588
7589 if (ah == 0x02) {
7590 // Read Diskette Sectors
7591
7592 //-----------------------------------
7593 // set up DMA controller for transfer
7594 //-----------------------------------
7595
7596 // es:bx = pointer to where to place information from diskette
7597 // port 04: DMA-1 base and current address, channel 2
7598 // port 05: DMA-1 base and current count, channel 2
7599 page = (ES >> 12); // upper 4 bits
7600 base_es = (ES << 4); // lower 16bits contributed by ES
7601 base_address = base_es + BX; // lower 16 bits of address
7602 // contributed by ES:BX
7603 if ( base_address < base_es ) {
7604 // in case of carry, adjust page by 1
7605 page++;
7606 }
7607 base_count = (num_sectors * 512) - 1;
7608
7609 // check for 64K boundary overrun
7610 last_addr = base_address + base_count;
7611 if (last_addr < base_address) {
7612 SET_AH(0x09);
7613 set_diskette_ret_status(0x09);
7614 SET_AL(0); // no sectors read
7615 SET_CF(); // error occurred
7616 return;
7617 }
7618
7619 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7620 outb(0x000a, 0x06);
7621
7622 BX_DEBUG_INT13_FL("clear flip-flop\n");
7623 outb(0x000c, 0x00); // clear flip-flop
7624 outb(0x0004, base_address);
7625 outb(0x0004, base_address>>8);
7626 BX_DEBUG_INT13_FL("clear flip-flop\n");
7627 outb(0x000c, 0x00); // clear flip-flop
7628 outb(0x0005, base_count);
7629 outb(0x0005, base_count>>8);
7630
7631 // port 0b: DMA-1 Mode Register
7632 mode_register = 0x46; // single mode, increment, autoinit disable,
7633 // transfer type=write, channel 2
7634 BX_DEBUG_INT13_FL("setting mode register\n");
7635 outb(0x000b, mode_register);
7636
7637 BX_DEBUG_INT13_FL("setting page register\n");
7638 // port 81: DMA-1 Page Register, channel 2
7639 outb(0x0081, page);
7640
7641 BX_DEBUG_INT13_FL("unmask chan 2\n");
7642 outb(0x000a, 0x02); // unmask channel 2
7643
7644 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7645 outb(0x000a, 0x02);
7646
7647 //--------------------------------------
7648 // set up floppy controller for transfer
7649 //--------------------------------------
7650 floppy_prepare_controller(drive);
7651
7652 // send read-normal-data command (9 bytes) to controller
7653 outb(0x03f5, 0xe6); // e6: read normal data
7654 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7655 outb(0x03f5, track);
7656 outb(0x03f5, head);
7657 outb(0x03f5, sector);
7658 outb(0x03f5, 2); // 512 byte sector size
7659 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7660 outb(0x03f5, 0); // Gap length
7661 outb(0x03f5, 0xff); // Gap length
7662
7663 // turn on interrupts
7664 ASM_START
7665 sti
7666 ASM_END
7667
7668 // wait on 40:3e bit 7 to become 1
7669 do {
7670 val8 = read_byte(0x0040, 0x0040);
7671 if (val8 == 0) {
7672 floppy_reset_controller();
7673 SET_AH(0x80); // drive not ready (timeout)
7674 set_diskette_ret_status(0x80);
7675 SET_AL(0); // no sectors read
7676 SET_CF(); // error occurred
7677 return;
7678 }
7679 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7680 } while ( val8 == 0 );
7681
7682 val8 = 0; // separate asm from while() loop
7683 // turn off interrupts
7684 ASM_START
7685 cli
7686 ASM_END
7687
7688 // set 40:3e bit 7 to 0
7689 val8 = read_byte(0x0040, 0x003e);
7690 val8 &= 0x7f;
7691 write_byte(0x0040, 0x003e, val8);
7692
7693 // check port 3f4 for accessibility to status bytes
7694 val8 = inb(0x3f4);
7695 if ( (val8 & 0xc0) != 0xc0 )
7696 BX_PANIC("int13_diskette: ctrl not ready\n");
7697
7698 // read 7 return status bytes from controller
7699 // using loop index broken, have to unroll...
7700 return_status[0] = inb(0x3f5);
7701 return_status[1] = inb(0x3f5);
7702 return_status[2] = inb(0x3f5);
7703 return_status[3] = inb(0x3f5);
7704 return_status[4] = inb(0x3f5);
7705 return_status[5] = inb(0x3f5);
7706 return_status[6] = inb(0x3f5);
7707 // record in BIOS Data Area
7708 write_byte(0x0040, 0x0042, return_status[0]);
7709 write_byte(0x0040, 0x0043, return_status[1]);
7710 write_byte(0x0040, 0x0044, return_status[2]);
7711 write_byte(0x0040, 0x0045, return_status[3]);
7712 write_byte(0x0040, 0x0046, return_status[4]);
7713 write_byte(0x0040, 0x0047, return_status[5]);
7714 write_byte(0x0040, 0x0048, return_status[6]);
7715
7716 if ( (return_status[0] & 0xc0) != 0 ) {
7717 SET_AH(0x20);
7718 set_diskette_ret_status(0x20);
7719 SET_AL(0); // no sectors read
7720 SET_CF(); // error occurred
7721 return;
7722 }
7723
7724 // ??? should track be new val from return_status[3] ?
7725 set_diskette_current_cyl(drive, track);
7726 // AL = number of sectors read (same value as passed)
7727 SET_AH(0x00); // success
7728 CLEAR_CF(); // success
7729 return;
7730 } else if (ah == 0x03) {
7731 // Write Diskette Sectors
7732
7733 //-----------------------------------
7734 // set up DMA controller for transfer
7735 //-----------------------------------
7736
7737 // es:bx = pointer to where to place information from diskette
7738 // port 04: DMA-1 base and current address, channel 2
7739 // port 05: DMA-1 base and current count, channel 2
7740 page = (ES >> 12); // upper 4 bits
7741 base_es = (ES << 4); // lower 16bits contributed by ES
7742 base_address = base_es + BX; // lower 16 bits of address
7743 // contributed by ES:BX
7744 if ( base_address < base_es ) {
7745 // in case of carry, adjust page by 1
7746 page++;
7747 }
7748 base_count = (num_sectors * 512) - 1;
7749
7750 // check for 64K boundary overrun
7751 last_addr = base_address + base_count;
7752 if (last_addr < base_address) {
7753 SET_AH(0x09);
7754 set_diskette_ret_status(0x09);
7755 SET_AL(0); // no sectors read
7756 SET_CF(); // error occurred
7757 return;
7758 }
7759
7760 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7761 outb(0x000a, 0x06);
7762
7763 outb(0x000c, 0x00); // clear flip-flop
7764 outb(0x0004, base_address);
7765 outb(0x0004, base_address>>8);
7766 outb(0x000c, 0x00); // clear flip-flop
7767 outb(0x0005, base_count);
7768 outb(0x0005, base_count>>8);
7769
7770 // port 0b: DMA-1 Mode Register
7771 mode_register = 0x4a; // single mode, increment, autoinit disable,
7772 // transfer type=read, channel 2
7773 outb(0x000b, mode_register);
7774
7775 // port 81: DMA-1 Page Register, channel 2
7776 outb(0x0081, page);
7777
7778 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7779 outb(0x000a, 0x02);
7780
7781 //--------------------------------------
7782 // set up floppy controller for transfer
7783 //--------------------------------------
7784 floppy_prepare_controller(drive);
7785
7786 // send write-normal-data command (9 bytes) to controller
7787 outb(0x03f5, 0xc5); // c5: write normal data
7788 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7789 outb(0x03f5, track);
7790 outb(0x03f5, head);
7791 outb(0x03f5, sector);
7792 outb(0x03f5, 2); // 512 byte sector size
7793 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7794 outb(0x03f5, 0); // Gap length
7795 outb(0x03f5, 0xff); // Gap length
7796
7797 // turn on interrupts
7798 ASM_START
7799 sti
7800 ASM_END
7801
7802 // wait on 40:3e bit 7 to become 1
7803 do {
7804 val8 = read_byte(0x0040, 0x0040);
7805 if (val8 == 0) {
7806 floppy_reset_controller();
7807 SET_AH(0x80); // drive not ready (timeout)
7808 set_diskette_ret_status(0x80);
7809 SET_AL(0); // no sectors written
7810 SET_CF(); // error occurred
7811 return;
7812 }
7813 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7814 } while ( val8 == 0 );
7815
7816 val8 = 0; // separate asm from while() loop
7817 // turn off interrupts
7818 ASM_START
7819 cli
7820 ASM_END
7821
7822 // set 40:3e bit 7 to 0
7823 val8 = read_byte(0x0040, 0x003e);
7824 val8 &= 0x7f;
7825 write_byte(0x0040, 0x003e, val8);
7826
7827 // check port 3f4 for accessibility to status bytes
7828 val8 = inb(0x3f4);
7829 if ( (val8 & 0xc0) != 0xc0 )
7830 BX_PANIC("int13_diskette: ctrl not ready\n");
7831
7832 // read 7 return status bytes from controller
7833 // using loop index broken, have to unroll...
7834 return_status[0] = inb(0x3f5);
7835 return_status[1] = inb(0x3f5);
7836 return_status[2] = inb(0x3f5);
7837 return_status[3] = inb(0x3f5);
7838 return_status[4] = inb(0x3f5);
7839 return_status[5] = inb(0x3f5);
7840 return_status[6] = inb(0x3f5);
7841 // record in BIOS Data Area
7842 write_byte(0x0040, 0x0042, return_status[0]);
7843 write_byte(0x0040, 0x0043, return_status[1]);
7844 write_byte(0x0040, 0x0044, return_status[2]);
7845 write_byte(0x0040, 0x0045, return_status[3]);
7846 write_byte(0x0040, 0x0046, return_status[4]);
7847 write_byte(0x0040, 0x0047, return_status[5]);
7848 write_byte(0x0040, 0x0048, return_status[6]);
7849
7850 if ( (return_status[0] & 0xc0) != 0 ) {
7851 if ( (return_status[1] & 0x02) != 0 ) {
7852 // diskette not writable.
7853 // AH=status code=0x03 (tried to write on write-protected disk)
7854 // AL=number of sectors written=0
7855 AX = 0x0300;
7856 SET_CF();
7857 return;
7858 } else {
7859 BX_PANIC("int13_diskette_function: read error\n");
7860 }
7861 }
7862
7863 // ??? should track be new val from return_status[3] ?
7864 set_diskette_current_cyl(drive, track);
7865 // AL = number of sectors read (same value as passed)
7866 SET_AH(0x00); // success
7867 CLEAR_CF(); // success
7868 return;
7869 } else { // if (ah == 0x04)
7870 // Verify Diskette Sectors
7871
7872 // ??? should track be new val from return_status[3] ?
7873 set_diskette_current_cyl(drive, track);
7874 // AL = number of sectors verified (same value as passed)
7875 CLEAR_CF(); // success
7876 SET_AH(0x00); // success
7877 return;
7878 }
7879 break;
7880
7881 case 0x05: // format diskette track
7882BX_DEBUG_INT13_FL("floppy f05\n");
7883
7884 num_sectors = GET_AL();
7885 track = GET_CH();
7886 head = GET_DH();
7887 drive = GET_ELDL();
7888
7889 if ((drive > 1) || (head > 1) || (track > 79) ||
7890 (num_sectors == 0) || (num_sectors > 18)) {
7891 SET_AH(1);
7892 set_diskette_ret_status(1);
7893 SET_CF(); // error occurred
7894 }
7895
7896 // see if drive exists
7897 if (floppy_drive_exists(drive) == 0) {
7898 SET_AH(0x80); // drive not responding
7899 set_diskette_ret_status(0x80);
7900 SET_CF(); // error occurred
7901 return;
7902 }
7903
7904 // see if media in drive, and type is known
7905 if (floppy_media_known(drive) == 0) {
7906 if (floppy_media_sense(drive) == 0) {
7907 SET_AH(0x0C); // Media type not found
7908 set_diskette_ret_status(0x0C);
7909 SET_AL(0); // no sectors read
7910 SET_CF(); // error occurred
7911 return;
7912 }
7913 }
7914
7915 // set up DMA controller for transfer
7916 page = (ES >> 12); // upper 4 bits
7917 base_es = (ES << 4); // lower 16bits contributed by ES
7918 base_address = base_es + BX; // lower 16 bits of address
7919 // contributed by ES:BX
7920 if ( base_address < base_es ) {
7921 // in case of carry, adjust page by 1
7922 page++;
7923 }
7924 base_count = (num_sectors * 4) - 1;
7925
7926 // check for 64K boundary overrun
7927 last_addr = base_address + base_count;
7928 if (last_addr < base_address) {
7929 SET_AH(0x09);
7930 set_diskette_ret_status(0x09);
7931 SET_AL(0); // no sectors read
7932 SET_CF(); // error occurred
7933 return;
7934 }
7935
7936 outb(0x000a, 0x06);
7937 outb(0x000c, 0x00); // clear flip-flop
7938 outb(0x0004, base_address);
7939 outb(0x0004, base_address>>8);
7940 outb(0x000c, 0x00); // clear flip-flop
7941 outb(0x0005, base_count);
7942 outb(0x0005, base_count>>8);
7943 mode_register = 0x4a; // single mode, increment, autoinit disable,
7944 // transfer type=read, channel 2
7945 outb(0x000b, mode_register);
7946 // port 81: DMA-1 Page Register, channel 2
7947 outb(0x0081, page);
7948 outb(0x000a, 0x02);
7949
7950 // set up floppy controller for transfer
7951 floppy_prepare_controller(drive);
7952
7953 // send format-track command (6 bytes) to controller
7954 outb(0x03f5, 0x4d); // 4d: format track
7955 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7956 outb(0x03f5, 2); // 512 byte sector size
7957 outb(0x03f5, num_sectors); // number of sectors per track
7958 outb(0x03f5, 0); // Gap length
7959 outb(0x03f5, 0xf6); // Fill byte
7960 // turn on interrupts
7961 ASM_START
7962 sti
7963 ASM_END
7964
7965 // wait on 40:3e bit 7 to become 1
7966 do {
7967 val8 = read_byte(0x0040, 0x0040);
7968 if (val8 == 0) {
7969 floppy_reset_controller();
7970 SET_AH(0x80); // drive not ready (timeout)
7971 set_diskette_ret_status(0x80);
7972 SET_CF(); // error occurred
7973 return;
7974 }
7975 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7976 } while ( val8 == 0 );
7977
7978 val8 = 0; // separate asm from while() loop
7979 // turn off interrupts
7980 ASM_START
7981 cli
7982 ASM_END
7983 // set 40:3e bit 7 to 0
7984 val8 = read_byte(0x0040, 0x003e);
7985 val8 &= 0x7f;
7986 write_byte(0x0040, 0x003e, val8);
7987 // check port 3f4 for accessibility to status bytes
7988 val8 = inb(0x3f4);
7989 if ( (val8 & 0xc0) != 0xc0 )
7990 BX_PANIC("int13_diskette: ctrl not ready\n");
7991
7992 // read 7 return status bytes from controller
7993 // using loop index broken, have to unroll...
7994 return_status[0] = inb(0x3f5);
7995 return_status[1] = inb(0x3f5);
7996 return_status[2] = inb(0x3f5);
7997 return_status[3] = inb(0x3f5);
7998 return_status[4] = inb(0x3f5);
7999 return_status[5] = inb(0x3f5);
8000 return_status[6] = inb(0x3f5);
8001 // record in BIOS Data Area
8002 write_byte(0x0040, 0x0042, return_status[0]);
8003 write_byte(0x0040, 0x0043, return_status[1]);
8004 write_byte(0x0040, 0x0044, return_status[2]);
8005 write_byte(0x0040, 0x0045, return_status[3]);
8006 write_byte(0x0040, 0x0046, return_status[4]);
8007 write_byte(0x0040, 0x0047, return_status[5]);
8008 write_byte(0x0040, 0x0048, return_status[6]);
8009
8010 if ( (return_status[0] & 0xc0) != 0 ) {
8011 if ( (return_status[1] & 0x02) != 0 ) {
8012 // diskette not writable.
8013 // AH=status code=0x03 (tried to write on write-protected disk)
8014 // AL=number of sectors written=0
8015 AX = 0x0300;
8016 SET_CF();
8017 return;
8018 } else {
8019 BX_PANIC("int13_diskette_function: write error\n");
8020 }
8021 }
8022
8023 SET_AH(0);
8024 set_diskette_ret_status(0);
8025 set_diskette_current_cyl(drive, 0);
8026 CLEAR_CF(); // successful
8027 return;
8028
8029
8030 case 0x08: // read diskette drive parameters
8031BX_DEBUG_INT13_FL("floppy f08\n");
8032 drive = GET_ELDL();
8033
8034 if (drive > 1) {
8035 AX = 0;
8036 BX = 0;
8037 CX = 0;
8038 DX = 0;
8039 ES = 0;
8040 DI = 0;
8041 SET_DL(num_floppies);
8042 SET_CF();
8043 return;
8044 }
8045
8046 drive_type = inb_cmos(0x10);
8047 num_floppies = 0;
8048 if (drive_type & 0xf0)
8049 num_floppies++;
8050 if (drive_type & 0x0f)
8051 num_floppies++;
8052
8053 if (drive == 0)
8054 drive_type >>= 4;
8055 else
8056 drive_type &= 0x0f;
8057
8058 SET_BH(0);
8059 SET_BL(drive_type);
8060 SET_AH(0);
8061 SET_AL(0);
8062 SET_DL(num_floppies);
8063
8064 switch (drive_type) {
8065 case 0: // none
8066 CX = 0;
8067 SET_DH(0); // max head #
8068 break;
8069
8070 case 1: // 360KB, 5.25"
8071 CX = 0x2709; // 40 tracks, 9 sectors
8072 SET_DH(1); // max head #
8073 break;
8074
8075 case 2: // 1.2MB, 5.25"
8076 CX = 0x4f0f; // 80 tracks, 15 sectors
8077 SET_DH(1); // max head #
8078 break;
8079
8080 case 3: // 720KB, 3.5"
8081 CX = 0x4f09; // 80 tracks, 9 sectors
8082 SET_DH(1); // max head #
8083 break;
8084
8085 case 4: // 1.44MB, 3.5"
8086 CX = 0x4f12; // 80 tracks, 18 sectors
8087 SET_DH(1); // max head #
8088 break;
8089
8090 case 5: // 2.88MB, 3.5"
8091 CX = 0x4f24; // 80 tracks, 36 sectors
8092 SET_DH(1); // max head #
8093 break;
8094
8095 case 6: // 160k, 5.25"
8096 CX = 0x2708; // 40 tracks, 8 sectors
8097 SET_DH(0); // max head #
8098 break;
8099
8100 case 7: // 180k, 5.25"
8101 CX = 0x2709; // 40 tracks, 9 sectors
8102 SET_DH(0); // max head #
8103 break;
8104
8105 case 8: // 320k, 5.25"
8106 CX = 0x2708; // 40 tracks, 8 sectors
8107 SET_DH(1); // max head #
8108 break;
8109
8110 default: // ?
8111 BX_PANIC("floppy: int13: bad floppy type\n");
8112 }
8113
8114 /* set es & di to point to 11 byte diskette param table in ROM */
8115ASM_START
8116 push bp
8117 mov bp, sp
8118 mov ax, #diskette_param_table2
8119 mov _int13_diskette_function.DI+2[bp], ax
8120 mov _int13_diskette_function.ES+2[bp], cs
8121 pop bp
8122ASM_END
8123 CLEAR_CF(); // success
8124 /* disk status not changed upon success */
8125 return;
8126
8127
8128 case 0x15: // read diskette drive type
8129BX_DEBUG_INT13_FL("floppy f15\n");
8130 drive = GET_ELDL();
8131 if (drive > 1) {
8132 SET_AH(0); // only 2 drives supported
8133 // set_diskette_ret_status here ???
8134 SET_CF();
8135 return;
8136 }
8137 drive_type = inb_cmos(0x10);
8138
8139 if (drive == 0)
8140 drive_type >>= 4;
8141 else
8142 drive_type &= 0x0f;
8143 CLEAR_CF(); // successful, not present
8144 if (drive_type==0) {
8145 SET_AH(0); // drive not present
8146 }
8147 else {
8148 SET_AH(1); // drive present, does not support change line
8149 }
8150
8151 return;
8152
8153 case 0x16: // get diskette change line status
8154BX_DEBUG_INT13_FL("floppy f16\n");
8155 drive = GET_ELDL();
8156 if (drive > 1) {
8157 SET_AH(0x01); // invalid drive
8158 set_diskette_ret_status(0x01);
8159 SET_CF();
8160 return;
8161 }
8162
8163 SET_AH(0x06); // change line not supported
8164 set_diskette_ret_status(0x06);
8165 SET_CF();
8166 return;
8167
8168 case 0x17: // set diskette type for format(old)
8169BX_DEBUG_INT13_FL("floppy f17\n");
8170 /* not used for 1.44M floppies */
8171 SET_AH(0x01); // not supported
8172 set_diskette_ret_status(1); /* not supported */
8173 SET_CF();
8174 return;
8175
8176 case 0x18: // set diskette type for format(new)
8177BX_DEBUG_INT13_FL("floppy f18\n");
8178 SET_AH(0x01); // do later
8179 set_diskette_ret_status(1);
8180 SET_CF();
8181 return;
8182
8183 default:
8184 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8185
8186 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8187 SET_AH(0x01); // ???
8188 set_diskette_ret_status(1);
8189 SET_CF();
8190 return;
8191 // }
8192 }
8193}
8194#else // #if BX_SUPPORT_FLOPPY
8195 void
8196int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8197 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8198{
8199 Bit8u val8;
8200
8201 switch ( GET_AH() ) {
8202
8203 case 0x01: // Read Diskette Status
8204 CLEAR_CF();
8205 val8 = read_byte(0x0000, 0x0441);
8206 SET_AH(val8);
8207 if (val8) {
8208 SET_CF();
8209 }
8210 return;
8211
8212 default:
8213 SET_CF();
8214 write_byte(0x0000, 0x0441, 0x01);
8215 SET_AH(0x01);
8216 }
8217}
8218#endif // #if BX_SUPPORT_FLOPPY
8219
8220 void
8221set_diskette_ret_status(value)
8222 Bit8u value;
8223{
8224 write_byte(0x0040, 0x0041, value);
8225}
8226
8227 void
8228set_diskette_current_cyl(drive, cyl)
8229 Bit8u drive;
8230 Bit8u cyl;
8231{
8232 if (drive > 1)
8233 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8234 write_byte(0x0040, 0x0094+drive, cyl);
8235}
8236
8237 void
8238determine_floppy_media(drive)
8239 Bit16u drive;
8240{
8241#if 0
8242 Bit8u val8, DOR, ctrl_info;
8243
8244 ctrl_info = read_byte(0x0040, 0x008F);
8245 if (drive==1)
8246 ctrl_info >>= 4;
8247 else
8248 ctrl_info &= 0x0f;
8249
8250#if 0
8251 if (drive == 0) {
8252 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8253 }
8254 else {
8255 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8256 }
8257#endif
8258
8259 if ( (ctrl_info & 0x04) != 0x04 ) {
8260 // Drive not determined means no drive exists, done.
8261 return;
8262 }
8263
8264#if 0
8265 // check Main Status Register for readiness
8266 val8 = inb(0x03f4) & 0x80; // Main Status Register
8267 if (val8 != 0x80)
8268 BX_PANIC("d_f_m: MRQ bit not set\n");
8269
8270 // change line
8271
8272 // existing BDA values
8273
8274 // turn on drive motor
8275 outb(0x03f2, DOR); // Digital Output Register
8276 //
8277#endif
8278 BX_PANIC("d_f_m: OK so far\n");
8279#endif
8280}
8281
8282 void
8283int17_function(regs, ds, iret_addr)
8284 pusha_regs_t regs; // regs pushed from PUSHA instruction
8285 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8286 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8287{
8288 Bit16u addr,timeout;
8289 Bit8u val8;
8290
8291 ASM_START
8292 sti
8293 ASM_END
8294
8295 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8296 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8297 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8298 if (regs.u.r8.ah == 0) {
8299 outb(addr, regs.u.r8.al);
8300 val8 = inb(addr+2);
8301 outb(addr+2, val8 | 0x01); // send strobe
8302 ASM_START
8303 nop
8304 ASM_END
8305 outb(addr+2, val8 & ~0x01);
8306 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8307 timeout--;
8308 }
8309 }
8310 if (regs.u.r8.ah == 1) {
8311 val8 = inb(addr+2);
8312 outb(addr+2, val8 & ~0x04); // send init
8313 ASM_START
8314 nop
8315 ASM_END
8316 outb(addr+2, val8 | 0x04);
8317 }
8318 val8 = inb(addr+1);
8319 regs.u.r8.ah = (val8 ^ 0x48);
8320 if (!timeout) regs.u.r8.ah |= 0x01;
8321 ClearCF(iret_addr.flags);
8322 } else {
8323 SetCF(iret_addr.flags); // Unsupported
8324 }
8325}
8326
8327// returns bootsegment in ax, drive in bl
8328 Bit32u
8329int19_function(bseqnr)
8330Bit8u bseqnr;
8331{
8332 Bit16u ebda_seg=read_word(0x0040,0x000E);
8333 Bit16u bootseq;
8334 Bit8u bootdrv;
8335 Bit8u bootcd;
8336#ifdef VBOX
8337 Bit8u bootlan;
8338#endif /* VBOX */
8339 Bit8u bootchk;
8340 Bit16u bootseg;
8341 Bit16u status;
8342 Bit8u lastdrive=0;
8343
8344 // if BX_ELTORITO_BOOT is not defined, old behavior
8345 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8346 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8347 // 0: system boot sequence, first drive C: then A:
8348 // 1: system boot sequence, first drive A: then C:
8349 // else BX_ELTORITO_BOOT is defined
8350 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8351 // CMOS reg 0x3D & 0x0f : 1st boot device
8352 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8353 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8354#ifdef VBOX
8355 // CMOS reg 0x3C & 0x0f : 4th boot device
8356#endif /* VBOX */
8357 // boot device codes:
8358 // 0x00 : not defined
8359 // 0x01 : first floppy
8360 // 0x02 : first harddrive
8361 // 0x03 : first cdrom
8362#ifdef VBOX
8363 // 0x04 : local area network
8364#endif /* VBOX */
8365 // else : boot failure
8366
8367 // Get the boot sequence
8368#if BX_ELTORITO_BOOT
8369 bootseq=inb_cmos(0x3d);
8370 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8371#ifdef VBOX
8372 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8373 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8374 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8375 /* Boot delay hack. */
8376 if (bseqnr == 1)
8377 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8378#endif /* VBOX */
8379
8380 if (bseqnr==2) bootseq >>= 4;
8381 if (bseqnr==3) bootseq >>= 8;
8382#ifdef VBOX
8383 if (bseqnr==4) bootseq >>= 12;
8384#endif /* VBOX */
8385 if (bootseq<0x10) lastdrive = 1;
8386 bootdrv=0x00; bootcd=0;
8387#ifdef VBOX
8388 bootlan=0;
8389#endif /* VBOX */
8390
8391 switch(bootseq & 0x0f) {
8392 case 0x01:
8393 bootdrv=0x00;
8394 bootcd=0;
8395 break;
8396 case 0x02:
8397 {
8398 // Get the Boot drive.
8399 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8400
8401 bootdrv = boot_drive + 0x80;
8402 bootcd=0;
8403 break;
8404 }
8405 case 0x03:
8406 bootdrv=0x00;
8407 bootcd=1;
8408 break;
8409#ifdef VBOX
8410 case 0x04: bootlan=1; break;
8411#endif /* VBOX */
8412 default: return 0x00000000;
8413 }
8414#else
8415 bootseq=inb_cmos(0x2d);
8416
8417 if (bseqnr==2) {
8418 bootseq ^= 0x20;
8419 lastdrive = 1;
8420 }
8421 bootdrv=0x00; bootcd=0;
8422 if((bootseq&0x20)==0) bootdrv=0x80;
8423#endif // BX_ELTORITO_BOOT
8424
8425#if BX_ELTORITO_BOOT
8426 // We have to boot from cd
8427 if (bootcd != 0) {
8428 status = cdrom_boot();
8429
8430 // If failure
8431 if ( (status & 0x00ff) !=0 ) {
8432 print_cdromboot_failure(status);
8433#ifdef VBOX
8434 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8435#else /* !VBOX */
8436 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8437#endif /* !VBOX */
8438 return 0x00000000;
8439 }
8440
8441 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8442 bootdrv = (Bit8u)(status>>8);
8443 }
8444
8445#endif // BX_ELTORITO_BOOT
8446
8447#ifdef VBOX
8448 // Check for boot from LAN first
8449 if (bootlan == 1) {
8450 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8451 Bit16u pnpoff;
8452 Bit32u manuf;
8453 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8454 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8455 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8456 // Found PnP signature
8457 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8458 if (manuf == 0x65687445) {
8459 // Found Etherboot ROM
8460 print_boot_device(bootcd, bootlan, bootdrv);
8461ASM_START
8462 push ds
8463 push es
8464 pusha
8465 calli 0x0006,VBOX_LANBOOT_SEG
8466 popa
8467 pop es
8468 pop ds
8469ASM_END
8470 } else if (manuf == 0x65746E49) {
8471 // Found Intel PXE ROM
8472 print_boot_device(bootcd, bootlan, bootdrv);
8473ASM_START
8474 push ds
8475 push es
8476 pusha
8477 sti ; Why are interrupts disabled now? Because we were called through an INT!
8478 push #VBOX_LANBOOT_SEG
8479 pop ds
8480 mov bx,#0x1a ; PnP header offset
8481 mov bx,[bx]
8482 add bx,#0x1a ; BEV offset in PnP header
8483 mov ax,[bx]
8484 test ax,ax
8485 jz no_rom
8486bev_jump:
8487 push cs
8488 push #no_rom
8489 push #VBOX_LANBOOT_SEG
8490 push ax
8491 retf ; call Boot Entry Vector
8492no_rom:
8493 popa
8494 pop es
8495 pop ds
8496ASM_END
8497 }
8498 }
8499 }
8500
8501 // boot from LAN will not return if successful.
8502 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8503 return 0x00000000;
8504 }
8505#endif /* VBOX */
8506 // We have to boot from harddisk or floppy
8507#ifdef VBOX
8508 if (bootcd == 0 && bootlan == 0) {
8509#else /* !VBOX */
8510 if (bootcd == 0) {
8511#endif /* !VBOX */
8512 bootseg=0x07c0;
8513
8514ASM_START
8515 push bp
8516 mov bp, sp
8517
8518 xor ax, ax
8519 mov _int19_function.status + 2[bp], ax
8520 mov dl, _int19_function.bootdrv + 2[bp]
8521 mov ax, _int19_function.bootseg + 2[bp]
8522 mov es, ax ;; segment
8523 xor bx, bx ;; offset
8524 mov ah, #0x02 ;; function 2, read diskette sector
8525 mov al, #0x01 ;; read 1 sector
8526 mov ch, #0x00 ;; track 0
8527 mov cl, #0x01 ;; sector 1
8528 mov dh, #0x00 ;; head 0
8529 int #0x13 ;; read sector
8530 jnc int19_load_done
8531 mov ax, #0x0001
8532 mov _int19_function.status + 2[bp], ax
8533
8534int19_load_done:
8535 pop bp
8536ASM_END
8537
8538 if (status != 0) {
8539#ifdef VBOX
8540 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8541#else /* !VBOX */
8542 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8543#endif /* !VBOX */
8544 return 0x00000000;
8545 }
8546 }
8547
8548#ifdef VBOX
8549 // Don't check boot sectors on floppies and don't read CMOS - byte
8550 // 0x38 in CMOS always has the low bit clear.
8551 // There is *no* requirement whatsoever for a valid boot sector to
8552 // have a 55AAh signature. UNIX boot floppies typically have no such
8553 // signature. In general, it is impossible to tell a valid bootsector
8554 // from an invalid one.
8555 // NB: It is somewhat common for failed OS installs to have the
8556 // 0x55AA signature and a valid partition table but zeros in the
8557 // rest of the boot sector. We do a quick check by comparing the first
8558 // two words of boot sector; if identical, the boot sector is
8559 // extremely unlikely to be valid.
8560#endif
8561 // check signature if instructed by cmos reg 0x38, only for floppy
8562 // bootchk = 1 : signature check disabled
8563 // bootchk = 0 : signature check enabled
8564 if (bootdrv != 0) bootchk = 0;
8565#ifdef VBOX
8566 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8567#else
8568 else bootchk = inb_cmos(0x38) & 0x01;
8569#endif
8570
8571#if BX_ELTORITO_BOOT
8572 // if boot from cd, no signature check
8573 if (bootcd != 0)
8574 bootchk = 1;
8575#endif // BX_ELTORITO_BOOT
8576
8577 if (bootchk == 0) {
8578 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8579 read_word(bootseg,0) == read_word(bootseg,2)) {
8580#ifdef VBOX
8581 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8582#else /* !VBOX */
8583 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8584#endif /* VBOX */
8585 return 0x00000000;
8586 }
8587 }
8588
8589#if BX_ELTORITO_BOOT
8590 // Print out the boot string
8591#ifdef VBOX
8592 print_boot_device(bootcd, bootlan, bootdrv);
8593#else /* !VBOX */
8594 print_boot_device(bootcd, bootdrv);
8595#endif /* !VBOX */
8596#else // BX_ELTORITO_BOOT
8597#ifdef VBOX
8598 print_boot_device(0, bootlan, bootdrv);
8599#else /* !VBOX */
8600 print_boot_device(0, bootdrv);
8601#endif /* !VBOX */
8602#endif // BX_ELTORITO_BOOT
8603
8604 // return the boot segment
8605 return (((Bit32u)bootdrv) << 16) + bootseg;
8606}
8607
8608 void
8609int1a_function(regs, ds, iret_addr)
8610 pusha_regs_t regs; // regs pushed from PUSHA instruction
8611 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8612 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8613{
8614 Bit8u val8;
8615
8616 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);
8617
8618 ASM_START
8619 sti
8620 ASM_END
8621
8622 switch (regs.u.r8.ah) {
8623 case 0: // get current clock count
8624 ASM_START
8625 cli
8626 ASM_END
8627 regs.u.r16.cx = BiosData->ticks_high;
8628 regs.u.r16.dx = BiosData->ticks_low;
8629 regs.u.r8.al = BiosData->midnight_flag;
8630 BiosData->midnight_flag = 0; // reset flag
8631 ASM_START
8632 sti
8633 ASM_END
8634 // AH already 0
8635 ClearCF(iret_addr.flags); // OK
8636 break;
8637
8638 case 1: // Set Current Clock Count
8639 ASM_START
8640 cli
8641 ASM_END
8642 BiosData->ticks_high = regs.u.r16.cx;
8643 BiosData->ticks_low = regs.u.r16.dx;
8644 BiosData->midnight_flag = 0; // reset flag
8645 ASM_START
8646 sti
8647 ASM_END
8648 regs.u.r8.ah = 0;
8649 ClearCF(iret_addr.flags); // OK
8650 break;
8651
8652
8653 case 2: // Read CMOS Time
8654 if (rtc_updating()) {
8655 SetCF(iret_addr.flags);
8656 break;
8657 }
8658
8659 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8660 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8661 regs.u.r8.ch = inb_cmos(0x04); // Hours
8662 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8663 regs.u.r8.ah = 0;
8664 regs.u.r8.al = regs.u.r8.ch;
8665 ClearCF(iret_addr.flags); // OK
8666 break;
8667
8668 case 3: // Set CMOS Time
8669 // Using a debugger, I notice the following masking/setting
8670 // of bits in Status Register B, by setting Reg B to
8671 // a few values and getting its value after INT 1A was called.
8672 //
8673 // try#1 try#2 try#3
8674 // before 1111 1101 0111 1101 0000 0000
8675 // after 0110 0010 0110 0010 0000 0010
8676 //
8677 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8678 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8679 if (rtc_updating()) {
8680 init_rtc();
8681 // fall through as if an update were not in progress
8682 }
8683 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8684 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8685 outb_cmos(0x04, regs.u.r8.ch); // Hours
8686 // Set Daylight Savings time enabled bit to requested value
8687 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8688 // (reg B already selected)
8689 outb_cmos(0x0b, val8);
8690 regs.u.r8.ah = 0;
8691 regs.u.r8.al = val8; // val last written to Reg B
8692 ClearCF(iret_addr.flags); // OK
8693 break;
8694
8695 case 4: // Read CMOS Date
8696 regs.u.r8.ah = 0;
8697 if (rtc_updating()) {
8698 SetCF(iret_addr.flags);
8699 break;
8700 }
8701 regs.u.r8.cl = inb_cmos(0x09); // Year
8702 regs.u.r8.dh = inb_cmos(0x08); // Month
8703 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8704 regs.u.r8.ch = inb_cmos(0x32); // Century
8705 regs.u.r8.al = regs.u.r8.ch;
8706 ClearCF(iret_addr.flags); // OK
8707 break;
8708
8709 case 5: // Set CMOS Date
8710 // Using a debugger, I notice the following masking/setting
8711 // of bits in Status Register B, by setting Reg B to
8712 // a few values and getting its value after INT 1A was called.
8713 //
8714 // try#1 try#2 try#3 try#4
8715 // before 1111 1101 0111 1101 0000 0010 0000 0000
8716 // after 0110 1101 0111 1101 0000 0010 0000 0000
8717 //
8718 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8719 // My assumption: RegB = (RegB & 01111111b)
8720 if (rtc_updating()) {
8721 init_rtc();
8722 SetCF(iret_addr.flags);
8723 break;
8724 }
8725 outb_cmos(0x09, regs.u.r8.cl); // Year
8726 outb_cmos(0x08, regs.u.r8.dh); // Month
8727 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8728 outb_cmos(0x32, regs.u.r8.ch); // Century
8729 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8730 outb_cmos(0x0b, val8);
8731 regs.u.r8.ah = 0;
8732 regs.u.r8.al = val8; // AL = val last written to Reg B
8733 ClearCF(iret_addr.flags); // OK
8734 break;
8735
8736 case 6: // Set Alarm Time in CMOS
8737 // Using a debugger, I notice the following masking/setting
8738 // of bits in Status Register B, by setting Reg B to
8739 // a few values and getting its value after INT 1A was called.
8740 //
8741 // try#1 try#2 try#3
8742 // before 1101 1111 0101 1111 0000 0000
8743 // after 0110 1111 0111 1111 0010 0000
8744 //
8745 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8746 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8747 val8 = inb_cmos(0x0b); // Get Status Reg B
8748 regs.u.r16.ax = 0;
8749 if (val8 & 0x20) {
8750 // Alarm interrupt enabled already
8751 SetCF(iret_addr.flags); // Error: alarm in use
8752 break;
8753 }
8754 if (rtc_updating()) {
8755 init_rtc();
8756 // fall through as if an update were not in progress
8757 }
8758 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8759 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8760 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8761 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8762 // enable Status Reg B alarm bit, clear halt clock bit
8763 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8764 ClearCF(iret_addr.flags); // OK
8765 break;
8766
8767 case 7: // Turn off Alarm
8768 // Using a debugger, I notice the following masking/setting
8769 // of bits in Status Register B, by setting Reg B to
8770 // a few values and getting its value after INT 1A was called.
8771 //
8772 // try#1 try#2 try#3 try#4
8773 // before 1111 1101 0111 1101 0010 0000 0010 0010
8774 // after 0100 0101 0101 0101 0000 0000 0000 0010
8775 //
8776 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8777 // My assumption: RegB = (RegB & 01010111b)
8778 val8 = inb_cmos(0x0b); // Get Status Reg B
8779 // clear clock-halt bit, disable alarm bit
8780 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8781 regs.u.r8.ah = 0;
8782 regs.u.r8.al = val8; // val last written to Reg B
8783 ClearCF(iret_addr.flags); // OK
8784 break;
8785#if BX_PCIBIOS
8786 case 0xb1:
8787 // real mode PCI BIOS functions now handled in assembler code
8788 // this C code handles the error code for information only
8789 if (regs.u.r8.bl == 0xff) {
8790 BX_INFO("PCI BIOS: PCI not present\n");
8791 } else if (regs.u.r8.bl == 0x81) {
8792 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8793 } else if (regs.u.r8.bl == 0x83) {
8794 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8795 } else if (regs.u.r8.bl == 0x86) {
8796 if (regs.u.r8.al == 0x02) {
8797 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8798 } else {
8799 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);
8800 }
8801 }
8802 regs.u.r8.ah = regs.u.r8.bl;
8803 SetCF(iret_addr.flags);
8804 break;
8805#endif
8806
8807 default:
8808 SetCF(iret_addr.flags); // Unsupported
8809 }
8810}
8811
8812 void
8813int70_function(regs, ds, iret_addr)
8814 pusha_regs_t regs; // regs pushed from PUSHA instruction
8815 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8816 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8817{
8818 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8819 Bit8u registerB = 0, registerC = 0;
8820
8821 // Check which modes are enabled and have occurred.
8822 registerB = inb_cmos( 0xB );
8823 registerC = inb_cmos( 0xC );
8824
8825 if( ( registerB & 0x60 ) != 0 ) {
8826 if( ( registerC & 0x20 ) != 0 ) {
8827 // Handle Alarm Interrupt.
8828ASM_START
8829 sti
8830 int #0x4a
8831 cli
8832ASM_END
8833 }
8834 if( ( registerC & 0x40 ) != 0 ) {
8835 // Handle Periodic Interrupt.
8836
8837 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8838 // Wait Interval (Int 15, AH=83) active.
8839 Bit32u time, toggle;
8840
8841 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8842 if( time < 0x3D1 ) {
8843 // Done waiting.
8844 Bit16u segment, offset;
8845
8846 segment = read_word( 0x40, 0x98 );
8847 offset = read_word( 0x40, 0x9A );
8848 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8849 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8850 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8851 } else {
8852 // Continue waiting.
8853 time -= 0x3D1;
8854 write_dword( 0x40, 0x9C, time );
8855 }
8856 }
8857 }
8858 }
8859
8860ASM_START
8861 call eoi_both_pics
8862ASM_END
8863}
8864
8865 void
8866dummy_isr_function(regs, ds, iret_addr)
8867 pusha_regs_t regs; // regs pushed from PUSHA instruction
8868 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8869 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8870{
8871 // Interrupt handler for unexpected hardware interrupts. We have to clear
8872 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8873 // and all hell will break loose! This routine also masks the unexpected
8874 // interrupt so it will generally be called only once for each unexpected
8875 // interrupt level.
8876 Bit8u isrA, isrB, imr, last_int = 0xFF;
8877
8878 outb( 0x20, 0x0B );
8879 isrA = inb( 0x20 );
8880 if (isrA) {
8881 outb( 0xA0, 0x0B );
8882 isrB = inb( 0xA0 );
8883 if (isrB) {
8884 imr = inb( 0xA1 );
8885 outb( 0xA1, imr | isrB ); // Mask this interrupt
8886 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8887 } else {
8888 imr = inb( 0x21 );
8889 isrA &= 0xFB; // Never mask the cascade interrupt
8890 outb( 0x21, imr | isrA); // Mask this interrupt
8891 }
8892 outb( 0x20, 0x20 ); // Send EOI on master PIC
8893 last_int = isrA;
8894 }
8895 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8896}
8897
8898ASM_START
8899;------------------------------------------
8900;- INT74h : PS/2 mouse hardware interrupt -
8901;------------------------------------------
8902int74_handler:
8903 sti
8904 pusha
8905 push ds ;; save DS
8906 push #0x00 ;; placeholder for status
8907 push #0x00 ;; placeholder for X
8908 push #0x00 ;; placeholder for Y
8909 push #0x00 ;; placeholder for Z
8910 push #0x00 ;; placeholder for make_far_call boolean
8911 call _int74_function
8912 pop cx ;; remove make_far_call from stack
8913 jcxz int74_done
8914
8915 ;; make far call to EBDA:0022
8916 push #0x00
8917 pop ds
8918 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8919 pop ds
8920 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8921 call far ptr[0x22]
8922int74_done:
8923 cli
8924 call eoi_both_pics
8925 add sp, #8 ;; pop status, x, y, z
8926
8927 pop ds ;; restore DS
8928 popa
8929 iret
8930
8931
8932;; This will perform an IRET, but will retain value of current CF
8933;; by altering flags on stack. Better than RETF #02.
8934iret_modify_cf:
8935 jc carry_set
8936 push bp
8937 mov bp, sp
8938 and BYTE [bp + 0x06], #0xfe
8939 pop bp
8940 iret
8941carry_set:
8942 push bp
8943 mov bp, sp
8944 or BYTE [bp + 0x06], #0x01
8945 pop bp
8946 iret
8947
8948
8949;----------------------
8950;- INT13h (relocated) -
8951;----------------------
8952;
8953; int13_relocated is a little bit messed up since I played with it
8954; I have to rewrite it:
8955; - call a function that detect which function to call
8956; - make all called C function get the same parameters list
8957;
8958int13_relocated:
8959
8960#if BX_ELTORITO_BOOT
8961 ;; check for an eltorito function
8962 cmp ah,#0x4a
8963 jb int13_not_eltorito
8964 cmp ah,#0x4d
8965 ja int13_not_eltorito
8966
8967 pusha
8968 push es
8969 push ds
8970 push ss
8971 pop ds
8972
8973 push #int13_out
8974 jmp _int13_eltorito ;; ELDX not used
8975
8976int13_not_eltorito:
8977 push ax
8978 push bx
8979 push cx
8980 push dx
8981
8982 ;; check if emulation active
8983 call _cdemu_isactive
8984 cmp al,#0x00
8985 je int13_cdemu_inactive
8986
8987 ;; check if access to the emulated drive
8988 call _cdemu_emulated_drive
8989 pop dx
8990 push dx
8991 cmp al,dl ;; int13 on emulated drive
8992 jne int13_nocdemu
8993
8994 pop dx
8995 pop cx
8996 pop bx
8997 pop ax
8998
8999 pusha
9000 push es
9001 push ds
9002 push ss
9003 pop ds
9004
9005 push #int13_out
9006 jmp _int13_cdemu ;; ELDX not used
9007
9008int13_nocdemu:
9009 and dl,#0xE0 ;; mask to get device class, including cdroms
9010 cmp al,dl ;; al is 0x00 or 0x80
9011 jne int13_cdemu_inactive ;; inactive for device class
9012
9013 pop dx
9014 pop cx
9015 pop bx
9016 pop ax
9017
9018 push ax
9019 push cx
9020 push dx
9021 push bx
9022
9023 dec dl ;; real drive is dl - 1
9024 jmp int13_legacy
9025
9026int13_cdemu_inactive:
9027 pop dx
9028 pop cx
9029 pop bx
9030 pop ax
9031
9032#endif // BX_ELTORITO_BOOT
9033
9034int13_noeltorito:
9035
9036 push ax
9037 push cx
9038 push dx
9039 push bx
9040
9041int13_legacy:
9042
9043 push dx ;; push eltorito value of dx instead of sp
9044
9045 push bp
9046 push si
9047 push di
9048
9049 push es
9050 push ds
9051 push ss
9052 pop ds
9053
9054 ;; now the 16-bit registers can be restored with:
9055 ;; pop ds; pop es; popa; iret
9056 ;; arguments passed to functions should be
9057 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9058
9059 test dl, #0x80
9060 jnz int13_notfloppy
9061
9062 push #int13_out
9063 jmp _int13_diskette_function
9064
9065int13_notfloppy:
9066
9067#if BX_USE_ATADRV
9068
9069 cmp dl, #0xE0
9070 jb int13_notcdrom
9071
9072 // ebx is modified: BSD 5.2.1 boot loader problem
9073 // someone should figure out which 32 bit register that actually are used
9074
9075 shr ebx, #16
9076 push bx
9077
9078 call _int13_cdrom
9079
9080 pop bx
9081 shl ebx, #16
9082
9083 jmp int13_out
9084
9085int13_notcdrom:
9086
9087#endif
9088
9089int13_disk:
9090 ;; int13_harddisk modifies high word of EAX
9091 shr eax, #16
9092 push ax
9093 call _int13_harddisk
9094 pop ax
9095 shl eax, #16
9096
9097int13_out:
9098 pop ds
9099 pop es
9100 popa
9101 iret
9102
9103;----------
9104;- INT18h -
9105;----------
9106int18_handler: ;; Boot Failure routing
9107 call _int18_panic_msg
9108 hlt
9109 iret
9110
9111;----------
9112;- INT19h -
9113;----------
9114int19_relocated: ;; Boot function, relocated
9115
9116#ifdef VBOX
9117 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9118 // just to try booting from the configured drives. All BIOS variables and
9119 // interrupt vectors need to be reset, otherwise strange things may happen.
9120 // The approach used is faking a warm reboot (which just skips showing the
9121 // logo), which is a bit more than what we need, but hey, it's fast.
9122 mov bp, sp
9123 mov ax, 2[bp]
9124 cmp ax, #0xf000
9125 jz bios_initiated_boot
9126 xor ax, ax
9127 mov ds, ax
9128 mov ax, #0x1234
9129 mov 0x472, ax
9130 jmp post
9131bios_initiated_boot:
9132#endif /* VBOX */
9133
9134 ;; int19 was beginning to be really complex, so now it
9135 ;; just calls a C function that does the work
9136 ;; it returns in BL the boot drive, and in AX the boot segment
9137 ;; the boot segment will be 0x0000 if something has failed
9138
9139 push bp
9140 mov bp, sp
9141
9142 ;; drop ds
9143 xor ax, ax
9144 mov ds, ax
9145
9146 ;; 1st boot device
9147 mov ax, #0x0001
9148 push ax
9149 call _int19_function
9150 inc sp
9151 inc sp
9152 ;; bl contains the boot drive
9153 ;; ax contains the boot segment or 0 if failure
9154
9155 test ax, ax ;; if ax is 0 try next boot device
9156 jnz boot_setup
9157
9158 ;; 2nd boot device
9159 mov ax, #0x0002
9160 push ax
9161 call _int19_function
9162 inc sp
9163 inc sp
9164 test ax, ax ;; if ax is 0 try next boot device
9165 jnz boot_setup
9166
9167 ;; 3rd boot device
9168 mov ax, #0x0003
9169 push ax
9170 call _int19_function
9171 inc sp
9172 inc sp
9173#ifdef VBOX
9174 test ax, ax ;; if ax is 0 try next boot device
9175 jnz boot_setup
9176
9177 ;; 4th boot device
9178 mov ax, #0x0004
9179 push ax
9180 call _int19_function
9181 inc sp
9182 inc sp
9183#endif /* VBOX */
9184 test ax, ax ;; if ax is 0 call int18
9185 jz int18_handler
9186
9187boot_setup:
9188 mov dl, bl ;; set drive so guest os find it
9189 shl eax, #0x04 ;; convert seg to ip
9190 mov 2[bp], ax ;; set ip
9191
9192 shr eax, #0x04 ;; get cs back
9193 and ax, #0xF000 ;; remove what went in ip
9194 mov 4[bp], ax ;; set cs
9195 xor ax, ax
9196 mov es, ax ;; set es to zero fixes [ 549815 ]
9197 mov [bp], ax ;; set bp to zero
9198 mov ax, #0xaa55 ;; set ok flag
9199
9200 pop bp
9201 iret ;; Beam me up Scotty
9202
9203;----------
9204;- INT1Ch -
9205;----------
9206int1c_handler: ;; User Timer Tick
9207 iret
9208
9209
9210;----------------------
9211;- POST: Floppy Drive -
9212;----------------------
9213floppy_drive_post:
9214 xor ax, ax
9215 mov ds, ax
9216
9217 mov al, #0x00
9218 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9219
9220 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9221
9222 mov 0x0440, al ;; diskette motor timeout counter: not active
9223 mov 0x0441, al ;; diskette controller status return code
9224
9225 mov 0x0442, al ;; disk & diskette controller status register 0
9226 mov 0x0443, al ;; diskette controller status register 1
9227 mov 0x0444, al ;; diskette controller status register 2
9228 mov 0x0445, al ;; diskette controller cylinder number
9229 mov 0x0446, al ;; diskette controller head number
9230 mov 0x0447, al ;; diskette controller sector number
9231 mov 0x0448, al ;; diskette controller bytes written
9232
9233 mov 0x048b, al ;; diskette configuration data
9234
9235 ;; -----------------------------------------------------------------
9236 ;; (048F) diskette controller information
9237 ;;
9238 mov al, #0x10 ;; get CMOS diskette drive type
9239 out 0x70, AL
9240 in AL, 0x71
9241 mov ah, al ;; save byte to AH
9242
9243look_drive0:
9244 shr al, #4 ;; look at top 4 bits for drive 0
9245 jz f0_missing ;; jump if no drive0
9246 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9247 jmp look_drive1
9248f0_missing:
9249 mov bl, #0x00 ;; no drive0
9250
9251look_drive1:
9252 mov al, ah ;; restore from AH
9253 and al, #0x0f ;; look at bottom 4 bits for drive 1
9254 jz f1_missing ;; jump if no drive1
9255 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9256f1_missing:
9257 ;; leave high bits in BL zerod
9258 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9259 ;; -----------------------------------------------------------------
9260
9261 mov al, #0x00
9262 mov 0x0490, al ;; diskette 0 media state
9263 mov 0x0491, al ;; diskette 1 media state
9264
9265 ;; diskette 0,1 operational starting state
9266 ;; drive type has not been determined,
9267 ;; has no changed detection line
9268 mov 0x0492, al
9269 mov 0x0493, al
9270
9271 mov 0x0494, al ;; diskette 0 current cylinder
9272 mov 0x0495, al ;; diskette 1 current cylinder
9273
9274 mov al, #0x02
9275 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9276
9277 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9278 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9279 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9280
9281 ret
9282
9283
9284;--------------------
9285;- POST: HARD DRIVE -
9286;--------------------
9287; relocated here because the primary POST area isnt big enough.
9288hard_drive_post:
9289 // IRQ 14 = INT 76h
9290 // INT 76h calls INT 15h function ax=9100
9291
9292 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9293 mov dx, #0x03f6
9294 out dx, al
9295
9296 xor ax, ax
9297 mov ds, ax
9298 mov 0x0474, al /* hard disk status of last operation */
9299 mov 0x0477, al /* hard disk port offset (XT only ???) */
9300 mov 0x048c, al /* hard disk status register */
9301 mov 0x048d, al /* hard disk error register */
9302 mov 0x048e, al /* hard disk task complete flag */
9303 mov al, #0x01
9304 mov 0x0475, al /* hard disk number attached */
9305 mov al, #0xc0
9306 mov 0x0476, al /* hard disk control byte */
9307 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9308 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9309 ;; INT 41h: hard disk 0 configuration pointer
9310 ;; INT 46h: hard disk 1 configuration pointer
9311 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9312 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9313
9314#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9315 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9316 mov al, #0x12
9317 out #0x70, al
9318 in al, #0x71
9319 and al, #0xf0
9320 cmp al, #0xf0
9321 je post_d0_extended
9322 jmp check_for_hd1
9323post_d0_extended:
9324 mov al, #0x19
9325 out #0x70, al
9326 in al, #0x71
9327 cmp al, #47 ;; decimal 47 - user definable
9328 je post_d0_type47
9329 HALT(__LINE__)
9330post_d0_type47:
9331 ;; CMOS purpose param table offset
9332 ;; 1b cylinders low 0
9333 ;; 1c cylinders high 1
9334 ;; 1d heads 2
9335 ;; 1e write pre-comp low 5
9336 ;; 1f write pre-comp high 6
9337 ;; 20 retries/bad map/heads>8 8
9338 ;; 21 landing zone low C
9339 ;; 22 landing zone high D
9340 ;; 23 sectors/track E
9341
9342 mov ax, #EBDA_SEG
9343 mov ds, ax
9344
9345 ;;; Filling EBDA table for hard disk 0.
9346 mov al, #0x1f
9347 out #0x70, al
9348 in al, #0x71
9349 mov ah, al
9350 mov al, #0x1e
9351 out #0x70, al
9352 in al, #0x71
9353 mov (0x003d + 0x05), ax ;; write precomp word
9354
9355 mov al, #0x20
9356 out #0x70, al
9357 in al, #0x71
9358 mov (0x003d + 0x08), al ;; drive control byte
9359
9360 mov al, #0x22
9361 out #0x70, al
9362 in al, #0x71
9363 mov ah, al
9364 mov al, #0x21
9365 out #0x70, al
9366 in al, #0x71
9367 mov (0x003d + 0x0C), ax ;; landing zone word
9368
9369 mov al, #0x1c ;; get cylinders word in AX
9370 out #0x70, al
9371 in al, #0x71 ;; high byte
9372 mov ah, al
9373 mov al, #0x1b
9374 out #0x70, al
9375 in al, #0x71 ;; low byte
9376 mov bx, ax ;; BX = cylinders
9377
9378 mov al, #0x1d
9379 out #0x70, al
9380 in al, #0x71
9381 mov cl, al ;; CL = heads
9382
9383 mov al, #0x23
9384 out #0x70, al
9385 in al, #0x71
9386 mov dl, al ;; DL = sectors
9387
9388 cmp bx, #1024
9389 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9390
9391hd0_post_physical_chs:
9392 ;; no logical CHS mapping used, just physical CHS
9393 ;; use Standard Fixed Disk Parameter Table (FDPT)
9394 mov (0x003d + 0x00), bx ;; number of physical cylinders
9395 mov (0x003d + 0x02), cl ;; number of physical heads
9396 mov (0x003d + 0x0E), dl ;; number of physical sectors
9397 jmp check_for_hd1
9398
9399hd0_post_logical_chs:
9400 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9401 mov (0x003d + 0x09), bx ;; number of physical cylinders
9402 mov (0x003d + 0x0b), cl ;; number of physical heads
9403 mov (0x003d + 0x04), dl ;; number of physical sectors
9404 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9405 mov al, #0xa0
9406 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9407
9408 cmp bx, #2048
9409 jnbe hd0_post_above_2048
9410 ;; 1024 < c <= 2048 cylinders
9411 shr bx, #0x01
9412 shl cl, #0x01
9413 jmp hd0_post_store_logical
9414
9415hd0_post_above_2048:
9416 cmp bx, #4096
9417 jnbe hd0_post_above_4096
9418 ;; 2048 < c <= 4096 cylinders
9419 shr bx, #0x02
9420 shl cl, #0x02
9421 jmp hd0_post_store_logical
9422
9423hd0_post_above_4096:
9424 cmp bx, #8192
9425 jnbe hd0_post_above_8192
9426 ;; 4096 < c <= 8192 cylinders
9427 shr bx, #0x03
9428 shl cl, #0x03
9429 jmp hd0_post_store_logical
9430
9431hd0_post_above_8192:
9432 ;; 8192 < c <= 16384 cylinders
9433 shr bx, #0x04
9434 shl cl, #0x04
9435
9436hd0_post_store_logical:
9437 mov (0x003d + 0x00), bx ;; number of physical cylinders
9438 mov (0x003d + 0x02), cl ;; number of physical heads
9439 ;; checksum
9440 mov cl, #0x0f ;; repeat count
9441 mov si, #0x003d ;; offset to disk0 FDPT
9442 mov al, #0x00 ;; sum
9443hd0_post_checksum_loop:
9444 add al, [si]
9445 inc si
9446 dec cl
9447 jnz hd0_post_checksum_loop
9448 not al ;; now take 2s complement
9449 inc al
9450 mov [si], al
9451;;; Done filling EBDA table for hard disk 0.
9452
9453
9454check_for_hd1:
9455 ;; is there really a second hard disk? if not, return now
9456 mov al, #0x12
9457 out #0x70, al
9458 in al, #0x71
9459 and al, #0x0f
9460 jnz post_d1_exists
9461 ret
9462post_d1_exists:
9463 ;; check that the hd type is really 0x0f.
9464 cmp al, #0x0f
9465 jz post_d1_extended
9466 HALT(__LINE__)
9467post_d1_extended:
9468 ;; check that the extended type is 47 - user definable
9469 mov al, #0x1a
9470 out #0x70, al
9471 in al, #0x71
9472 cmp al, #47 ;; decimal 47 - user definable
9473 je post_d1_type47
9474 HALT(__LINE__)
9475post_d1_type47:
9476 ;; Table for disk1.
9477 ;; CMOS purpose param table offset
9478 ;; 0x24 cylinders low 0
9479 ;; 0x25 cylinders high 1
9480 ;; 0x26 heads 2
9481 ;; 0x27 write pre-comp low 5
9482 ;; 0x28 write pre-comp high 6
9483 ;; 0x29 heads>8 8
9484 ;; 0x2a landing zone low C
9485 ;; 0x2b landing zone high D
9486 ;; 0x2c sectors/track E
9487;;; Fill EBDA table for hard disk 1.
9488 mov ax, #EBDA_SEG
9489 mov ds, ax
9490 mov al, #0x28
9491 out #0x70, al
9492 in al, #0x71
9493 mov ah, al
9494 mov al, #0x27
9495 out #0x70, al
9496 in al, #0x71
9497 mov (0x004d + 0x05), ax ;; write precomp word
9498
9499 mov al, #0x29
9500 out #0x70, al
9501 in al, #0x71
9502 mov (0x004d + 0x08), al ;; drive control byte
9503
9504 mov al, #0x2b
9505 out #0x70, al
9506 in al, #0x71
9507 mov ah, al
9508 mov al, #0x2a
9509 out #0x70, al
9510 in al, #0x71
9511 mov (0x004d + 0x0C), ax ;; landing zone word
9512
9513 mov al, #0x25 ;; get cylinders word in AX
9514 out #0x70, al
9515 in al, #0x71 ;; high byte
9516 mov ah, al
9517 mov al, #0x24
9518 out #0x70, al
9519 in al, #0x71 ;; low byte
9520 mov bx, ax ;; BX = cylinders
9521
9522 mov al, #0x26
9523 out #0x70, al
9524 in al, #0x71
9525 mov cl, al ;; CL = heads
9526
9527 mov al, #0x2c
9528 out #0x70, al
9529 in al, #0x71
9530 mov dl, al ;; DL = sectors
9531
9532 cmp bx, #1024
9533 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9534
9535hd1_post_physical_chs:
9536 ;; no logical CHS mapping used, just physical CHS
9537 ;; use Standard Fixed Disk Parameter Table (FDPT)
9538 mov (0x004d + 0x00), bx ;; number of physical cylinders
9539 mov (0x004d + 0x02), cl ;; number of physical heads
9540 mov (0x004d + 0x0E), dl ;; number of physical sectors
9541 ret
9542
9543hd1_post_logical_chs:
9544 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9545 mov (0x004d + 0x09), bx ;; number of physical cylinders
9546 mov (0x004d + 0x0b), cl ;; number of physical heads
9547 mov (0x004d + 0x04), dl ;; number of physical sectors
9548 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9549 mov al, #0xa0
9550 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9551
9552 cmp bx, #2048
9553 jnbe hd1_post_above_2048
9554 ;; 1024 < c <= 2048 cylinders
9555 shr bx, #0x01
9556 shl cl, #0x01
9557 jmp hd1_post_store_logical
9558
9559hd1_post_above_2048:
9560 cmp bx, #4096
9561 jnbe hd1_post_above_4096
9562 ;; 2048 < c <= 4096 cylinders
9563 shr bx, #0x02
9564 shl cl, #0x02
9565 jmp hd1_post_store_logical
9566
9567hd1_post_above_4096:
9568 cmp bx, #8192
9569 jnbe hd1_post_above_8192
9570 ;; 4096 < c <= 8192 cylinders
9571 shr bx, #0x03
9572 shl cl, #0x03
9573 jmp hd1_post_store_logical
9574
9575hd1_post_above_8192:
9576 ;; 8192 < c <= 16384 cylinders
9577 shr bx, #0x04
9578 shl cl, #0x04
9579
9580hd1_post_store_logical:
9581 mov (0x004d + 0x00), bx ;; number of physical cylinders
9582 mov (0x004d + 0x02), cl ;; number of physical heads
9583 ;; checksum
9584 mov cl, #0x0f ;; repeat count
9585 mov si, #0x004d ;; offset to disk0 FDPT
9586 mov al, #0x00 ;; sum
9587hd1_post_checksum_loop:
9588 add al, [si]
9589 inc si
9590 dec cl
9591 jnz hd1_post_checksum_loop
9592 not al ;; now take 2s complement
9593 inc al
9594 mov [si], al
9595;;; Done filling EBDA table for hard disk 1.
9596#endif /* !VBOX */
9597
9598 ret
9599
9600;--------------------
9601;- POST: EBDA segment
9602;--------------------
9603; relocated here because the primary POST area isnt big enough.
9604; the SET_INT_VECTORs have nothing to do with EBDA but do not
9605; fit into the primary POST area either
9606ebda_post:
9607 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9608 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9609 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9610 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9611
9612#if BX_USE_EBDA
9613 mov ax, #EBDA_SEG
9614 mov ds, ax
9615 mov byte ptr [0x0], #EBDA_SIZE
9616#endif
9617 xor ax, ax ; mov EBDA seg into 40E
9618 mov ds, ax
9619 mov word ptr [0x40E], #EBDA_SEG
9620 ret;;
9621
9622;--------------------
9623;- POST: EOI + jmp via [0x40:67)
9624;--------------------
9625; relocated here because the primary POST area isnt big enough.
9626eoi_jmp_post:
9627 call eoi_both_pics
9628
9629 xor ax, ax
9630 mov ds, ax
9631
9632 jmp far ptr [0x467]
9633
9634
9635;--------------------
9636eoi_both_pics:
9637 mov al, #0x20
9638 out #0xA0, al ;; slave PIC EOI
9639eoi_master_pic:
9640 mov al, #0x20
9641 out #0x20, al ;; master PIC EOI
9642 ret
9643
9644;--------------------
9645BcdToBin:
9646 ;; in: AL in BCD format
9647 ;; out: AL in binary format, AH will always be 0
9648 ;; trashes BX
9649 mov bl, al
9650 and bl, #0x0f ;; bl has low digit
9651 shr al, #4 ;; al has high digit
9652 mov bh, #10
9653 mul al, bh ;; multiply high digit by 10 (result in AX)
9654 add al, bl ;; then add low digit
9655 ret
9656
9657;--------------------
9658timer_tick_post:
9659 ;; Setup the Timer Ticks Count (0x46C:dword) and
9660 ;; Timer Ticks Roller Flag (0x470:byte)
9661 ;; The Timer Ticks Count needs to be set according to
9662 ;; the current CMOS time, as if ticks have been occurring
9663 ;; at 18.2hz since midnight up to this point. Calculating
9664 ;; this is a little complicated. Here are the factors I gather
9665 ;; regarding this. 14,318,180 hz was the original clock speed,
9666 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9667 ;; at the time, or 4 to drive the CGA video adapter. The div3
9668 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9669 ;; the timer. With a maximum 16bit timer count, this is again
9670 ;; divided down by 65536 to 18.2hz.
9671 ;;
9672 ;; 14,318,180 Hz clock
9673 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9674 ;; /4 = 1,193,181 Hz fed to timer
9675 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9676 ;; 1 second = 18.20650736 ticks
9677 ;; 1 minute = 1092.390442 ticks
9678 ;; 1 hour = 65543.42651 ticks
9679 ;;
9680 ;; Given the values in the CMOS clock, one could calculate
9681 ;; the number of ticks by the following:
9682 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9683 ;; (BcdToBin(minutes) * 1092.3904)
9684 ;; (BcdToBin(hours) * 65543.427)
9685 ;; To get a little more accuracy, since Im using integer
9686 ;; arithmatic, I use:
9687 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9688 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9689 ;; (BcdToBin(hours) * 65543427) / 1000
9690
9691 ;; assuming DS=0000
9692
9693 ;; get CMOS seconds
9694 xor eax, eax ;; clear EAX
9695 mov al, #0x00
9696 out #0x70, al
9697 in al, #0x71 ;; AL has CMOS seconds in BCD
9698 call BcdToBin ;; EAX now has seconds in binary
9699 mov edx, #18206507
9700 mul eax, edx
9701 mov ebx, #1000000
9702 xor edx, edx
9703 div eax, ebx
9704 mov ecx, eax ;; ECX will accumulate total ticks
9705
9706 ;; get CMOS minutes
9707 xor eax, eax ;; clear EAX
9708 mov al, #0x02
9709 out #0x70, al
9710 in al, #0x71 ;; AL has CMOS minutes in BCD
9711 call BcdToBin ;; EAX now has minutes in binary
9712 mov edx, #10923904
9713 mul eax, edx
9714 mov ebx, #10000
9715 xor edx, edx
9716 div eax, ebx
9717 add ecx, eax ;; add to total ticks
9718
9719 ;; get CMOS hours
9720 xor eax, eax ;; clear EAX
9721 mov al, #0x04
9722 out #0x70, al
9723 in al, #0x71 ;; AL has CMOS hours in BCD
9724 call BcdToBin ;; EAX now has hours in binary
9725 mov edx, #65543427
9726 mul eax, edx
9727 mov ebx, #1000
9728 xor edx, edx
9729 div eax, ebx
9730 add ecx, eax ;; add to total ticks
9731
9732 mov 0x46C, ecx ;; Timer Ticks Count
9733 xor al, al
9734 mov 0x470, al ;; Timer Ticks Rollover Flag
9735 ret
9736
9737;--------------------
9738int76_handler:
9739 ;; record completion in BIOS task complete flag
9740 push ax
9741 push ds
9742 mov ax, #0x0040
9743 mov ds, ax
9744 mov 0x008E, #0xff
9745 call eoi_both_pics
9746 pop ds
9747 pop ax
9748 iret
9749
9750
9751;--------------------
9752#ifdef VBOX
9753init_pic:
9754 ;; init PIC
9755 mov al, #0x11 ; send initialisation commands
9756 out 0x20, al
9757 out 0xa0, al
9758 mov al, #0x08
9759 out 0x21, al
9760 mov al, #0x70
9761 out 0xa1, al
9762 mov al, #0x04
9763 out 0x21, al
9764 mov al, #0x02
9765 out 0xa1, al
9766 mov al, #0x01
9767 out 0x21, al
9768 out 0xa1, al
9769 mov al, #0xb8
9770 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9771#if BX_USE_PS2_MOUSE
9772 mov al, #0x8f
9773#else
9774 mov al, #0x9f
9775#endif
9776 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9777 ret
9778#endif /* VBOX */
9779
9780;--------------------
9781#if BX_APM
9782
9783use32 386
9784#define APM_PROT32
9785#include "apmbios.S"
9786
9787use16 386
9788#define APM_PROT16
9789#include "apmbios.S"
9790
9791#define APM_REAL
9792#include "apmbios.S"
9793
9794#endif
9795
9796;--------------------
9797#if BX_PCIBIOS
9798use32 386
9799.align 16
9800bios32_structure:
9801 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9802 dw bios32_entry_point, 0xf ;; 32 bit physical address
9803 db 0 ;; revision level
9804 ;; length in paragraphs and checksum stored in a word to prevent errors
9805 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9806 & 0xff) << 8) + 0x01
9807 db 0,0,0,0,0 ;; reserved
9808
9809.align 16
9810bios32_entry_point:
9811 pushfd
9812 cmp eax, #0x49435024 ;; "$PCI"
9813 jne unknown_service
9814 mov eax, #0x80000000
9815 mov dx, #0x0cf8
9816 out dx, eax
9817 mov dx, #0x0cfc
9818 in eax, dx
9819#ifdef PCI_FIXED_HOST_BRIDGE
9820 cmp eax, #PCI_FIXED_HOST_BRIDGE
9821 jne unknown_service
9822#else
9823 ;; say ok if a device is present
9824 cmp eax, #0xffffffff
9825 je unknown_service
9826#endif
9827 mov ebx, #0x000f0000
9828 mov ecx, #0
9829 mov edx, #pcibios_protected
9830 xor al, al
9831 jmp bios32_end
9832unknown_service:
9833 mov al, #0x80
9834bios32_end:
9835#ifdef BX_QEMU
9836 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9837#endif
9838 popfd
9839 retf
9840
9841.align 16
9842pcibios_protected:
9843 pushfd
9844 cli
9845 push esi
9846 push edi
9847 cmp al, #0x01 ;; installation check
9848 jne pci_pro_f02
9849 mov bx, #0x0210
9850 mov cx, #0
9851 mov edx, #0x20494350 ;; "PCI "
9852 mov al, #0x01
9853 jmp pci_pro_ok
9854pci_pro_f02: ;; find pci device
9855 cmp al, #0x02
9856 jne pci_pro_f03
9857 shl ecx, #16
9858 mov cx, dx
9859 xor ebx, ebx
9860 mov di, #0x00
9861pci_pro_devloop:
9862 call pci_pro_select_reg
9863 mov dx, #0x0cfc
9864 in eax, dx
9865 cmp eax, ecx
9866 jne pci_pro_nextdev
9867 cmp si, #0
9868 je pci_pro_ok
9869 dec si
9870pci_pro_nextdev:
9871 inc ebx
9872 cmp ebx, #0x10000
9873 jne pci_pro_devloop
9874 mov ah, #0x86
9875 jmp pci_pro_fail
9876pci_pro_f03: ;; find class code
9877 cmp al, #0x03
9878 jne pci_pro_f08
9879 xor ebx, ebx
9880 mov di, #0x08
9881pci_pro_devloop2:
9882 call pci_pro_select_reg
9883 mov dx, #0x0cfc
9884 in eax, dx
9885 shr eax, #8
9886 cmp eax, ecx
9887 jne pci_pro_nextdev2
9888 cmp si, #0
9889 je pci_pro_ok
9890 dec si
9891pci_pro_nextdev2:
9892 inc ebx
9893 cmp ebx, #0x10000
9894 jne pci_pro_devloop2
9895 mov ah, #0x86
9896 jmp pci_pro_fail
9897pci_pro_f08: ;; read configuration byte
9898 cmp al, #0x08
9899 jne pci_pro_f09
9900 call pci_pro_select_reg
9901 push edx
9902 mov dx, di
9903 and dx, #0x03
9904 add dx, #0x0cfc
9905 in al, dx
9906 pop edx
9907 mov cl, al
9908 jmp pci_pro_ok
9909pci_pro_f09: ;; read configuration word
9910 cmp al, #0x09
9911 jne pci_pro_f0a
9912 call pci_pro_select_reg
9913 push edx
9914 mov dx, di
9915 and dx, #0x02
9916 add dx, #0x0cfc
9917 in ax, dx
9918 pop edx
9919 mov cx, ax
9920 jmp pci_pro_ok
9921pci_pro_f0a: ;; read configuration dword
9922 cmp al, #0x0a
9923 jne pci_pro_f0b
9924 call pci_pro_select_reg
9925 push edx
9926 mov dx, #0x0cfc
9927 in eax, dx
9928 pop edx
9929 mov ecx, eax
9930 jmp pci_pro_ok
9931pci_pro_f0b: ;; write configuration byte
9932 cmp al, #0x0b
9933 jne pci_pro_f0c
9934 call pci_pro_select_reg
9935 push edx
9936 mov dx, di
9937 and dx, #0x03
9938 add dx, #0x0cfc
9939 mov al, cl
9940 out dx, al
9941 pop edx
9942 jmp pci_pro_ok
9943pci_pro_f0c: ;; write configuration word
9944 cmp al, #0x0c
9945 jne pci_pro_f0d
9946 call pci_pro_select_reg
9947 push edx
9948 mov dx, di
9949 and dx, #0x02
9950 add dx, #0x0cfc
9951 mov ax, cx
9952 out dx, ax
9953 pop edx
9954 jmp pci_pro_ok
9955pci_pro_f0d: ;; write configuration dword
9956 cmp al, #0x0d
9957 jne pci_pro_unknown
9958 call pci_pro_select_reg
9959 push edx
9960 mov dx, #0x0cfc
9961 mov eax, ecx
9962 out dx, eax
9963 pop edx
9964 jmp pci_pro_ok
9965pci_pro_unknown:
9966 mov ah, #0x81
9967pci_pro_fail:
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 stc
9975 retf
9976pci_pro_ok:
9977 xor ah, ah
9978 pop edi
9979 pop esi
9980#ifdef BX_QEMU
9981 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9982#endif
9983 popfd
9984 clc
9985 retf
9986
9987pci_pro_select_reg:
9988 push edx
9989 mov eax, #0x800000
9990 mov ax, bx
9991 shl eax, #8
9992 and di, #0xff
9993 or ax, di
9994 and al, #0xfc
9995 mov dx, #0x0cf8
9996 out dx, eax
9997 pop edx
9998 ret
9999
10000use16 386
10001
10002pcibios_real:
10003 push eax
10004 push dx
10005 mov eax, #0x80000000
10006 mov dx, #0x0cf8
10007 out dx, eax
10008 mov dx, #0x0cfc
10009 in eax, dx
10010#ifdef PCI_FIXED_HOST_BRIDGE
10011 cmp eax, #PCI_FIXED_HOST_BRIDGE
10012 je pci_present
10013#else
10014 ;; say ok if a device is present
10015 cmp eax, #0xffffffff
10016 jne pci_present
10017#endif
10018 pop dx
10019 pop eax
10020 mov ah, #0xff
10021 stc
10022 ret
10023pci_present:
10024 pop dx
10025 pop eax
10026 cmp al, #0x01 ;; installation check
10027 jne pci_real_f02
10028 mov ax, #0x0001
10029 mov bx, #0x0210
10030 mov cx, #0
10031 mov edx, #0x20494350 ;; "PCI "
10032 mov edi, #0xf0000
10033 mov di, #pcibios_protected
10034 clc
10035 ret
10036pci_real_f02: ;; find pci device
10037 push esi
10038 push edi
10039 cmp al, #0x02
10040 jne pci_real_f03
10041 shl ecx, #16
10042 mov cx, dx
10043 xor ebx, ebx
10044 mov di, #0x00
10045pci_real_devloop:
10046 call pci_real_select_reg
10047 mov dx, #0x0cfc
10048 in eax, dx
10049 cmp eax, ecx
10050 jne pci_real_nextdev
10051 cmp si, #0
10052 je pci_real_ok
10053 dec si
10054pci_real_nextdev:
10055 inc ebx
10056 cmp ebx, #0x10000
10057 jne pci_real_devloop
10058 mov dx, cx
10059 shr ecx, #16
10060 mov ax, #0x8602
10061 jmp pci_real_fail
10062pci_real_f03: ;; find class code
10063 cmp al, #0x03
10064 jne pci_real_f08
10065 xor ebx, ebx
10066 mov di, #0x08
10067pci_real_devloop2:
10068 call pci_real_select_reg
10069 mov dx, #0x0cfc
10070 in eax, dx
10071 shr eax, #8
10072 cmp eax, ecx
10073 jne pci_real_nextdev2
10074 cmp si, #0
10075 je pci_real_ok
10076 dec si
10077pci_real_nextdev2:
10078 inc ebx
10079 cmp ebx, #0x10000
10080 jne pci_real_devloop2
10081 mov dx, cx
10082 shr ecx, #16
10083 mov ax, #0x8603
10084 jmp pci_real_fail
10085pci_real_f08: ;; read configuration byte
10086 cmp al, #0x08
10087 jne pci_real_f09
10088 call pci_real_select_reg
10089 push dx
10090 mov dx, di
10091 and dx, #0x03
10092 add dx, #0x0cfc
10093 in al, dx
10094 pop dx
10095 mov cl, al
10096 jmp pci_real_ok
10097pci_real_f09: ;; read configuration word
10098 cmp al, #0x09
10099 jne pci_real_f0a
10100 call pci_real_select_reg
10101 push dx
10102 mov dx, di
10103 and dx, #0x02
10104 add dx, #0x0cfc
10105 in ax, dx
10106 pop dx
10107 mov cx, ax
10108 jmp pci_real_ok
10109pci_real_f0a: ;; read configuration dword
10110 cmp al, #0x0a
10111 jne pci_real_f0b
10112 call pci_real_select_reg
10113 push dx
10114 mov dx, #0x0cfc
10115 in eax, dx
10116 pop dx
10117 mov ecx, eax
10118 jmp pci_real_ok
10119pci_real_f0b: ;; write configuration byte
10120 cmp al, #0x0b
10121 jne pci_real_f0c
10122 call pci_real_select_reg
10123 push dx
10124 mov dx, di
10125 and dx, #0x03
10126 add dx, #0x0cfc
10127 mov al, cl
10128 out dx, al
10129 pop dx
10130 jmp pci_real_ok
10131pci_real_f0c: ;; write configuration word
10132 cmp al, #0x0c
10133 jne pci_real_f0d
10134 call pci_real_select_reg
10135 push dx
10136 mov dx, di
10137 and dx, #0x02
10138 add dx, #0x0cfc
10139 mov ax, cx
10140 out dx, ax
10141 pop dx
10142 jmp pci_real_ok
10143pci_real_f0d: ;; write configuration dword
10144 cmp al, #0x0d
10145 jne pci_real_f0e
10146 call pci_real_select_reg
10147 push dx
10148 mov dx, #0x0cfc
10149 mov eax, ecx
10150 out dx, eax
10151 pop dx
10152 jmp pci_real_ok
10153pci_real_f0e: ;; get irq routing options
10154 cmp al, #0x0e
10155 jne pci_real_unknown
10156 SEG ES
10157 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10158 jb pci_real_too_small
10159 SEG ES
10160 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10161 pushf
10162 push ds
10163 push es
10164 push cx
10165 push si
10166 push di
10167 cld
10168 mov si, #pci_routing_table_structure_start
10169 push cs
10170 pop ds
10171 SEG ES
10172 mov cx, [di+2]
10173 SEG ES
10174 mov es, [di+4]
10175 mov di, cx
10176 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10177 rep
10178 movsb
10179 pop di
10180 pop si
10181 pop cx
10182 pop es
10183 pop ds
10184 popf
10185 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10186 jmp pci_real_ok
10187pci_real_too_small:
10188 SEG ES
10189 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10190 mov ah, #0x89
10191 jmp pci_real_fail
10192
10193pci_real_unknown:
10194 mov ah, #0x81
10195pci_real_fail:
10196 pop edi
10197 pop esi
10198 stc
10199 ret
10200pci_real_ok:
10201 xor ah, ah
10202 pop edi
10203 pop esi
10204 clc
10205 ret
10206
10207pci_real_select_reg:
10208 push dx
10209 mov eax, #0x800000
10210 mov ax, bx
10211 shl eax, #8
10212 and di, #0xff
10213 or ax, di
10214 and al, #0xfc
10215 mov dx, #0x0cf8
10216 out dx, eax
10217 pop dx
10218 ret
10219
10220.align 16
10221pci_routing_table_structure:
10222 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10223 db 0, 1 ;; version
10224#ifdef VBOX
10225#if 0
10226 dw 32 + (30 * 16) ;; table size
10227#else
10228 dw 32 + (10 * 16) ;; table size
10229#endif
10230#else /* !VBOX */
10231 dw 32 + (6 * 16) ;; table size
10232#endif /* !VBOX */
10233 db 0 ;; PCI interrupt router bus
10234 db 0x08 ;; PCI interrupt router DevFunc
10235 dw 0x0000 ;; PCI exclusive IRQs
10236 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10237 dw 0x7000 ;; compatible PCI interrupt router device ID
10238 dw 0,0 ;; Miniport data
10239 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10240#ifdef VBOX
10241 db 0x00 ;; checksum (set by biossums)
10242#else /* !VBOX */
10243 db 0x07 ;; checksum
10244#endif /* !VBOX */
10245pci_routing_table_structure_start:
10246 ;; first slot entry PCI-to-ISA (embedded)
10247 db 0 ;; pci bus number
10248 db 0x08 ;; pci device number (bit 7-3)
10249 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10250 dw 0xdef8 ;; IRQ bitmap INTA#
10251 db 0x61 ;; link value INTB#
10252 dw 0xdef8 ;; IRQ bitmap INTB#
10253 db 0x62 ;; link value INTC#
10254 dw 0xdef8 ;; IRQ bitmap INTC#
10255 db 0x63 ;; link value INTD#
10256 dw 0xdef8 ;; IRQ bitmap INTD#
10257 db 0 ;; physical slot (0 = embedded)
10258 db 0 ;; reserved
10259 ;; second slot entry: 1st PCI slot
10260 db 0 ;; pci bus number
10261 db 0x10 ;; pci device number (bit 7-3)
10262 db 0x61 ;; link value INTA#
10263 dw 0xdef8 ;; IRQ bitmap INTA#
10264 db 0x62 ;; link value INTB#
10265 dw 0xdef8 ;; IRQ bitmap INTB#
10266 db 0x63 ;; link value INTC#
10267 dw 0xdef8 ;; IRQ bitmap INTC#
10268 db 0x60 ;; link value INTD#
10269 dw 0xdef8 ;; IRQ bitmap INTD#
10270 db 1 ;; physical slot (0 = embedded)
10271 db 0 ;; reserved
10272 ;; third slot entry: 2nd PCI slot
10273 db 0 ;; pci bus number
10274 db 0x18 ;; pci device number (bit 7-3)
10275 db 0x62 ;; link value INTA#
10276 dw 0xdef8 ;; IRQ bitmap INTA#
10277 db 0x63 ;; link value INTB#
10278 dw 0xdef8 ;; IRQ bitmap INTB#
10279 db 0x60 ;; link value INTC#
10280 dw 0xdef8 ;; IRQ bitmap INTC#
10281 db 0x61 ;; link value INTD#
10282 dw 0xdef8 ;; IRQ bitmap INTD#
10283 db 2 ;; physical slot (0 = embedded)
10284 db 0 ;; reserved
10285 ;; 4th slot entry: 3rd PCI slot
10286 db 0 ;; pci bus number
10287 db 0x20 ;; pci device number (bit 7-3)
10288 db 0x63 ;; link value INTA#
10289 dw 0xdef8 ;; IRQ bitmap INTA#
10290 db 0x60 ;; link value INTB#
10291 dw 0xdef8 ;; IRQ bitmap INTB#
10292 db 0x61 ;; link value INTC#
10293 dw 0xdef8 ;; IRQ bitmap INTC#
10294 db 0x62 ;; link value INTD#
10295 dw 0xdef8 ;; IRQ bitmap INTD#
10296 db 3 ;; physical slot (0 = embedded)
10297 db 0 ;; reserved
10298 ;; 5th slot entry: 4rd PCI slot
10299 db 0 ;; pci bus number
10300 db 0x28 ;; pci device number (bit 7-3)
10301 db 0x60 ;; link value INTA#
10302 dw 0xdef8 ;; IRQ bitmap INTA#
10303 db 0x61 ;; link value INTB#
10304 dw 0xdef8 ;; IRQ bitmap INTB#
10305 db 0x62 ;; link value INTC#
10306 dw 0xdef8 ;; IRQ bitmap INTC#
10307 db 0x63 ;; link value INTD#
10308 dw 0xdef8 ;; IRQ bitmap INTD#
10309 db 4 ;; physical slot (0 = embedded)
10310 db 0 ;; reserved
10311 ;; 6th slot entry: 5rd PCI slot
10312 db 0 ;; pci bus number
10313 db 0x30 ;; pci device number (bit 7-3)
10314 db 0x61 ;; link value INTA#
10315 dw 0xdef8 ;; IRQ bitmap INTA#
10316 db 0x62 ;; link value INTB#
10317 dw 0xdef8 ;; IRQ bitmap INTB#
10318 db 0x63 ;; link value INTC#
10319 dw 0xdef8 ;; IRQ bitmap INTC#
10320 db 0x60 ;; link value INTD#
10321 dw 0xdef8 ;; IRQ bitmap INTD#
10322 db 5 ;; physical slot (0 = embedded)
10323 db 0 ;; reserved
10324#ifdef VBOX
10325 ;; 7th slot entry: 6th PCI slot
10326 db 0 ;; pci bus number
10327 db 0x38 ;; pci device number (bit 7-3)
10328 db 0x62 ;; link value INTA#
10329 dw 0xdef8 ;; IRQ bitmap INTA#
10330 db 0x63 ;; link value INTB#
10331 dw 0xdef8 ;; IRQ bitmap INTB#
10332 db 0x60 ;; link value INTC#
10333 dw 0xdef8 ;; IRQ bitmap INTC#
10334 db 0x61 ;; link value INTD#
10335 dw 0xdef8 ;; IRQ bitmap INTD#
10336 db 6 ;; physical slot (0 = embedded)
10337 db 0 ;; reserved
10338 ;; 8th slot entry: 7th PCI slot
10339 db 0 ;; pci bus number
10340 db 0x40 ;; pci device number (bit 7-3)
10341 db 0x63 ;; link value INTA#
10342 dw 0xdef8 ;; IRQ bitmap INTA#
10343 db 0x60 ;; link value INTB#
10344 dw 0xdef8 ;; IRQ bitmap INTB#
10345 db 0x61 ;; link value INTC#
10346 dw 0xdef8 ;; IRQ bitmap INTC#
10347 db 0x62 ;; link value INTD#
10348 dw 0xdef8 ;; IRQ bitmap INTD#
10349 db 7 ;; physical slot (0 = embedded)
10350 db 0 ;; reserved
10351 ;; 9th slot entry: 8th PCI slot
10352 db 0 ;; pci bus number
10353 db 0x48 ;; pci device number (bit 7-3)
10354 db 0x60 ;; link value INTA#
10355 dw 0xdef8 ;; IRQ bitmap INTA#
10356 db 0x61 ;; link value INTB#
10357 dw 0xdef8 ;; IRQ bitmap INTB#
10358 db 0x62 ;; link value INTC#
10359 dw 0xdef8 ;; IRQ bitmap INTC#
10360 db 0x63 ;; link value INTD#
10361 dw 0xdef8 ;; IRQ bitmap INTD#
10362 db 8 ;; physical slot (0 = embedded)
10363 db 0 ;; reserved
10364 ;; 10th slot entry: 9th PCI slot
10365 db 0 ;; pci bus number
10366 db 0x50 ;; pci device number (bit 7-3)
10367 db 0x61 ;; link value INTA#
10368 dw 0xdef8 ;; IRQ bitmap INTA#
10369 db 0x62 ;; link value INTB#
10370 dw 0xdef8 ;; IRQ bitmap INTB#
10371 db 0x63 ;; link value INTC#
10372 dw 0xdef8 ;; IRQ bitmap INTC#
10373 db 0x60 ;; link value INTD#
10374 dw 0xdef8 ;; IRQ bitmap INTD#
10375 db 9 ;; physical slot (0 = embedded)
10376 db 0 ;; reserved
10377 ;; 11th slot entry: 10th PCI slot
10378 db 0 ;; pci bus number
10379 db 0x58 ;; pci device number (bit 7-3)
10380 db 0x61 ;; link value INTA#
10381 dw 0xdef8 ;; IRQ bitmap INTA#
10382 db 0x62 ;; link value INTB#
10383 dw 0xdef8 ;; IRQ bitmap INTB#
10384 db 0x63 ;; link value INTC#
10385 dw 0xdef8 ;; IRQ bitmap INTC#
10386 db 0x60 ;; link value INTD#
10387 dw 0xdef8 ;; IRQ bitmap INTD#
10388 db 10 ;; physical slot (0 = embedded)
10389 db 0 ;; reserved
10390 ;; 12th slot entry: 11th PCI slot
10391 db 0 ;; pci bus number
10392 db 0x60 ;; pci device number (bit 7-3)
10393 db 0x61 ;; link value INTA#
10394 dw 0xdef8 ;; IRQ bitmap INTA#
10395 db 0x62 ;; link value INTB#
10396 dw 0xdef8 ;; IRQ bitmap INTB#
10397 db 0x63 ;; link value INTC#
10398 dw 0xdef8 ;; IRQ bitmap INTC#
10399 db 0x60 ;; link value INTD#
10400 dw 0xdef8 ;; IRQ bitmap INTD#
10401 db 11 ;; physical slot (0 = embedded)
10402 db 0 ;; reserved
10403 ;; 13th slot entry: 12th PCI slot
10404 db 0 ;; pci bus number
10405 db 0x68 ;; pci device number (bit 7-3)
10406 db 0x61 ;; link value INTA#
10407 dw 0xdef8 ;; IRQ bitmap INTA#
10408 db 0x62 ;; link value INTB#
10409 dw 0xdef8 ;; IRQ bitmap INTB#
10410 db 0x63 ;; link value INTC#
10411 dw 0xdef8 ;; IRQ bitmap INTC#
10412 db 0x60 ;; link value INTD#
10413 dw 0xdef8 ;; IRQ bitmap INTD#
10414 db 12 ;; physical slot (0 = embedded)
10415 db 0 ;; reserved
10416 ;; 14th slot entry: 13th PCI slot
10417 db 0 ;; pci bus number
10418 db 0x70 ;; pci device number (bit 7-3)
10419 db 0x61 ;; link value INTA#
10420 dw 0xdef8 ;; IRQ bitmap INTA#
10421 db 0x62 ;; link value INTB#
10422 dw 0xdef8 ;; IRQ bitmap INTB#
10423 db 0x63 ;; link value INTC#
10424 dw 0xdef8 ;; IRQ bitmap INTC#
10425 db 0x60 ;; link value INTD#
10426 dw 0xdef8 ;; IRQ bitmap INTD#
10427 db 13 ;; physical slot (0 = embedded)
10428 db 0 ;; reserved
10429 ;; 15th slot entry: 14th PCI slot
10430 db 0 ;; pci bus number
10431 db 0x78 ;; pci device number (bit 7-3)
10432 db 0x61 ;; link value INTA#
10433 dw 0xdef8 ;; IRQ bitmap INTA#
10434 db 0x62 ;; link value INTB#
10435 dw 0xdef8 ;; IRQ bitmap INTB#
10436 db 0x63 ;; link value INTC#
10437 dw 0xdef8 ;; IRQ bitmap INTC#
10438 db 0x60 ;; link value INTD#
10439 dw 0xdef8 ;; IRQ bitmap INTD#
10440 db 14 ;; physical slot (0 = embedded)
10441 db 0 ;; reserved
10442 ;; 16th slot entry: 15th PCI slot
10443 db 0 ;; pci bus number
10444 db 0x80 ;; pci device number (bit 7-3)
10445 db 0x61 ;; link value INTA#
10446 dw 0xdef8 ;; IRQ bitmap INTA#
10447 db 0x62 ;; link value INTB#
10448 dw 0xdef8 ;; IRQ bitmap INTB#
10449 db 0x63 ;; link value INTC#
10450 dw 0xdef8 ;; IRQ bitmap INTC#
10451 db 0x60 ;; link value INTD#
10452 dw 0xdef8 ;; IRQ bitmap INTD#
10453 db 15 ;; physical slot (0 = embedded)
10454 db 0 ;; reserved
10455 ;; 17th slot entry: 16th PCI slot
10456 db 0 ;; pci bus number
10457 db 0x88 ;; pci device number (bit 7-3)
10458 db 0x61 ;; link value INTA#
10459 dw 0xdef8 ;; IRQ bitmap INTA#
10460 db 0x62 ;; link value INTB#
10461 dw 0xdef8 ;; IRQ bitmap INTB#
10462 db 0x63 ;; link value INTC#
10463 dw 0xdef8 ;; IRQ bitmap INTC#
10464 db 0x60 ;; link value INTD#
10465 dw 0xdef8 ;; IRQ bitmap INTD#
10466 db 16 ;; physical slot (0 = embedded)
10467 db 0 ;; reserved
10468 ;; 18th slot entry: 17th PCI slot
10469 db 0 ;; pci bus number
10470 db 0x90 ;; pci device number (bit 7-3)
10471 db 0x61 ;; link value INTA#
10472 dw 0xdef8 ;; IRQ bitmap INTA#
10473 db 0x62 ;; link value INTB#
10474 dw 0xdef8 ;; IRQ bitmap INTB#
10475 db 0x63 ;; link value INTC#
10476 dw 0xdef8 ;; IRQ bitmap INTC#
10477 db 0x60 ;; link value INTD#
10478 dw 0xdef8 ;; IRQ bitmap INTD#
10479 db 17 ;; physical slot (0 = embedded)
10480 db 0 ;; reserved
10481 ;; 19th slot entry: 18th PCI slot
10482 db 0 ;; pci bus number
10483 db 0x98 ;; pci device number (bit 7-3)
10484 db 0x61 ;; link value INTA#
10485 dw 0xdef8 ;; IRQ bitmap INTA#
10486 db 0x62 ;; link value INTB#
10487 dw 0xdef8 ;; IRQ bitmap INTB#
10488 db 0x63 ;; link value INTC#
10489 dw 0xdef8 ;; IRQ bitmap INTC#
10490 db 0x60 ;; link value INTD#
10491 dw 0xdef8 ;; IRQ bitmap INTD#
10492 db 18 ;; physical slot (0 = embedded)
10493 db 0 ;; reserved
10494 ;; 20th slot entry: 19th PCI slot
10495 db 0 ;; pci bus number
10496 db 0xa0 ;; pci device number (bit 7-3)
10497 db 0x61 ;; link value INTA#
10498 dw 0xdef8 ;; IRQ bitmap INTA#
10499 db 0x62 ;; link value INTB#
10500 dw 0xdef8 ;; IRQ bitmap INTB#
10501 db 0x63 ;; link value INTC#
10502 dw 0xdef8 ;; IRQ bitmap INTC#
10503 db 0x60 ;; link value INTD#
10504 dw 0xdef8 ;; IRQ bitmap INTD#
10505 db 19 ;; physical slot (0 = embedded)
10506 db 0 ;; reserved
10507 ;; 21th slot entry: 20th PCI slot
10508 db 0 ;; pci bus number
10509 db 0xa8 ;; pci device number (bit 7-3)
10510 db 0x61 ;; link value INTA#
10511 dw 0xdef8 ;; IRQ bitmap INTA#
10512 db 0x62 ;; link value INTB#
10513 dw 0xdef8 ;; IRQ bitmap INTB#
10514 db 0x63 ;; link value INTC#
10515 dw 0xdef8 ;; IRQ bitmap INTC#
10516 db 0x60 ;; link value INTD#
10517 dw 0xdef8 ;; IRQ bitmap INTD#
10518 db 20 ;; physical slot (0 = embedded)
10519 db 0 ;; reserved
10520 ;; 21th slot entry: 20th PCI slot
10521 db 0 ;; pci bus number
10522 db 0xb0 ;; pci device number (bit 7-3)
10523 db 0x61 ;; link value INTA#
10524 dw 0xdef8 ;; IRQ bitmap INTA#
10525 db 0x62 ;; link value INTB#
10526 dw 0xdef8 ;; IRQ bitmap INTB#
10527 db 0x63 ;; link value INTC#
10528 dw 0xdef8 ;; IRQ bitmap INTC#
10529 db 0x60 ;; link value INTD#
10530 dw 0xdef8 ;; IRQ bitmap INTD#
10531 db 20 ;; physical slot (0 = embedded)
10532 db 0 ;; reserved
10533 ;; 22th slot entry: 21th PCI slot
10534 db 0 ;; pci bus number
10535 db 0xb8 ;; pci device number (bit 7-3)
10536 db 0x61 ;; link value INTA#
10537 dw 0xdef8 ;; IRQ bitmap INTA#
10538 db 0x62 ;; link value INTB#
10539 dw 0xdef8 ;; IRQ bitmap INTB#
10540 db 0x63 ;; link value INTC#
10541 dw 0xdef8 ;; IRQ bitmap INTC#
10542 db 0x60 ;; link value INTD#
10543 dw 0xdef8 ;; IRQ bitmap INTD#
10544 db 21 ;; physical slot (0 = embedded)
10545 db 0 ;; reserved
10546 ;; 23th slot entry: 22th PCI slot
10547 db 0 ;; pci bus number
10548 db 0xc0 ;; pci device number (bit 7-3)
10549 db 0x61 ;; link value INTA#
10550 dw 0xdef8 ;; IRQ bitmap INTA#
10551 db 0x62 ;; link value INTB#
10552 dw 0xdef8 ;; IRQ bitmap INTB#
10553 db 0x63 ;; link value INTC#
10554 dw 0xdef8 ;; IRQ bitmap INTC#
10555 db 0x60 ;; link value INTD#
10556 dw 0xdef8 ;; IRQ bitmap INTD#
10557 db 22 ;; physical slot (0 = embedded)
10558 db 0 ;; reserved
10559 ;; 24th slot entry: 23th PCI slot
10560 db 0 ;; pci bus number
10561 db 0xc8 ;; pci device number (bit 7-3)
10562 db 0x61 ;; link value INTA#
10563 dw 0xdef8 ;; IRQ bitmap INTA#
10564 db 0x62 ;; link value INTB#
10565 dw 0xdef8 ;; IRQ bitmap INTB#
10566 db 0x63 ;; link value INTC#
10567 dw 0xdef8 ;; IRQ bitmap INTC#
10568 db 0x60 ;; link value INTD#
10569 dw 0xdef8 ;; IRQ bitmap INTD#
10570 db 23 ;; physical slot (0 = embedded)
10571 db 0 ;; reserved
10572 ;; 25th slot entry: 24th PCI slot
10573 db 0 ;; pci bus number
10574 db 0xd0 ;; pci device number (bit 7-3)
10575 db 0x61 ;; link value INTA#
10576 dw 0xdef8 ;; IRQ bitmap INTA#
10577 db 0x62 ;; link value INTB#
10578 dw 0xdef8 ;; IRQ bitmap INTB#
10579 db 0x63 ;; link value INTC#
10580 dw 0xdef8 ;; IRQ bitmap INTC#
10581 db 0x60 ;; link value INTD#
10582 dw 0xdef8 ;; IRQ bitmap INTD#
10583 db 24 ;; physical slot (0 = embedded)
10584 db 0 ;; reserved
10585 ;; 26th slot entry: 25th PCI slot
10586 db 0 ;; pci bus number
10587 db 0xd8 ;; pci device number (bit 7-3)
10588 db 0x61 ;; link value INTA#
10589 dw 0xdef8 ;; IRQ bitmap INTA#
10590 db 0x62 ;; link value INTB#
10591 dw 0xdef8 ;; IRQ bitmap INTB#
10592 db 0x63 ;; link value INTC#
10593 dw 0xdef8 ;; IRQ bitmap INTC#
10594 db 0x60 ;; link value INTD#
10595 dw 0xdef8 ;; IRQ bitmap INTD#
10596 db 25 ;; physical slot (0 = embedded)
10597 db 0 ;; reserved
10598 ;; 27th slot entry: 26th PCI slot
10599 db 0 ;; pci bus number
10600 db 0xe0 ;; pci device number (bit 7-3)
10601 db 0x61 ;; link value INTA#
10602 dw 0xdef8 ;; IRQ bitmap INTA#
10603 db 0x62 ;; link value INTB#
10604 dw 0xdef8 ;; IRQ bitmap INTB#
10605 db 0x63 ;; link value INTC#
10606 dw 0xdef8 ;; IRQ bitmap INTC#
10607 db 0x60 ;; link value INTD#
10608 dw 0xdef8 ;; IRQ bitmap INTD#
10609 db 26 ;; physical slot (0 = embedded)
10610 db 0 ;; reserved
10611 ;; 28th slot entry: 27th PCI slot
10612 db 0 ;; pci bus number
10613 db 0xe8 ;; pci device number (bit 7-3)
10614 db 0x61 ;; link value INTA#
10615 dw 0xdef8 ;; IRQ bitmap INTA#
10616 db 0x62 ;; link value INTB#
10617 dw 0xdef8 ;; IRQ bitmap INTB#
10618 db 0x63 ;; link value INTC#
10619 dw 0xdef8 ;; IRQ bitmap INTC#
10620 db 0x60 ;; link value INTD#
10621 dw 0xdef8 ;; IRQ bitmap INTD#
10622 db 27 ;; physical slot (0 = embedded)
10623 db 0 ;; reserved
10624 ;; 29th slot entry: 28th PCI slot
10625 db 0 ;; pci bus number
10626 db 0xf0 ;; pci device number (bit 7-3)
10627 db 0x61 ;; link value INTA#
10628 dw 0xdef8 ;; IRQ bitmap INTA#
10629 db 0x62 ;; link value INTB#
10630 dw 0xdef8 ;; IRQ bitmap INTB#
10631 db 0x63 ;; link value INTC#
10632 dw 0xdef8 ;; IRQ bitmap INTC#
10633 db 0x60 ;; link value INTD#
10634 dw 0xdef8 ;; IRQ bitmap INTD#
10635 db 28 ;; physical slot (0 = embedded)
10636 db 0 ;; reserved
10637 ;; 30th slot entry: 29th PCI slot
10638 db 0 ;; pci bus number
10639 db 0xf8 ;; pci device number (bit 7-3)
10640 db 0x61 ;; link value INTA#
10641 dw 0xdef8 ;; IRQ bitmap INTA#
10642 db 0x62 ;; link value INTB#
10643 dw 0xdef8 ;; IRQ bitmap INTB#
10644 db 0x63 ;; link value INTC#
10645 dw 0xdef8 ;; IRQ bitmap INTC#
10646 db 0x60 ;; link value INTD#
10647 dw 0xdef8 ;; IRQ bitmap INTD#
10648 db 29 ;; physical slot (0 = embedded)
10649 db 0 ;; reserved
10650#endif /* VBOX */
10651pci_routing_table_structure_end:
10652
10653#if !BX_ROMBIOS32
10654pci_irq_list:
10655 db 11, 10, 9, 5;
10656
10657pcibios_init_sel_reg:
10658 push eax
10659 mov eax, #0x800000
10660 mov ax, bx
10661 shl eax, #8
10662 and dl, #0xfc
10663 or al, dl
10664 mov dx, #0x0cf8
10665 out dx, eax
10666 pop eax
10667 ret
10668
10669pcibios_init_iomem_bases:
10670 push bp
10671 mov bp, sp
10672 mov eax, #0xe0000000 ;; base for memory init
10673 push eax
10674 mov ax, #0xc000 ;; base for i/o init
10675 push ax
10676 mov ax, #0x0010 ;; start at base address #0
10677 push ax
10678 mov bx, #0x0008
10679pci_init_io_loop1:
10680 mov dl, #0x00
10681 call pcibios_init_sel_reg
10682 mov dx, #0x0cfc
10683 in ax, dx
10684 cmp ax, #0xffff
10685 jz next_pci_dev
10686#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10687 mov dl, #0x04 ;; disable i/o and memory space access
10688 call pcibios_init_sel_reg
10689 mov dx, #0x0cfc
10690 in al, dx
10691 and al, #0xfc
10692 out dx, al
10693pci_init_io_loop2:
10694 mov dl, [bp-8]
10695 call pcibios_init_sel_reg
10696 mov dx, #0x0cfc
10697 in eax, dx
10698 test al, #0x01
10699 jnz init_io_base
10700 mov ecx, eax
10701 mov eax, #0xffffffff
10702 out dx, eax
10703 in eax, dx
10704 cmp eax, ecx
10705 je next_pci_base
10706 xor eax, #0xffffffff
10707 mov ecx, eax
10708 mov eax, [bp-4]
10709 out dx, eax
10710 add eax, ecx ;; calculate next free mem base
10711 add eax, #0x01000000
10712 and eax, #0xff000000
10713 mov [bp-4], eax
10714 jmp next_pci_base
10715init_io_base:
10716 mov cx, ax
10717 mov ax, #0xffff
10718 out dx, ax
10719 in ax, dx
10720 cmp ax, cx
10721 je next_pci_base
10722 xor ax, #0xfffe
10723 mov cx, ax
10724 mov ax, [bp-6]
10725 out dx, ax
10726 add ax, cx ;; calculate next free i/o base
10727 add ax, #0x0100
10728 and ax, #0xff00
10729 mov [bp-6], ax
10730next_pci_base:
10731 mov al, [bp-8]
10732 add al, #0x04
10733 cmp al, #0x28
10734 je enable_iomem_space
10735 mov byte ptr[bp-8], al
10736 jmp pci_init_io_loop2
10737#endif /* !VBOX */
10738enable_iomem_space:
10739 mov dl, #0x04 ;; enable i/o and memory space access if available
10740 call pcibios_init_sel_reg
10741 mov dx, #0x0cfc
10742 in al, dx
10743 or al, #0x07
10744 out dx, al
10745#ifdef VBOX
10746 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10747 call pcibios_init_sel_reg
10748 mov dx, #0x0cfc
10749 in eax, dx
10750 cmp eax, #0x20001022
10751 jne next_pci_dev
10752 mov dl, #0x10 ;; get I/O address
10753 call pcibios_init_sel_reg
10754 mov dx, #0x0cfc
10755 in ax, dx
10756 and ax, #0xfffc
10757 mov cx, ax
10758 mov dx, cx
10759 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10760 in ax, dx ;; reset is performed by reading the reset register
10761 mov dx, cx
10762 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10763 in eax, dx ;; reset is performed by reading the reset register
10764#endif /* VBOX */
10765next_pci_dev:
10766 mov byte ptr[bp-8], #0x10
10767 inc bx
10768 cmp bx, #0x0100
10769 jne pci_init_io_loop1
10770 mov sp, bp
10771 pop bp
10772 ret
10773
10774pcibios_init_set_elcr:
10775 push ax
10776 push cx
10777 mov dx, #0x04d0
10778 test al, #0x08
10779 jz is_master_pic
10780 inc dx
10781 and al, #0x07
10782is_master_pic:
10783 mov cl, al
10784 mov bl, #0x01
10785 shl bl, cl
10786 in al, dx
10787 or al, bl
10788 out dx, al
10789 pop cx
10790 pop ax
10791 ret
10792
10793pcibios_init_irqs:
10794 push ds
10795 push bp
10796 mov ax, #0xf000
10797 mov ds, ax
10798 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10799 mov al, #0x00
10800 out dx, al
10801 inc dx
10802 out dx, al
10803 mov si, #pci_routing_table_structure
10804 mov bh, [si+8]
10805 mov bl, [si+9]
10806 mov dl, #0x00
10807 call pcibios_init_sel_reg
10808 mov dx, #0x0cfc
10809 in eax, dx
10810 cmp eax, [si+12] ;; check irq router
10811 jne pci_init_end
10812 mov dl, [si+34]
10813 call pcibios_init_sel_reg
10814 push bx ;; save irq router bus + devfunc
10815 mov dx, #0x0cfc
10816 mov ax, #0x8080
10817 out dx, ax ;; reset PIRQ route control
10818 add dx, #2
10819 out dx, ax
10820 mov ax, [si+6]
10821 sub ax, #0x20
10822 shr ax, #4
10823 mov cx, ax
10824 add si, #0x20 ;; set pointer to 1st entry
10825 mov bp, sp
10826 mov ax, #pci_irq_list
10827 push ax
10828 xor ax, ax
10829 push ax
10830pci_init_irq_loop1:
10831 mov bh, [si]
10832 mov bl, [si+1]
10833pci_init_irq_loop2:
10834 mov dl, #0x00
10835 call pcibios_init_sel_reg
10836 mov dx, #0x0cfc
10837 in ax, dx
10838 cmp ax, #0xffff
10839 jnz pci_test_int_pin
10840 test bl, #0x07
10841 jz next_pir_entry
10842 jmp next_pci_func
10843pci_test_int_pin:
10844 mov dl, #0x3c
10845 call pcibios_init_sel_reg
10846 mov dx, #0x0cfd
10847 in al, dx
10848 and al, #0x07
10849 jz next_pci_func
10850 dec al ;; determine pirq reg
10851 mov dl, #0x03
10852 mul al, dl
10853 add al, #0x02
10854 xor ah, ah
10855 mov bx, ax
10856 mov al, [si+bx]
10857 mov dl, al
10858 mov bx, [bp]
10859 call pcibios_init_sel_reg
10860 mov dx, #0x0cfc
10861 and al, #0x03
10862 add dl, al
10863 in al, dx
10864 cmp al, #0x80
10865 jb pirq_found
10866 mov bx, [bp-2] ;; pci irq list pointer
10867 mov al, [bx]
10868 out dx, al
10869 inc bx
10870 mov [bp-2], bx
10871 call pcibios_init_set_elcr
10872pirq_found:
10873 mov bh, [si]
10874 mov bl, [si+1]
10875 add bl, [bp-3] ;; pci function number
10876 mov dl, #0x3c
10877 call pcibios_init_sel_reg
10878 mov dx, #0x0cfc
10879 out dx, al
10880next_pci_func:
10881 inc byte ptr[bp-3]
10882 inc bl
10883 test bl, #0x07
10884 jnz pci_init_irq_loop2
10885next_pir_entry:
10886 add si, #0x10
10887 mov byte ptr[bp-3], #0x00
10888 loop pci_init_irq_loop1
10889 mov sp, bp
10890 pop bx
10891pci_init_end:
10892 pop bp
10893 pop ds
10894 ret
10895#endif // !BX_ROMBIOS32
10896#endif // BX_PCIBIOS
10897
10898#if BX_ROMBIOS32
10899rombios32_init:
10900 ;; save a20 and enable it
10901 in al, 0x92
10902 push ax
10903 or al, #0x02
10904 out 0x92, al
10905
10906 ;; save SS:SP to the BDA
10907 xor ax, ax
10908 mov ds, ax
10909 mov 0x0469, ss
10910 mov 0x0467, sp
10911
10912 SEG CS
10913 lidt [pmode_IDT_info]
10914 SEG CS
10915 lgdt [rombios32_gdt_48]
10916 ;; set PE bit in CR0
10917 mov eax, cr0
10918 or al, #0x01
10919 mov cr0, eax
10920 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10921 db 0x66, 0xea
10922 dw rombios32_05
10923 dw 0x000f ;; high 16 bit address
10924 dw 0x0010
10925
10926use32 386
10927rombios32_05:
10928 ;; init data segments
10929 mov eax, #0x18
10930 mov ds, ax
10931 mov es, ax
10932 mov ss, ax
10933 xor eax, eax
10934 mov fs, ax
10935 mov gs, ax
10936 cld
10937
10938 ;; copy rombios32 code to ram (ram offset = 1MB)
10939 mov esi, #0xfffe0000
10940 mov edi, #0x00040000
10941 mov ecx, #0x10000 / 4
10942 rep
10943 movsd
10944
10945 ;; init the stack pointer
10946 mov esp, #0x00080000
10947
10948 ;; call rombios32 code
10949 mov eax, #0x00040000
10950 call eax
10951
10952 ;; return to 16 bit protected mode first
10953 db 0xea
10954 dd rombios32_10
10955 dw 0x20
10956
10957use16 386
10958rombios32_10:
10959 ;; restore data segment limits to 0xffff
10960 mov ax, #0x28
10961 mov ds, ax
10962 mov es, ax
10963 mov ss, ax
10964 mov fs, ax
10965 mov gs, ax
10966
10967 ;; reset PE bit in CR0
10968 mov eax, cr0
10969 and al, #0xFE
10970 mov cr0, eax
10971
10972 ;; far jump to flush CPU queue after transition to real mode
10973 JMP_AP(0xf000, rombios32_real_mode)
10974
10975rombios32_real_mode:
10976 ;; restore IDT to normal real-mode defaults
10977 SEG CS
10978 lidt [rmode_IDT_info]
10979
10980 xor ax, ax
10981 mov ds, ax
10982 mov es, ax
10983 mov fs, ax
10984 mov gs, ax
10985
10986 ;; restore SS:SP from the BDA
10987 mov ss, 0x0469
10988 xor esp, esp
10989 mov sp, 0x0467
10990 ;; restore a20
10991 pop ax
10992 out 0x92, al
10993 ret
10994
10995rombios32_gdt_48:
10996 dw 0x30
10997 dw rombios32_gdt
10998 dw 0x000f
10999
11000rombios32_gdt:
11001 dw 0, 0, 0, 0
11002 dw 0, 0, 0, 0
11003 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11004 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11005 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11006 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11007#endif // BX_ROMBIOS32
11008
11009
11010; parallel port detection: base address in DX, index in BX, timeout in CL
11011detect_parport:
11012 push dx
11013 add dx, #2
11014 in al, dx
11015 and al, #0xdf ; clear input mode
11016 out dx, al
11017 pop dx
11018 mov al, #0xaa
11019 out dx, al
11020 in al, dx
11021 cmp al, #0xaa
11022 jne no_parport
11023 push bx
11024 shl bx, #1
11025 mov [bx+0x408], dx ; Parallel I/O address
11026 pop bx
11027 mov [bx+0x478], cl ; Parallel printer timeout
11028 inc bx
11029no_parport:
11030 ret
11031
11032; serial port detection: base address in DX, index in BX, timeout in CL
11033detect_serial:
11034 push dx
11035 inc dx
11036 mov al, #0x02
11037 out dx, al
11038 in al, dx
11039 cmp al, #0x02
11040 jne no_serial
11041 inc dx
11042 in al, dx
11043 cmp al, #0x02
11044 jne no_serial
11045 dec dx
11046 xor al, al
11047 out dx, al
11048 pop dx
11049 push bx
11050 shl bx, #1
11051 mov [bx+0x400], dx ; Serial I/O address
11052 pop bx
11053 mov [bx+0x47c], cl ; Serial timeout
11054 inc bx
11055 ret
11056no_serial:
11057 pop dx
11058 ret
11059
11060rom_checksum:
11061 push ax
11062 push bx
11063 push cx
11064 xor ax, ax
11065 xor bx, bx
11066 xor cx, cx
11067 mov ch, [2]
11068 shl cx, #1
11069checksum_loop:
11070 add al, [bx]
11071 inc bx
11072 loop checksum_loop
11073 and al, #0xff
11074 pop cx
11075 pop bx
11076 pop ax
11077 ret
11078
11079rom_scan:
11080 ;; Scan for existence of valid expansion ROMS.
11081 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11082 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11083 ;; System ROM: only 0xE0000
11084 ;;
11085 ;; Header:
11086 ;; Offset Value
11087 ;; 0 0x55
11088 ;; 1 0xAA
11089 ;; 2 ROM length in 512-byte blocks
11090 ;; 3 ROM initialization entry point (FAR CALL)
11091
11092 mov cx, #0xc000
11093rom_scan_loop:
11094 mov ds, cx
11095 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11096 cmp [0], #0xAA55 ;; look for signature
11097 jne rom_scan_increment
11098 call rom_checksum
11099 jnz rom_scan_increment
11100 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11101
11102 ;; We want our increment in 512-byte quantities, rounded to
11103 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11104 test al, #0x03
11105 jz block_count_rounded
11106 and al, #0xfc ;; needs rounding up
11107 add al, #0x04
11108block_count_rounded:
11109
11110 xor bx, bx ;; Restore DS back to 0000:
11111 mov ds, bx
11112 push ax ;; Save AX
11113 ;; Push addr of ROM entry point
11114 push cx ;; Push seg
11115 push #0x0003 ;; Push offset
11116 mov bp, sp ;; Call ROM init routine using seg:off on stack
11117 db 0xff ;; call_far ss:[bp+0]
11118 db 0x5e
11119 db 0
11120 cli ;; In case expansion ROM BIOS turns IF on
11121 add sp, #2 ;; Pop offset value
11122 pop cx ;; Pop seg value (restore CX)
11123 pop ax ;; Restore AX
11124rom_scan_increment:
11125 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11126 ;; because the segment selector is shifted left 4 bits.
11127 add cx, ax
11128 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11129 jbe rom_scan_loop
11130
11131 xor ax, ax ;; Restore DS back to 0000:
11132 mov ds, ax
11133 ret
11134
11135;; for 'C' strings and other data, insert them here with
11136;; a the following hack:
11137;; DATA_SEG_DEFS_HERE
11138
11139
11140;; the following area can be used to write dynamically generated tables
11141 .align 16
11142bios_table_area_start:
11143 dd 0xaafb4442
11144 dd bios_table_area_end - bios_table_area_start - 8;
11145
11146;--------
11147;- POST -
11148;--------
11149.org 0xe05b ; POST Entry Point
11150bios_table_area_end:
11151post:
11152
11153 xor ax, ax
11154
11155 ;; first reset the DMA controllers
11156 out 0x0d,al
11157 out 0xda,al
11158
11159 ;; then initialize the DMA controllers
11160 mov al, #0xC0
11161 out 0xD6, al ; cascade mode of channel 4 enabled
11162 mov al, #0x00
11163 out 0xD4, al ; unmask channel 4
11164
11165 ;; Examine CMOS shutdown status.
11166 mov AL, #0x0f
11167 out 0x70, AL
11168 in AL, 0x71
11169
11170 ;; backup status
11171 mov bl, al
11172
11173 ;; Reset CMOS shutdown status.
11174 mov AL, #0x0f
11175 out 0x70, AL ; select CMOS register Fh
11176 mov AL, #0x00
11177 out 0x71, AL ; set shutdown action to normal
11178
11179 ;; Examine CMOS shutdown status.
11180 mov al, bl
11181
11182 ;; 0x00, 0x09, 0x0D+ = normal startup
11183 cmp AL, #0x00
11184 jz normal_post
11185 cmp AL, #0x0d
11186 jae normal_post
11187 cmp AL, #0x09
11188 je normal_post
11189
11190 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11191 cmp al, #0x05
11192 je eoi_jmp_post
11193
11194 ;; Examine CMOS shutdown status.
11195 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11196 push bx
11197 call _shutdown_status_panic
11198
11199#if 0
11200 HALT(__LINE__)
11201 ;
11202 ;#if 0
11203 ; 0xb0, 0x20, /* mov al, #0x20 */
11204 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11205 ;#endif
11206 ;
11207 pop es
11208 pop ds
11209 popa
11210 iret
11211#endif
11212
11213normal_post:
11214 ; case 0: normal startup
11215
11216 cli
11217 mov ax, #0xfffe
11218 mov sp, ax
11219 xor ax, ax
11220 mov ds, ax
11221 mov ss, ax
11222
11223#ifndef VBOX
11224 ;; zero out BIOS data area (40:00..40:ff)
11225 mov es, ax
11226 mov cx, #0x0080 ;; 128 words
11227 mov di, #0x0400
11228 cld
11229 rep
11230 stosw
11231#else /* VBOX */
11232 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11233 mov es, ax
11234 xor di, di
11235 cld
11236 mov cx, #0x0239 ;; 569 words
11237 rep
11238 stosw
11239 inc di
11240 inc di
11241 mov cx, #0x7dc6 ;; 32198 words
11242 rep
11243 stosw
11244 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11245 ;; because we store the MP table there
11246 xor eax, eax
11247 xor bx, bx
11248memory_zero_loop:
11249 add bx, #0x1000
11250 cmp bx, #0x9000
11251 jae memory_cleared
11252 mov es, bx
11253 xor di, di
11254 mov cx, #0x4000
11255 rep
11256 stosd
11257 jmp memory_zero_loop
11258memory_cleared:
11259 mov es, bx
11260 xor di, di
11261 mov cx, #0x3f00
11262 rep
11263 stosd
11264 xor bx, bx
11265#endif
11266
11267 call _log_bios_start
11268
11269 ;; set all interrupts to default handler
11270 xor bx, bx ;; offset index
11271 mov cx, #0x0100 ;; counter (256 interrupts)
11272 mov ax, #dummy_iret_handler
11273 mov dx, #0xF000
11274
11275post_default_ints:
11276 mov [bx], ax
11277 add bx, #2
11278 mov [bx], dx
11279 add bx, #2
11280 loop post_default_ints
11281
11282 ;; set vector 0x79 to zero
11283 ;; this is used by 'gardian angel' protection system
11284 SET_INT_VECTOR(0x79, #0, #0)
11285
11286 ;; base memory in K 40:13 (word)
11287 mov ax, #BASE_MEM_IN_K
11288 mov 0x0413, ax
11289
11290
11291 ;; Manufacturing Test 40:12
11292 ;; zerod out above
11293
11294#ifndef VBOX
11295 ;; Warm Boot Flag 0040:0072
11296 ;; value of 1234h = skip memory checks
11297 ;; zerod out above
11298#endif /* !VBOX */
11299
11300
11301 ;; Printer Services vector
11302 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11303
11304 ;; Bootstrap failure vector
11305 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11306
11307 ;; Bootstrap Loader vector
11308 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11309
11310 ;; User Timer Tick vector
11311 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11312
11313 ;; Memory Size Check vector
11314 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11315
11316 ;; Equipment Configuration Check vector
11317 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11318
11319 ;; System Services
11320 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11321
11322 ;; EBDA setup
11323 call ebda_post
11324
11325 ;; PIT setup
11326 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11327 ;; int 1C already points at dummy_iret_handler (above)
11328 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11329 out 0x43, al
11330 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11331 out 0x40, al
11332 out 0x40, al
11333
11334 ;; Keyboard
11335 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11336 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11337
11338 xor ax, ax
11339 mov ds, ax
11340 mov 0x0417, al /* keyboard shift flags, set 1 */
11341 mov 0x0418, al /* keyboard shift flags, set 2 */
11342 mov 0x0419, al /* keyboard alt-numpad work area */
11343 mov 0x0471, al /* keyboard ctrl-break flag */
11344 mov 0x0497, al /* keyboard status flags 4 */
11345 mov al, #0x10
11346 mov 0x0496, al /* keyboard status flags 3 */
11347
11348
11349 /* keyboard head of buffer pointer */
11350 mov bx, #0x001E
11351 mov 0x041A, bx
11352
11353 /* keyboard end of buffer pointer */
11354 mov 0x041C, bx
11355
11356 /* keyboard pointer to start of buffer */
11357 mov bx, #0x001E
11358 mov 0x0480, bx
11359
11360 /* keyboard pointer to end of buffer */
11361 mov bx, #0x003E
11362 mov 0x0482, bx
11363
11364 /* init the keyboard */
11365 call _keyboard_init
11366
11367 ;; mov CMOS Equipment Byte to BDA Equipment Word
11368 mov ax, 0x0410
11369 mov al, #0x14
11370 out 0x70, al
11371 in al, 0x71
11372 mov 0x0410, ax
11373
11374
11375 ;; Parallel setup
11376 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11377 xor ax, ax
11378 mov ds, ax
11379 xor bx, bx
11380 mov cl, #0x14 ; timeout value
11381 mov dx, #0x378 ; Parallel I/O address, port 1
11382 call detect_parport
11383 mov dx, #0x278 ; Parallel I/O address, port 2
11384 call detect_parport
11385 shl bx, #0x0e
11386 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
11387 and ax, #0x3fff
11388 or ax, bx ; set number of parallel ports
11389 mov 0x410, ax
11390
11391 ;; Serial setup
11392 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11393 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11394 xor bx, bx
11395 mov cl, #0x0a ; timeout value
11396 mov dx, #0x03f8 ; Serial I/O address, port 1
11397 call detect_serial
11398 mov dx, #0x02f8 ; Serial I/O address, port 2
11399 call detect_serial
11400 mov dx, #0x03e8 ; Serial I/O address, port 3
11401 call detect_serial
11402 mov dx, #0x02e8 ; Serial I/O address, port 4
11403 call detect_serial
11404 shl bx, #0x09
11405 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11406 and ax, #0xf1ff
11407 or ax, bx ; set number of serial port
11408 mov 0x410, ax
11409
11410 ;; CMOS RTC
11411 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11412 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11413 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11414 ;; BIOS DATA AREA 0x4CE ???
11415 call timer_tick_post
11416
11417 ;; PS/2 mouse setup
11418 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11419
11420 ;; IRQ13 (FPU exception) setup
11421 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11422
11423 ;; Video setup
11424 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11425
11426#ifdef VBOX
11427 ;; moved the PIC initialization to another place as we need
11428 ;; some space for additions init calls. Otherwise this code
11429 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11430 call init_pic
11431#else /* !VBOX */
11432 ;; PIC
11433 mov al, #0x11 ; send initialisation commands
11434 out 0x20, al
11435 out 0xa0, al
11436 mov al, #0x08
11437 out 0x21, al
11438 mov al, #0x70
11439 out 0xa1, al
11440 mov al, #0x04
11441 out 0x21, al
11442 mov al, #0x02
11443 out 0xa1, al
11444 mov al, #0x01
11445 out 0x21, al
11446 out 0xa1, al
11447 mov al, #0xb8
11448 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11449#if BX_USE_PS2_MOUSE
11450 mov al, #0x8f
11451#else
11452 mov al, #0x9f
11453#endif
11454 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11455#endif /* !VBOX */
11456
11457#if BX_ROMBIOS32
11458 call rombios32_init
11459#else
11460 call pcibios_init_iomem_bases
11461 call pcibios_init_irqs
11462#endif
11463 call rom_scan
11464
11465#if BX_USE_ATADRV
11466 ;;
11467 ;; ATA/ATAPI driver setup
11468 ;;
11469 call _ata_init
11470 call _ata_detect
11471 ;;
11472#endif
11473
11474#ifdef VBOX_WITH_SCSI
11475 ;;
11476 ;; SCSI driver setup
11477 ;;
11478 call _scsi_init
11479 ;;
11480#endif
11481
11482 call _print_bios_banner
11483
11484 ;;
11485 ;; Floppy setup
11486 ;;
11487 call floppy_drive_post
11488
11489 ;;
11490 ;; Hard Drive setup
11491 ;;
11492 call hard_drive_post
11493
11494#if BX_ELTORITO_BOOT
11495 ;;
11496 ;; eltorito floppy/harddisk emulation from cd
11497 ;;
11498 call _cdemu_init
11499 ;;
11500#endif // BX_ELTORITO_BOOT
11501
11502 sti ;; enable interrupts
11503 int #0x19
11504
11505.org 0xe2c3 ; NMI Handler Entry Point
11506nmi:
11507 ;; FIXME the NMI handler should not panic
11508 ;; but iret when called from int75 (fpu exception)
11509 call _nmi_handler_msg
11510 iret
11511
11512int75_handler:
11513 out 0xf0, al // clear irq13
11514 call eoi_both_pics // clear interrupt
11515 int 2 // legacy nmi call
11516 iret
11517
11518;-------------------------------------------
11519;- INT 13h Fixed Disk Services Entry Point -
11520;-------------------------------------------
11521.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11522int13_handler:
11523 //JMPL(int13_relocated)
11524 jmp int13_relocated
11525
11526.org 0xe401 ; Fixed Disk Parameter Table
11527
11528;----------
11529;- INT19h -
11530;----------
11531.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11532int19_handler:
11533
11534 jmp int19_relocated
11535;-------------------------------------------
11536;- System BIOS Configuration Data Table
11537;-------------------------------------------
11538.org BIOS_CONFIG_TABLE
11539db 0x08 ; Table size (bytes) -Lo
11540db 0x00 ; Table size (bytes) -Hi
11541db SYS_MODEL_ID
11542db SYS_SUBMODEL_ID
11543db BIOS_REVISION
11544; Feature byte 1
11545; b7: 1=DMA channel 3 used by hard disk
11546; b6: 1=2 interrupt controllers present
11547; b5: 1=RTC present
11548; b4: 1=BIOS calls int 15h/4Fh every key
11549; b3: 1=wait for extern event supported (Int 15h/41h)
11550; b2: 1=extended BIOS data area used
11551; b1: 0=AT or ESDI bus, 1=MicroChannel
11552; b0: 1=Dual bus (MicroChannel + ISA)
11553db (0 << 7) | \
11554 (1 << 6) | \
11555 (1 << 5) | \
11556 (BX_CALL_INT15_4F << 4) | \
11557 (0 << 3) | \
11558 (BX_USE_EBDA << 2) | \
11559 (0 << 1) | \
11560 (0 << 0)
11561; Feature byte 2
11562; b7: 1=32-bit DMA supported
11563; b6: 1=int16h, function 9 supported
11564; b5: 1=int15h/C6h (get POS data) supported
11565; b4: 1=int15h/C7h (get mem map info) supported
11566; b3: 1=int15h/C8h (en/dis CPU) supported
11567; b2: 1=non-8042 kb controller
11568; b1: 1=data streaming supported
11569; b0: reserved
11570db (0 << 7) | \
11571 (1 << 6) | \
11572 (0 << 5) | \
11573 (0 << 4) | \
11574 (0 << 3) | \
11575 (0 << 2) | \
11576 (0 << 1) | \
11577 (0 << 0)
11578; Feature byte 3
11579; b7: not used
11580; b6: reserved
11581; b5: reserved
11582; b4: POST supports ROM-to-RAM enable/disable
11583; b3: SCSI on system board
11584; b2: info panel installed
11585; b1: Initial Machine Load (IML) system - BIOS on disk
11586; b0: SCSI supported in IML
11587db 0x00
11588; Feature byte 4
11589; b7: IBM private
11590; b6: EEPROM present
11591; b5-3: ABIOS presence (011 = not supported)
11592; b2: private
11593; b1: memory split above 16Mb supported
11594; b0: POSTEXT directly supported by POST
11595db 0x00
11596; Feature byte 5 (IBM)
11597; b1: enhanced mouse
11598; b0: flash EPROM
11599db 0x00
11600
11601
11602
11603.org 0xe729 ; Baud Rate Generator Table
11604
11605;----------
11606;- INT14h -
11607;----------
11608.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11609int14_handler:
11610 push ds
11611 pusha
11612 xor ax, ax
11613 mov ds, ax
11614 call _int14_function
11615 popa
11616 pop ds
11617 iret
11618
11619
11620;----------------------------------------
11621;- INT 16h Keyboard Service Entry Point -
11622;----------------------------------------
11623.org 0xe82e
11624int16_handler:
11625
11626 sti
11627 push ds
11628 pushf
11629 pusha
11630
11631 cmp ah, #0x00
11632 je int16_F00
11633 cmp ah, #0x10
11634 je int16_F00
11635
11636 mov bx, #0xf000
11637 mov ds, bx
11638 call _int16_function
11639 popa
11640 popf
11641 pop ds
11642 jz int16_zero_set
11643
11644int16_zero_clear:
11645 push bp
11646 mov bp, sp
11647 //SEG SS
11648 and BYTE [bp + 0x06], #0xbf
11649 pop bp
11650 iret
11651
11652int16_zero_set:
11653 push bp
11654 mov bp, sp
11655 //SEG SS
11656 or BYTE [bp + 0x06], #0x40
11657 pop bp
11658 iret
11659
11660int16_F00:
11661 mov bx, #0x0040
11662 mov ds, bx
11663
11664int16_wait_for_key:
11665 cli
11666 mov bx, 0x001a
11667 cmp bx, 0x001c
11668 jne int16_key_found
11669 sti
11670 nop
11671#if 0
11672 /* no key yet, call int 15h, function AX=9002 */
11673 0x50, /* push AX */
11674 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11675 0xcd, 0x15, /* int 15h */
11676 0x58, /* pop AX */
11677 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11678#endif
11679 jmp int16_wait_for_key
11680
11681int16_key_found:
11682 mov bx, #0xf000
11683 mov ds, bx
11684 call _int16_function
11685 popa
11686 popf
11687 pop ds
11688#if 0
11689 /* notify int16 complete w/ int 15h, function AX=9102 */
11690 0x50, /* push AX */
11691 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11692 0xcd, 0x15, /* int 15h */
11693 0x58, /* pop AX */
11694#endif
11695 iret
11696
11697
11698
11699;-------------------------------------------------
11700;- INT09h : Keyboard Hardware Service Entry Point -
11701;-------------------------------------------------
11702.org 0xe987
11703int09_handler:
11704 cli
11705 push ax
11706
11707 mov al, #0xAD ;;disable keyboard
11708 out #0x64, al
11709
11710 mov al, #0x0B
11711 out #0x20, al
11712 in al, #0x20
11713 and al, #0x02
11714 jz int09_finish
11715
11716 in al, #0x60 ;;read key from keyboard controller
11717 sti
11718 push ds
11719 pusha
11720#ifdef BX_CALL_INT15_4F
11721 mov ah, #0x4f ;; allow for keyboard intercept
11722 stc
11723 int #0x15
11724 jnc int09_done
11725#endif
11726
11727 ;; check for extended key
11728 cmp al, #0xe0
11729 jne int09_check_pause
11730 xor ax, ax
11731 mov ds, ax
11732 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11733 or al, #0x02
11734 mov BYTE [0x496], al
11735 jmp int09_done
11736
11737int09_check_pause: ;; check for pause key
11738 cmp al, #0xe1
11739 jne int09_process_key
11740 xor ax, ax
11741 mov ds, ax
11742 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11743 or al, #0x01
11744 mov BYTE [0x496], al
11745 jmp int09_done
11746
11747int09_process_key:
11748 mov bx, #0xf000
11749 mov ds, bx
11750 call _int09_function
11751
11752int09_done:
11753 popa
11754 pop ds
11755 cli
11756 call eoi_master_pic
11757
11758int09_finish:
11759 mov al, #0xAE ;;enable keyboard
11760 out #0x64, al
11761 pop ax
11762 iret
11763
11764
11765;----------------------------------------
11766;- INT 13h Diskette Service Entry Point -
11767;----------------------------------------
11768.org 0xec59
11769int13_diskette:
11770 jmp int13_noeltorito
11771
11772;---------------------------------------------
11773;- INT 0Eh Diskette Hardware ISR Entry Point -
11774;---------------------------------------------
11775.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11776int0e_handler:
11777 push ax
11778 push dx
11779 mov dx, #0x03f4
11780 in al, dx
11781 and al, #0xc0
11782 cmp al, #0xc0
11783 je int0e_normal
11784 mov dx, #0x03f5
11785 mov al, #0x08 ; sense interrupt status
11786 out dx, al
11787int0e_loop1:
11788 mov dx, #0x03f4
11789 in al, dx
11790 and al, #0xc0
11791 cmp al, #0xc0
11792 jne int0e_loop1
11793int0e_loop2:
11794 mov dx, #0x03f5
11795 in al, dx
11796 mov dx, #0x03f4
11797 in al, dx
11798 and al, #0xc0
11799 cmp al, #0xc0
11800 je int0e_loop2
11801int0e_normal:
11802 push ds
11803 xor ax, ax ;; segment 0000
11804 mov ds, ax
11805 call eoi_master_pic
11806 mov al, 0x043e
11807 or al, #0x80 ;; diskette interrupt has occurred
11808 mov 0x043e, al
11809 pop ds
11810 pop dx
11811 pop ax
11812 iret
11813
11814
11815.org 0xefc7 ; Diskette Controller Parameter Table
11816diskette_param_table:
11817;; Since no provisions are made for multiple drive types, most
11818;; values in this table are ignored. I set parameters for 1.44M
11819;; floppy here
11820db 0xAF
11821db 0x02 ;; head load time 0000001, DMA used
11822db 0x25
11823db 0x02
11824db 18
11825db 0x1B
11826db 0xFF
11827db 0x6C
11828db 0xF6
11829db 0x0F
11830db 0x08
11831
11832
11833;----------------------------------------
11834;- INT17h : Printer Service Entry Point -
11835;----------------------------------------
11836.org 0xefd2
11837int17_handler:
11838 push ds
11839 pusha
11840 xor ax, ax
11841 mov ds, ax
11842 call _int17_function
11843 popa
11844 pop ds
11845 iret
11846
11847diskette_param_table2:
11848;; New diskette parameter table adding 3 parameters from IBM
11849;; Since no provisions are made for multiple drive types, most
11850;; values in this table are ignored. I set parameters for 1.44M
11851;; floppy here
11852db 0xAF
11853db 0x02 ;; head load time 0000001, DMA used
11854db 0x25
11855db 0x02
11856db 18
11857db 0x1B
11858db 0xFF
11859db 0x6C
11860db 0xF6
11861db 0x0F
11862db 0x08
11863db 79 ;; maximum track
11864db 0 ;; data transfer rate
11865db 4 ;; drive type in cmos
11866
11867.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11868 HALT(__LINE__)
11869 iret
11870
11871;----------
11872;- INT10h -
11873;----------
11874.org 0xf065 ; INT 10h Video Support Service Entry Point
11875int10_handler:
11876 ;; dont do anything, since the VGA BIOS handles int10h requests
11877 iret
11878
11879.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11880
11881;----------
11882;- INT12h -
11883;----------
11884.org 0xf841 ; INT 12h Memory Size Service Entry Point
11885; ??? different for Pentium (machine check)?
11886int12_handler:
11887 push ds
11888 mov ax, #0x0040
11889 mov ds, ax
11890 mov ax, 0x0013
11891 pop ds
11892 iret
11893
11894;----------
11895;- INT11h -
11896;----------
11897.org 0xf84d ; INT 11h Equipment List Service Entry Point
11898int11_handler:
11899 push ds
11900 mov ax, #0x0040
11901 mov ds, ax
11902 mov ax, 0x0010
11903 pop ds
11904 iret
11905
11906;----------
11907;- INT15h -
11908;----------
11909.org 0xf859 ; INT 15h System Services Entry Point
11910int15_handler:
11911 pushf
11912#if BX_APM
11913 cmp ah, #0x53
11914 je apm_call
11915#endif
11916 push ds
11917 push es
11918 cmp ah, #0x86
11919 je int15_handler32
11920 cmp ah, #0xE8
11921 je int15_handler32
11922 pusha
11923#if BX_USE_PS2_MOUSE
11924 cmp ah, #0xC2
11925 je int15_handler_mouse
11926#endif
11927 call _int15_function
11928int15_handler_mouse_ret:
11929 popa
11930int15_handler32_ret:
11931 pop es
11932 pop ds
11933 popf
11934 jmp iret_modify_cf
11935#if BX_APM
11936apm_call:
11937 jmp _apmreal_entry
11938#endif
11939
11940#if BX_USE_PS2_MOUSE
11941int15_handler_mouse:
11942 call _int15_function_mouse
11943 jmp int15_handler_mouse_ret
11944#endif
11945
11946int15_handler32:
11947 pushad
11948 call _int15_function32
11949 popad
11950 jmp int15_handler32_ret
11951
11952;; Protected mode IDT descriptor
11953;;
11954;; I just make the limit 0, so the machine will shutdown
11955;; if an exception occurs during protected mode memory
11956;; transfers.
11957;;
11958;; Set base to f0000 to correspond to beginning of BIOS,
11959;; in case I actually define an IDT later
11960;; Set limit to 0
11961
11962pmode_IDT_info:
11963dw 0x0000 ;; limit 15:00
11964dw 0x0000 ;; base 15:00
11965db 0x0f ;; base 23:16
11966
11967;; Real mode IDT descriptor
11968;;
11969;; Set to typical real-mode values.
11970;; base = 000000
11971;; limit = 03ff
11972
11973rmode_IDT_info:
11974dw 0x03ff ;; limit 15:00
11975dw 0x0000 ;; base 15:00
11976db 0x00 ;; base 23:16
11977
11978;;
11979;; Handler for unexpected hardware interrupts
11980;;
11981dummy_isr:
11982 push ds
11983 pushad
11984 xor ax, ax
11985 mov ds, ax
11986 call _dummy_isr_function
11987 popad
11988 pop ds
11989 iret
11990
11991;----------
11992;- INT1Ah -
11993;----------
11994.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
11995int1a_handler:
11996#if BX_PCIBIOS
11997 cmp ah, #0xb1
11998 jne int1a_normal
11999 call pcibios_real
12000 jc pcibios_error
12001 retf 2
12002pcibios_error:
12003 mov bl, ah
12004 mov ah, #0xb1
12005 push ds
12006 pusha
12007 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12008 mov ds, ax ; on 16bit protected mode.
12009 jmp int1a_callfunction
12010int1a_normal:
12011#endif
12012 push ds
12013 pusha
12014 xor ax, ax
12015 mov ds, ax
12016int1a_callfunction:
12017 call _int1a_function
12018 popa
12019 pop ds
12020 iret
12021
12022;;
12023;; int70h: IRQ8 - CMOS RTC
12024;;
12025int70_handler:
12026 push ds
12027 pushad
12028 xor ax, ax
12029 mov ds, ax
12030 call _int70_function
12031 popad
12032 pop ds
12033 iret
12034
12035;---------
12036;- INT08 -
12037;---------
12038.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12039int08_handler:
12040 sti
12041 push eax
12042 push ds
12043 xor ax, ax
12044 mov ds, ax
12045
12046 ;; time to turn off drive(s)?
12047 mov al,0x0440
12048 or al,al
12049 jz int08_floppy_off
12050 dec al
12051 mov 0x0440,al
12052 jnz int08_floppy_off
12053 ;; turn motor(s) off
12054 push dx
12055 mov dx,#0x03f2
12056 in al,dx
12057 and al,#0xcf
12058 out dx,al
12059 pop dx
12060int08_floppy_off:
12061
12062 mov eax, 0x046c ;; get ticks dword
12063 inc eax
12064
12065 ;; compare eax to one days worth of timer ticks at 18.2 hz
12066 cmp eax, #0x001800B0
12067 jb int08_store_ticks
12068 ;; there has been a midnight rollover at this point
12069 xor eax, eax ;; zero out counter
12070 inc BYTE 0x0470 ;; increment rollover flag
12071
12072int08_store_ticks:
12073 mov 0x046c, eax ;; store new ticks dword
12074 ;; chain to user timer tick INT #0x1c
12075 //pushf
12076 //;; call_ep [ds:loc]
12077 //CALL_EP( 0x1c << 2 )
12078 int #0x1c
12079 cli
12080 call eoi_master_pic
12081 pop ds
12082 pop eax
12083 iret
12084
12085.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12086
12087
12088.org 0xff00
12089.ascii BIOS_COPYRIGHT_STRING
12090
12091#ifdef VBOX
12092// The SMBIOS header
12093.org 0xff30
12094.align 16
12095 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12096 db 0x00 ; checksum (set by biossums)
12097 db 0x1f ; EPS length, defined by standard
12098 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12099 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12100 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12101 db 0x00 ; Entry point revision
12102 db 0x00, 0x00, 0x00, 0x00, 0x00
12103
12104// The DMI header
12105 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12106 db 0x00 ; checksum (set by biossums)
12107 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12108 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12109 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12110 db VBOX_DMI_TABLE_VER ; DMI version
12111 db 0x00 ; Just for alignment
12112#endif
12113
12114;------------------------------------------------
12115;- IRET Instruction for Dummy Interrupt Handler -
12116;------------------------------------------------
12117.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12118dummy_iret_handler:
12119 iret
12120
12121.org 0xff54 ; INT 05h Print Screen Service Entry Point
12122 HALT(__LINE__)
12123 iret
12124
12125.org 0xfff0 ; Power-up Entry Point
12126 jmp 0xf000:post
12127
12128.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12129.ascii BIOS_BUILD_DATE
12130
12131.org 0xfffe ; System Model ID
12132db SYS_MODEL_ID
12133db 0x00 ; filler
12134
12135.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12136ASM_END
12137/*
12138 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12139 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12140 * This font is public domain
12141 */
12142static Bit8u vgafont8[128*8]=
12143{
12144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12145 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12146 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12147 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12148 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12149 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12150 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12151 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12152 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12153 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12154 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12155 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12156 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12157 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12158 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12159 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12160 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12161 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12162 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12163 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12164 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12165 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12166 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12167 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12168 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12169 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12170 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12171 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12172 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12173 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12174 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12175 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12177 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12178 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12179 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12180 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12181 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12182 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12183 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12184 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12185 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12186 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12187 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12188 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12189 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12190 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12191 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12192 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12193 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12194 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12195 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12196 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12197 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12198 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12199 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12200 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12201 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12202 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12203 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12204 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12205 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12206 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12207 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12208 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12209 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12210 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12211 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12212 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12213 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12214 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12215 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12216 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12217 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12218 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12219 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12220 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12221 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12222 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12223 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12224 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12225 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12226 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12227 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12228 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12229 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12230 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12231 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12232 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12233 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12234 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12235 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12236 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12237 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12238 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12240 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12241 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12242 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12243 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12244 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12245 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12246 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12247 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12248 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12249 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12250 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12251 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12252 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12253 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12254 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12255 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12256 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12257 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12258 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12259 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12260 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12261 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12262 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12263 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12264 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12265 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12266 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12267 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12268 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12269 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12270 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12271 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12272};
12273
12274ASM_START
12275.org 0xcc00
12276// bcc-generated data will be placed here
12277ASM_END
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use