VirtualBox

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

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

config file cleanup + small copyright year update

  • Property svn:eol-style set to native
File size: 331.1 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
37
38
39// ROM BIOS compatability entry points:
40// ===================================
41// $e05b ; POST Entry Point
42// $e2c3 ; NMI Handler Entry Point
43// $e3fe ; INT 13h Fixed Disk Services Entry Point
44// $e401 ; Fixed Disk Parameter Table
45// $e6f2 ; INT 19h Boot Load Service Entry Point
46// $e6f5 ; Configuration Data Table
47// $e729 ; Baud Rate Generator Table
48// $e739 ; INT 14h Serial Communications Service Entry Point
49// $e82e ; INT 16h Keyboard Service Entry Point
50// $e987 ; INT 09h Keyboard Service Entry Point
51// $ec59 ; INT 13h Diskette Service Entry Point
52// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
53// $efc7 ; Diskette Controller Parameter Table
54// $efd2 ; INT 17h Printer Service Entry Point
55// $f045 ; INT 10 Functions 0-Fh Entry Point
56// $f065 ; INT 10h Video Support Service Entry Point
57// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
58// $f841 ; INT 12h Memory Size Service Entry Point
59// $f84d ; INT 11h Equipment List Service Entry Point
60// $f859 ; INT 15h System Services Entry Point
61// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
62// $fe6e ; INT 1Ah Time-of-day Service Entry Point
63// $fea5 ; INT 08h System Timer ISR Entry Point
64// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
65// $ff53 ; IRET Instruction for Dummy Interrupt Handler
66// $ff54 ; INT 05h Print Screen Service Entry Point
67// $fff0 ; Power-up Entry Point
68// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
69// $fffe ; System Model ID
70
71// NOTES for ATA/ATAPI driver ([email protected])
72// Features
73// - supports up to 4 ATA interfaces
74// - device/geometry detection
75// - 16bits/32bits device access
76// - pchs/lba access
77// - datain/dataout/packet command support
78//
79// NOTES for El-Torito Boot ([email protected])
80// - CD-ROM booting is only available if ATA/ATAPI Driver is available
81// - Current code is only able to boot mono-session cds
82// - Current code can not boot and emulate a hard-disk
83// the bios will panic otherwise
84// - Current code also use memory in EBDA segement.
85// - I used cmos byte 0x3D to store extended information on boot-device
86// - Code has to be modified modified to handle multiple cdrom drives
87// - Here are the cdrom boot failure codes:
88// 1 : no atapi device found
89// 2 : no atapi cdrom found
90// 3 : can not read cd - BRVD
91// 4 : cd is not eltorito (BRVD)
92// 5 : cd is not eltorito (ISO TAG)
93// 6 : cd is not eltorito (ELTORITO TAG)
94// 7 : can not read cd - boot catalog
95// 8 : boot catalog : bad header
96// 9 : boot catalog : bad platform
97// 10 : boot catalog : bad signature
98// 11 : boot catalog : bootable flag not set
99// 12 : can not read cd - boot image
100//
101// ATA driver
102// - EBDA segment.
103// I used memory starting at 0x121 in the segment
104#ifndef VBOX
105// - the translation policy is defined in cmos regs 0x39 & 0x3a
106#endif /* !VBOX */
107//
108// TODO :
109//
110// int74
111// - needs to be reworked. Uses direct [bp] offsets. (?)
112//
113// int13:
114// - f04 (verify sectors) isn't complete (?)
115// - f02/03/04 should set current cyl,etc in BDA (?)
116// - rewrite int13_relocated & clean up int13 entry code
117//
118// NOTES:
119// - NMI access (bit7 of addr written to 70h)
120//
121// ATA driver
122// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
123// - could send the multiple-sector read/write commands
124//
125// El-Torito
126// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
127// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
128// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
129// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
130// This is ok. But DL should be reincremented afterwards.
131// - Fix all "FIXME ElTorito Various"
132// - should be able to boot any cdrom instead of the first one
133//
134// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
135
136#ifdef VBOX
137#include "DevPcBios.h"
138#include <VBox/version.h>
139#endif
140
141#define BX_ROMBIOS32 0
142#define DEBUG_ROMBIOS 0
143
144#define DEBUG_ATA 0
145#define DEBUG_INT13_HD 0
146#define DEBUG_INT13_CD 0
147#define DEBUG_INT13_ET 0
148#define DEBUG_INT13_FL 0
149#define DEBUG_INT15 0
150#define DEBUG_INT16 0
151#define DEBUG_INT1A 0
152#define DEBUG_INT74 0
153#define DEBUG_APM 0
154
155#define BX_CPU 3
156#define BX_USE_PS2_MOUSE 1
157#define BX_CALL_INT15_4F 1
158#define BX_USE_EBDA 1
159#define BX_SUPPORT_FLOPPY 1
160#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
161#define BX_PCIBIOS 1
162#define BX_APM 1
163
164#define BX_USE_ATADRV 1
165#define BX_ELTORITO_BOOT 1
166
167#define BX_MAX_ATA_INTERFACES 4
168#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
169
170#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
171#define BX_DEBUG_SERIAL 0 /* output to COM1 */
172
173 /* model byte 0xFC = AT */
174#define SYS_MODEL_ID 0xFC
175#define SYS_SUBMODEL_ID 0x00
176#define BIOS_REVISION 1
177#define BIOS_CONFIG_TABLE 0xe6f5
178
179#ifndef BIOS_BUILD_DATE
180# define BIOS_BUILD_DATE "06/23/99"
181#endif
182
183 // 1K of base memory used for Extended Bios Data Area (EBDA)
184 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
185#define EBDA_SEG 0x9FC0
186#define EBDA_SIZE 1 // In KiB
187#define BASE_MEM_IN_K (640 - EBDA_SIZE)
188
189#define ACPI_DATA_SIZE 0x00010000L
190
191 // Define the application NAME
192#if defined(BX_QEMU)
193# define BX_APPNAME "QEMU"
194#elif defined(PLEX86)
195# define BX_APPNAME "Plex86"
196#else
197# define BX_APPNAME "Bochs"
198#endif
199
200 // Sanity Checks
201#if BX_USE_ATADRV && BX_CPU<3
202# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
203#endif
204#if BX_USE_ATADRV && !BX_USE_EBDA
205# error ATA/ATAPI Driver can only be used if EBDA is available
206#endif
207#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
208# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
209#endif
210#if BX_PCIBIOS && BX_CPU<3
211# error PCI BIOS can only be used with 386+ cpu
212#endif
213#if BX_APM && BX_CPU<3
214# error APM BIOS can only be used with 386+ cpu
215#endif
216
217#if defined(VBOX) && !BX_USE_ATADRV
218# error VBOX requires enabling the ATA/ATAPI driver
219#endif
220
221#ifdef VBOX_WITH_SCSI
222# define BX_MAX_SCSI_DEVICES 2
223#endif
224
225#ifndef VBOX
226#define PANIC_PORT 0x400
227#define PANIC_PORT2 0x401
228#define INFO_PORT 0x402
229#define DEBUG_PORT 0x403
230#else /* VBOX */
231/* Redirect INFO output to backdoor logging port. */
232#define PANIC_PORT 0x400
233#define PANIC_PORT2 0x401
234#define INFO_PORT 0x504
235#define DEBUG_PORT 0x403
236#endif /* VBOX */
237
238// define this if you want to make PCIBIOS working on a specific bridge only
239// undef enables PCIBIOS when at least one PCI device is found
240// i440FX is emulated by Bochs and QEMU
241#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
242
243// #20 is dec 20
244// #$20 is hex 20 = 32
245// #0x20 is hex 20 = 32
246// LDA #$20
247// JSR $E820
248// LDD .i,S
249// JSR $C682
250// mov al, #$20
251
252// all hex literals should be prefixed with '0x'
253// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
254// no mov SEG-REG, #value, must mov register into seg-reg
255// grep -i "mov[ ]*.s" rombios.c
256
257// This is for compiling with gcc2 and gcc3
258#define ASM_START #asm
259#define ASM_END #endasm
260
261ASM_START
262.rom
263
264.org 0x0000
265
266#if BX_CPU >= 3
267use16 386
268#else
269use16 286
270#endif
271
272MACRO HALT
273 ;; the HALT macro is called with the line number of the HALT call.
274 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
275 ;; to print a BX_PANIC message. This will normally halt the simulation
276 ;; with a message such as "BIOS panic at rombios.c, line 4091".
277 ;; However, users can choose to make panics non-fatal and continue.
278#if BX_VIRTUAL_PORTS
279 mov dx,#PANIC_PORT
280 mov ax,#?1
281 out dx,ax
282#else
283 mov dx,#0x80
284 mov ax,#?1
285 out dx,al
286#endif
287MEND
288
289MACRO JMP_AP
290 db 0xea
291 dw ?2
292 dw ?1
293MEND
294
295MACRO SET_INT_VECTOR
296 mov ax, ?3
297 mov ?1*4, ax
298 mov ax, ?2
299 mov ?1*4+2, ax
300MEND
301
302ASM_END
303
304typedef unsigned char Bit8u;
305typedef unsigned short Bit16u;
306typedef unsigned short bx_bool;
307typedef unsigned long Bit32u;
308
309#if BX_USE_ATADRV
310
311 void memsetb(seg,offset,value,count);
312 void memcpyb(dseg,doffset,sseg,soffset,count);
313 void memcpyd(dseg,doffset,sseg,soffset,count);
314
315 // memset of count bytes
316 void
317 memsetb(seg,offset,value,count)
318 Bit16u seg;
319 Bit16u offset;
320 Bit16u value;
321 Bit16u count;
322 {
323 ASM_START
324 push bp
325 mov bp, sp
326
327 push ax
328 push cx
329 push es
330 push di
331
332 mov cx, 10[bp] ; count
333 cmp cx, #0x00
334 je memsetb_end
335 mov ax, 4[bp] ; segment
336 mov es, ax
337 mov ax, 6[bp] ; offset
338 mov di, ax
339 mov al, 8[bp] ; value
340 cld
341 rep
342 stosb
343
344 memsetb_end:
345 pop di
346 pop es
347 pop cx
348 pop ax
349
350 pop bp
351 ASM_END
352 }
353
354#if 0
355 // memcpy of count bytes
356 void
357 memcpyb(dseg,doffset,sseg,soffset,count)
358 Bit16u dseg;
359 Bit16u doffset;
360 Bit16u sseg;
361 Bit16u soffset;
362 Bit16u count;
363 {
364 ASM_START
365 push bp
366 mov bp, sp
367
368 push ax
369 push cx
370 push es
371 push di
372 push ds
373 push si
374
375 mov cx, 12[bp] ; count
376 cmp cx, #0x0000
377 je memcpyb_end
378 mov ax, 4[bp] ; dsegment
379 mov es, ax
380 mov ax, 6[bp] ; doffset
381 mov di, ax
382 mov ax, 8[bp] ; ssegment
383 mov ds, ax
384 mov ax, 10[bp] ; soffset
385 mov si, ax
386 cld
387 rep
388 movsb
389
390 memcpyb_end:
391 pop si
392 pop ds
393 pop di
394 pop es
395 pop cx
396 pop ax
397
398 pop bp
399 ASM_END
400 }
401
402 // memcpy of count dword
403 void
404 memcpyd(dseg,doffset,sseg,soffset,count)
405 Bit16u dseg;
406 Bit16u doffset;
407 Bit16u sseg;
408 Bit16u soffset;
409 Bit16u count;
410 {
411 ASM_START
412 push bp
413 mov bp, sp
414
415 push ax
416 push cx
417 push es
418 push di
419 push ds
420 push si
421
422 mov cx, 12[bp] ; count
423 cmp cx, #0x0000
424 je memcpyd_end
425 mov ax, 4[bp] ; dsegment
426 mov es, ax
427 mov ax, 6[bp] ; doffset
428 mov di, ax
429 mov ax, 8[bp] ; ssegment
430 mov ds, ax
431 mov ax, 10[bp] ; soffset
432 mov si, ax
433 cld
434 rep
435 movsd
436
437 memcpyd_end:
438 pop si
439 pop ds
440 pop di
441 pop es
442 pop cx
443 pop ax
444
445 pop bp
446 ASM_END
447 }
448#endif
449#endif //BX_USE_ATADRV
450
451 // read_dword and write_dword functions
452 static Bit32u read_dword();
453 static void write_dword();
454
455 Bit32u
456 read_dword(seg, offset)
457 Bit16u seg;
458 Bit16u offset;
459 {
460 ASM_START
461 push bp
462 mov bp, sp
463
464 push bx
465 push ds
466 mov ax, 4[bp] ; segment
467 mov ds, ax
468 mov bx, 6[bp] ; offset
469 mov ax, [bx]
470 inc bx
471 inc bx
472 mov dx, [bx]
473 ;; ax = return value (word)
474 ;; dx = return value (word)
475 pop ds
476 pop bx
477
478 pop bp
479 ASM_END
480 }
481
482 void
483 write_dword(seg, offset, data)
484 Bit16u seg;
485 Bit16u offset;
486 Bit32u data;
487 {
488 ASM_START
489 push bp
490 mov bp, sp
491
492 push ax
493 push bx
494 push ds
495 mov ax, 4[bp] ; segment
496 mov ds, ax
497 mov bx, 6[bp] ; offset
498 mov ax, 8[bp] ; data word
499 mov [bx], ax ; write data word
500 inc bx
501 inc bx
502 mov ax, 10[bp] ; data word
503 mov [bx], ax ; write data word
504 pop ds
505 pop bx
506 pop ax
507
508 pop bp
509 ASM_END
510 }
511
512 // Bit32u (unsigned long) and long helper functions
513 ASM_START
514
515 ;; and function
516 landl:
517 landul:
518 SEG SS
519 and ax,[di]
520 SEG SS
521 and bx,2[di]
522 ret
523
524 ;; add function
525 laddl:
526 laddul:
527 SEG SS
528 add ax,[di]
529 SEG SS
530 adc bx,2[di]
531 ret
532
533 ;; cmp function
534 lcmpl:
535 lcmpul:
536 and eax, #0x0000FFFF
537 shl ebx, #16
538 add eax, ebx
539 shr ebx, #16
540 SEG SS
541 cmp eax, dword ptr [di]
542 ret
543
544 ;; sub function
545 lsubl:
546 lsubul:
547 SEG SS
548 sub ax,[di]
549 SEG SS
550 sbb bx,2[di]
551 ret
552
553 ;; mul function
554 lmull:
555 lmulul:
556 and eax, #0x0000FFFF
557 shl ebx, #16
558 add eax, ebx
559 SEG SS
560 mul eax, dword ptr [di]
561 mov ebx, eax
562 shr ebx, #16
563 ret
564
565 ;; dec function
566 ldecl:
567 ldecul:
568 SEG SS
569 dec dword ptr [bx]
570 ret
571
572 ;; or function
573 lorl:
574 lorul:
575 SEG SS
576 or ax,[di]
577 SEG SS
578 or bx,2[di]
579 ret
580
581 ;; inc function
582 lincl:
583 lincul:
584 SEG SS
585 inc dword ptr [bx]
586 ret
587
588 ;; tst function
589 ltstl:
590 ltstul:
591 and eax, #0x0000FFFF
592 shl ebx, #16
593 add eax, ebx
594 shr ebx, #16
595 test eax, eax
596 ret
597
598 ;; sr function
599 lsrul:
600 mov cx,di
601 jcxz lsr_exit
602 and eax, #0x0000FFFF
603 shl ebx, #16
604 add eax, ebx
605 lsr_loop:
606 shr eax, #1
607 loop lsr_loop
608 mov ebx, eax
609 shr ebx, #16
610 lsr_exit:
611 ret
612
613 ;; sl function
614 lsll:
615 lslul:
616 mov cx,di
617 jcxz lsl_exit
618 and eax, #0x0000FFFF
619 shl ebx, #16
620 add eax, ebx
621 lsl_loop:
622 shl eax, #1
623 loop lsl_loop
624 mov ebx, eax
625 shr ebx, #16
626 lsl_exit:
627 ret
628
629 idiv_:
630 cwd
631 idiv bx
632 ret
633
634 idiv_u:
635 xor dx,dx
636 div bx
637 ret
638
639 ldivul:
640 and eax, #0x0000FFFF
641 shl ebx, #16
642 add eax, ebx
643 xor edx, edx
644 SEG SS
645 mov bx, 2[di]
646 shl ebx, #16
647 SEG SS
648 mov bx, [di]
649 div ebx
650 mov ebx, eax
651 shr ebx, #16
652 ret
653
654 ASM_END
655
656// for access to RAM area which is used by interrupt vectors
657// and BIOS Data Area
658
659typedef struct {
660 unsigned char filler1[0x400];
661 unsigned char filler2[0x6c];
662 Bit16u ticks_low;
663 Bit16u ticks_high;
664 Bit8u midnight_flag;
665 } bios_data_t;
666
667#define BiosData ((bios_data_t *) 0)
668
669#if BX_USE_ATADRV
670 typedef struct {
671 Bit16u heads; // # heads
672 Bit16u cylinders; // # cylinders
673 Bit16u spt; // # sectors / track
674 } chs_t;
675
676 // DPTE definition
677 typedef struct {
678 Bit16u iobase1;
679 Bit16u iobase2;
680 Bit8u prefix;
681 Bit8u unused;
682 Bit8u irq;
683 Bit8u blkcount;
684 Bit8u dma;
685 Bit8u pio;
686 Bit16u options;
687 Bit16u reserved;
688 Bit8u revision;
689 Bit8u checksum;
690 } dpte_t;
691
692 typedef struct {
693 Bit8u iface; // ISA or PCI
694 Bit16u iobase1; // IO Base 1
695 Bit16u iobase2; // IO Base 2
696 Bit8u irq; // IRQ
697 } ata_channel_t;
698
699 typedef struct {
700 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
701 Bit8u device; // Detected type of attached devices (hd/cd/none)
702 Bit8u removable; // Removable device flag
703 Bit8u lock; // Locks for removable devices
704 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
705 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
706 Bit16u blksize; // block size
707
708 Bit8u translation; // type of translation
709 chs_t lchs; // Logical CHS
710 chs_t pchs; // Physical CHS
711
712 Bit32u sectors; // Total sectors count
713 } ata_device_t;
714
715 typedef struct {
716 // ATA channels info
717 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
718
719 // ATA devices info
720 ata_device_t devices[BX_MAX_ATA_DEVICES];
721 //
722 // map between (bios hd id - 0x80) and ata channels and scsi disks.
723#ifdef VBOX_WITH_SCSI
724 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
725#else
726 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
727#endif
728
729 // map between (bios cd id - 0xE0) and ata channels
730 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
731
732 // Buffer for DPTE table
733 dpte_t dpte;
734
735 // Count of transferred sectors and bytes
736 Bit16u trsfsectors;
737 Bit32u trsfbytes;
738
739 } ata_t;
740
741#if BX_ELTORITO_BOOT
742 // ElTorito Device Emulation data
743 typedef struct {
744 Bit8u active;
745 Bit8u media;
746 Bit8u emulated_drive;
747 Bit8u controller_index;
748 Bit16u device_spec;
749 Bit32u ilba;
750 Bit16u buffer_segment;
751 Bit16u load_segment;
752 Bit16u sector_count;
753
754 // Virtual device
755 chs_t vdevice;
756 } cdemu_t;
757#endif // BX_ELTORITO_BOOT
758
759#ifdef VBOX_WITH_SCSI
760 typedef struct {
761 // I/O port this device is attached to.
762 Bit16u io_base;
763 // Target Id.
764 Bit8u target_id;
765 // SCSI devices info
766 ata_device_t device_info;
767 } scsi_device_t;
768
769 typedef struct {
770 // SCSi device info
771 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
772 // Number of scsi disks.
773 Bit8u hdcount;
774 } scsi_t;
775#endif
776
777 // for access to EBDA area
778 // The EBDA structure should conform to
779 // http://www.frontiernet.net/~fys/rombios.htm document
780 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
781 typedef struct {
782 unsigned char filler1[0x3D];
783
784 // FDPT - Can be splitted in data members if needed
785 unsigned char fdpt0[0x10];
786 unsigned char fdpt1[0x10];
787
788 unsigned char filler2[0xC4];
789
790 // ATA Driver data
791 ata_t ata;
792
793#if BX_ELTORITO_BOOT
794 // El Torito Emulation data
795 cdemu_t cdemu;
796#endif // BX_ELTORITO_BOOT
797
798#ifdef VBOX
799
800#ifdef VBOX_WITH_SCSI
801 // SCSI Driver data
802 scsi_t scsi;
803# endif
804
805 unsigned char uForceBootDrive;
806 unsigned char uForceBootDevice;
807#endif /* VBOX */
808
809 } ebda_data_t;
810
811#ifdef VBOX
812 // the last 16 bytes of the EBDA segment are used for the MPS floating
813 // pointer structure (only if an IOAPIC is present)
814#endif
815
816 #define EbdaData ((ebda_data_t *) 0)
817
818 // for access to the int13ext structure
819 typedef struct {
820 Bit8u size;
821 Bit8u reserved;
822 Bit16u count;
823 Bit16u offset;
824 Bit16u segment;
825 Bit32u lba1;
826 Bit32u lba2;
827 } int13ext_t;
828
829 #define Int13Ext ((int13ext_t *) 0)
830
831 // Disk Physical Table definition
832 typedef struct {
833 Bit16u size;
834 Bit16u infos;
835 Bit32u cylinders;
836 Bit32u heads;
837 Bit32u spt;
838 Bit32u sector_count1;
839 Bit32u sector_count2;
840 Bit16u blksize;
841 Bit16u dpte_offset;
842 Bit16u dpte_segment;
843 Bit16u key;
844 Bit8u dpi_length;
845 Bit8u reserved1;
846 Bit16u reserved2;
847 Bit8u host_bus[4];
848 Bit8u iface_type[8];
849 Bit8u iface_path[8];
850 Bit8u device_path[8];
851 Bit8u reserved3;
852 Bit8u checksum;
853 } dpt_t;
854
855 #define Int13DPT ((dpt_t *) 0)
856
857#endif // BX_USE_ATADRV
858
859typedef struct {
860 union {
861 struct {
862 Bit16u di, si, bp, sp;
863 Bit16u bx, dx, cx, ax;
864 } r16;
865 struct {
866 Bit16u filler[4];
867 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
868 } r8;
869 } u;
870 } pusha_regs_t;
871
872typedef struct {
873 union {
874 struct {
875 Bit32u edi, esi, ebp, esp;
876 Bit32u ebx, edx, ecx, eax;
877 } r32;
878 struct {
879 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
880 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
881 } r16;
882 struct {
883 Bit32u filler[4];
884 Bit8u bl, bh;
885 Bit16u filler1;
886 Bit8u dl, dh;
887 Bit16u filler2;
888 Bit8u cl, ch;
889 Bit16u filler3;
890 Bit8u al, ah;
891 Bit16u filler4;
892 } r8;
893 } u;
894} pushad_regs_t;
895
896typedef struct {
897 union {
898 struct {
899 Bit16u flags;
900 } r16;
901 struct {
902 Bit8u flagsl;
903 Bit8u flagsh;
904 } r8;
905 } u;
906 } flags_t;
907
908#define SetCF(x) x.u.r8.flagsl |= 0x01
909#define SetZF(x) x.u.r8.flagsl |= 0x40
910#define ClearCF(x) x.u.r8.flagsl &= 0xfe
911#define ClearZF(x) x.u.r8.flagsl &= 0xbf
912#define GetCF(x) (x.u.r8.flagsl & 0x01)
913
914typedef struct {
915 Bit16u ip;
916 Bit16u cs;
917 flags_t flags;
918 } iret_addr_t;
919
920
921
922static Bit8u inb();
923static Bit8u inb_cmos();
924static void outb();
925static void outb_cmos();
926static Bit16u inw();
927static void outw();
928static void init_rtc();
929static bx_bool rtc_updating();
930
931static Bit8u read_byte();
932static Bit16u read_word();
933static void write_byte();
934static void write_word();
935static void bios_printf();
936
937static Bit8u send_to_mouse_ctrl();
938static Bit8u get_mouse_data();
939static void set_kbd_command_byte();
940
941static void int09_function();
942static void int13_harddisk();
943static void int13_cdrom();
944static void int13_cdemu();
945static void int13_eltorito();
946static void int13_diskette_function();
947static void int14_function();
948static void int15_function();
949static void int16_function();
950static void int17_function();
951static Bit32u int19_function();
952static void int1a_function();
953static void int70_function();
954static void int74_function();
955static void dummy_isr_function();
956static Bit16u get_CS();
957static Bit16u get_SS();
958static unsigned int enqueue_key();
959static unsigned int dequeue_key();
960static void get_hd_geometry();
961static void set_diskette_ret_status();
962static void set_diskette_current_cyl();
963static void determine_floppy_media();
964static bx_bool floppy_drive_exists();
965static bx_bool floppy_drive_recal();
966static bx_bool floppy_media_known();
967static bx_bool floppy_media_sense();
968static bx_bool set_enable_a20();
969static void debugger_on();
970static void debugger_off();
971static void keyboard_init();
972static void keyboard_panic();
973static void shutdown_status_panic();
974static void nmi_handler_msg();
975
976static void print_bios_banner();
977static void print_boot_device();
978static void print_boot_failure();
979static void print_cdromboot_failure();
980
981# if BX_USE_ATADRV
982
983// ATA / ATAPI driver
984void ata_init();
985void ata_detect();
986void ata_reset();
987
988Bit16u ata_cmd_non_data();
989Bit16u ata_cmd_data_in();
990Bit16u ata_cmd_data_out();
991Bit16u ata_cmd_packet();
992
993Bit16u atapi_get_sense();
994Bit16u atapi_is_ready();
995Bit16u atapi_is_cdrom();
996
997#endif // BX_USE_ATADRV
998
999#if BX_ELTORITO_BOOT
1000
1001void cdemu_init();
1002Bit8u cdemu_isactive();
1003Bit8u cdemu_emulated_drive();
1004
1005Bit16u cdrom_boot();
1006
1007#endif // BX_ELTORITO_BOOT
1008
1009#ifdef VBOX
1010static char bios_prefix_string[] = "BIOS: ";
1011/* Do not use build timestamps in this string. Otherwise even rebuilding the
1012 * very same code will lead to compare errors when restoring saved state. */
1013static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1014#define BIOS_COPYRIGHT_STRING "Sun VirtualBox BIOS"
1015#else /* !VBOX */
1016static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1017
1018#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1019#endif /* !VBOX */
1020
1021#define BIOS_PRINTF_HALT 1
1022#define BIOS_PRINTF_SCREEN 2
1023#define BIOS_PRINTF_INFO 4
1024#define BIOS_PRINTF_DEBUG 8
1025#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1026#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1027
1028#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1029
1030// Defines the output macros.
1031// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1032// per-device basis. Debug info are sent only in debug mode
1033#if DEBUG_ROMBIOS
1034# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1035#else
1036# define BX_DEBUG(format, p...)
1037#endif
1038#ifdef VBOX
1039#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
1040#else /* !VBOX */
1041#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1042#endif /* !VBOX */
1043#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1044
1045#if DEBUG_ATA
1046# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1047#else
1048# define BX_DEBUG_ATA(a...)
1049#endif
1050#if DEBUG_INT13_HD
1051# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1052#else
1053# define BX_DEBUG_INT13_HD(a...)
1054#endif
1055#if DEBUG_INT13_CD
1056# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1057#else
1058# define BX_DEBUG_INT13_CD(a...)
1059#endif
1060#if DEBUG_INT13_ET
1061# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1062#else
1063# define BX_DEBUG_INT13_ET(a...)
1064#endif
1065#if DEBUG_INT13_FL
1066# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1067#else
1068# define BX_DEBUG_INT13_FL(a...)
1069#endif
1070#if DEBUG_INT15
1071# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1072#else
1073# define BX_DEBUG_INT15(a...)
1074#endif
1075#if DEBUG_INT16
1076# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1077#else
1078# define BX_DEBUG_INT16(a...)
1079#endif
1080#if DEBUG_INT1A
1081# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1082#else
1083# define BX_DEBUG_INT1A(a...)
1084#endif
1085#if DEBUG_INT74
1086# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1087#else
1088# define BX_DEBUG_INT74(a...)
1089#endif
1090
1091#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1092#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1093#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1094#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1095#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1096#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1097#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1098#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1099
1100#define GET_AL() ( AX & 0x00ff )
1101#define GET_BL() ( BX & 0x00ff )
1102#define GET_CL() ( CX & 0x00ff )
1103#define GET_DL() ( DX & 0x00ff )
1104#define GET_AH() ( AX >> 8 )
1105#define GET_BH() ( BX >> 8 )
1106#define GET_CH() ( CX >> 8 )
1107#define GET_DH() ( DX >> 8 )
1108
1109#define GET_ELDL() ( ELDX & 0x00ff )
1110#define GET_ELDH() ( ELDX >> 8 )
1111
1112#define SET_CF() FLAGS |= 0x0001
1113#define CLEAR_CF() FLAGS &= 0xfffe
1114#define GET_CF() (FLAGS & 0x0001)
1115
1116#define SET_ZF() FLAGS |= 0x0040
1117#define CLEAR_ZF() FLAGS &= 0xffbf
1118#define GET_ZF() (FLAGS & 0x0040)
1119
1120#define UNSUPPORTED_FUNCTION 0x86
1121
1122#define none 0
1123#define MAX_SCAN_CODE 0x58
1124
1125static struct {
1126 Bit16u normal;
1127 Bit16u shift;
1128 Bit16u control;
1129 Bit16u alt;
1130 Bit8u lock_flags;
1131 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1132 { none, none, none, none, none },
1133 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1134 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1135 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1136 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1137 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1138 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1139 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1140 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1141 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1142 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1143 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1144 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1145 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1146 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1147 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1148 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1149 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1150 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1151 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1152 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1153 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1154 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1155 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1156 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1157 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1158 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1159 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1160 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1161 { none, none, none, none, none }, /* L Ctrl */
1162 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1163 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1164 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1165 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1166 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1167 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1168 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1169 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1170 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1171 { 0x273b, 0x273a, none, none, none }, /* ;: */
1172 { 0x2827, 0x2822, none, none, none }, /* '" */
1173 { 0x2960, 0x297e, none, none, none }, /* `~ */
1174 { none, none, none, none, none }, /* L shift */
1175 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1176 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1177 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1178 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1179 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1180 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1181 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1182 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1183 { 0x332c, 0x333c, none, none, none }, /* ,< */
1184 { 0x342e, 0x343e, none, none, none }, /* .> */
1185 { 0x352f, 0x353f, none, none, none }, /* /? */
1186 { none, none, none, none, none }, /* R Shift */
1187 { 0x372a, 0x372a, none, none, none }, /* * */
1188 { none, none, none, none, none }, /* L Alt */
1189 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1190 { none, none, none, none, none }, /* caps lock */
1191 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1192 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1193 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1194 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1195 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1196 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1197 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1198 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1199 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1200 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1201 { none, none, none, none, none }, /* Num Lock */
1202 { none, none, none, none, none }, /* Scroll Lock */
1203 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1204 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1205 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1206 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1207 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1208 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1209 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1210 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1211 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1212 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1213 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1214 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1215 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1216 { none, none, none, none, none },
1217 { none, none, none, none, none },
1218 { 0x565c, 0x567c, none, none, none }, /* \| */
1219#ifndef VBOX
1220 { 0x5700, 0x5700, none, none, none }, /* F11 */
1221 { 0x5800, 0x5800, none, none, none } /* F12 */
1222#else
1223 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1224 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1225#endif
1226 };
1227
1228 Bit8u
1229inb(port)
1230 Bit16u port;
1231{
1232ASM_START
1233 push bp
1234 mov bp, sp
1235
1236 push dx
1237 mov dx, 4[bp]
1238 in al, dx
1239 pop dx
1240
1241 pop bp
1242ASM_END
1243}
1244
1245#if BX_USE_ATADRV
1246 Bit16u
1247inw(port)
1248 Bit16u port;
1249{
1250ASM_START
1251 push bp
1252 mov bp, sp
1253
1254 push dx
1255 mov dx, 4[bp]
1256 in ax, dx
1257 pop dx
1258
1259 pop bp
1260ASM_END
1261}
1262#endif
1263
1264 void
1265outb(port, val)
1266 Bit16u port;
1267 Bit8u val;
1268{
1269ASM_START
1270 push bp
1271 mov bp, sp
1272
1273 push ax
1274 push dx
1275 mov dx, 4[bp]
1276 mov al, 6[bp]
1277 out dx, al
1278 pop dx
1279 pop ax
1280
1281 pop bp
1282ASM_END
1283}
1284
1285#if BX_USE_ATADRV
1286 void
1287outw(port, val)
1288 Bit16u port;
1289 Bit16u val;
1290{
1291ASM_START
1292 push bp
1293 mov bp, sp
1294
1295 push ax
1296 push dx
1297 mov dx, 4[bp]
1298 mov ax, 6[bp]
1299 out dx, ax
1300 pop dx
1301 pop ax
1302
1303 pop bp
1304ASM_END
1305}
1306#endif
1307
1308 void
1309outb_cmos(cmos_reg, val)
1310 Bit8u cmos_reg;
1311 Bit8u val;
1312{
1313ASM_START
1314 push bp
1315 mov bp, sp
1316
1317 mov al, 4[bp] ;; cmos_reg
1318 out 0x70, al
1319 mov al, 6[bp] ;; val
1320 out 0x71, al
1321
1322 pop bp
1323ASM_END
1324}
1325
1326 Bit8u
1327inb_cmos(cmos_reg)
1328 Bit8u cmos_reg;
1329{
1330ASM_START
1331 push bp
1332 mov bp, sp
1333
1334 mov al, 4[bp] ;; cmos_reg
1335 out 0x70, al
1336 in al, 0x71
1337
1338 pop bp
1339ASM_END
1340}
1341
1342 void
1343init_rtc()
1344{
1345 outb_cmos(0x0a, 0x26);
1346 outb_cmos(0x0b, 0x02);
1347 inb_cmos(0x0c);
1348 inb_cmos(0x0d);
1349}
1350
1351 bx_bool
1352rtc_updating()
1353{
1354 // This function checks to see if the update-in-progress bit
1355 // is set in CMOS Status Register A. If not, it returns 0.
1356 // If it is set, it tries to wait until there is a transition
1357 // to 0, and will return 0 if such a transition occurs. A 1
1358 // is returned only after timing out. The maximum period
1359 // that this bit should be set is constrained to 244useconds.
1360 // The count I use below guarantees coverage or more than
1361 // this time, with any reasonable IPS setting.
1362
1363 Bit16u count;
1364
1365 count = 25000;
1366 while (--count != 0) {
1367 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1368 return(0);
1369 }
1370 return(1); // update-in-progress never transitioned to 0
1371}
1372
1373
1374 Bit8u
1375read_byte(seg, offset)
1376 Bit16u seg;
1377 Bit16u offset;
1378{
1379ASM_START
1380 push bp
1381 mov bp, sp
1382
1383 push bx
1384 push ds
1385 mov ax, 4[bp] ; segment
1386 mov ds, ax
1387 mov bx, 6[bp] ; offset
1388 mov al, [bx]
1389 ;; al = return value (byte)
1390 pop ds
1391 pop bx
1392
1393 pop bp
1394ASM_END
1395}
1396
1397 Bit16u
1398read_word(seg, offset)
1399 Bit16u seg;
1400 Bit16u offset;
1401{
1402ASM_START
1403 push bp
1404 mov bp, sp
1405
1406 push bx
1407 push ds
1408 mov ax, 4[bp] ; segment
1409 mov ds, ax
1410 mov bx, 6[bp] ; offset
1411 mov ax, [bx]
1412 ;; ax = return value (word)
1413 pop ds
1414 pop bx
1415
1416 pop bp
1417ASM_END
1418}
1419
1420 void
1421write_byte(seg, offset, data)
1422 Bit16u seg;
1423 Bit16u offset;
1424 Bit8u data;
1425{
1426ASM_START
1427 push bp
1428 mov bp, sp
1429
1430 push ax
1431 push bx
1432 push ds
1433 mov ax, 4[bp] ; segment
1434 mov ds, ax
1435 mov bx, 6[bp] ; offset
1436 mov al, 8[bp] ; data byte
1437 mov [bx], al ; write data byte
1438 pop ds
1439 pop bx
1440 pop ax
1441
1442 pop bp
1443ASM_END
1444}
1445
1446 void
1447write_word(seg, offset, data)
1448 Bit16u seg;
1449 Bit16u offset;
1450 Bit16u data;
1451{
1452ASM_START
1453 push bp
1454 mov bp, sp
1455
1456 push ax
1457 push bx
1458 push ds
1459 mov ax, 4[bp] ; segment
1460 mov ds, ax
1461 mov bx, 6[bp] ; offset
1462 mov ax, 8[bp] ; data word
1463 mov [bx], ax ; write data word
1464 pop ds
1465 pop bx
1466 pop ax
1467
1468 pop bp
1469ASM_END
1470}
1471
1472 Bit16u
1473get_CS()
1474{
1475ASM_START
1476 mov ax, cs
1477ASM_END
1478}
1479
1480 Bit16u
1481get_SS()
1482{
1483ASM_START
1484 mov ax, ss
1485ASM_END
1486}
1487
1488#if BX_DEBUG_SERIAL
1489/* serial debug port*/
1490#define BX_DEBUG_PORT 0x03f8
1491
1492/* data */
1493#define UART_RBR 0x00
1494#define UART_THR 0x00
1495
1496/* control */
1497#define UART_IER 0x01
1498#define UART_IIR 0x02
1499#define UART_FCR 0x02
1500#define UART_LCR 0x03
1501#define UART_MCR 0x04
1502#define UART_DLL 0x00
1503#define UART_DLM 0x01
1504
1505/* status */
1506#define UART_LSR 0x05
1507#define UART_MSR 0x06
1508#define UART_SCR 0x07
1509
1510int uart_can_tx_byte(base_port)
1511 Bit16u base_port;
1512{
1513 return inb(base_port + UART_LSR) & 0x20;
1514}
1515
1516void uart_wait_to_tx_byte(base_port)
1517 Bit16u base_port;
1518{
1519 while (!uart_can_tx_byte(base_port));
1520}
1521
1522void uart_wait_until_sent(base_port)
1523 Bit16u base_port;
1524{
1525 while (!(inb(base_port + UART_LSR) & 0x40));
1526}
1527
1528void uart_tx_byte(base_port, data)
1529 Bit16u base_port;
1530 Bit8u data;
1531{
1532 uart_wait_to_tx_byte(base_port);
1533 outb(base_port + UART_THR, data);
1534 uart_wait_until_sent(base_port);
1535}
1536#endif
1537
1538 void
1539wrch(c)
1540 Bit8u c;
1541{
1542 ASM_START
1543 push bp
1544 mov bp, sp
1545
1546 push bx
1547 mov ah, #0x0e
1548 mov al, 4[bp]
1549 xor bx,bx
1550 int #0x10
1551 pop bx
1552
1553 pop bp
1554 ASM_END
1555}
1556
1557 void
1558send(action, c)
1559 Bit16u action;
1560 Bit8u c;
1561{
1562#if BX_DEBUG_SERIAL
1563 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1564 uart_tx_byte(BX_DEBUG_PORT, c);
1565#endif
1566#if BX_VIRTUAL_PORTS
1567 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1568 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1569#endif
1570 if (action & BIOS_PRINTF_SCREEN) {
1571 if (c == '\n') wrch('\r');
1572 wrch(c);
1573 }
1574}
1575
1576 void
1577put_int(action, val, width, neg)
1578 Bit16u action;
1579 short val, width;
1580 bx_bool neg;
1581{
1582 short nval = val / 10;
1583 if (nval)
1584 put_int(action, nval, width - 1, neg);
1585 else {
1586 while (--width > 0) send(action, ' ');
1587 if (neg) send(action, '-');
1588 }
1589 send(action, val - (nval * 10) + '0');
1590}
1591
1592 void
1593put_uint(action, val, width, neg)
1594 Bit16u action;
1595 unsigned short val;
1596 short width;
1597 bx_bool neg;
1598{
1599 unsigned short nval = val / 10;
1600 if (nval)
1601 put_uint(action, nval, width - 1, neg);
1602 else {
1603 while (--width > 0) send(action, ' ');
1604 if (neg) send(action, '-');
1605 }
1606 send(action, val - (nval * 10) + '0');
1607}
1608
1609 void
1610put_luint(action, val, width, neg)
1611 Bit16u action;
1612 unsigned long val;
1613 short width;
1614 bx_bool neg;
1615{
1616 unsigned long nval = val / 10;
1617 if (nval)
1618 put_luint(action, nval, width - 1, neg);
1619 else {
1620 while (--width > 0) send(action, ' ');
1621 if (neg) send(action, '-');
1622 }
1623 send(action, val - (nval * 10) + '0');
1624}
1625
1626#ifdef VBOX
1627void put_str(action, s)
1628 Bit16u action;
1629 Bit8u *s;
1630{
1631 Bit8u c;
1632 if (!s)
1633 s = "<NULL>";
1634
1635 while (c = read_byte(get_CS(), s)) {
1636 send(action, c);
1637 s++;
1638 }
1639}
1640#endif /* VBOX */
1641
1642//--------------------------------------------------------------------------
1643// bios_printf()
1644// A compact variable argument printf function which prints its output via
1645// an I/O port so that it can be logged by Bochs/Plex.
1646// Currently, only %x is supported (or %02x, %04x, etc).
1647//
1648// Supports %[format_width][format]
1649// where format can be d,x,c,s
1650//--------------------------------------------------------------------------
1651 void
1652bios_printf(action, s)
1653 Bit16u action;
1654 Bit8u *s;
1655{
1656 Bit8u c, format_char;
1657 bx_bool in_format;
1658 short i;
1659 Bit16u *arg_ptr;
1660 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width;
1661
1662 arg_ptr = &s;
1663 arg_seg = get_SS();
1664
1665 in_format = 0;
1666 format_width = 0;
1667
1668 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1669#if BX_VIRTUAL_PORTS
1670 outb(PANIC_PORT2, 0x00);
1671#endif
1672 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1673 }
1674
1675 while (c = read_byte(get_CS(), s)) {
1676 if ( c == '%' ) {
1677 in_format = 1;
1678 format_width = 0;
1679 }
1680 else if (in_format) {
1681 if ( (c>='0') && (c<='9') ) {
1682 format_width = (format_width * 10) + (c - '0');
1683 }
1684 else {
1685 arg_ptr++; // increment to next arg
1686 arg = read_word(arg_seg, arg_ptr);
1687 if (c == 'x') {
1688 if (format_width == 0)
1689 format_width = 4;
1690 for (i=format_width-1; i>=0; i--) {
1691 nibble = (arg >> (4 * i)) & 0x000f;
1692 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1693 }
1694 }
1695 else if (c == 'u') {
1696 put_uint(action, arg, format_width, 0);
1697 }
1698 else if (c == 'l') {
1699 s++;
1700 arg_ptr++; /* increment to next arg */
1701 hibyte = read_word(arg_seg, arg_ptr);
1702 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1703 }
1704 else if (c == 'd') {
1705 if (arg & 0x8000)
1706 put_int(action, -arg, format_width - 1, 1);
1707 else
1708 put_int(action, arg, format_width, 0);
1709 }
1710 else if (c == 's') {
1711#ifndef VBOX
1712 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1713#else /* VBOX */
1714 put_str(action, arg);
1715#endif /* VBOX */
1716 }
1717 else if (c == 'c') {
1718 send(action, arg);
1719 }
1720 else
1721 BX_PANIC("bios_printf: unknown format\n");
1722 in_format = 0;
1723 }
1724 }
1725 else {
1726 send(action, c);
1727 }
1728 s ++;
1729 }
1730
1731 if (action & BIOS_PRINTF_HALT) {
1732 // freeze in a busy loop.
1733ASM_START
1734 cli
1735 halt2_loop:
1736 hlt
1737 jmp halt2_loop
1738ASM_END
1739 }
1740}
1741
1742//--------------------------------------------------------------------------
1743// keyboard_init
1744//--------------------------------------------------------------------------
1745// this file is based on LinuxBIOS implementation of keyboard.c
1746// could convert to #asm to gain space
1747 void
1748keyboard_init()
1749{
1750 Bit16u max;
1751
1752 /* ------------------- Flush buffers ------------------------*/
1753 /* Wait until buffer is empty */
1754 max=0xffff;
1755 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1756
1757 /* flush incoming keys */
1758 max=0x2000;
1759 while (--max > 0) {
1760 outb(0x80, 0x00);
1761 if (inb(0x64) & 0x01) {
1762 inb(0x60);
1763 max = 0x2000;
1764 }
1765 }
1766
1767 // Due to timer issues, and if the IPS setting is > 15000000,
1768 // the incoming keys might not be flushed here. That will
1769 // cause a panic a few lines below. See sourceforge bug report :
1770 // [ 642031 ] FATAL: Keyboard RESET error:993
1771
1772 /* ------------------- controller side ----------------------*/
1773 /* send cmd = 0xAA, self test 8042 */
1774 outb(0x64, 0xaa);
1775
1776 /* Wait until buffer is empty */
1777 max=0xffff;
1778 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1779 if (max==0x0) keyboard_panic(00);
1780
1781 /* Wait for data */
1782 max=0xffff;
1783 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1784 if (max==0x0) keyboard_panic(01);
1785
1786 /* read self-test result, 0x55 should be returned from 0x60 */
1787 if ((inb(0x60) != 0x55)){
1788 keyboard_panic(991);
1789 }
1790
1791 /* send cmd = 0xAB, keyboard interface test */
1792 outb(0x64,0xab);
1793
1794 /* Wait until buffer is empty */
1795 max=0xffff;
1796 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1797 if (max==0x0) keyboard_panic(10);
1798
1799 /* Wait for data */
1800 max=0xffff;
1801 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1802 if (max==0x0) keyboard_panic(11);
1803
1804 /* read keyboard interface test result, */
1805 /* 0x00 should be returned form 0x60 */
1806 if ((inb(0x60) != 0x00)) {
1807 keyboard_panic(992);
1808 }
1809
1810 /* Enable Keyboard clock */
1811 outb(0x64,0xae);
1812 outb(0x64,0xa8);
1813
1814 /* ------------------- keyboard side ------------------------*/
1815 /* reset kerboard and self test (keyboard side) */
1816 outb(0x60, 0xff);
1817
1818 /* Wait until buffer is empty */
1819 max=0xffff;
1820 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1821 if (max==0x0) keyboard_panic(20);
1822
1823 /* Wait for data */
1824 max=0xffff;
1825 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1826 if (max==0x0) keyboard_panic(21);
1827
1828 /* keyboard should return ACK */
1829 if ((inb(0x60) != 0xfa)) {
1830 keyboard_panic(993);
1831 }
1832
1833 /* Wait for data */
1834 max=0xffff;
1835 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1836 if (max==0x0) keyboard_panic(31);
1837
1838 if ((inb(0x60) != 0xaa)) {
1839 keyboard_panic(994);
1840 }
1841
1842 /* Disable keyboard */
1843 outb(0x60, 0xf5);
1844
1845 /* Wait until buffer is empty */
1846 max=0xffff;
1847 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1848 if (max==0x0) keyboard_panic(40);
1849
1850 /* Wait for data */
1851 max=0xffff;
1852 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1853 if (max==0x0) keyboard_panic(41);
1854
1855 /* keyboard should return ACK */
1856 if ((inb(0x60) != 0xfa)) {
1857 keyboard_panic(995);
1858 }
1859
1860 /* Write Keyboard Mode */
1861 outb(0x64, 0x60);
1862
1863 /* Wait until buffer is empty */
1864 max=0xffff;
1865 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1866 if (max==0x0) keyboard_panic(50);
1867
1868 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1869 outb(0x60, 0x65);
1870
1871 /* Wait until buffer is empty */
1872 max=0xffff;
1873 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1874 if (max==0x0) keyboard_panic(60);
1875
1876 /* Enable keyboard */
1877 outb(0x60, 0xf4);
1878
1879 /* Wait until buffer is empty */
1880 max=0xffff;
1881 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1882 if (max==0x0) keyboard_panic(70);
1883
1884 /* Wait for data */
1885 max=0xffff;
1886 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1887 if (max==0x0) keyboard_panic(70);
1888
1889 /* keyboard should return ACK */
1890 if ((inb(0x60) != 0xfa)) {
1891 keyboard_panic(996);
1892 }
1893
1894 outb(0x80, 0x77);
1895}
1896
1897//--------------------------------------------------------------------------
1898// keyboard_panic
1899//--------------------------------------------------------------------------
1900 void
1901keyboard_panic(status)
1902 Bit16u status;
1903{
1904 // If you're getting a 993 keyboard panic here,
1905 // please see the comment in keyboard_init
1906
1907 BX_PANIC("Keyboard error:%u\n",status);
1908}
1909
1910//--------------------------------------------------------------------------
1911// shutdown_status_panic
1912// called when the shutdown statsu is not implemented, displays the status
1913//--------------------------------------------------------------------------
1914 void
1915shutdown_status_panic(status)
1916 Bit16u status;
1917{
1918 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1919}
1920
1921#ifdef VBOX
1922#include "logo.c"
1923#endif /* VBOX */
1924
1925//--------------------------------------------------------------------------
1926// print_bios_banner
1927// displays a the bios version
1928//--------------------------------------------------------------------------
1929void
1930print_bios_banner()
1931{
1932#ifdef VBOX
1933 // Skip the logo if a warm boot is requested.
1934 Bit16u warm_boot = read_word(0x0040,0x0072);
1935 write_word(0x0040,0x0072, 0);
1936 if (warm_boot == 0x1234)
1937 return;
1938#if !defined(DEBUG) || defined(DEBUG_sunlover)
1939 /* show graphical logo */
1940 show_logo();
1941#else
1942 /* set text mode */
1943 ASM_START
1944 mov ax, #0x0003
1945 int #0x10
1946 ASM_END
1947#endif /* !DEBUG */
1948#else /* !VBOX */
1949 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1950 BIOS_BUILD_DATE, bios_cvs_version_string);
1951 printf(
1952#if BX_APM
1953 "apmbios "
1954#endif
1955#if BX_PCIBIOS
1956 "pcibios "
1957#endif
1958#if BX_ELTORITO_BOOT
1959 "eltorito "
1960#endif
1961#if BX_ROMBIOS32
1962 "rombios32 "
1963#endif
1964 "\n\n");
1965#endif /* VBOX */
1966}
1967
1968//--------------------------------------------------------------------------
1969// print_boot_device
1970// displays the boot device
1971//--------------------------------------------------------------------------
1972
1973#ifdef VBOX
1974static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
1975#else /* !VBOX */
1976static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1977#endif /* !VBOX */
1978
1979#ifdef VBOX
1980void
1981print_boot_device(cdboot, lanboot, drive)
1982 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
1983#else /* !VBOX */
1984void
1985print_boot_device(cdboot, drive)
1986 Bit8u cdboot; Bit16u drive;
1987#endif /* !VBOX */
1988{
1989 Bit8u i;
1990
1991#ifdef VBOX
1992 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
1993 // lanboot contains 0 if floppy/harddisk, 1 otherwise
1994#else /* !VBOX */
1995 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1996#endif /* !VBOX */
1997 // drive contains real/emulated boot drive
1998
1999 if(cdboot)i=2; // CD-Rom
2000#ifdef VBOX
2001 else if(lanboot)i=3; // LAN
2002#endif /* VBOX */
2003 else if((drive&0x0080)==0x00)i=0; // Floppy
2004 else if((drive&0x0080)==0x80)i=1; // Hard drive
2005 else return;
2006
2007#ifdef VBOX
2008 BX_INFO("Booting from %s...\n",drivetypes[i]);
2009#else /* !VBOX */
2010 printf("Booting from %s...\n",drivetypes[i]);
2011#endif /* !VBOX */
2012}
2013
2014//--------------------------------------------------------------------------
2015// print_boot_failure
2016// displays the reason why boot failed
2017//--------------------------------------------------------------------------
2018#ifdef VBOX
2019 void
2020print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2021 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2022#else /* !VBOX */
2023 void
2024print_boot_failure(cdboot, drive, reason, lastdrive)
2025 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2026#endif /* !VBOX */
2027{
2028 Bit16u drivenum = drive&0x7f;
2029
2030 // cdboot: 1 if boot from cd, 0 otherwise
2031#ifdef VBOX
2032 // lanboot: 1 if boot from lan, 0 otherwise
2033#endif /* VBOX */
2034 // drive : drive number
2035 // reason: 0 signature check failed, 1 read error
2036 // lastdrive: 1 boot drive is the last one in boot sequence
2037
2038 if (cdboot)
2039#ifndef VBOX
2040 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2041#else /* VBOX */
2042 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2043 else if (lanboot)
2044 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2045#endif /* VBOX */
2046 else if (drive & 0x80)
2047#ifndef VBOX
2048 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2049#else /* VBOX */
2050 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2051#endif /* VBOX */
2052 else
2053#ifndef VBOX
2054 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2055#else /* VBOX */
2056 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2057#endif /* VBOX */
2058
2059 if (lastdrive==1) {
2060 if (reason==0)
2061#ifndef VBOX
2062 BX_PANIC("Not a bootable disk\n");
2063#else /* VBOX */
2064 BX_PANIC("No bootable medium found! System halted.\n");
2065#endif /* VBOX */
2066 else
2067#ifndef VBOX
2068 BX_PANIC("Could not read the boot disk\n");
2069#else /* VBOX */
2070 BX_PANIC("Could not read from the boot medium! System halted.\n");
2071#endif /* VBOX */
2072 }
2073}
2074
2075//--------------------------------------------------------------------------
2076// print_cdromboot_failure
2077// displays the reason why boot failed
2078//--------------------------------------------------------------------------
2079 void
2080print_cdromboot_failure( code )
2081 Bit16u code;
2082{
2083#ifndef VBOX
2084 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2085#else /* VBOX */
2086 BX_INFO("CDROM boot failure code : %04x\n",code);
2087#endif /* VBOX */
2088
2089 return;
2090}
2091
2092void
2093nmi_handler_msg()
2094{
2095 BX_PANIC("NMI Handler called\n");
2096}
2097
2098void
2099int18_panic_msg()
2100{
2101 BX_PANIC("INT18: BOOT FAILURE\n");
2102}
2103
2104void
2105log_bios_start()
2106{
2107#if BX_DEBUG_SERIAL
2108 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2109#endif
2110 BX_INFO("%s\n", bios_cvs_version_string);
2111}
2112
2113 bx_bool
2114set_enable_a20(val)
2115 bx_bool val;
2116{
2117 Bit8u oldval;
2118
2119 // Use PS2 System Control port A to set A20 enable
2120
2121 // get current setting first
2122 oldval = inb(0x92);
2123
2124 // change A20 status
2125 if (val)
2126 outb(0x92, oldval | 0x02);
2127 else
2128 outb(0x92, oldval & 0xfd);
2129
2130 return((oldval & 0x02) != 0);
2131}
2132
2133 void
2134debugger_on()
2135{
2136 outb(0xfedc, 0x01);
2137}
2138
2139 void
2140debugger_off()
2141{
2142 outb(0xfedc, 0x00);
2143}
2144
2145#if BX_USE_ATADRV
2146
2147// ---------------------------------------------------------------------------
2148// Start of ATA/ATAPI Driver
2149// ---------------------------------------------------------------------------
2150
2151// Global defines -- ATA register and register bits.
2152// command block & control block regs
2153#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2154#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2155#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2156#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2157#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2158#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2159#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2160#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2161#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2162#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2163#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2164#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2165#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2166
2167#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2168#define ATA_CB_ER_BBK 0x80 // ATA bad block
2169#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2170#define ATA_CB_ER_MC 0x20 // ATA media change
2171#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2172#define ATA_CB_ER_MCR 0x08 // ATA media change request
2173#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2174#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2175#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2176
2177#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2178#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2179#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2180#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2181#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2182
2183// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2184#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2185#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2186#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2187#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2188
2189// bits 7-4 of the device/head (CB_DH) reg
2190#define ATA_CB_DH_DEV0 0xa0 // select device 0
2191#define ATA_CB_DH_DEV1 0xb0 // select device 1
2192
2193// status reg (CB_STAT and CB_ASTAT) bits
2194#define ATA_CB_STAT_BSY 0x80 // busy
2195#define ATA_CB_STAT_RDY 0x40 // ready
2196#define ATA_CB_STAT_DF 0x20 // device fault
2197#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2198#define ATA_CB_STAT_SKC 0x10 // seek complete
2199#define ATA_CB_STAT_SERV 0x10 // service
2200#define ATA_CB_STAT_DRQ 0x08 // data request
2201#define ATA_CB_STAT_CORR 0x04 // corrected
2202#define ATA_CB_STAT_IDX 0x02 // index
2203#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2204#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2205
2206// device control reg (CB_DC) bits
2207#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2208#define ATA_CB_DC_SRST 0x04 // soft reset
2209#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2210
2211// Most mandtory and optional ATA commands (from ATA-3),
2212#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2213#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2214#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2215#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2216#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2217#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2218#define ATA_CMD_CHECK_POWER_MODE2 0x98
2219#define ATA_CMD_DEVICE_RESET 0x08
2220#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2221#define ATA_CMD_FLUSH_CACHE 0xE7
2222#define ATA_CMD_FORMAT_TRACK 0x50
2223#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2224#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2225#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2226#define ATA_CMD_IDLE1 0xE3
2227#define ATA_CMD_IDLE2 0x97
2228#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2229#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2230#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2231#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2232#define ATA_CMD_NOP 0x00
2233#define ATA_CMD_PACKET 0xA0
2234#define ATA_CMD_READ_BUFFER 0xE4
2235#define ATA_CMD_READ_DMA 0xC8
2236#define ATA_CMD_READ_DMA_QUEUED 0xC7
2237#define ATA_CMD_READ_MULTIPLE 0xC4
2238#define ATA_CMD_READ_SECTORS 0x20
2239#ifdef VBOX
2240#define ATA_CMD_READ_SECTORS_EXT 0x24
2241#endif /* VBOX */
2242#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2243#define ATA_CMD_RECALIBRATE 0x10
2244#define ATA_CMD_SEEK 0x70
2245#define ATA_CMD_SET_FEATURES 0xEF
2246#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2247#define ATA_CMD_SLEEP1 0xE6
2248#define ATA_CMD_SLEEP2 0x99
2249#define ATA_CMD_STANDBY1 0xE2
2250#define ATA_CMD_STANDBY2 0x96
2251#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2252#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2253#define ATA_CMD_WRITE_BUFFER 0xE8
2254#define ATA_CMD_WRITE_DMA 0xCA
2255#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2256#define ATA_CMD_WRITE_MULTIPLE 0xC5
2257#define ATA_CMD_WRITE_SECTORS 0x30
2258#ifdef VBOX
2259#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2260#endif /* VBOX */
2261#define ATA_CMD_WRITE_VERIFY 0x3C
2262
2263#define ATA_IFACE_NONE 0x00
2264#define ATA_IFACE_ISA 0x00
2265#define ATA_IFACE_PCI 0x01
2266
2267#define ATA_TYPE_NONE 0x00
2268#define ATA_TYPE_UNKNOWN 0x01
2269#define ATA_TYPE_ATA 0x02
2270#define ATA_TYPE_ATAPI 0x03
2271#ifdef VBOX
2272#define ATA_TYPE_SCSI 0x04 // SCSI disk
2273#endif
2274
2275#define ATA_DEVICE_NONE 0x00
2276#define ATA_DEVICE_HD 0xFF
2277#define ATA_DEVICE_CDROM 0x05
2278
2279#define ATA_MODE_NONE 0x00
2280#define ATA_MODE_PIO16 0x00
2281#define ATA_MODE_PIO32 0x01
2282#define ATA_MODE_ISADMA 0x02
2283#define ATA_MODE_PCIDMA 0x03
2284#define ATA_MODE_USEIRQ 0x10
2285
2286#define ATA_TRANSLATION_NONE 0
2287#define ATA_TRANSLATION_LBA 1
2288#define ATA_TRANSLATION_LARGE 2
2289#define ATA_TRANSLATION_RECHS 3
2290
2291#define ATA_DATA_NO 0x00
2292#define ATA_DATA_IN 0x01
2293#define ATA_DATA_OUT 0x02
2294
2295// ---------------------------------------------------------------------------
2296// ATA/ATAPI driver : initialization
2297// ---------------------------------------------------------------------------
2298void ata_init( )
2299{
2300 Bit16u ebda_seg=read_word(0x0040,0x000E);
2301 Bit8u channel, device;
2302
2303 // Channels info init.
2304 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2305 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2306 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2307 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2308 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2309 }
2310
2311 // Devices info init.
2312 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2313 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2314 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2315 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2316 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2317 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2318 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2319 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2320 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2321 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2322 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2323 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2324 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2325 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2326
2327 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2328 }
2329
2330 // hdidmap and cdidmap init.
2331 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2332 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2333 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2334 }
2335
2336 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2337 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2338}
2339
2340// ---------------------------------------------------------------------------
2341// ATA/ATAPI driver : device detection
2342// ---------------------------------------------------------------------------
2343
2344void ata_detect( )
2345{
2346 Bit16u ebda_seg=read_word(0x0040,0x000E);
2347 Bit8u hdcount, cdcount, device, type;
2348 Bit8u buffer[0x0200];
2349
2350#if BX_MAX_ATA_INTERFACES > 0
2351 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2352 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2353 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2354 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2355#endif
2356#if BX_MAX_ATA_INTERFACES > 1
2357 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2358 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2359 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2360 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2361#endif
2362#if BX_MAX_ATA_INTERFACES > 2
2363 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2364 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2365 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2366 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2367#endif
2368#if BX_MAX_ATA_INTERFACES > 3
2369 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2370 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2371 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2372 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2373#endif
2374#if BX_MAX_ATA_INTERFACES > 4
2375#error Please fill the ATA interface informations
2376#endif
2377
2378 // Device detection
2379 hdcount=cdcount=0;
2380
2381 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2382 Bit16u iobase1, iobase2;
2383 Bit8u channel, slave, shift;
2384 Bit8u sc, sn, cl, ch, st;
2385
2386 channel = device / 2;
2387 slave = device % 2;
2388
2389 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2390 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2391
2392 // Disable interrupts
2393 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2394
2395 // Look for device
2396 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2397 outb(iobase1+ATA_CB_SC, 0x55);
2398 outb(iobase1+ATA_CB_SN, 0xaa);
2399 outb(iobase1+ATA_CB_SC, 0xaa);
2400 outb(iobase1+ATA_CB_SN, 0x55);
2401 outb(iobase1+ATA_CB_SC, 0x55);
2402 outb(iobase1+ATA_CB_SN, 0xaa);
2403
2404 // If we found something
2405 sc = inb(iobase1+ATA_CB_SC);
2406 sn = inb(iobase1+ATA_CB_SN);
2407
2408 if ( (sc == 0x55) && (sn == 0xaa) ) {
2409 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2410
2411 // reset the channel
2412 ata_reset(device);
2413
2414 // check for ATA or ATAPI
2415 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2416 sc = inb(iobase1+ATA_CB_SC);
2417 sn = inb(iobase1+ATA_CB_SN);
2418
2419 if ((sc==0x01) && (sn==0x01)) {
2420 cl = inb(iobase1+ATA_CB_CL);
2421 ch = inb(iobase1+ATA_CB_CH);
2422 st = inb(iobase1+ATA_CB_STAT);
2423
2424 if ((cl==0x14) && (ch==0xeb)) {
2425 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2426 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2427 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2428 } else if ((cl==0xff) && (ch==0xff)) {
2429 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2430 }
2431 }
2432 }
2433
2434#ifdef VBOX
2435 // Enable interrupts
2436 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2437#endif /* VBOX */
2438
2439 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2440
2441 // Now we send a IDENTIFY command to ATA device
2442 if(type == ATA_TYPE_ATA) {
2443 Bit32u sectors;
2444 Bit16u cylinders, heads, spt, blksize;
2445#ifdef VBOX
2446 Bit16u lcylinders, lheads, lspt;
2447 Bit8u chsgeo_base;
2448#endif /* VBOX */
2449 Bit8u translation, removable, mode;
2450
2451 //Temporary values to do the transfer
2452 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2453 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2454
2455 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2456 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2457
2458 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2459 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2460#ifdef VBOX
2461 blksize = 512; /* There is no sector size field any more. */
2462#else /* !VBOX */
2463 blksize = read_word(get_SS(),buffer+10);
2464#endif /* !VBOX */
2465
2466 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2467 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2468 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2469
2470 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2471#ifdef VBOX
2472 /** @todo update sectors to be a 64 bit number (also lba...). */
2473 if (sectors == 268435455)
2474 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2475 switch (device)
2476 {
2477 case 0:
2478 chsgeo_base = 0x1e;
2479 break;
2480 case 1:
2481 chsgeo_base = 0x26;
2482 break;
2483 case 2:
2484 chsgeo_base = 0x67;
2485 break;
2486 case 3:
2487 chsgeo_base = 0x70;
2488 break;
2489 case 4:
2490 chsgeo_base = 0x40;
2491 break;
2492 case 5:
2493 chsgeo_base = 0x48;
2494 break;
2495 case 6:
2496 chsgeo_base = 0x50;
2497 break;
2498 case 7:
2499 chsgeo_base = 0x58;
2500 break;
2501 default:
2502 chsgeo_base = 0;
2503 }
2504 if (chsgeo_base != 0)
2505 {
2506 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2507 lheads = inb_cmos(chsgeo_base+2);
2508 lspt = inb_cmos(chsgeo_base+7);
2509 }
2510 else
2511 {
2512 lcylinders = 0;
2513 lheads = 0;
2514 lspt = 0;
2515 }
2516 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2517#endif /* VBOX */
2518
2519 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2520 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2521 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2522 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2523 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2524 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2525 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2526 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2527#ifdef VBOX
2528 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2529 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2530 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2531 if (device < 2)
2532 {
2533 Bit8u sum, i;
2534 unsigned char *fdpt;
2535 if (device == 0)
2536 fdpt = &EbdaData->fdpt0;
2537 else
2538 fdpt = &EbdaData->fdpt1;
2539
2540 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2541 * to be done at POST time with lots of ugly assembler code, which
2542 * isn't worth the effort of converting from AMI to Award CMOS
2543 * format. Just do it here. */
2544 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2545 write_byte(ebda_seg, fdpt + 0x02, lheads);
2546 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2547 write_word(ebda_seg, fdpt + 0x09, cylinders);
2548 write_byte(ebda_seg, fdpt + 0x0b, heads);
2549 write_byte(ebda_seg, fdpt + 0x04, spt);
2550 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2551 sum = 0;
2552 for (i = 0; i < 0xf; i++)
2553 sum += read_byte(ebda_seg, fdpt + i);
2554 sum = 1 - sum;
2555 write_byte(ebda_seg, fdpt + 0x0f, sum);
2556 }
2557#else /* !VBOX */
2558 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2559
2560 translation = inb_cmos(0x39 + channel/2);
2561 for (shift=device%4; shift>0; shift--) translation >>= 2;
2562 translation &= 0x03;
2563
2564 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2565
2566 switch (translation) {
2567 case ATA_TRANSLATION_NONE:
2568 BX_INFO("none");
2569 break;
2570 case ATA_TRANSLATION_LBA:
2571 BX_INFO("lba");
2572 break;
2573 case ATA_TRANSLATION_LARGE:
2574 BX_INFO("large");
2575 break;
2576 case ATA_TRANSLATION_RECHS:
2577 BX_INFO("r-echs");
2578 break;
2579 }
2580 switch (translation) {
2581 case ATA_TRANSLATION_NONE:
2582 break;
2583 case ATA_TRANSLATION_LBA:
2584 spt = 63;
2585 sectors /= 63;
2586 heads = sectors / 1024;
2587 if (heads>128) heads = 255;
2588 else if (heads>64) heads = 128;
2589 else if (heads>32) heads = 64;
2590 else if (heads>16) heads = 32;
2591 else heads=16;
2592 cylinders = sectors / heads;
2593 break;
2594 case ATA_TRANSLATION_RECHS:
2595 // Take care not to overflow
2596 if (heads==16) {
2597 if(cylinders>61439) cylinders=61439;
2598 heads=15;
2599 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2600 }
2601 // then go through the large bitshift process
2602 case ATA_TRANSLATION_LARGE:
2603 while(cylinders > 1024) {
2604 cylinders >>= 1;
2605 heads <<= 1;
2606
2607 // If we max out the head count
2608 if (heads > 127) break;
2609 }
2610 break;
2611 }
2612 // clip to 1024 cylinders in lchs
2613 if (cylinders > 1024) cylinders=1024;
2614 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2615
2616 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2617 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2618 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2619#endif /* VBOX */
2620
2621 // fill hdidmap
2622 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2623 hdcount++;
2624 }
2625
2626 // Now we send a IDENTIFY command to ATAPI device
2627 if(type == ATA_TYPE_ATAPI) {
2628
2629 Bit8u type, removable, mode;
2630 Bit16u blksize;
2631
2632 //Temporary values to do the transfer
2633 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2634 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2635
2636 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2637 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2638
2639 type = read_byte(get_SS(),buffer+1) & 0x1f;
2640 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2641 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2642 blksize = 2048;
2643
2644 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2645 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2646 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2647 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2648
2649 // fill cdidmap
2650 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2651 cdcount++;
2652 }
2653
2654 {
2655 Bit32u sizeinmb;
2656 Bit16u ataversion;
2657 Bit8u c, i, version, model[41];
2658
2659 switch (type) {
2660 case ATA_TYPE_ATA:
2661 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2662 sizeinmb >>= 11;
2663 case ATA_TYPE_ATAPI:
2664 // Read ATA/ATAPI version
2665 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2666 for(version=15;version>0;version--) {
2667 if((ataversion&(1<<version))!=0)
2668 break;
2669 }
2670
2671 // Read model name
2672 for(i=0;i<20;i++){
2673 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2674 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2675 }
2676
2677 // Reformat
2678 write_byte(get_SS(),model+40,0x00);
2679 for(i=39;i>0;i--){
2680 if(read_byte(get_SS(),model+i)==0x20)
2681 write_byte(get_SS(),model+i,0x00);
2682 else break;
2683 }
2684 break;
2685 }
2686
2687#ifdef VBOX
2688 // we don't want any noisy output for now
2689#else /* !VBOX */
2690 switch (type) {
2691 case ATA_TYPE_ATA:
2692 printf("ata%d %s: ",channel,slave?" slave":"master");
2693 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2694 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2695 break;
2696 case ATA_TYPE_ATAPI:
2697 printf("ata%d %s: ",channel,slave?" slave":"master");
2698 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2699 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2700 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2701 else
2702 printf(" ATAPI-%d Device\n",version);
2703 break;
2704 case ATA_TYPE_UNKNOWN:
2705 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2706 break;
2707 }
2708#endif /* !VBOX */
2709 }
2710 }
2711
2712 // Store the devices counts
2713 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2714 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2715 write_byte(0x40,0x75, hdcount);
2716
2717#ifdef VBOX
2718 // we don't want any noisy output for now
2719#else /* !VBOX */
2720 printf("\n");
2721#endif /* !VBOX */
2722
2723 // FIXME : should use bios=cmos|auto|disable bits
2724 // FIXME : should know about translation bits
2725 // FIXME : move hard_drive_post here
2726
2727}
2728
2729// ---------------------------------------------------------------------------
2730// ATA/ATAPI driver : software reset
2731// ---------------------------------------------------------------------------
2732// ATA-3
2733// 8.2.1 Software reset - Device 0
2734
2735void ata_reset(device)
2736Bit16u device;
2737{
2738 Bit16u ebda_seg=read_word(0x0040,0x000E);
2739 Bit16u iobase1, iobase2;
2740 Bit8u channel, slave, sn, sc;
2741 Bit16u max;
2742#ifdef VBOX
2743 Bit16u pdelay;
2744#endif /* VBOX */
2745
2746 channel = device / 2;
2747 slave = device % 2;
2748
2749 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2750 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2751
2752 // Reset
2753
2754// 8.2.1 (a) -- set SRST in DC
2755 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2756
2757// 8.2.1 (b) -- wait for BSY
2758 max=0xff;
2759 while(--max>0) {
2760 Bit8u status = inb(iobase1+ATA_CB_STAT);
2761 if ((status & ATA_CB_STAT_BSY) != 0) break;
2762 }
2763
2764// 8.2.1 (f) -- clear SRST
2765 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2766
2767 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2768
2769// 8.2.1 (g) -- check for sc==sn==0x01
2770 // select device
2771 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2772 sc = inb(iobase1+ATA_CB_SC);
2773 sn = inb(iobase1+ATA_CB_SN);
2774
2775 if ( (sc==0x01) && (sn==0x01) ) {
2776
2777// 8.2.1 (h) -- wait for not BSY
2778#ifdef VBOX
2779 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2780#else /* !VBOX */
2781 max=0xff;
2782#endif /* !VBOX */
2783 while(--max>0) {
2784 Bit8u status = inb(iobase1+ATA_CB_STAT);
2785 if ((status & ATA_CB_STAT_BSY) == 0) break;
2786#ifdef VBOX
2787 pdelay=0xffff;
2788 while (--pdelay>0) {
2789 /* nothing */
2790 }
2791#endif /* VBOX */
2792 }
2793 }
2794 }
2795
2796// 8.2.1 (i) -- wait for DRDY
2797#ifdef VBOX
2798 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2799#else /* !VBOX */
2800 max=0xfff;
2801#endif /* !VBOX */
2802 while(--max>0) {
2803 Bit8u status = inb(iobase1+ATA_CB_STAT);
2804 if ((status & ATA_CB_STAT_RDY) != 0) break;
2805 }
2806
2807 // Enable interrupts
2808 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2809}
2810
2811// ---------------------------------------------------------------------------
2812// ATA/ATAPI driver : execute a non data command
2813// ---------------------------------------------------------------------------
2814
2815Bit16u ata_cmd_non_data()
2816{return 0;}
2817
2818// ---------------------------------------------------------------------------
2819// ATA/ATAPI driver : execute a data-in command
2820// ---------------------------------------------------------------------------
2821 // returns
2822 // 0 : no error
2823 // 1 : BUSY bit set
2824 // 2 : read error
2825 // 3 : expected DRQ=1
2826 // 4 : no sectors left to read/verify
2827 // 5 : more sectors to read/verify
2828 // 6 : no sectors left to write
2829 // 7 : more sectors to write
2830Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2831Bit16u device, command, count, cylinder, head, sector, segment, offset;
2832Bit32u lba;
2833{
2834 Bit16u ebda_seg=read_word(0x0040,0x000E);
2835 Bit16u iobase1, iobase2, blksize;
2836 Bit8u channel, slave;
2837 Bit8u status, current, mode;
2838
2839 channel = device / 2;
2840 slave = device % 2;
2841
2842 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2843 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2844 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2845 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2846 if (mode == ATA_MODE_PIO32) blksize>>=2;
2847 else blksize>>=1;
2848
2849#ifdef VBOX
2850 status = inb(iobase1 + ATA_CB_STAT);
2851 if (status & ATA_CB_STAT_BSY)
2852 {
2853 // Enable interrupts
2854 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2855 return 1;
2856 }
2857#endif /* VBOX */
2858
2859 // sector will be 0 only on lba access. Convert to lba-chs
2860 if (sector == 0) {
2861#ifdef VBOX
2862 if (count >= 256 || lba + count >= 268435456)
2863 {
2864 sector = (lba & 0xff000000L) >> 24;
2865 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2866 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2867 outb(iobase1 + ATA_CB_SN, sector);
2868 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2869 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2870 /* Leave the bottom 24 bits as is, they are treated correctly by the
2871 * LBA28 code path. */
2872 lba &= 0xffffff;
2873 }
2874#endif /* VBOX */
2875 sector = (Bit16u) (lba & 0x000000ffL);
2876 lba >>= 8;
2877 cylinder = (Bit16u) (lba & 0x0000ffffL);
2878 lba >>= 16;
2879 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2880 }
2881
2882 // Reset count of transferred data
2883 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2884 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2885 current = 0;
2886
2887#ifndef VBOX
2888 status = inb(iobase1 + ATA_CB_STAT);
2889 if (status & ATA_CB_STAT_BSY) return 1;
2890#endif /* !VBOX */
2891
2892 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2893 outb(iobase1 + ATA_CB_FR, 0x00);
2894 outb(iobase1 + ATA_CB_SC, count);
2895 outb(iobase1 + ATA_CB_SN, sector);
2896 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2897 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2898 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2899 outb(iobase1 + ATA_CB_CMD, command);
2900
2901 while (1) {
2902 status = inb(iobase1 + ATA_CB_STAT);
2903 if ( !(status & ATA_CB_STAT_BSY) ) break;
2904 }
2905
2906 if (status & ATA_CB_STAT_ERR) {
2907 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2908#ifdef VBOX
2909 // Enable interrupts
2910 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2911#endif /* VBOX */
2912 return 2;
2913 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2914 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2915#ifdef VBOX
2916 // Enable interrupts
2917 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2918#endif /* VBOX */
2919 return 3;
2920 }
2921
2922 // FIXME : move seg/off translation here
2923
2924ASM_START
2925 sti ;; enable higher priority interrupts
2926ASM_END
2927
2928 while (1) {
2929
2930ASM_START
2931 push bp
2932 mov bp, sp
2933 mov di, _ata_cmd_data_in.offset + 2[bp]
2934 mov ax, _ata_cmd_data_in.segment + 2[bp]
2935 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2936
2937 ;; adjust if there will be an overrun. 2K max sector size
2938 cmp di, #0xf800 ;;
2939 jbe ata_in_no_adjust
2940
2941ata_in_adjust:
2942 sub di, #0x0800 ;; sub 2 kbytes from offset
2943 add ax, #0x0080 ;; add 2 Kbytes to segment
2944
2945ata_in_no_adjust:
2946 mov es, ax ;; segment in es
2947
2948 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2949
2950 mov ah, _ata_cmd_data_in.mode + 2[bp]
2951 cmp ah, #ATA_MODE_PIO32
2952 je ata_in_32
2953
2954ata_in_16:
2955 rep
2956 insw ;; CX words transfered from port(DX) to ES:[DI]
2957 jmp ata_in_done
2958
2959ata_in_32:
2960 rep
2961 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2962
2963ata_in_done:
2964 mov _ata_cmd_data_in.offset + 2[bp], di
2965 mov _ata_cmd_data_in.segment + 2[bp], es
2966 pop bp
2967ASM_END
2968
2969 current++;
2970 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2971 count--;
2972#ifdef VBOX
2973 while (1) {
2974 status = inb(iobase1 + ATA_CB_STAT);
2975 if ( !(status & ATA_CB_STAT_BSY) ) break;
2976 }
2977#else /* !VBOX */
2978 status = inb(iobase1 + ATA_CB_STAT);
2979#endif /* !VBOX */
2980 if (count == 0) {
2981 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2982 != ATA_CB_STAT_RDY ) {
2983 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2984#ifdef VBOX
2985 // Enable interrupts
2986 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2987#endif /* VBOX */
2988 return 4;
2989 }
2990 break;
2991 }
2992 else {
2993 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2994 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2995 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2996#ifdef VBOX
2997 // Enable interrupts
2998 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2999#endif /* VBOX */
3000 return 5;
3001 }
3002 continue;
3003 }
3004 }
3005 // Enable interrupts
3006 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3007 return 0;
3008}
3009
3010// ---------------------------------------------------------------------------
3011// ATA/ATAPI driver : execute a data-out command
3012// ---------------------------------------------------------------------------
3013 // returns
3014 // 0 : no error
3015 // 1 : BUSY bit set
3016 // 2 : read error
3017 // 3 : expected DRQ=1
3018 // 4 : no sectors left to read/verify
3019 // 5 : more sectors to read/verify
3020 // 6 : no sectors left to write
3021 // 7 : more sectors to write
3022Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3023Bit16u device, command, count, cylinder, head, sector, segment, offset;
3024Bit32u lba;
3025{
3026 Bit16u ebda_seg=read_word(0x0040,0x000E);
3027 Bit16u iobase1, iobase2, blksize;
3028 Bit8u channel, slave;
3029 Bit8u status, current, mode;
3030
3031 channel = device / 2;
3032 slave = device % 2;
3033
3034 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3035 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3036 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3037 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3038 if (mode == ATA_MODE_PIO32) blksize>>=2;
3039 else blksize>>=1;
3040
3041#ifdef VBOX
3042 status = inb(iobase1 + ATA_CB_STAT);
3043 if (status & ATA_CB_STAT_BSY)
3044 {
3045 // Enable interrupts
3046 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3047 return 1;
3048 }
3049#endif /* VBOX */
3050
3051 // sector will be 0 only on lba access. Convert to lba-chs
3052 if (sector == 0) {
3053#ifdef VBOX
3054 if (count >= 256 || lba + count >= 268435456)
3055 {
3056 sector = (lba & 0xff000000L) >> 24;
3057 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3058 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3059 outb(iobase1 + ATA_CB_SN, sector);
3060 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3061 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3062 /* Leave the bottom 24 bits as is, they are treated correctly by the
3063 * LBA28 code path. */
3064 lba &= 0xffffff;
3065 }
3066#endif /* VBOX */
3067 sector = (Bit16u) (lba & 0x000000ffL);
3068 lba >>= 8;
3069 cylinder = (Bit16u) (lba & 0x0000ffffL);
3070 lba >>= 16;
3071 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3072 }
3073
3074 // Reset count of transferred data
3075 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3076 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3077 current = 0;
3078
3079#ifndef VBOX
3080 status = inb(iobase1 + ATA_CB_STAT);
3081 if (status & ATA_CB_STAT_BSY) return 1;
3082#endif /* !VBOX */
3083
3084 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3085 outb(iobase1 + ATA_CB_FR, 0x00);
3086 outb(iobase1 + ATA_CB_SC, count);
3087 outb(iobase1 + ATA_CB_SN, sector);
3088 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3089 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3090 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3091 outb(iobase1 + ATA_CB_CMD, command);
3092
3093 while (1) {
3094 status = inb(iobase1 + ATA_CB_STAT);
3095 if ( !(status & ATA_CB_STAT_BSY) ) break;
3096 }
3097
3098 if (status & ATA_CB_STAT_ERR) {
3099 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3100#ifdef VBOX
3101 // Enable interrupts
3102 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3103#endif /* VBOX */
3104 return 2;
3105 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3106 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3107#ifdef VBOX
3108 // Enable interrupts
3109 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3110#endif /* VBOX */
3111 return 3;
3112 }
3113
3114 // FIXME : move seg/off translation here
3115
3116ASM_START
3117 sti ;; enable higher priority interrupts
3118ASM_END
3119
3120 while (1) {
3121
3122ASM_START
3123 push bp
3124 mov bp, sp
3125 mov si, _ata_cmd_data_out.offset + 2[bp]
3126 mov ax, _ata_cmd_data_out.segment + 2[bp]
3127 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3128
3129 ;; adjust if there will be an overrun. 2K max sector size
3130 cmp si, #0xf800 ;;
3131 jbe ata_out_no_adjust
3132
3133ata_out_adjust:
3134 sub si, #0x0800 ;; sub 2 kbytes from offset
3135 add ax, #0x0080 ;; add 2 Kbytes to segment
3136
3137ata_out_no_adjust:
3138 mov es, ax ;; segment in es
3139
3140 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3141
3142 mov ah, _ata_cmd_data_out.mode + 2[bp]
3143 cmp ah, #ATA_MODE_PIO32
3144 je ata_out_32
3145
3146ata_out_16:
3147 seg ES
3148 rep
3149 outsw ;; CX words transfered from port(DX) to ES:[SI]
3150 jmp ata_out_done
3151
3152ata_out_32:
3153 seg ES
3154 rep
3155 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3156
3157ata_out_done:
3158 mov _ata_cmd_data_out.offset + 2[bp], si
3159 mov _ata_cmd_data_out.segment + 2[bp], es
3160 pop bp
3161ASM_END
3162
3163 current++;
3164 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3165 count--;
3166#ifdef VBOX
3167 while (1) {
3168 status = inb(iobase1 + ATA_CB_STAT);
3169 if ( !(status & ATA_CB_STAT_BSY) ) break;
3170 }
3171#else /* !VBOX */
3172 status = inb(iobase1 + ATA_CB_STAT);
3173#endif /* VBOX */
3174 if (count == 0) {
3175 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3176 != ATA_CB_STAT_RDY ) {
3177 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3178#ifdef VBOX
3179 // Enable interrupts
3180 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3181#endif /* VBOX */
3182 return 6;
3183 }
3184 break;
3185 }
3186 else {
3187 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3188 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3189 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3190#ifdef VBOX
3191 // Enable interrupts
3192 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3193#endif /* VBOX */
3194 return 7;
3195 }
3196 continue;
3197 }
3198 }
3199 // Enable interrupts
3200 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3201 return 0;
3202}
3203
3204// ---------------------------------------------------------------------------
3205// ATA/ATAPI driver : execute a packet command
3206// ---------------------------------------------------------------------------
3207 // returns
3208 // 0 : no error
3209 // 1 : error in parameters
3210 // 2 : BUSY bit set
3211 // 3 : error
3212 // 4 : not ready
3213Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3214Bit8u cmdlen,inout;
3215Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3216Bit16u header;
3217Bit32u length;
3218{
3219 Bit16u ebda_seg=read_word(0x0040,0x000E);
3220 Bit16u iobase1, iobase2;
3221 Bit16u lcount, lbefore, lafter, count;
3222 Bit8u channel, slave;
3223 Bit8u status, mode, lmode;
3224 Bit32u total, transfer;
3225
3226 channel = device / 2;
3227 slave = device % 2;
3228
3229 // Data out is not supported yet
3230 if (inout == ATA_DATA_OUT) {
3231 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3232 return 1;
3233 }
3234
3235 // The header length must be even
3236 if (header & 1) {
3237 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3238 return 1;
3239 }
3240
3241 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3242 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3243 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3244 transfer= 0L;
3245
3246 if (cmdlen < 12) cmdlen=12;
3247 if (cmdlen > 12) cmdlen=16;
3248 cmdlen>>=1;
3249
3250 // Reset count of transferred data
3251 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3252 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3253
3254 status = inb(iobase1 + ATA_CB_STAT);
3255 if (status & ATA_CB_STAT_BSY) return 2;
3256
3257 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3258 // outb(iobase1 + ATA_CB_FR, 0x00);
3259 // outb(iobase1 + ATA_CB_SC, 0x00);
3260 // outb(iobase1 + ATA_CB_SN, 0x00);
3261 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3262 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3263 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3264 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3265
3266 // Device should ok to receive command
3267 while (1) {
3268 status = inb(iobase1 + ATA_CB_STAT);
3269 if ( !(status & ATA_CB_STAT_BSY) ) break;
3270 }
3271
3272 if (status & ATA_CB_STAT_ERR) {
3273 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3274#ifdef VBOX
3275 // Enable interrupts
3276 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3277#endif /* VBOX */
3278 return 3;
3279 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3280 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3281#ifdef VBOX
3282 // Enable interrupts
3283 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3284#endif /* VBOX */
3285 return 4;
3286 }
3287
3288 // Normalize address
3289 cmdseg += (cmdoff / 16);
3290 cmdoff %= 16;
3291
3292 // Send command to device
3293ASM_START
3294 sti ;; enable higher priority interrupts
3295
3296 push bp
3297 mov bp, sp
3298
3299 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3300 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3301 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3302 mov es, ax ;; segment in es
3303
3304 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3305
3306 seg ES
3307 rep
3308 outsw ;; CX words transfered from port(DX) to ES:[SI]
3309
3310 pop bp
3311ASM_END
3312
3313 if (inout == ATA_DATA_NO) {
3314 status = inb(iobase1 + ATA_CB_STAT);
3315 }
3316 else {
3317 while (1) {
3318
3319#ifdef VBOX
3320 while (1) {
3321 status = inb(iobase1 + ATA_CB_STAT);
3322 if ( !(status & ATA_CB_STAT_BSY) ) break;
3323 }
3324#else /* VBOX */
3325 status = inb(iobase1 + ATA_CB_STAT);
3326#endif /* VBOX */
3327
3328 // Check if command completed
3329 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3330
3331 if (status & ATA_CB_STAT_ERR) {
3332 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3333#ifdef VBOX
3334 // Enable interrupts
3335 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3336#endif /* VBOX */
3337 return 3;
3338 }
3339
3340 // Device must be ready to send data
3341 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3342 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3343 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3344#ifdef VBOX
3345 // Enable interrupts
3346 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3347#endif /* VBOX */
3348 return 4;
3349 }
3350
3351 // Normalize address
3352 bufseg += (bufoff / 16);
3353 bufoff %= 16;
3354
3355 // Get the byte count
3356 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3357
3358 // adjust to read what we want
3359 if(header>lcount) {
3360 lbefore=lcount;
3361 header-=lcount;
3362 lcount=0;
3363 }
3364 else {
3365 lbefore=header;
3366 header=0;
3367 lcount-=lbefore;
3368 }
3369
3370 if(lcount>length) {
3371 lafter=lcount-length;
3372 lcount=length;
3373 length=0;
3374 }
3375 else {
3376 lafter=0;
3377 length-=lcount;
3378 }
3379
3380 // Save byte count
3381 count = lcount;
3382
3383 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3384 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3385
3386 // If counts not dividable by 4, use 16bits mode
3387 lmode = mode;
3388 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3389 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3390 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3391
3392 // adds an extra byte if count are odd. before is always even
3393 if (lcount & 0x01) {
3394 lcount+=1;
3395 if ((lafter > 0) && (lafter & 0x01)) {
3396 lafter-=1;
3397 }
3398 }
3399
3400 if (lmode == ATA_MODE_PIO32) {
3401 lcount>>=2; lbefore>>=2; lafter>>=2;
3402 }
3403 else {
3404 lcount>>=1; lbefore>>=1; lafter>>=1;
3405 }
3406
3407 ; // FIXME bcc bug
3408
3409ASM_START
3410 push bp
3411 mov bp, sp
3412
3413 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3414
3415 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3416 jcxz ata_packet_no_before
3417
3418 mov ah, _ata_cmd_packet.lmode + 2[bp]
3419 cmp ah, #ATA_MODE_PIO32
3420 je ata_packet_in_before_32
3421
3422ata_packet_in_before_16:
3423 in ax, dx
3424 loop ata_packet_in_before_16
3425 jmp ata_packet_no_before
3426
3427ata_packet_in_before_32:
3428 push eax
3429ata_packet_in_before_32_loop:
3430 in eax, dx
3431 loop ata_packet_in_before_32_loop
3432 pop eax
3433
3434ata_packet_no_before:
3435 mov cx, _ata_cmd_packet.lcount + 2[bp]
3436 jcxz ata_packet_after
3437
3438 mov di, _ata_cmd_packet.bufoff + 2[bp]
3439 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3440 mov es, ax
3441
3442 mov ah, _ata_cmd_packet.lmode + 2[bp]
3443 cmp ah, #ATA_MODE_PIO32
3444 je ata_packet_in_32
3445
3446ata_packet_in_16:
3447 rep
3448 insw ;; CX words transfered tp port(DX) to ES:[DI]
3449 jmp ata_packet_after
3450
3451ata_packet_in_32:
3452 rep
3453 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3454
3455ata_packet_after:
3456 mov cx, _ata_cmd_packet.lafter + 2[bp]
3457 jcxz ata_packet_done
3458
3459 mov ah, _ata_cmd_packet.lmode + 2[bp]
3460 cmp ah, #ATA_MODE_PIO32
3461 je ata_packet_in_after_32
3462
3463ata_packet_in_after_16:
3464 in ax, dx
3465 loop ata_packet_in_after_16
3466 jmp ata_packet_done
3467
3468ata_packet_in_after_32:
3469 push eax
3470ata_packet_in_after_32_loop:
3471 in eax, dx
3472 loop ata_packet_in_after_32_loop
3473 pop eax
3474
3475ata_packet_done:
3476 pop bp
3477ASM_END
3478
3479 // Compute new buffer address
3480 bufoff += count;
3481
3482 // Save transferred bytes count
3483 transfer += count;
3484 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3485 }
3486 }
3487
3488 // Final check, device must be ready
3489 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3490 != ATA_CB_STAT_RDY ) {
3491 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3492#ifdef VBOX
3493 // Enable interrupts
3494 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3495#endif /* VBOX */
3496 return 4;
3497 }
3498
3499 // Enable interrupts
3500 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3501 return 0;
3502}
3503
3504// ---------------------------------------------------------------------------
3505// End of ATA/ATAPI Driver
3506// ---------------------------------------------------------------------------
3507
3508// ---------------------------------------------------------------------------
3509// Start of ATA/ATAPI generic functions
3510// ---------------------------------------------------------------------------
3511
3512 Bit16u
3513atapi_get_sense(device)
3514 Bit16u device;
3515{
3516 Bit8u atacmd[12];
3517 Bit8u buffer[16];
3518 Bit8u i;
3519
3520 memsetb(get_SS(),atacmd,0,12);
3521
3522 // Request SENSE
3523 atacmd[0]=0x03;
3524 atacmd[4]=0x20;
3525 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3526 return 0x0002;
3527
3528 if ((buffer[0] & 0x7e) == 0x70) {
3529 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3530 }
3531
3532 return 0;
3533}
3534
3535 Bit16u
3536atapi_is_ready(device)
3537 Bit16u device;
3538{
3539 Bit8u atacmd[12];
3540 Bit8u buffer[];
3541
3542 memsetb(get_SS(),atacmd,0,12);
3543
3544 // Test Unit Ready
3545 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3546 return 0x000f;
3547
3548 if (atapi_get_sense(device) !=0 ) {
3549 memsetb(get_SS(),atacmd,0,12);
3550
3551 // try to send Test Unit Ready again
3552 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3553 return 0x000f;
3554
3555 return atapi_get_sense(device);
3556 }
3557 return 0;
3558}
3559
3560 Bit16u
3561atapi_is_cdrom(device)
3562 Bit8u device;
3563{
3564 Bit16u ebda_seg=read_word(0x0040,0x000E);
3565
3566 if (device >= BX_MAX_ATA_DEVICES)
3567 return 0;
3568
3569 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3570 return 0;
3571
3572 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3573 return 0;
3574
3575 return 1;
3576}
3577
3578// ---------------------------------------------------------------------------
3579// End of ATA/ATAPI generic functions
3580// ---------------------------------------------------------------------------
3581
3582#endif // BX_USE_ATADRV
3583
3584#if BX_ELTORITO_BOOT
3585
3586// ---------------------------------------------------------------------------
3587// Start of El-Torito boot functions
3588// ---------------------------------------------------------------------------
3589
3590 void
3591cdemu_init()
3592{
3593 Bit16u ebda_seg=read_word(0x0040,0x000E);
3594
3595 // the only important data is this one for now
3596 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3597}
3598
3599 Bit8u
3600cdemu_isactive()
3601{
3602 Bit16u ebda_seg=read_word(0x0040,0x000E);
3603
3604 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3605}
3606
3607 Bit8u
3608cdemu_emulated_drive()
3609{
3610 Bit16u ebda_seg=read_word(0x0040,0x000E);
3611
3612 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3613}
3614
3615static char isotag[6]="CD001";
3616static char eltorito[24]="EL TORITO SPECIFICATION";
3617//
3618// Returns ah: emulated drive, al: error code
3619//
3620 Bit16u
3621cdrom_boot()
3622{
3623 Bit16u ebda_seg=read_word(0x0040,0x000E);
3624 Bit8u atacmd[12], buffer[2048];
3625 Bit32u lba;
3626 Bit16u boot_segment, nbsectors, i, error;
3627 Bit8u device;
3628#ifdef VBOX
3629 Bit8u read_try;
3630#endif /* VBOX */
3631
3632 // Find out the first cdrom
3633 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3634 if (atapi_is_cdrom(device)) break;
3635 }
3636
3637 // if not found
3638 if(device >= BX_MAX_ATA_DEVICES) return 2;
3639
3640 // Read the Boot Record Volume Descriptor
3641 memsetb(get_SS(),atacmd,0,12);
3642 atacmd[0]=0x28; // READ command
3643 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3644 atacmd[8]=(0x01 & 0x00ff); // Sectors
3645 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3646 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3647 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3648 atacmd[5]=(0x11 & 0x000000ff);
3649#ifdef VBOX
3650 for (read_try = 0; read_try <= 4; read_try++)
3651 {
3652 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3653 if (!error)
3654 break;
3655 }
3656 if (error)
3657 return 3;
3658#else /* !VBOX */
3659 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3660 return 3;
3661#endif /* !VBOX */
3662
3663 // Validity checks
3664 if(buffer[0]!=0)return 4;
3665 for(i=0;i<5;i++){
3666 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3667 }
3668 for(i=0;i<23;i++)
3669 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3670
3671 // ok, now we calculate the Boot catalog address
3672 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3673
3674 // And we read the Boot Catalog
3675 memsetb(get_SS(),atacmd,0,12);
3676 atacmd[0]=0x28; // READ command
3677 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3678 atacmd[8]=(0x01 & 0x00ff); // Sectors
3679 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3680 atacmd[3]=(lba & 0x00ff0000) >> 16;
3681 atacmd[4]=(lba & 0x0000ff00) >> 8;
3682 atacmd[5]=(lba & 0x000000ff);
3683 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3684 return 7;
3685
3686 // Validation entry
3687 if(buffer[0x00]!=0x01)return 8; // Header
3688 if(buffer[0x01]!=0x00)return 9; // Platform
3689 if(buffer[0x1E]!=0x55)return 10; // key 1
3690 if(buffer[0x1F]!=0xAA)return 10; // key 2
3691
3692 // Initial/Default Entry
3693 if(buffer[0x20]!=0x88)return 11; // Bootable
3694
3695 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3696 if(buffer[0x21]==0){
3697 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3698 // Win2000 cd boot needs to know it booted from cd
3699 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3700 }
3701 else if(buffer[0x21]<4)
3702 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3703 else
3704 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3705
3706 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3707 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3708
3709 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3710 if(boot_segment==0x0000)boot_segment=0x07C0;
3711
3712 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3713 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3714
3715 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3716 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3717
3718 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3719 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3720
3721 // And we read the image in memory
3722 memsetb(get_SS(),atacmd,0,12);
3723 atacmd[0]=0x28; // READ command
3724 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3725 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3726 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3727 atacmd[3]=(lba & 0x00ff0000) >> 16;
3728 atacmd[4]=(lba & 0x0000ff00) >> 8;
3729 atacmd[5]=(lba & 0x000000ff);
3730 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3731 return 12;
3732
3733 // Remember the media type
3734 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3735 case 0x01: // 1.2M floppy
3736 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3737 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3738 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3739 break;
3740 case 0x02: // 1.44M floppy
3741 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3742 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3743 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3744 break;
3745 case 0x03: // 2.88M floppy
3746 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3747 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3748 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3749 break;
3750 case 0x04: // Harddrive
3751 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3752 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3753 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3754 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3755 break;
3756 }
3757
3758 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3759 // Increase bios installed hardware number of devices
3760 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3761 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3762 else
3763 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3764 }
3765
3766
3767 // everything is ok, so from now on, the emulation is active
3768 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3769 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3770
3771 // return the boot drive + no error
3772 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3773}
3774
3775// ---------------------------------------------------------------------------
3776// End of El-Torito boot functions
3777// ---------------------------------------------------------------------------
3778#endif // BX_ELTORITO_BOOT
3779
3780#ifdef VBOX_WITH_SCSI
3781# include "scsi.c"
3782#endif
3783
3784 void
3785int14_function(regs, ds, iret_addr)
3786 pusha_regs_t regs; // regs pushed from PUSHA instruction
3787 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3788 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3789{
3790 Bit16u addr,timer,val16;
3791 Bit8u timeout;
3792
3793 ASM_START
3794 sti
3795 ASM_END
3796
3797 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3798 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3799 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3800 switch (regs.u.r8.ah) {
3801 case 0:
3802 outb(addr+3, inb(addr+3) | 0x80);
3803 if (regs.u.r8.al & 0xE0 == 0) {
3804 outb(addr, 0x17);
3805 outb(addr+1, 0x04);
3806 } else {
3807 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3808 outb(addr, val16 & 0xFF);
3809 outb(addr+1, val16 >> 8);
3810 }
3811 outb(addr+3, regs.u.r8.al & 0x1F);
3812 regs.u.r8.ah = inb(addr+5);
3813 regs.u.r8.al = inb(addr+6);
3814 ClearCF(iret_addr.flags);
3815 break;
3816 case 1:
3817 timer = read_word(0x0040, 0x006C);
3818 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3819 val16 = read_word(0x0040, 0x006C);
3820 if (val16 != timer) {
3821 timer = val16;
3822 timeout--;
3823 }
3824 }
3825 if (timeout) outb(addr, regs.u.r8.al);
3826 regs.u.r8.ah = inb(addr+5);
3827 if (!timeout) regs.u.r8.ah |= 0x80;
3828 ClearCF(iret_addr.flags);
3829 break;
3830 case 2:
3831 timer = read_word(0x0040, 0x006C);
3832 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3833 val16 = read_word(0x0040, 0x006C);
3834 if (val16 != timer) {
3835 timer = val16;
3836 timeout--;
3837 }
3838 }
3839 if (timeout) {
3840 regs.u.r8.ah = 0;
3841 regs.u.r8.al = inb(addr);
3842 } else {
3843 regs.u.r8.ah = inb(addr+5);
3844 }
3845 ClearCF(iret_addr.flags);
3846 break;
3847 case 3:
3848 regs.u.r8.ah = inb(addr+5);
3849 regs.u.r8.al = inb(addr+6);
3850 ClearCF(iret_addr.flags);
3851 break;
3852 default:
3853 SetCF(iret_addr.flags); // Unsupported
3854 }
3855 } else {
3856 SetCF(iret_addr.flags); // Unsupported
3857 }
3858}
3859
3860 void
3861int15_function(regs, ES, DS, FLAGS)
3862 pusha_regs_t regs; // REGS pushed via pusha
3863 Bit16u ES, DS, FLAGS;
3864{
3865 Bit16u ebda_seg=read_word(0x0040,0x000E);
3866 bx_bool prev_a20_enable;
3867 Bit16u base15_00;
3868 Bit8u base23_16;
3869 Bit16u ss;
3870 Bit16u BX,CX,DX;
3871
3872 Bit16u bRegister;
3873 Bit8u irqDisable;
3874
3875BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3876
3877 switch (regs.u.r8.ah) {
3878#ifdef VBOX
3879 case 0x00: /* assorted functions */
3880 if (regs.u.r8.al != 0xc0)
3881 goto undecoded;
3882 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3883 * which we don't support, but logging that event is annoying. In fact
3884 * it is likely that they just misread some specs, because there is a
3885 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3886 * wants to achieve. */
3887 SET_CF();
3888 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3889 break;
3890#endif
3891 case 0x24: /* A20 Control */
3892 switch (regs.u.r8.al) {
3893 case 0x00:
3894 set_enable_a20(0);
3895 CLEAR_CF();
3896 regs.u.r8.ah = 0;
3897 break;
3898 case 0x01:
3899 set_enable_a20(1);
3900 CLEAR_CF();
3901 regs.u.r8.ah = 0;
3902 break;
3903 case 0x02:
3904 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3905 CLEAR_CF();
3906 regs.u.r8.ah = 0;
3907 break;
3908 case 0x03:
3909 CLEAR_CF();
3910 regs.u.r8.ah = 0;
3911 regs.u.r16.bx = 3;
3912 break;
3913 default:
3914 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3915 SET_CF();
3916 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3917 }
3918 break;
3919
3920 case 0x41:
3921 SET_CF();
3922 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3923 break;
3924
3925 case 0x4f:
3926 /* keyboard intercept */
3927#if BX_CPU < 2
3928 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3929#else
3930 // nop
3931#endif
3932 SET_CF();
3933 break;
3934
3935 case 0x52: // removable media eject
3936 CLEAR_CF();
3937 regs.u.r8.ah = 0; // "ok ejection may proceed"
3938 break;
3939
3940 case 0x83: {
3941 if( regs.u.r8.al == 0 ) {
3942 // Set Interval requested.
3943 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3944 // Interval not already set.
3945 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3946 write_word( 0x40, 0x98, ES ); // Byte location, segment
3947 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3948 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3949 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3950 CLEAR_CF( );
3951 irqDisable = inb( 0xA1 );
3952 outb( 0xA1, irqDisable & 0xFE );
3953 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3954 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3955 } else {
3956 // Interval already set.
3957 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3958 SET_CF();
3959 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3960 }
3961 } else if( regs.u.r8.al == 1 ) {
3962 // Clear Interval requested
3963 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3964 CLEAR_CF( );
3965 bRegister = inb_cmos( 0xB );
3966 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3967 } else {
3968 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3969 SET_CF();
3970 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3971 regs.u.r8.al--;
3972 }
3973
3974 break;
3975 }
3976
3977 case 0x87:
3978#if BX_CPU < 3
3979# error "Int15 function 87h not supported on < 80386"
3980#endif
3981 // +++ should probably have descriptor checks
3982 // +++ should have exception handlers
3983
3984 // turn off interrupts
3985ASM_START
3986 cli
3987ASM_END
3988
3989 prev_a20_enable = set_enable_a20(1); // enable A20 line
3990
3991 // 128K max of transfer on 386+ ???
3992 // source == destination ???
3993
3994 // ES:SI points to descriptor table
3995 // offset use initially comments
3996 // ==============================================
3997 // 00..07 Unused zeros Null descriptor
3998 // 08..0f GDT zeros filled in by BIOS
3999 // 10..17 source ssssssss source of data
4000 // 18..1f dest dddddddd destination of data
4001 // 20..27 CS zeros filled in by BIOS
4002 // 28..2f SS zeros filled in by BIOS
4003
4004 //es:si
4005 //eeee0
4006 //0ssss
4007 //-----
4008
4009// check for access rights of source & dest here
4010
4011 // Initialize GDT descriptor
4012 base15_00 = (ES << 4) + regs.u.r16.si;
4013 base23_16 = ES >> 12;
4014 if (base15_00 < (ES<<4))
4015 base23_16++;
4016 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4017 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4018 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4019 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4020 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4021
4022 // Initialize CS descriptor
4023 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4024 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4025 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4026 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4027 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4028
4029 // Initialize SS descriptor
4030 ss = get_SS();
4031 base15_00 = ss << 4;
4032 base23_16 = ss >> 12;
4033 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4034 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4035 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4036 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4037 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4038
4039 CX = regs.u.r16.cx;
4040ASM_START
4041 // Compile generates locals offset info relative to SP.
4042 // Get CX (word count) from stack.
4043 mov bx, sp
4044 SEG SS
4045 mov cx, _int15_function.CX [bx]
4046
4047 // since we need to set SS:SP, save them to the BDA
4048 // for future restore
4049 push eax
4050 xor eax, eax
4051 mov ds, ax
4052 mov 0x0469, ss
4053 mov 0x0467, sp
4054
4055 SEG ES
4056 lgdt [si + 0x08]
4057 SEG CS
4058 lidt [pmode_IDT_info]
4059 ;; perhaps do something with IDT here
4060
4061 ;; set PE bit in CR0
4062 mov eax, cr0
4063 or al, #0x01
4064 mov cr0, eax
4065 ;; far jump to flush CPU queue after transition to protected mode
4066 JMP_AP(0x0020, protected_mode)
4067
4068protected_mode:
4069 ;; GDT points to valid descriptor table, now load SS, DS, ES
4070 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4071 mov ss, ax
4072 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4073 mov ds, ax
4074 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4075 mov es, ax
4076 xor si, si
4077 xor di, di
4078 cld
4079 rep
4080 movsw ;; move CX words from DS:SI to ES:DI
4081
4082 ;; make sure DS and ES limits are 64KB
4083 mov ax, #0x28
4084 mov ds, ax
4085 mov es, ax
4086
4087 ;; reset PG bit in CR0 ???
4088 mov eax, cr0
4089 and al, #0xFE
4090 mov cr0, eax
4091
4092 ;; far jump to flush CPU queue after transition to real mode
4093 JMP_AP(0xf000, real_mode)
4094
4095real_mode:
4096 ;; restore IDT to normal real-mode defaults
4097 SEG CS
4098 lidt [rmode_IDT_info]
4099
4100 // restore SS:SP from the BDA
4101 xor ax, ax
4102 mov ds, ax
4103 mov ss, 0x0469
4104 mov sp, 0x0467
4105 pop eax
4106ASM_END
4107
4108 set_enable_a20(prev_a20_enable);
4109
4110 // turn back on interrupts
4111ASM_START
4112 sti
4113ASM_END
4114
4115 regs.u.r8.ah = 0;
4116 CLEAR_CF();
4117 break;
4118
4119
4120 case 0x88:
4121 // Get the amount of extended memory (above 1M)
4122#if BX_CPU < 2
4123 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4124 SET_CF();
4125#else
4126 regs.u.r8.al = inb_cmos(0x30);
4127 regs.u.r8.ah = inb_cmos(0x31);
4128
4129 // According to Ralf Brown's interrupt the limit should be 15M,
4130 // but real machines mostly return max. 63M.
4131 if(regs.u.r16.ax > 0xffc0)
4132 regs.u.r16.ax = 0xffc0;
4133
4134 CLEAR_CF();
4135#endif
4136 break;
4137
4138#ifdef VBOX
4139 case 0x89:
4140 // Switch to Protected Mode.
4141 // ES:DI points to user-supplied GDT
4142 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4143 // This subfunction does not return!
4144
4145// turn off interrupts
4146ASM_START
4147 cli
4148ASM_END
4149
4150 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4151
4152 // Initialize CS descriptor for BIOS
4153 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4154 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4155 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4156 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4157 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4158
4159 BX = regs.u.r16.bx;
4160ASM_START
4161 // Compiler generates locals offset info relative to SP.
4162 // Get BX (PIC offsets) from stack.
4163 mov bx, sp
4164 SEG SS
4165 mov bx, _int15_function.BX [bx]
4166
4167 // Program PICs
4168 mov al, #0x11 ; send initialisation commands
4169 out 0x20, al
4170 out 0xa0, al
4171 mov al, bh
4172 out 0x21, al
4173 mov al, bl
4174 out 0xa1, al
4175 mov al, #0x04
4176 out 0x21, al
4177 mov al, #0x02
4178 out 0xa1, al
4179 mov al, #0x01
4180 out 0x21, al
4181 out 0xa1, al
4182 mov al, #0xff ; mask all IRQs, user must re-enable
4183 out 0x21, al
4184 out 0xa1, al
4185
4186 // Load GDT and IDT from supplied data
4187 SEG ES
4188 lgdt [si + 0x08]
4189 SEG ES
4190 lidt [si + 0x10]
4191
4192 // set PE bit in CR0
4193 mov eax, cr0
4194 or al, #0x01
4195 mov cr0, eax
4196 // far jump to flush CPU queue after transition to protected mode
4197 JMP_AP(0x0038, protmode_switch)
4198
4199protmode_switch:
4200 ;; GDT points to valid descriptor table, now load SS, DS, ES
4201 mov ax, #0x28
4202 mov ss, ax
4203 mov ax, #0x18
4204 mov ds, ax
4205 mov ax, #0x20
4206 mov es, ax
4207
4208 // unwind the stack - this will break if calling sequence changes!
4209 mov sp,bp
4210 add sp,#4 ; skip return address
4211 popa ; restore regs
4212 pop ax ; skip saved es
4213 pop ax ; skip saved ds
4214 pop ax ; skip saved flags
4215
4216 // return to caller - note that we do not use IRET because
4217 // we cannot enable interrupts
4218 pop cx ; get return offset
4219 pop ax ; skip return segment
4220 pop ax ; skip flags
4221 mov ax, #0x30 ; ah must be 0 on successful exit
4222 push ax
4223 push cx ; re-create modified ret address on stack
4224 retf
4225
4226ASM_END
4227
4228 break;
4229#endif /* VBOX */
4230
4231 case 0x90:
4232 /* Device busy interrupt. Called by Int 16h when no key available */
4233 break;
4234
4235 case 0x91:
4236 /* Interrupt complete. Called by Int 16h when key becomes available */
4237 break;
4238
4239 case 0xbf:
4240 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4241 SET_CF();
4242 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4243 break;
4244
4245 case 0xC0:
4246#if 0
4247 SET_CF();
4248 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4249 break;
4250#endif
4251 CLEAR_CF();
4252 regs.u.r8.ah = 0;
4253 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4254 ES = 0xF000;
4255 break;
4256
4257 case 0xc1:
4258 ES = ebda_seg;
4259 CLEAR_CF();
4260 break;
4261
4262 case 0xd8:
4263 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4264 SET_CF();
4265 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4266 break;
4267
4268#ifdef VBOX
4269 /* Make the BIOS warning for pretty much every Linux kernel start
4270 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4271 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4272 SET_CF();
4273 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4274 break;
4275undecoded:
4276#endif /* VBOX */
4277 default:
4278 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4279 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4280 SET_CF();
4281 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4282 break;
4283 }
4284}
4285
4286#if BX_USE_PS2_MOUSE
4287 void
4288int15_function_mouse(regs, ES, DS, FLAGS)
4289 pusha_regs_t regs; // REGS pushed via pusha
4290 Bit16u ES, DS, FLAGS;
4291{
4292 Bit16u ebda_seg=read_word(0x0040,0x000E);
4293 Bit8u mouse_flags_1, mouse_flags_2;
4294 Bit16u mouse_driver_seg;
4295 Bit16u mouse_driver_offset;
4296 Bit8u mouse_cmd;
4297 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4298
4299BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4300
4301 switch (regs.u.r8.ah) {
4302 case 0xC2:
4303 // Return Codes status in AH
4304 // =========================
4305 // 00: success
4306 // 01: invalid subfunction (AL > 7)
4307 // 02: invalid input value (out of allowable range)
4308 // 03: interface error
4309 // 04: resend command received from mouse controller,
4310 // device driver should attempt command again
4311 // 05: cannot enable mouse, since no far call has been installed
4312 // 80/86: mouse service not implemented
4313
4314 if (regs.u.r8.al > 7) {
4315BX_DEBUG_INT15("unsupported subfn\n");
4316 // invalid function
4317 SET_CF();
4318 regs.u.r8.ah = 1;
4319 break;
4320 }
4321
4322 // Valid subfn; disable AUX input and IRQ12, assume no error
4323 set_kbd_command_byte(0x65);
4324 CLEAR_CF();
4325 regs.u.r8.ah = 0;
4326
4327 switch (regs.u.r8.al) {
4328 case 0: // Disable/Enable Mouse
4329BX_DEBUG_INT15("case 0: ");
4330 if (regs.u.r8.bh > 1) {
4331 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4332 // invalid subfunction
4333 SET_CF();
4334 regs.u.r8.ah = 1;
4335 break;
4336 }
4337 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4338 if ( (mouse_flags_2 & 0x80) == 0 ) {
4339 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4340 SET_CF();
4341 regs.u.r8.ah = 5; // no far call installed
4342 break;
4343 }
4344 if (regs.u.r8.bh == 0) {
4345BX_DEBUG_INT15("Disable Mouse\n");
4346 mouse_cmd = 0xF5; // disable mouse command
4347 } else {
4348BX_DEBUG_INT15("Enable Mouse\n");
4349 mouse_cmd = 0xF4; // enable mouse command
4350 }
4351
4352 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4353 if (ret == 0) {
4354 ret = get_mouse_data(&mouse_data1);
4355 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4356 // success
4357 break;
4358 }
4359 }
4360
4361 // interface error
4362 SET_CF();
4363 regs.u.r8.ah = 3;
4364 break;
4365
4366 case 5: // Initialize Mouse
4367 // Valid package sizes are 1 to 8
4368 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4369 SET_CF();
4370 regs.u.r8.ah = 2; // invalid input
4371 break;
4372 }
4373 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4374 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4375 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4376 // fall through!
4377
4378 case 1: // Reset Mouse
4379BX_DEBUG_INT15("case 1 or 5:\n");
4380 // clear current package byte index
4381 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4382 mouse_flags_1 = mouse_flags_1 & 0xf8;
4383 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4384 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4385 if (ret == 0) {
4386 ret = get_mouse_data(&mouse_data3);
4387 // if no mouse attached, it will return RESEND
4388 if (mouse_data3 == 0xfe) {
4389 SET_CF();
4390 regs.u.r8.ah = 4; // resend
4391 break;
4392 }
4393 if (mouse_data3 != 0xfa)
4394 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4395 if ( ret == 0 ) {
4396 ret = get_mouse_data(&mouse_data1);
4397 if ( ret == 0 ) {
4398 ret = get_mouse_data(&mouse_data2);
4399 if ( ret == 0 ) {
4400 // success
4401 regs.u.r8.bl = mouse_data1;
4402 regs.u.r8.bh = mouse_data2;
4403 break;
4404 }
4405 }
4406 }
4407 }
4408
4409 // interface error
4410 SET_CF();
4411 regs.u.r8.ah = 3;
4412 break;
4413
4414 case 2: // Set Sample Rate
4415BX_DEBUG_INT15("case 2:\n");
4416 switch (regs.u.r8.bh) {
4417 case 0: mouse_data1 = 10; break; // 10 reports/sec
4418 case 1: mouse_data1 = 20; break; // 20 reports/sec
4419 case 2: mouse_data1 = 40; break; // 40 reports/sec
4420 case 3: mouse_data1 = 60; break; // 60 reports/sec
4421 case 4: mouse_data1 = 80; break; // 80 reports/sec
4422 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4423 case 6: mouse_data1 = 200; break; // 200 reports/sec
4424 default: mouse_data1 = 0;
4425 }
4426 if (mouse_data1 > 0) {
4427 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4428 if (ret == 0) {
4429 ret = get_mouse_data(&mouse_data2);
4430 ret = send_to_mouse_ctrl(mouse_data1);
4431 ret = get_mouse_data(&mouse_data2);
4432 // success
4433 } else {
4434 // interface error
4435 SET_CF();
4436 regs.u.r8.ah = 3;
4437 }
4438 } else {
4439 // invalid input
4440 SET_CF();
4441 regs.u.r8.ah = 2;
4442 }
4443 break;
4444
4445 case 3: // Set Resolution
4446BX_DEBUG_INT15("case 3:\n");
4447 // BX:
4448 // 0 = 25 dpi, 1 count per millimeter
4449 // 1 = 50 dpi, 2 counts per millimeter
4450 // 2 = 100 dpi, 4 counts per millimeter
4451 // 3 = 200 dpi, 8 counts per millimeter
4452 if (regs.u.r8.bh < 4) {
4453 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4454 if (ret == 0) {
4455 ret = get_mouse_data(&mouse_data1);
4456 if (mouse_data1 != 0xfa)
4457 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4458 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4459 ret = get_mouse_data(&mouse_data1);
4460 if (mouse_data1 != 0xfa)
4461 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4462 // success
4463 } else {
4464 // interface error
4465 SET_CF();
4466 regs.u.r8.ah = 3;
4467 }
4468 } else {
4469 // invalid input
4470 SET_CF();
4471 regs.u.r8.ah = 2;
4472 }
4473 break;
4474
4475 case 4: // Get Device ID
4476BX_DEBUG_INT15("case 4:\n");
4477 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4478 if (ret == 0) {
4479 ret = get_mouse_data(&mouse_data1);
4480 ret = get_mouse_data(&mouse_data2);
4481 regs.u.r8.bh = mouse_data2;
4482 // success
4483 } else {
4484 // interface error
4485 SET_CF();
4486 regs.u.r8.ah = 3;
4487 }
4488 break;
4489
4490 case 6: // Return Status & Set Scaling Factor...
4491BX_DEBUG_INT15("case 6:\n");
4492 switch (regs.u.r8.bh) {
4493 case 0: // Return Status
4494 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4495 if (ret == 0) {
4496 ret = get_mouse_data(&mouse_data1);
4497 if (mouse_data1 != 0xfa)
4498 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4499 if (ret == 0) {
4500 ret = get_mouse_data(&mouse_data1);
4501 if ( ret == 0 ) {
4502 ret = get_mouse_data(&mouse_data2);
4503 if ( ret == 0 ) {
4504 ret = get_mouse_data(&mouse_data3);
4505 if ( ret == 0 ) {
4506 regs.u.r8.bl = mouse_data1;
4507 regs.u.r8.cl = mouse_data2;
4508 regs.u.r8.dl = mouse_data3;
4509 // success
4510 break;
4511 }
4512 }
4513 }
4514 }
4515 }
4516
4517 // interface error
4518 SET_CF();
4519 regs.u.r8.ah = 3;
4520 break;
4521
4522 case 1: // Set Scaling Factor to 1:1
4523 case 2: // Set Scaling Factor to 2:1
4524 if (regs.u.r8.bh == 1) {
4525 ret = send_to_mouse_ctrl(0xE6);
4526 } else {
4527 ret = send_to_mouse_ctrl(0xE7);
4528 }
4529 if (ret == 0) {
4530 get_mouse_data(&mouse_data1);
4531 ret = (mouse_data1 != 0xFA);
4532 }
4533 if (ret != 0) {
4534 // interface error
4535 SET_CF();
4536 regs.u.r8.ah = 3;
4537 }
4538 break;
4539
4540 default:
4541 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4542 // invalid subfunction
4543 SET_CF();
4544 regs.u.r8.ah = 1;
4545 }
4546 break;
4547
4548 case 7: // Set Mouse Handler Address
4549BX_DEBUG_INT15("case 7:\n");
4550 mouse_driver_seg = ES;
4551 mouse_driver_offset = regs.u.r16.bx;
4552 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4553 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4554 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4555 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4556 /* remove handler */
4557 if ( (mouse_flags_2 & 0x80) != 0 ) {
4558 mouse_flags_2 &= ~0x80;
4559 }
4560 }
4561 else {
4562 /* install handler */
4563 mouse_flags_2 |= 0x80;
4564 }
4565 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4566 break;
4567
4568 default:
4569 BX_PANIC("INT 15h C2 default case entered\n");
4570 // invalid subfunction
4571 SET_CF();
4572 regs.u.r8.ah = 1;
4573 }
4574BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4575 // Re-enable AUX input and IRQ12
4576 set_kbd_command_byte(0x47);
4577 break;
4578
4579 default:
4580 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4581 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4582 SET_CF();
4583 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4584 break;
4585 }
4586}
4587#endif
4588
4589
4590void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4591 Bit16u ES;
4592 Bit16u DI;
4593 Bit32u start;
4594 Bit32u end;
4595 Bit8u extra_start;
4596 Bit8u extra_end;
4597 Bit16u type;
4598{
4599 write_word(ES, DI, start);
4600 write_word(ES, DI+2, start >> 16);
4601 write_word(ES, DI+4, extra_start);
4602 write_word(ES, DI+6, 0x00);
4603
4604 end -= start;
4605 extra_end -= extra_start;
4606 write_word(ES, DI+8, end);
4607 write_word(ES, DI+10, end >> 16);
4608 write_word(ES, DI+12, extra_end);
4609 write_word(ES, DI+14, 0x0000);
4610
4611 write_word(ES, DI+16, type);
4612 write_word(ES, DI+18, 0x0);
4613}
4614
4615 void
4616int15_function32(regs, ES, DS, FLAGS)
4617 pushad_regs_t regs; // REGS pushed via pushad
4618 Bit16u ES, DS, FLAGS;
4619{
4620 Bit32u extended_memory_size=0; // 64bits long
4621 Bit32u extra_lowbits_memory_size=0;
4622 Bit16u CX,DX;
4623 Bit8u extra_highbits_memory_size=0;
4624
4625BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4626
4627 switch (regs.u.r8.ah) {
4628 case 0x86:
4629 // Wait for CX:DX microseconds. currently using the
4630 // refresh request port 0x61 bit4, toggling every 15usec
4631
4632 CX = regs.u.r16.cx;
4633 DX = regs.u.r16.dx;
4634
4635ASM_START
4636 sti
4637
4638 ;; Get the count in eax
4639 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4640 mov bx, sp
4641 SEG SS
4642 mov ax, _int15_function32.CX [bx]
4643 shl eax, #16
4644 SEG SS
4645 mov ax, _int15_function32.DX [bx]
4646
4647 ;; convert to numbers of 15usec ticks
4648 mov ebx, #15
4649 xor edx, edx
4650 div eax, ebx
4651 mov ecx, eax
4652
4653 ;; wait for ecx number of refresh requests
4654 in al, #0x61
4655 and al,#0x10
4656 mov ah, al
4657
4658 or ecx, ecx
4659 je int1586_tick_end
4660int1586_tick:
4661 in al, #0x61
4662 and al,#0x10
4663 cmp al, ah
4664 je int1586_tick
4665 mov ah, al
4666 dec ecx
4667 jnz int1586_tick
4668int1586_tick_end:
4669ASM_END
4670
4671 break;
4672
4673 case 0xe8:
4674 switch(regs.u.r8.al)
4675 {
4676 case 0x20: // coded by osmaker aka K.J.
4677 if(regs.u.r32.edx == 0x534D4150)
4678 {
4679 extended_memory_size = inb_cmos(0x35);
4680 extended_memory_size <<= 8;
4681 extended_memory_size |= inb_cmos(0x34);
4682 extended_memory_size *= 64;
4683#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4684 // greater than EFF00000???
4685 if(extended_memory_size > 0x3bc000) {
4686 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4687 }
4688#endif /* !VBOX */
4689 extended_memory_size *= 1024;
4690 extended_memory_size += (16L * 1024 * 1024);
4691
4692 if(extended_memory_size <= (16L * 1024 * 1024)) {
4693 extended_memory_size = inb_cmos(0x31);
4694 extended_memory_size <<= 8;
4695 extended_memory_size |= inb_cmos(0x30);
4696 extended_memory_size *= 1024;
4697 extended_memory_size += (1L * 1024 * 1024);
4698 }
4699
4700#ifdef VBOX /* We've already used the CMOS entries for SATA.
4701 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4702 extra_lowbits_memory_size = inb_cmos(0x62);
4703 extra_lowbits_memory_size <<= 8;
4704 extra_lowbits_memory_size |= inb_cmos(0x61);
4705 extra_lowbits_memory_size <<= 16;
4706 extra_highbits_memory_size = inb_cmos(0x63);
4707 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4708#else
4709 extra_lowbits_memory_size = inb_cmos(0x5c);
4710 extra_lowbits_memory_size <<= 8;
4711 extra_lowbits_memory_size |= inb_cmos(0x5b);
4712 extra_lowbits_memory_size *= 64;
4713 extra_lowbits_memory_size *= 1024;
4714 extra_highbits_memory_size = inb_cmos(0x5d);
4715#endif /* !VBOX */
4716
4717 switch(regs.u.r16.bx)
4718 {
4719 case 0:
4720 set_e820_range(ES, regs.u.r16.di,
4721#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4722 0x0000000L, 0x0009f000L, 0, 0, 1);
4723#else
4724 0x0000000L, 0x0009fc00L, 0, 0, 1);
4725#endif
4726 regs.u.r32.ebx = 1;
4727 break;
4728 case 1:
4729 set_e820_range(ES, regs.u.r16.di,
4730#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4731 0x0009f000L, 0x000a0000L, 0, 0, 2);
4732#else
4733 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4734#endif
4735 regs.u.r32.ebx = 2;
4736 break;
4737 case 2:
4738#ifdef VBOX
4739 /* Mark the BIOS as reserved. VBox doesn't currently
4740 * use the 0xe0000-0xeffff area. It does use the
4741 * 0xd0000-0xdffff area for the BIOS logo, but it's
4742 * not worth marking it as reserved. Note that various
4743 * Windows versions don't accept (read: in debug builds
4744 * they trigger the "Too many similar traps" assertion)
4745 * a single reserved range from 0xd0000 to 0xffffff.
4746 * A 128K area starting from 0xd0000 works. */
4747 set_e820_range(ES, regs.u.r16.di,
4748 0x000f0000L, 0x00100000L, 0, 0, 2);
4749#else /* !VBOX */
4750 set_e820_range(ES, regs.u.r16.di,
4751 0x000e8000L, 0x00100000L, 0, 0, 2);
4752#endif /* !VBOX */
4753 regs.u.r32.ebx = 3;
4754 break;
4755 case 3:
4756#if BX_ROMBIOS32 || defined(VBOX)
4757 set_e820_range(ES, regs.u.r16.di,
4758 0x00100000L,
4759 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4760 regs.u.r32.ebx = 4;
4761#else
4762 set_e820_range(ES, regs.u.r16.di,
4763 0x00100000L,
4764 extended_memory_size, 1);
4765 regs.u.r32.ebx = 5;
4766#endif
4767 break;
4768 case 4:
4769 set_e820_range(ES, regs.u.r16.di,
4770 extended_memory_size - ACPI_DATA_SIZE,
4771 extended_memory_size, 0, 0, 3); // ACPI RAM
4772 regs.u.r32.ebx = 5;
4773 break;
4774 case 5:
4775 /* 256KB BIOS area at the end of 4 GB */
4776#ifdef VBOX
4777 /* We don't set the end to 1GB here and rely on the 32-bit
4778 unsigned wrap around effect (0-0xfffc0000L). */
4779#endif
4780 set_e820_range(ES, regs.u.r16.di,
4781 0xfffc0000L, 0x00000000L, 0, 0, 2);
4782 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4783 regs.u.r32.ebx = 6;
4784 else
4785 regs.u.r32.ebx = 0;
4786 break;
4787 case 6:
4788#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4789 /* Mapping of memory above 4 GB if present.
4790 Note: set_e820_range needs do no borrowing in the
4791 subtraction because of the nice numbers. */
4792 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4793 {
4794 set_e820_range(ES, regs.u.r16.di,
4795 0x00000000L, extra_lowbits_memory_size,
4796 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4797 regs.u.r32.ebx = 0;
4798 break;
4799 }
4800 /* fall thru */
4801#else /* !VBOX */
4802 /* Maping of memory above 4 GB */
4803 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4804 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4805 + 1, 1);
4806 regs.u.r32.ebx = 0;
4807 break;
4808#endif /* !VBOX */
4809 default: /* AX=E820, DX=534D4150, BX unrecognized */
4810 goto int15_unimplemented;
4811 break;
4812 }
4813 regs.u.r32.eax = 0x534D4150;
4814 regs.u.r32.ecx = 0x14;
4815 CLEAR_CF();
4816 } else {
4817 // if DX != 0x534D4150)
4818 goto int15_unimplemented;
4819 }
4820 break;
4821
4822 case 0x01:
4823 // do we have any reason to fail here ?
4824 CLEAR_CF();
4825
4826 // my real system sets ax and bx to 0
4827 // this is confirmed by Ralph Brown list
4828 // but syslinux v1.48 is known to behave
4829 // strangely if ax is set to 0
4830 // regs.u.r16.ax = 0;
4831 // regs.u.r16.bx = 0;
4832
4833 // Get the amount of extended memory (above 1M)
4834 regs.u.r8.cl = inb_cmos(0x30);
4835 regs.u.r8.ch = inb_cmos(0x31);
4836
4837 // limit to 15M
4838 if(regs.u.r16.cx > 0x3c00)
4839 {
4840 regs.u.r16.cx = 0x3c00;
4841 }
4842
4843 // Get the amount of extended memory above 16M in 64k blocs
4844 regs.u.r8.dl = inb_cmos(0x34);
4845 regs.u.r8.dh = inb_cmos(0x35);
4846
4847 // Set configured memory equal to extended memory
4848 regs.u.r16.ax = regs.u.r16.cx;
4849 regs.u.r16.bx = regs.u.r16.dx;
4850 break;
4851 default: /* AH=0xE8?? but not implemented */
4852 goto int15_unimplemented;
4853 }
4854 break;
4855 int15_unimplemented:
4856 // fall into the default
4857 default:
4858 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4859 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4860 SET_CF();
4861 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4862 break;
4863 }
4864}
4865
4866 void
4867int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4868 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4869{
4870 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4871 Bit16u kbd_code, max;
4872
4873 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4874
4875 shift_flags = read_byte(0x0040, 0x17);
4876 led_flags = read_byte(0x0040, 0x97);
4877 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4878ASM_START
4879 cli
4880ASM_END
4881 outb(0x60, 0xed);
4882 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4883 if ((inb(0x60) == 0xfa)) {
4884 led_flags &= 0xf8;
4885 led_flags |= ((shift_flags >> 4) & 0x07);
4886 outb(0x60, led_flags & 0x07);
4887 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4888 inb(0x60);
4889 write_byte(0x0040, 0x97, led_flags);
4890 }
4891ASM_START
4892 sti
4893ASM_END
4894 }
4895
4896 switch (GET_AH()) {
4897 case 0x00: /* read keyboard input */
4898
4899 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4900 BX_PANIC("KBD: int16h: out of keyboard input\n");
4901 }
4902 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4903 else if (ascii_code == 0xE0) ascii_code = 0;
4904 AX = (scan_code << 8) | ascii_code;
4905 break;
4906
4907 case 0x01: /* check keyboard status */
4908 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4909 SET_ZF();
4910 return;
4911 }
4912 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4913 else if (ascii_code == 0xE0) ascii_code = 0;
4914 AX = (scan_code << 8) | ascii_code;
4915 CLEAR_ZF();
4916 break;
4917
4918 case 0x02: /* get shift flag status */
4919 shift_flags = read_byte(0x0040, 0x17);
4920 SET_AL(shift_flags);
4921 break;
4922
4923 case 0x05: /* store key-stroke into buffer */
4924 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4925 SET_AL(1);
4926 }
4927 else {
4928 SET_AL(0);
4929 }
4930 break;
4931
4932 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4933 // bit Bochs Description
4934 // 7 0 reserved
4935 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4936 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4937 // 4 1 INT 16/AH=0Ah supported
4938 // 3 0 INT 16/AX=0306h supported
4939 // 2 0 INT 16/AX=0305h supported
4940 // 1 0 INT 16/AX=0304h supported
4941 // 0 0 INT 16/AX=0300h supported
4942 //
4943 SET_AL(0x30);
4944 break;
4945
4946 case 0x0A: /* GET KEYBOARD ID */
4947 count = 2;
4948 kbd_code = 0x0;
4949 outb(0x60, 0xf2);
4950 /* Wait for data */
4951 max=0xffff;
4952 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4953 if (max>0x0) {
4954 if ((inb(0x60) == 0xfa)) {
4955 do {
4956 max=0xffff;
4957 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4958 if (max>0x0) {
4959 kbd_code >>= 8;
4960 kbd_code |= (inb(0x60) << 8);
4961 }
4962 } while (--count>0);
4963 }
4964 }
4965 BX=kbd_code;
4966 break;
4967
4968 case 0x10: /* read MF-II keyboard input */
4969
4970 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4971 BX_PANIC("KBD: int16h: out of keyboard input\n");
4972 }
4973 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4974 AX = (scan_code << 8) | ascii_code;
4975 break;
4976
4977 case 0x11: /* check MF-II keyboard status */
4978 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4979 SET_ZF();
4980 return;
4981 }
4982 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4983 AX = (scan_code << 8) | ascii_code;
4984 CLEAR_ZF();
4985 break;
4986
4987 case 0x12: /* get extended keyboard status */
4988 shift_flags = read_byte(0x0040, 0x17);
4989 SET_AL(shift_flags);
4990 shift_flags = read_byte(0x0040, 0x18) & 0x73;
4991 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
4992 SET_AH(shift_flags);
4993 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4994 break;
4995
4996 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4997 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4998 break;
4999
5000 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5001 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5002 break;
5003
5004 case 0x6F:
5005 if (GET_AL() == 0x08)
5006 SET_AH(0x02); // unsupported, aka normal keyboard
5007
5008 default:
5009 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5010 }
5011}
5012
5013 unsigned int
5014dequeue_key(scan_code, ascii_code, incr)
5015 Bit8u *scan_code;
5016 Bit8u *ascii_code;
5017 unsigned int incr;
5018{
5019 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5020 Bit16u ss;
5021 Bit8u acode, scode;
5022
5023#if BX_CPU < 2
5024 buffer_start = 0x001E;
5025 buffer_end = 0x003E;
5026#else
5027 buffer_start = read_word(0x0040, 0x0080);
5028 buffer_end = read_word(0x0040, 0x0082);
5029#endif
5030
5031 buffer_head = read_word(0x0040, 0x001a);
5032 buffer_tail = read_word(0x0040, 0x001c);
5033
5034 if (buffer_head != buffer_tail) {
5035 ss = get_SS();
5036 acode = read_byte(0x0040, buffer_head);
5037 scode = read_byte(0x0040, buffer_head+1);
5038 write_byte(ss, ascii_code, acode);
5039 write_byte(ss, scan_code, scode);
5040
5041 if (incr) {
5042 buffer_head += 2;
5043 if (buffer_head >= buffer_end)
5044 buffer_head = buffer_start;
5045 write_word(0x0040, 0x001a, buffer_head);
5046 }
5047 return(1);
5048 }
5049 else {
5050 return(0);
5051 }
5052}
5053
5054static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5055
5056 Bit8u
5057send_to_mouse_ctrl(sendbyte)
5058 Bit8u sendbyte;
5059{
5060 Bit8u response;
5061
5062 // wait for chance to write to ctrl
5063 if ( inb(0x64) & 0x02 )
5064 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5065 outb(0x64, 0xD4);
5066 outb(0x60, sendbyte);
5067 return(0);
5068}
5069
5070
5071 Bit8u
5072get_mouse_data(data)
5073 Bit8u *data;
5074{
5075 Bit8u response;
5076 Bit16u ss;
5077
5078 while ( (inb(0x64) & 0x21) != 0x21 ) {
5079 }
5080
5081 response = inb(0x60);
5082
5083 ss = get_SS();
5084 write_byte(ss, data, response);
5085 return(0);
5086}
5087
5088 void
5089set_kbd_command_byte(command_byte)
5090 Bit8u command_byte;
5091{
5092 if ( inb(0x64) & 0x02 )
5093 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5094
5095 outb(0x64, 0x60); // write command byte
5096 outb(0x60, command_byte);
5097}
5098
5099 void
5100int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5101 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5102{
5103 Bit8u scancode, asciicode, shift_flags;
5104 Bit8u mf2_flags, mf2_state;
5105
5106 //
5107 // DS has been set to F000 before call
5108 //
5109
5110
5111 scancode = GET_AL();
5112
5113 if (scancode == 0) {
5114 BX_INFO("KBD: int09 handler: AL=0\n");
5115 return;
5116 }
5117
5118
5119 shift_flags = read_byte(0x0040, 0x17);
5120 mf2_flags = read_byte(0x0040, 0x18);
5121 mf2_state = read_byte(0x0040, 0x96);
5122 asciicode = 0;
5123
5124 switch (scancode) {
5125 case 0x3a: /* Caps Lock press */
5126 shift_flags ^= 0x40;
5127 write_byte(0x0040, 0x17, shift_flags);
5128 mf2_flags |= 0x40;
5129 write_byte(0x0040, 0x18, mf2_flags);
5130 break;
5131 case 0xba: /* Caps Lock release */
5132 mf2_flags &= ~0x40;
5133 write_byte(0x0040, 0x18, mf2_flags);
5134 break;
5135
5136 case 0x2a: /* L Shift press */
5137 shift_flags |= 0x02;
5138 write_byte(0x0040, 0x17, shift_flags);
5139 break;
5140 case 0xaa: /* L Shift release */
5141 shift_flags &= ~0x02;
5142 write_byte(0x0040, 0x17, shift_flags);
5143 break;
5144
5145 case 0x36: /* R Shift press */
5146 shift_flags |= 0x01;
5147 write_byte(0x0040, 0x17, shift_flags);
5148 break;
5149 case 0xb6: /* R Shift release */
5150 shift_flags &= ~0x01;
5151 write_byte(0x0040, 0x17, shift_flags);
5152 break;
5153
5154 case 0x1d: /* Ctrl press */
5155 if ((mf2_state & 0x01) == 0) {
5156 shift_flags |= 0x04;
5157 write_byte(0x0040, 0x17, shift_flags);
5158 if (mf2_state & 0x02) {
5159 mf2_state |= 0x04;
5160 write_byte(0x0040, 0x96, mf2_state);
5161 } else {
5162 mf2_flags |= 0x01;
5163 write_byte(0x0040, 0x18, mf2_flags);
5164 }
5165 }
5166 break;
5167 case 0x9d: /* Ctrl release */
5168 if ((mf2_state & 0x01) == 0) {
5169 shift_flags &= ~0x04;
5170 write_byte(0x0040, 0x17, shift_flags);
5171 if (mf2_state & 0x02) {
5172 mf2_state &= ~0x04;
5173 write_byte(0x0040, 0x96, mf2_state);
5174 } else {
5175 mf2_flags &= ~0x01;
5176 write_byte(0x0040, 0x18, mf2_flags);
5177 }
5178 }
5179 break;
5180
5181 case 0x38: /* Alt press */
5182 shift_flags |= 0x08;
5183 write_byte(0x0040, 0x17, shift_flags);
5184 if (mf2_state & 0x02) {
5185 mf2_state |= 0x08;
5186 write_byte(0x0040, 0x96, mf2_state);
5187 } else {
5188 mf2_flags |= 0x02;
5189 write_byte(0x0040, 0x18, mf2_flags);
5190 }
5191 break;
5192 case 0xb8: /* Alt release */
5193 shift_flags &= ~0x08;
5194 write_byte(0x0040, 0x17, shift_flags);
5195 if (mf2_state & 0x02) {
5196 mf2_state &= ~0x08;
5197 write_byte(0x0040, 0x96, mf2_state);
5198 } else {
5199 mf2_flags &= ~0x02;
5200 write_byte(0x0040, 0x18, mf2_flags);
5201 }
5202 break;
5203
5204 case 0x45: /* Num Lock press */
5205 if ((mf2_state & 0x03) == 0) {
5206 mf2_flags |= 0x20;
5207 write_byte(0x0040, 0x18, mf2_flags);
5208 shift_flags ^= 0x20;
5209 write_byte(0x0040, 0x17, shift_flags);
5210 }
5211 break;
5212 case 0xc5: /* Num Lock release */
5213 if ((mf2_state & 0x03) == 0) {
5214 mf2_flags &= ~0x20;
5215 write_byte(0x0040, 0x18, mf2_flags);
5216 }
5217 break;
5218
5219 case 0x46: /* Scroll Lock press */
5220 mf2_flags |= 0x10;
5221 write_byte(0x0040, 0x18, mf2_flags);
5222 shift_flags ^= 0x10;
5223 write_byte(0x0040, 0x17, shift_flags);
5224 break;
5225
5226 case 0xc6: /* Scroll Lock release */
5227 mf2_flags &= ~0x10;
5228 write_byte(0x0040, 0x18, mf2_flags);
5229 break;
5230
5231 default:
5232 if (scancode & 0x80) {
5233 break; /* toss key releases ... */
5234 }
5235 if (scancode > MAX_SCAN_CODE) {
5236 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5237 return;
5238 }
5239 if (shift_flags & 0x08) { /* ALT */
5240 asciicode = scan_to_scanascii[scancode].alt;
5241 scancode = scan_to_scanascii[scancode].alt >> 8;
5242 } else if (shift_flags & 0x04) { /* CONTROL */
5243 asciicode = scan_to_scanascii[scancode].control;
5244 scancode = scan_to_scanascii[scancode].control >> 8;
5245 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5246 /* extended keys handling */
5247 asciicode = 0xe0;
5248 scancode = scan_to_scanascii[scancode].normal >> 8;
5249 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5250 /* check if lock state should be ignored
5251 * because a SHIFT key are pressed */
5252
5253 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5254 asciicode = scan_to_scanascii[scancode].normal;
5255 scancode = scan_to_scanascii[scancode].normal >> 8;
5256 } else {
5257 asciicode = scan_to_scanascii[scancode].shift;
5258 scancode = scan_to_scanascii[scancode].shift >> 8;
5259 }
5260 } else {
5261 /* check if lock is on */
5262 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5263 asciicode = scan_to_scanascii[scancode].shift;
5264 scancode = scan_to_scanascii[scancode].shift >> 8;
5265 } else {
5266 asciicode = scan_to_scanascii[scancode].normal;
5267 scancode = scan_to_scanascii[scancode].normal >> 8;
5268 }
5269 }
5270 if (scancode==0 && asciicode==0) {
5271 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5272 }
5273 enqueue_key(scancode, asciicode);
5274 break;
5275 }
5276 if ((scancode & 0x7f) != 0x1d) {
5277 mf2_state &= ~0x01;
5278 }
5279 mf2_state &= ~0x02;
5280 write_byte(0x0040, 0x96, mf2_state);
5281}
5282
5283 unsigned int
5284enqueue_key(scan_code, ascii_code)
5285 Bit8u scan_code, ascii_code;
5286{
5287 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5288
5289#if BX_CPU < 2
5290 buffer_start = 0x001E;
5291 buffer_end = 0x003E;
5292#else
5293 buffer_start = read_word(0x0040, 0x0080);
5294 buffer_end = read_word(0x0040, 0x0082);
5295#endif
5296
5297 buffer_head = read_word(0x0040, 0x001A);
5298 buffer_tail = read_word(0x0040, 0x001C);
5299
5300 temp_tail = buffer_tail;
5301 buffer_tail += 2;
5302 if (buffer_tail >= buffer_end)
5303 buffer_tail = buffer_start;
5304
5305 if (buffer_tail == buffer_head) {
5306 return(0);
5307 }
5308
5309 write_byte(0x0040, temp_tail, ascii_code);
5310 write_byte(0x0040, temp_tail+1, scan_code);
5311 write_word(0x0040, 0x001C, buffer_tail);
5312 return(1);
5313}
5314
5315
5316 void
5317int74_function(make_farcall, Z, Y, X, status)
5318 Bit16u make_farcall, Z, Y, X, status;
5319{
5320 Bit16u ebda_seg=read_word(0x0040,0x000E);
5321 Bit8u in_byte, index, package_count;
5322 Bit8u mouse_flags_1, mouse_flags_2;
5323
5324BX_DEBUG_INT74("entering int74_function\n");
5325 make_farcall = 0;
5326
5327 in_byte = inb(0x64);
5328 if ( (in_byte & 0x21) != 0x21 ) {
5329 return;
5330 }
5331 in_byte = inb(0x60);
5332BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5333
5334 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5335 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5336
5337 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5338 return;
5339 }
5340
5341 package_count = mouse_flags_2 & 0x07;
5342 index = mouse_flags_1 & 0x07;
5343 write_byte(ebda_seg, 0x28 + index, in_byte);
5344
5345 if ( index >= package_count ) {
5346BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5347 status = read_byte(ebda_seg, 0x0028 + 0);
5348 X = read_byte(ebda_seg, 0x0028 + 1);
5349 Y = read_byte(ebda_seg, 0x0028 + 2);
5350 Z = 0;
5351 mouse_flags_1 = 0;
5352 // check if far call handler installed
5353 if (mouse_flags_2 & 0x80)
5354 make_farcall = 1;
5355 }
5356 else {
5357 mouse_flags_1++;
5358 }
5359 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5360}
5361
5362#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5363
5364#if BX_USE_ATADRV
5365
5366 void
5367int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5368 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5369{
5370 Bit32u lba;
5371 Bit16u ebda_seg=read_word(0x0040,0x000E);
5372 Bit16u cylinder, head, sector;
5373 Bit16u segment, offset;
5374 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5375 Bit16u size, count;
5376 Bit8u device, status;
5377
5378 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5379
5380 write_byte(0x0040, 0x008e, 0); // clear completion flag
5381
5382#ifdef VBOX_WITH_SCSI
5383 // basic check : device has to be defined
5384 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) ) {
5385 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5386 goto int13_fail;
5387 }
5388#else
5389 // basic check : device has to be defined
5390 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5391 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5392 goto int13_fail;
5393 }
5394#endif
5395
5396 // Get the ata channel
5397 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5398
5399#ifdef VBOX_WITH_SCSI
5400 // basic check : device has to be valid
5401 if (device >= BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES) {
5402 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5403 goto int13_fail;
5404 }
5405#else
5406 // basic check : device has to be valid
5407 if (device >= BX_MAX_ATA_DEVICES) {
5408 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5409 goto int13_fail;
5410 }
5411#endif
5412
5413 switch (GET_AH()) {
5414
5415 case 0x00: /* disk controller reset */
5416#ifdef VBOX_WITH_SCSI
5417 /* SCSI controller does not need a reset. */
5418 if (!VBOX_IS_SCSI_DEVICE(device))
5419#endif
5420 ata_reset (device);
5421 goto int13_success;
5422 break;
5423
5424 case 0x01: /* read disk status */
5425 status = read_byte(0x0040, 0x0074);
5426 SET_AH(status);
5427 SET_DISK_RET_STATUS(0);
5428 /* set CF if error status read */
5429 if (status) goto int13_fail_nostatus;
5430 else goto int13_success_noah;
5431 break;
5432
5433 case 0x02: // read disk sectors
5434 case 0x03: // write disk sectors
5435 case 0x04: // verify disk sectors
5436
5437 count = GET_AL();
5438 cylinder = GET_CH();
5439 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5440 sector = (GET_CL() & 0x3f);
5441 head = GET_DH();
5442
5443 segment = ES;
5444 offset = BX;
5445
5446 if ( (count > 128) || (count == 0) ) {
5447 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5448 goto int13_fail;
5449 }
5450
5451#ifdef VBOX_WITH_SCSI
5452 if (!VBOX_IS_SCSI_DEVICE(device))
5453#endif
5454 {
5455 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5456 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5457 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5458 }
5459#ifdef VBOX_WITH_SCSI
5460 else
5461 {
5462 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5463
5464 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5465 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5466 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5467 }
5468#endif
5469
5470 // sanity check on cyl heads, sec
5471 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5472 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5473 goto int13_fail;
5474 }
5475
5476 // FIXME verify
5477 if ( GET_AH() == 0x04 ) goto int13_success;
5478
5479#ifdef VBOX_WITH_SCSI
5480 if (!VBOX_IS_SCSI_DEVICE(device))
5481#endif
5482 {
5483 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5484 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5485 }
5486#ifdef VBOX_WITH_SCSI
5487 else
5488 {
5489 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5490 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5491 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5492 }
5493#endif
5494
5495 // if needed, translate lchs to lba, and execute command
5496#ifdef VBOX_WITH_SCSI
5497 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5498 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5499 sector = 0; // this forces the command to be lba
5500 }
5501#else
5502 if (( (nph != nlh) || (npspt != nlspt)) ) {
5503 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5504 sector = 0; // this forces the command to be lba
5505 }
5506#endif
5507
5508 if ( GET_AH() == 0x02 )
5509 {
5510#ifdef VBOX_WITH_SCSI
5511 if (VBOX_IS_SCSI_DEVICE(device))
5512 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5513 else
5514#endif
5515 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5516 }
5517 else
5518 {
5519#ifdef VBOX_WITH_SCSI
5520 if (VBOX_IS_SCSI_DEVICE(device))
5521 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5522 else
5523#endif
5524 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5525 }
5526
5527 // Set nb of sector transferred
5528 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5529
5530 if (status != 0) {
5531 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5532 SET_AH(0x0c);
5533 goto int13_fail_noah;
5534 }
5535
5536 goto int13_success;
5537 break;
5538
5539 case 0x05: /* format disk track */
5540 BX_INFO("format disk track called\n");
5541 goto int13_success;
5542 return;
5543 break;
5544
5545 case 0x08: /* read disk drive parameters */
5546
5547 // Get logical geometry from table
5548#ifdef VBOX_WITH_SCSI
5549 if (!VBOX_IS_SCSI_DEVICE(device))
5550#endif
5551 {
5552 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5553 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5554 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5555 }
5556#ifdef VBOX_WITH_SCSI
5557 else
5558 {
5559 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5560 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5561 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5562 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5563 }
5564#endif
5565
5566 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5567#ifndef VBOX
5568 nlc = nlc - 2; /* 0 based , last sector not used */
5569#else /* VBOX */
5570 /* Maximum cylinder number is just one less than the number of cylinders. */
5571 nlc = nlc - 1; /* 0 based , last sector not used */
5572#endif /* VBOX */
5573 SET_AL(0);
5574 SET_CH(nlc & 0xff);
5575 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5576 SET_DH(nlh - 1);
5577 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5578
5579 // FIXME should set ES & DI
5580
5581 goto int13_success;
5582 break;
5583
5584 case 0x10: /* check drive ready */
5585 // should look at 40:8E also???
5586
5587 // Read the status from controller
5588 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5589 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5590 goto int13_success;
5591 }
5592 else {
5593 SET_AH(0xAA);
5594 goto int13_fail_noah;
5595 }
5596 break;
5597
5598 case 0x15: /* read disk drive size */
5599
5600 // Get physical geometry from table
5601#ifdef VBOX_WITH_SCSI
5602 if (!VBOX_IS_SCSI_DEVICE(device))
5603#endif
5604 {
5605 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5606 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5607 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5608 }
5609#ifdef VBOX_WITH_SCSI
5610 else
5611 {
5612 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5613 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5614 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5615 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5616 }
5617#endif
5618
5619 // Compute sector count seen by int13
5620#ifndef VBOX
5621 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5622#else /* VBOX */
5623 /* Is it so hard to multiply a couple of counts (without introducing
5624 * arbitrary off by one errors)? */
5625 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5626#endif /* VBOX */
5627 CX = lba >> 16;
5628 DX = lba & 0xffff;
5629
5630 SET_AH(3); // hard disk accessible
5631 goto int13_success_noah;
5632 break;
5633
5634 case 0x41: // IBM/MS installation check
5635 BX=0xaa55; // install check
5636 SET_AH(0x30); // EDD 3.0
5637 CX=0x0007; // ext disk access and edd, removable supported
5638 goto int13_success_noah;
5639 break;
5640
5641 case 0x42: // IBM/MS extended read
5642 case 0x43: // IBM/MS extended write
5643 case 0x44: // IBM/MS verify
5644 case 0x47: // IBM/MS extended seek
5645
5646 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5647 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5648 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5649
5650 // Can't use 64 bits lba
5651 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5652 if (lba != 0L) {
5653 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5654 goto int13_fail;
5655 }
5656
5657 // Get 32 bits lba and check
5658 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5659
5660#ifdef VBOX_WITH_SCSI
5661 if (VBOX_IS_SCSI_DEVICE(device))
5662 {
5663 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5664 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5665 goto int13_fail;
5666 }
5667 }
5668 else
5669#endif
5670 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5671 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5672 goto int13_fail;
5673 }
5674
5675
5676 // If verify or seek
5677 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5678 goto int13_success;
5679
5680 // Execute the command
5681 if ( GET_AH() == 0x42 )
5682#ifdef VBOX
5683 {
5684#ifdef VBOX_WITH_SCSI
5685 if (VBOX_IS_SCSI_DEVICE(device))
5686 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5687 else
5688#endif
5689 {
5690 if (count >= 256 || lba + count >= 268435456)
5691 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5692 else
5693 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5694 }
5695 }
5696#else /* !VBOX */
5697 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5698#endif /* VBOX */
5699 else
5700#ifdef VBOX
5701 {
5702#ifdef VBOX_WITH_SCSI
5703 if (VBOX_IS_SCSI_DEVICE(device))
5704 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5705 else
5706#endif
5707 {
5708 if (count >= 256 || lba + count >= 268435456)
5709 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5710 else
5711 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5712 }
5713 }
5714#else /* !VBOX */
5715 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5716#endif /* VBOX */
5717
5718 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5719 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5720
5721 if (status != 0) {
5722 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5723 SET_AH(0x0c);
5724 goto int13_fail_noah;
5725 }
5726
5727 goto int13_success;
5728 break;
5729
5730 case 0x45: // IBM/MS lock/unlock drive
5731 case 0x49: // IBM/MS extended media change
5732 goto int13_success; // Always success for HD
5733 break;
5734
5735 case 0x46: // IBM/MS eject media
5736 SET_AH(0xb2); // Volume Not Removable
5737 goto int13_fail_noah; // Always fail for HD
5738 break;
5739
5740 case 0x48: // IBM/MS get drive parameters
5741 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5742
5743 // Buffer is too small
5744 if(size < 0x1a)
5745 goto int13_fail;
5746
5747 // EDD 1.x
5748 if(size >= 0x1a) {
5749 Bit16u blksize;
5750
5751#ifdef VBOX_WITH_SCSI
5752 if (!VBOX_IS_SCSI_DEVICE(device))
5753#endif
5754 {
5755 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5756 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5757 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5758 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5759 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5760 }
5761#ifdef VBOX_WITH_SCSI
5762 else
5763 {
5764 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5765 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5766 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5767 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5768 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5769 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5770 }
5771#endif
5772
5773 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5774 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5775 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5776 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5777 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5778 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5779 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5780 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5781 }
5782
5783 // EDD 2.x
5784 if(size >= 0x1e) {
5785 Bit8u channel, dev, irq, mode, checksum, i, translation;
5786 Bit16u iobase1, iobase2, options;
5787
5788 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5789
5790 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5791 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5792
5793 // Fill in dpte
5794 channel = device / 2;
5795 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5796 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5797 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5798 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5799 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5800
5801 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5802 options |= (1<<4); // lba translation
5803 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5804 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5805 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5806
5807 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5808 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5809 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5810 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5811 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5812 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5813 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5814 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5815 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5816 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5817 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5818
5819 checksum=0;
5820 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5821 checksum = ~checksum;
5822 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5823 }
5824
5825 // EDD 3.x
5826 if(size >= 0x42) {
5827 Bit8u channel, iface, checksum, i;
5828 Bit16u iobase1;
5829
5830 channel = device / 2;
5831 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5832 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5833
5834 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5835 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5836 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5837 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5838 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5839
5840 if (iface==ATA_IFACE_ISA) {
5841 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5842 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5843 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5844 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5845 }
5846 else {
5847 // FIXME PCI
5848 }
5849 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5850 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5851 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5852 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5853
5854 if (iface==ATA_IFACE_ISA) {
5855 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5856 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5857 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5858 }
5859 else {
5860 // FIXME PCI
5861 }
5862 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5863 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5864 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5865 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5866
5867 checksum=0;
5868 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5869 checksum = ~checksum;
5870 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5871 }
5872
5873 goto int13_success;
5874 break;
5875
5876 case 0x4e: // // IBM/MS set hardware configuration
5877 // DMA, prefetch, PIO maximum not supported
5878 switch (GET_AL()) {
5879 case 0x01:
5880 case 0x03:
5881 case 0x04:
5882 case 0x06:
5883 goto int13_success;
5884 break;
5885 default :
5886 goto int13_fail;
5887 }
5888 break;
5889
5890 case 0x09: /* initialize drive parameters */
5891 case 0x0c: /* seek to specified cylinder */
5892 case 0x0d: /* alternate disk reset */
5893 case 0x11: /* recalibrate */
5894 case 0x14: /* controller internal diagnostic */
5895 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5896 goto int13_success;
5897 break;
5898
5899 case 0x0a: /* read disk sectors with ECC */
5900 case 0x0b: /* write disk sectors with ECC */
5901 case 0x18: // set media type for format
5902 case 0x50: // IBM/MS send packet command
5903 default:
5904 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5905 goto int13_fail;
5906 break;
5907 }
5908
5909int13_fail:
5910 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5911int13_fail_noah:
5912 SET_DISK_RET_STATUS(GET_AH());
5913int13_fail_nostatus:
5914 SET_CF(); // error occurred
5915 return;
5916
5917int13_success:
5918 SET_AH(0x00); // no error
5919int13_success_noah:
5920 SET_DISK_RET_STATUS(0x00);
5921 CLEAR_CF(); // no error
5922 return;
5923}
5924
5925// ---------------------------------------------------------------------------
5926// Start of int13 for cdrom
5927// ---------------------------------------------------------------------------
5928
5929 void
5930int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5931 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5932{
5933 Bit16u ebda_seg=read_word(0x0040,0x000E);
5934 Bit8u device, status, locks;
5935 Bit8u atacmd[12];
5936 Bit32u lba;
5937 Bit16u count, segment, offset, i, size;
5938
5939 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5940
5941 SET_DISK_RET_STATUS(0x00);
5942
5943 /* basic check : device should be 0xE0+ */
5944 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5945 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5946 goto int13_fail;
5947 }
5948
5949 // Get the ata channel
5950 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5951
5952 /* basic check : device has to be valid */
5953 if (device >= BX_MAX_ATA_DEVICES) {
5954 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5955 goto int13_fail;
5956 }
5957
5958 switch (GET_AH()) {
5959
5960 // all those functions return SUCCESS
5961 case 0x00: /* disk controller reset */
5962 case 0x09: /* initialize drive parameters */
5963 case 0x0c: /* seek to specified cylinder */
5964 case 0x0d: /* alternate disk reset */
5965 case 0x10: /* check drive ready */
5966 case 0x11: /* recalibrate */
5967 case 0x14: /* controller internal diagnostic */
5968 case 0x16: /* detect disk change */
5969 goto int13_success;
5970 break;
5971
5972 // all those functions return disk write-protected
5973 case 0x03: /* write disk sectors */
5974 case 0x05: /* format disk track */
5975 case 0x43: // IBM/MS extended write
5976 SET_AH(0x03);
5977 goto int13_fail_noah;
5978 break;
5979
5980 case 0x01: /* read disk status */
5981 status = read_byte(0x0040, 0x0074);
5982 SET_AH(status);
5983 SET_DISK_RET_STATUS(0);
5984
5985 /* set CF if error status read */
5986 if (status) goto int13_fail_nostatus;
5987 else goto int13_success_noah;
5988 break;
5989
5990 case 0x15: /* read disk drive size */
5991 SET_AH(0x02);
5992 goto int13_fail_noah;
5993 break;
5994
5995 case 0x41: // IBM/MS installation check
5996 BX=0xaa55; // install check
5997 SET_AH(0x30); // EDD 2.1
5998 CX=0x0007; // ext disk access, removable and edd
5999 goto int13_success_noah;
6000 break;
6001
6002 case 0x42: // IBM/MS extended read
6003 case 0x44: // IBM/MS verify sectors
6004 case 0x47: // IBM/MS extended seek
6005
6006 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6007 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6008 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6009
6010 // Can't use 64 bits lba
6011 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6012 if (lba != 0L) {
6013 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6014 goto int13_fail;
6015 }
6016
6017 // Get 32 bits lba
6018 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6019
6020 // If verify or seek
6021 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6022 goto int13_success;
6023
6024 memsetb(get_SS(),atacmd,0,12);
6025 atacmd[0]=0x28; // READ command
6026 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6027 atacmd[8]=(count & 0x00ff); // Sectors
6028 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6029 atacmd[3]=(lba & 0x00ff0000) >> 16;
6030 atacmd[4]=(lba & 0x0000ff00) >> 8;
6031 atacmd[5]=(lba & 0x000000ff);
6032 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6033
6034 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6035 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6036
6037 if (status != 0) {
6038 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6039 SET_AH(0x0c);
6040 goto int13_fail_noah;
6041 }
6042
6043 goto int13_success;
6044 break;
6045
6046 case 0x45: // IBM/MS lock/unlock drive
6047 if (GET_AL() > 2) goto int13_fail;
6048
6049 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6050
6051 switch (GET_AL()) {
6052 case 0 : // lock
6053 if (locks == 0xff) {
6054 SET_AH(0xb4);
6055 SET_AL(1);
6056 goto int13_fail_noah;
6057 }
6058 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6059 SET_AL(1);
6060 break;
6061 case 1 : // unlock
6062 if (locks == 0x00) {
6063 SET_AH(0xb0);
6064 SET_AL(0);
6065 goto int13_fail_noah;
6066 }
6067 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6068 SET_AL(locks==0?0:1);
6069 break;
6070 case 2 : // status
6071 SET_AL(locks==0?0:1);
6072 break;
6073 }
6074 goto int13_success;
6075 break;
6076
6077 case 0x46: // IBM/MS eject media
6078 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6079
6080 if (locks != 0) {
6081 SET_AH(0xb1); // media locked
6082 goto int13_fail_noah;
6083 }
6084 // FIXME should handle 0x31 no media in device
6085 // FIXME should handle 0xb5 valid request failed
6086
6087 // Call removable media eject
6088 ASM_START
6089 push bp
6090 mov bp, sp
6091
6092 mov ah, #0x52
6093 int 15
6094 mov _int13_cdrom.status + 2[bp], ah
6095 jnc int13_cdrom_rme_end
6096 mov _int13_cdrom.status, #1
6097int13_cdrom_rme_end:
6098 pop bp
6099 ASM_END
6100
6101 if (status != 0) {
6102 SET_AH(0xb1); // media locked
6103 goto int13_fail_noah;
6104 }
6105
6106 goto int13_success;
6107 break;
6108
6109 case 0x48: // IBM/MS get drive parameters
6110 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6111
6112 // Buffer is too small
6113 if(size < 0x1a)
6114 goto int13_fail;
6115
6116 // EDD 1.x
6117 if(size >= 0x1a) {
6118 Bit16u cylinders, heads, spt, blksize;
6119
6120 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6121
6122 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6123 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6124 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6125 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6126 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6127 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6128 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6129 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6130 }
6131
6132 // EDD 2.x
6133 if(size >= 0x1e) {
6134 Bit8u channel, dev, irq, mode, checksum, i;
6135 Bit16u iobase1, iobase2, options;
6136
6137 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6138
6139 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6140 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6141
6142 // Fill in dpte
6143 channel = device / 2;
6144 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6145 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6146 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6147 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6148
6149 // FIXME atapi device
6150 options = (1<<4); // lba translation
6151 options |= (1<<5); // removable device
6152 options |= (1<<6); // atapi device
6153 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6154
6155 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6156 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6157 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6158 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6159 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6160 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6161 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6162 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6163 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6164 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6165 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6166
6167 checksum=0;
6168 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6169 checksum = ~checksum;
6170 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6171 }
6172
6173 // EDD 3.x
6174 if(size >= 0x42) {
6175 Bit8u channel, iface, checksum, i;
6176 Bit16u iobase1;
6177
6178 channel = device / 2;
6179 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6180 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6181
6182 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6183 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6184 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6185 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6186 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6187
6188 if (iface==ATA_IFACE_ISA) {
6189 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6190 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6191 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6192 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6193 }
6194 else {
6195 // FIXME PCI
6196 }
6197 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6198 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6199 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6200 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6201
6202 if (iface==ATA_IFACE_ISA) {
6203 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6204 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6205 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6206 }
6207 else {
6208 // FIXME PCI
6209 }
6210 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6211 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6212 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6213 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6214
6215 checksum=0;
6216 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6217 checksum = ~checksum;
6218 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6219 }
6220
6221 goto int13_success;
6222 break;
6223
6224 case 0x49: // IBM/MS extended media change
6225 // always send changed ??
6226 SET_AH(06);
6227 goto int13_fail_nostatus;
6228 break;
6229
6230 case 0x4e: // // IBM/MS set hardware configuration
6231 // DMA, prefetch, PIO maximum not supported
6232 switch (GET_AL()) {
6233 case 0x01:
6234 case 0x03:
6235 case 0x04:
6236 case 0x06:
6237 goto int13_success;
6238 break;
6239 default :
6240 goto int13_fail;
6241 }
6242 break;
6243
6244 // all those functions return unimplemented
6245 case 0x02: /* read sectors */
6246 case 0x04: /* verify sectors */
6247 case 0x08: /* read disk drive parameters */
6248 case 0x0a: /* read disk sectors with ECC */
6249 case 0x0b: /* write disk sectors with ECC */
6250 case 0x18: /* set media type for format */
6251 case 0x50: // ? - send packet command
6252 default:
6253 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6254 goto int13_fail;
6255 break;
6256 }
6257
6258int13_fail:
6259 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6260int13_fail_noah:
6261 SET_DISK_RET_STATUS(GET_AH());
6262int13_fail_nostatus:
6263 SET_CF(); // error occurred
6264 return;
6265
6266int13_success:
6267 SET_AH(0x00); // no error
6268int13_success_noah:
6269 SET_DISK_RET_STATUS(0x00);
6270 CLEAR_CF(); // no error
6271 return;
6272}
6273
6274// ---------------------------------------------------------------------------
6275// End of int13 for cdrom
6276// ---------------------------------------------------------------------------
6277
6278#if BX_ELTORITO_BOOT
6279// ---------------------------------------------------------------------------
6280// Start of int13 for eltorito functions
6281// ---------------------------------------------------------------------------
6282
6283 void
6284int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6285 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6286{
6287 Bit16u ebda_seg=read_word(0x0040,0x000E);
6288
6289 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6290 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6291
6292 switch (GET_AH()) {
6293
6294 // FIXME ElTorito Various. Should be implemented
6295 case 0x4a: // ElTorito - Initiate disk emu
6296 case 0x4c: // ElTorito - Initiate disk emu and boot
6297 case 0x4d: // ElTorito - Return Boot catalog
6298 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6299 goto int13_fail;
6300 break;
6301
6302 case 0x4b: // ElTorito - Terminate disk emu
6303 // FIXME ElTorito Hardcoded
6304 write_byte(DS,SI+0x00,0x13);
6305 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6306 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6307 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6308 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6309 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6310 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6311 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6312 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6313 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6314 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6315 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6316
6317 // If we have to terminate emulation
6318 if(GET_AL() == 0x00) {
6319 // FIXME ElTorito Various. Should be handled accordingly to spec
6320 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6321 }
6322
6323 goto int13_success;
6324 break;
6325
6326 default:
6327 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6328 goto int13_fail;
6329 break;
6330 }
6331
6332int13_fail:
6333 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6334 SET_DISK_RET_STATUS(GET_AH());
6335 SET_CF(); // error occurred
6336 return;
6337
6338int13_success:
6339 SET_AH(0x00); // no error
6340 SET_DISK_RET_STATUS(0x00);
6341 CLEAR_CF(); // no error
6342 return;
6343}
6344
6345// ---------------------------------------------------------------------------
6346// End of int13 for eltorito functions
6347// ---------------------------------------------------------------------------
6348
6349// ---------------------------------------------------------------------------
6350// Start of int13 when emulating a device from the cd
6351// ---------------------------------------------------------------------------
6352
6353 void
6354int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6355 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6356{
6357 Bit16u ebda_seg=read_word(0x0040,0x000E);
6358 Bit8u device, status;
6359 Bit16u vheads, vspt, vcylinders;
6360 Bit16u head, sector, cylinder, nbsectors;
6361 Bit32u vlba, ilba, slba, elba;
6362 Bit16u before, segment, offset;
6363 Bit8u atacmd[12];
6364
6365 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6366
6367 /* at this point, we are emulating a floppy/harddisk */
6368
6369 // Recompute the device number
6370 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6371 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6372
6373 SET_DISK_RET_STATUS(0x00);
6374
6375 /* basic checks : emulation should be active, dl should equal the emulated drive */
6376 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6377 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6378 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6379 goto int13_fail;
6380 }
6381
6382 switch (GET_AH()) {
6383
6384 // all those functions return SUCCESS
6385 case 0x00: /* disk controller reset */
6386 case 0x09: /* initialize drive parameters */
6387 case 0x0c: /* seek to specified cylinder */
6388 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6389 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6390 case 0x11: /* recalibrate */
6391 case 0x14: /* controller internal diagnostic */
6392 case 0x16: /* detect disk change */
6393 goto int13_success;
6394 break;
6395
6396 // all those functions return disk write-protected
6397 case 0x03: /* write disk sectors */
6398 case 0x05: /* format disk track */
6399 SET_AH(0x03);
6400 goto int13_fail_noah;
6401 break;
6402
6403 case 0x01: /* read disk status */
6404 status=read_byte(0x0040, 0x0074);
6405 SET_AH(status);
6406 SET_DISK_RET_STATUS(0);
6407
6408 /* set CF if error status read */
6409 if (status) goto int13_fail_nostatus;
6410 else goto int13_success_noah;
6411 break;
6412
6413 case 0x02: // read disk sectors
6414 case 0x04: // verify disk sectors
6415 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6416 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6417 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6418
6419 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6420
6421 sector = GET_CL() & 0x003f;
6422 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6423 head = GET_DH();
6424 nbsectors = GET_AL();
6425 segment = ES;
6426 offset = BX;
6427
6428 // no sector to read ?
6429 if(nbsectors==0) goto int13_success;
6430
6431 // sanity checks sco openserver needs this!
6432 if ((sector > vspt)
6433 || (cylinder >= vcylinders)
6434 || (head >= vheads)) {
6435 goto int13_fail;
6436 }
6437
6438 // After controls, verify do nothing
6439 if (GET_AH() == 0x04) goto int13_success;
6440
6441 segment = ES+(BX / 16);
6442 offset = BX % 16;
6443
6444 // calculate the virtual lba inside the image
6445 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6446
6447 // In advance so we don't loose the count
6448 SET_AL(nbsectors);
6449
6450 // start lba on cd
6451 slba = (Bit32u)vlba/4;
6452 before= (Bit16u)vlba%4;
6453
6454 // end lba on cd
6455 elba = (Bit32u)(vlba+nbsectors-1)/4;
6456
6457 memsetb(get_SS(),atacmd,0,12);
6458 atacmd[0]=0x28; // READ command
6459 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6460 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6461 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6462 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6463 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6464 atacmd[5]=(ilba+slba & 0x000000ff);
6465 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6466 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6467 SET_AH(0x02);
6468 SET_AL(0);
6469 goto int13_fail_noah;
6470 }
6471
6472 goto int13_success;
6473 break;
6474
6475 case 0x08: /* read disk drive parameters */
6476 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6477 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6478 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6479
6480 SET_AL( 0x00 );
6481 SET_BL( 0x00 );
6482 SET_CH( vcylinders & 0xff );
6483 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6484 SET_DH( vheads );
6485 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6486 // FIXME ElTorito Harddisk. should send the HD count
6487
6488 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6489 case 0x01: SET_BL( 0x02 ); break;
6490 case 0x02: SET_BL( 0x04 ); break;
6491 case 0x03: SET_BL( 0x06 ); break;
6492 }
6493
6494ASM_START
6495 push bp
6496 mov bp, sp
6497 mov ax, #diskette_param_table2
6498 mov _int13_cdemu.DI+2[bp], ax
6499 mov _int13_cdemu.ES+2[bp], cs
6500 pop bp
6501ASM_END
6502 goto int13_success;
6503 break;
6504
6505 case 0x15: /* read disk drive size */
6506 // FIXME ElTorito Harddisk. What geometry to send ?
6507 SET_AH(0x03);
6508 goto int13_success_noah;
6509 break;
6510
6511 // all those functions return unimplemented
6512 case 0x0a: /* read disk sectors with ECC */
6513 case 0x0b: /* write disk sectors with ECC */
6514 case 0x18: /* set media type for format */
6515 case 0x41: // IBM/MS installation check
6516 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6517 case 0x42: // IBM/MS extended read
6518 case 0x43: // IBM/MS extended write
6519 case 0x44: // IBM/MS verify sectors
6520 case 0x45: // IBM/MS lock/unlock drive
6521 case 0x46: // IBM/MS eject media
6522 case 0x47: // IBM/MS extended seek
6523 case 0x48: // IBM/MS get drive parameters
6524 case 0x49: // IBM/MS extended media change
6525 case 0x4e: // ? - set hardware configuration
6526 case 0x50: // ? - send packet command
6527 default:
6528 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6529 goto int13_fail;
6530 break;
6531 }
6532
6533int13_fail:
6534 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6535int13_fail_noah:
6536 SET_DISK_RET_STATUS(GET_AH());
6537int13_fail_nostatus:
6538 SET_CF(); // error occurred
6539 return;
6540
6541int13_success:
6542 SET_AH(0x00); // no error
6543int13_success_noah:
6544 SET_DISK_RET_STATUS(0x00);
6545 CLEAR_CF(); // no error
6546 return;
6547}
6548
6549// ---------------------------------------------------------------------------
6550// End of int13 when emulating a device from the cd
6551// ---------------------------------------------------------------------------
6552
6553#endif // BX_ELTORITO_BOOT
6554
6555#else //BX_USE_ATADRV
6556
6557 void
6558outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6559 Bit16u cylinder;
6560 Bit16u hd_heads;
6561 Bit16u head;
6562 Bit16u hd_sectors;
6563 Bit16u sector;
6564 Bit16u dl;
6565{
6566ASM_START
6567 push bp
6568 mov bp, sp
6569 push eax
6570 push ebx
6571 push edx
6572 xor eax,eax
6573 mov ax,4[bp] // cylinder
6574 xor ebx,ebx
6575 mov bl,6[bp] // hd_heads
6576 imul ebx
6577
6578 mov bl,8[bp] // head
6579 add eax,ebx
6580 mov bl,10[bp] // hd_sectors
6581 imul ebx
6582 mov bl,12[bp] // sector
6583 add eax,ebx
6584
6585 dec eax
6586 mov dx,#0x1f3
6587 out dx,al
6588 mov dx,#0x1f4
6589 mov al,ah
6590 out dx,al
6591 shr eax,#16
6592 mov dx,#0x1f5
6593 out dx,al
6594 and ah,#0xf
6595 mov bl,14[bp] // dl
6596 and bl,#1
6597 shl bl,#4
6598 or ah,bl
6599 or ah,#0xe0
6600 mov al,ah
6601 mov dx,#0x01f6
6602 out dx,al
6603 pop edx
6604 pop ebx
6605 pop eax
6606 pop bp
6607ASM_END
6608}
6609
6610 void
6611int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6612 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6613{
6614 Bit8u drive, num_sectors, sector, head, status, mod;
6615 Bit8u drive_map;
6616 Bit8u n_drives;
6617 Bit16u cyl_mod, ax;
6618 Bit16u max_cylinder, cylinder, total_sectors;
6619 Bit16u hd_cylinders;
6620 Bit8u hd_heads, hd_sectors;
6621 Bit16u val16;
6622 Bit8u sector_count;
6623 unsigned int i;
6624 Bit16u tempbx;
6625 Bit16u dpsize;
6626
6627 Bit16u count, segment, offset;
6628 Bit32u lba;
6629 Bit16u error;
6630
6631 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6632
6633 write_byte(0x0040, 0x008e, 0); // clear completion flag
6634
6635 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6636 handler code */
6637 /* check how many disks first (cmos reg 0x12), return an error if
6638 drive not present */
6639 drive_map = inb_cmos(0x12);
6640 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6641 (((drive_map & 0x0f)==0) ? 0 : 2);
6642 n_drives = (drive_map==0) ? 0 :
6643 ((drive_map==3) ? 2 : 1);
6644
6645 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6646 SET_AH(0x01);
6647 SET_DISK_RET_STATUS(0x01);
6648 SET_CF(); /* error occurred */
6649 return;
6650 }
6651
6652 switch (GET_AH()) {
6653
6654 case 0x00: /* disk controller reset */
6655BX_DEBUG_INT13_HD("int13_f00\n");
6656
6657 SET_AH(0);
6658 SET_DISK_RET_STATUS(0);
6659 set_diskette_ret_status(0);
6660 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6661 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6662 CLEAR_CF(); /* successful */
6663 return;
6664 break;
6665
6666 case 0x01: /* read disk status */
6667BX_DEBUG_INT13_HD("int13_f01\n");
6668 status = read_byte(0x0040, 0x0074);
6669 SET_AH(status);
6670 SET_DISK_RET_STATUS(0);
6671 /* set CF if error status read */
6672 if (status) SET_CF();
6673 else CLEAR_CF();
6674 return;
6675 break;
6676
6677 case 0x04: // verify disk sectors
6678 case 0x02: // read disk sectors
6679 drive = GET_ELDL();
6680 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6681
6682 num_sectors = GET_AL();
6683 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6684 sector = (GET_CL() & 0x3f);
6685 head = GET_DH();
6686
6687
6688 if (hd_cylinders > 1024) {
6689 if (hd_cylinders <= 2048) {
6690 cylinder <<= 1;
6691 }
6692 else if (hd_cylinders <= 4096) {
6693 cylinder <<= 2;
6694 }
6695 else if (hd_cylinders <= 8192) {
6696 cylinder <<= 3;
6697 }
6698 else { // hd_cylinders <= 16384
6699 cylinder <<= 4;
6700 }
6701
6702 ax = head / hd_heads;
6703 cyl_mod = ax & 0xff;
6704 head = ax >> 8;
6705 cylinder |= cyl_mod;
6706 }
6707
6708 if ( (cylinder >= hd_cylinders) ||
6709 (sector > hd_sectors) ||
6710 (head >= hd_heads) ) {
6711 SET_AH(1);
6712 SET_DISK_RET_STATUS(1);
6713 SET_CF(); /* error occurred */
6714 return;
6715 }
6716
6717 if ( (num_sectors > 128) || (num_sectors == 0) )
6718 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6719
6720 if (head > 15)
6721 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6722
6723 if ( GET_AH() == 0x04 ) {
6724 SET_AH(0);
6725 SET_DISK_RET_STATUS(0);
6726 CLEAR_CF();
6727 return;
6728 }
6729
6730 status = inb(0x1f7);
6731 if (status & 0x80) {
6732 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6733 }
6734 outb(0x01f2, num_sectors);
6735 /* activate LBA? (tomv) */
6736 if (hd_heads > 16) {
6737BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6738 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6739 }
6740 else {
6741 outb(0x01f3, sector);
6742 outb(0x01f4, cylinder & 0x00ff);
6743 outb(0x01f5, cylinder >> 8);
6744 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6745 }
6746 outb(0x01f7, 0x20);
6747
6748 while (1) {
6749 status = inb(0x1f7);
6750 if ( !(status & 0x80) ) break;
6751 }
6752
6753 if (status & 0x01) {
6754 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6755 } else if ( !(status & 0x08) ) {
6756 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6757 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6758 }
6759
6760 sector_count = 0;
6761 tempbx = BX;
6762
6763ASM_START
6764 sti ;; enable higher priority interrupts
6765ASM_END
6766
6767 while (1) {
6768ASM_START
6769 ;; store temp bx in real DI register
6770 push bp
6771 mov bp, sp
6772 mov di, _int13_harddisk.tempbx + 2 [bp]
6773 pop bp
6774
6775 ;; adjust if there will be an overrun
6776 cmp di, #0xfe00
6777 jbe i13_f02_no_adjust
6778i13_f02_adjust:
6779 sub di, #0x0200 ; sub 512 bytes from offset
6780 mov ax, es
6781 add ax, #0x0020 ; add 512 to segment
6782 mov es, ax
6783
6784i13_f02_no_adjust:
6785 mov cx, #0x0100 ;; counter (256 words = 512b)
6786 mov dx, #0x01f0 ;; AT data read port
6787
6788 rep
6789 insw ;; CX words transfered from port(DX) to ES:[DI]
6790
6791i13_f02_done:
6792 ;; store real DI register back to temp bx
6793 push bp
6794 mov bp, sp
6795 mov _int13_harddisk.tempbx + 2 [bp], di
6796 pop bp
6797ASM_END
6798
6799 sector_count++;
6800 num_sectors--;
6801 if (num_sectors == 0) {
6802 status = inb(0x1f7);
6803 if ( (status & 0xc9) != 0x40 )
6804 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6805 break;
6806 }
6807 else {
6808 status = inb(0x1f7);
6809 if ( (status & 0xc9) != 0x48 )
6810 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6811 continue;
6812 }
6813 }
6814
6815 SET_AH(0);
6816 SET_DISK_RET_STATUS(0);
6817 SET_AL(sector_count);
6818 CLEAR_CF(); /* successful */
6819 return;
6820 break;
6821
6822
6823 case 0x03: /* write disk sectors */
6824BX_DEBUG_INT13_HD("int13_f03\n");
6825 drive = GET_ELDL ();
6826 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6827
6828 num_sectors = GET_AL();
6829 cylinder = GET_CH();
6830 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6831 sector = (GET_CL() & 0x3f);
6832 head = GET_DH();
6833
6834 if (hd_cylinders > 1024) {
6835 if (hd_cylinders <= 2048) {
6836 cylinder <<= 1;
6837 }
6838 else if (hd_cylinders <= 4096) {
6839 cylinder <<= 2;
6840 }
6841 else if (hd_cylinders <= 8192) {
6842 cylinder <<= 3;
6843 }
6844 else { // hd_cylinders <= 16384
6845 cylinder <<= 4;
6846 }
6847
6848 ax = head / hd_heads;
6849 cyl_mod = ax & 0xff;
6850 head = ax >> 8;
6851 cylinder |= cyl_mod;
6852 }
6853
6854 if ( (cylinder >= hd_cylinders) ||
6855 (sector > hd_sectors) ||
6856 (head >= hd_heads) ) {
6857 SET_AH( 1);
6858 SET_DISK_RET_STATUS(1);
6859 SET_CF(); /* error occurred */
6860 return;
6861 }
6862
6863 if ( (num_sectors > 128) || (num_sectors == 0) )
6864 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6865
6866 if (head > 15)
6867 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6868
6869 status = inb(0x1f7);
6870 if (status & 0x80) {
6871 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6872 }
6873// should check for Drive Ready Bit also in status reg
6874 outb(0x01f2, num_sectors);
6875
6876 /* activate LBA? (tomv) */
6877 if (hd_heads > 16) {
6878BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6879 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6880 }
6881 else {
6882 outb(0x01f3, sector);
6883 outb(0x01f4, cylinder & 0x00ff);
6884 outb(0x01f5, cylinder >> 8);
6885 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6886 }
6887 outb(0x01f7, 0x30);
6888
6889 // wait for busy bit to turn off after seeking
6890 while (1) {
6891 status = inb(0x1f7);
6892 if ( !(status & 0x80) ) break;
6893 }
6894
6895 if ( !(status & 0x08) ) {
6896 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6897 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6898 }
6899
6900 sector_count = 0;
6901 tempbx = BX;
6902
6903ASM_START
6904 sti ;; enable higher priority interrupts
6905ASM_END
6906
6907 while (1) {
6908ASM_START
6909 ;; store temp bx in real SI register
6910 push bp
6911 mov bp, sp
6912 mov si, _int13_harddisk.tempbx + 2 [bp]
6913 pop bp
6914
6915 ;; adjust if there will be an overrun
6916 cmp si, #0xfe00
6917 jbe i13_f03_no_adjust
6918i13_f03_adjust:
6919 sub si, #0x0200 ; sub 512 bytes from offset
6920 mov ax, es
6921 add ax, #0x0020 ; add 512 to segment
6922 mov es, ax
6923
6924i13_f03_no_adjust:
6925 mov cx, #0x0100 ;; counter (256 words = 512b)
6926 mov dx, #0x01f0 ;; AT data read port
6927
6928 seg ES
6929 rep
6930 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6931
6932 ;; store real SI register back to temp bx
6933 push bp
6934 mov bp, sp
6935 mov _int13_harddisk.tempbx + 2 [bp], si
6936 pop bp
6937ASM_END
6938
6939 sector_count++;
6940 num_sectors--;
6941 if (num_sectors == 0) {
6942 status = inb(0x1f7);
6943 if ( (status & 0xe9) != 0x40 )
6944 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6945 break;
6946 }
6947 else {
6948 status = inb(0x1f7);
6949 if ( (status & 0xc9) != 0x48 )
6950 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6951 continue;
6952 }
6953 }
6954
6955 SET_AH(0);
6956 SET_DISK_RET_STATUS(0);
6957 SET_AL(sector_count);
6958 CLEAR_CF(); /* successful */
6959 return;
6960 break;
6961
6962 case 0x05: /* format disk track */
6963BX_DEBUG_INT13_HD("int13_f05\n");
6964 BX_PANIC("format disk track called\n");
6965 /* nop */
6966 SET_AH(0);
6967 SET_DISK_RET_STATUS(0);
6968 CLEAR_CF(); /* successful */
6969 return;
6970 break;
6971
6972 case 0x08: /* read disk drive parameters */
6973BX_DEBUG_INT13_HD("int13_f08\n");
6974
6975 drive = GET_ELDL ();
6976 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6977
6978 // translate CHS
6979 //
6980 if (hd_cylinders <= 1024) {
6981 // hd_cylinders >>= 0;
6982 // hd_heads <<= 0;
6983 }
6984 else if (hd_cylinders <= 2048) {
6985 hd_cylinders >>= 1;
6986 hd_heads <<= 1;
6987 }
6988 else if (hd_cylinders <= 4096) {
6989 hd_cylinders >>= 2;
6990 hd_heads <<= 2;
6991 }
6992 else if (hd_cylinders <= 8192) {
6993 hd_cylinders >>= 3;
6994 hd_heads <<= 3;
6995 }
6996 else { // hd_cylinders <= 16384
6997 hd_cylinders >>= 4;
6998 hd_heads <<= 4;
6999 }
7000
7001 max_cylinder = hd_cylinders - 2; /* 0 based */
7002 SET_AL(0);
7003 SET_CH(max_cylinder & 0xff);
7004 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7005 SET_DH(hd_heads - 1);
7006 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7007 SET_AH(0);
7008 SET_DISK_RET_STATUS(0);
7009 CLEAR_CF(); /* successful */
7010
7011 return;
7012 break;
7013
7014 case 0x09: /* initialize drive parameters */
7015BX_DEBUG_INT13_HD("int13_f09\n");
7016 SET_AH(0);
7017 SET_DISK_RET_STATUS(0);
7018 CLEAR_CF(); /* successful */
7019 return;
7020 break;
7021
7022 case 0x0a: /* read disk sectors with ECC */
7023BX_DEBUG_INT13_HD("int13_f0a\n");
7024 case 0x0b: /* write disk sectors with ECC */
7025BX_DEBUG_INT13_HD("int13_f0b\n");
7026 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7027 return;
7028 break;
7029
7030 case 0x0c: /* seek to specified cylinder */
7031BX_DEBUG_INT13_HD("int13_f0c\n");
7032 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7033 SET_AH(0);
7034 SET_DISK_RET_STATUS(0);
7035 CLEAR_CF(); /* successful */
7036 return;
7037 break;
7038
7039 case 0x0d: /* alternate disk reset */
7040BX_DEBUG_INT13_HD("int13_f0d\n");
7041 SET_AH(0);
7042 SET_DISK_RET_STATUS(0);
7043 CLEAR_CF(); /* successful */
7044 return;
7045 break;
7046
7047 case 0x10: /* check drive ready */
7048BX_DEBUG_INT13_HD("int13_f10\n");
7049 //SET_AH(0);
7050 //SET_DISK_RET_STATUS(0);
7051 //CLEAR_CF(); /* successful */
7052 //return;
7053 //break;
7054
7055 // should look at 40:8E also???
7056 status = inb(0x01f7);
7057 if ( (status & 0xc0) == 0x40 ) {
7058 SET_AH(0);
7059 SET_DISK_RET_STATUS(0);
7060 CLEAR_CF(); // drive ready
7061 return;
7062 }
7063 else {
7064 SET_AH(0xAA);
7065 SET_DISK_RET_STATUS(0xAA);
7066 SET_CF(); // not ready
7067 return;
7068 }
7069 break;
7070
7071 case 0x11: /* recalibrate */
7072BX_DEBUG_INT13_HD("int13_f11\n");
7073 SET_AH(0);
7074 SET_DISK_RET_STATUS(0);
7075 CLEAR_CF(); /* successful */
7076 return;
7077 break;
7078
7079 case 0x14: /* controller internal diagnostic */
7080BX_DEBUG_INT13_HD("int13_f14\n");
7081 SET_AH(0);
7082 SET_DISK_RET_STATUS(0);
7083 CLEAR_CF(); /* successful */
7084 SET_AL(0);
7085 return;
7086 break;
7087
7088 case 0x15: /* read disk drive size */
7089 drive = GET_ELDL();
7090 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7091ASM_START
7092 push bp
7093 mov bp, sp
7094 mov al, _int13_harddisk.hd_heads + 2 [bp]
7095 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7096 mul al, ah ;; ax = heads * sectors
7097 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7098 dec bx ;; use (cylinders - 1) ???
7099 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7100 ;; now we need to move the 32bit result dx:ax to what the
7101 ;; BIOS wants which is cx:dx.
7102 ;; and then into CX:DX on the stack
7103 mov _int13_harddisk.CX + 2 [bp], dx
7104 mov _int13_harddisk.DX + 2 [bp], ax
7105 pop bp
7106ASM_END
7107 SET_AH(3); // hard disk accessible
7108 SET_DISK_RET_STATUS(0); // ??? should this be 0
7109 CLEAR_CF(); // successful
7110 return;
7111 break;
7112
7113 case 0x18: // set media type for format
7114 case 0x41: // IBM/MS
7115 case 0x42: // IBM/MS
7116 case 0x43: // IBM/MS
7117 case 0x44: // IBM/MS
7118 case 0x45: // IBM/MS lock/unlock drive
7119 case 0x46: // IBM/MS eject media
7120 case 0x47: // IBM/MS extended seek
7121 case 0x49: // IBM/MS extended media change
7122 case 0x50: // IBM/MS send packet command
7123 default:
7124 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7125
7126 SET_AH(1); // code=invalid function in AH or invalid parameter
7127 SET_DISK_RET_STATUS(1);
7128 SET_CF(); /* unsuccessful */
7129 return;
7130 break;
7131 }
7132}
7133
7134static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7135static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7136
7137 void
7138get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7139 Bit8u drive;
7140 Bit16u *hd_cylinders;
7141 Bit8u *hd_heads;
7142 Bit8u *hd_sectors;
7143{
7144 Bit8u hd_type;
7145 Bit16u ss;
7146 Bit16u cylinders;
7147 Bit8u iobase;
7148
7149 ss = get_SS();
7150 if (drive == 0x80) {
7151 hd_type = inb_cmos(0x12) & 0xf0;
7152 if (hd_type != 0xf0)
7153 BX_INFO(panic_msg_reg12h,0);
7154 hd_type = inb_cmos(0x19); // HD0: extended type
7155 if (hd_type != 47)
7156 BX_INFO(panic_msg_reg19h,0,0x19);
7157 iobase = 0x1b;
7158 } else {
7159 hd_type = inb_cmos(0x12) & 0x0f;
7160 if (hd_type != 0x0f)
7161 BX_INFO(panic_msg_reg12h,1);
7162 hd_type = inb_cmos(0x1a); // HD0: extended type
7163 if (hd_type != 47)
7164 BX_INFO(panic_msg_reg19h,0,0x1a);
7165 iobase = 0x24;
7166 }
7167
7168 // cylinders
7169 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7170 write_word(ss, hd_cylinders, cylinders);
7171
7172 // heads
7173 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7174
7175 // sectors per track
7176 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7177}
7178
7179#endif //else BX_USE_ATADRV
7180
7181
7182//////////////////////
7183// FLOPPY functions //
7184//////////////////////
7185
7186void floppy_reset_controller()
7187{
7188 Bit8u val8;
7189
7190 // Reset controller
7191 val8 = inb(0x03f2);
7192 outb(0x03f2, val8 & ~0x04);
7193 outb(0x03f2, val8 | 0x04);
7194
7195 // Wait for controller to come out of reset
7196 do {
7197 val8 = inb(0x3f4);
7198 } while ( (val8 & 0xc0) != 0x80 );
7199}
7200
7201void floppy_prepare_controller(drive)
7202 Bit16u drive;
7203{
7204 Bit8u val8, dor, prev_reset;
7205
7206 // set 40:3e bit 7 to 0
7207 val8 = read_byte(0x0040, 0x003e);
7208 val8 &= 0x7f;
7209 write_byte(0x0040, 0x003e, val8);
7210
7211 // turn on motor of selected drive, DMA & int enabled, normal operation
7212 prev_reset = inb(0x03f2) & 0x04;
7213 if (drive)
7214 dor = 0x20;
7215 else
7216 dor = 0x10;
7217 dor |= 0x0c;
7218 dor |= drive;
7219 outb(0x03f2, dor);
7220
7221 // reset the disk motor timeout value of INT 08
7222 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7223
7224#ifdef VBOX
7225 // program data rate
7226 val8 = read_byte(0x0040, 0x008b);
7227 val8 >>= 6;
7228 outb(0x03f7, val8);
7229#endif
7230
7231 // wait for drive readiness
7232 do {
7233 val8 = inb(0x3f4);
7234 } while ( (val8 & 0xc0) != 0x80 );
7235
7236 if (prev_reset == 0) {
7237 // turn on interrupts
7238ASM_START
7239 sti
7240ASM_END
7241 // wait on 40:3e bit 7 to become 1
7242 do {
7243 val8 = read_byte(0x0040, 0x003e);
7244 } while ( (val8 & 0x80) == 0 );
7245 val8 &= 0x7f;
7246ASM_START
7247 cli
7248ASM_END
7249 write_byte(0x0040, 0x003e, val8);
7250 }
7251}
7252
7253 bx_bool
7254floppy_media_known(drive)
7255 Bit16u drive;
7256{
7257 Bit8u val8;
7258 Bit16u media_state_offset;
7259
7260 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7261 if (drive)
7262 val8 >>= 1;
7263 val8 &= 0x01;
7264 if (val8 == 0)
7265 return(0);
7266
7267 media_state_offset = 0x0090;
7268 if (drive)
7269 media_state_offset += 1;
7270
7271 val8 = read_byte(0x0040, media_state_offset);
7272 val8 = (val8 >> 4) & 0x01;
7273 if (val8 == 0)
7274 return(0);
7275
7276 // check pass, return KNOWN
7277 return(1);
7278}
7279
7280 bx_bool
7281floppy_media_sense(drive)
7282 Bit16u drive;
7283{
7284 bx_bool retval;
7285 Bit16u media_state_offset;
7286 Bit8u drive_type, config_data, media_state;
7287
7288 if (floppy_drive_recal(drive) == 0) {
7289 return(0);
7290 }
7291
7292 // for now cheat and get drive type from CMOS,
7293 // assume media is same as drive type
7294
7295 // ** config_data **
7296 // Bitfields for diskette media control:
7297 // Bit(s) Description (Table M0028)
7298 // 7-6 last data rate set by controller
7299 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7300 // 5-4 last diskette drive step rate selected
7301 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7302 // 3-2 {data rate at start of operation}
7303 // 1-0 reserved
7304
7305 // ** media_state **
7306 // Bitfields for diskette drive media state:
7307 // Bit(s) Description (Table M0030)
7308 // 7-6 data rate
7309 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7310 // 5 double stepping required (e.g. 360kB in 1.2MB)
7311 // 4 media type established
7312 // 3 drive capable of supporting 4MB media
7313 // 2-0 on exit from BIOS, contains
7314 // 000 trying 360kB in 360kB
7315 // 001 trying 360kB in 1.2MB
7316 // 010 trying 1.2MB in 1.2MB
7317 // 011 360kB in 360kB established
7318 // 100 360kB in 1.2MB established
7319 // 101 1.2MB in 1.2MB established
7320 // 110 reserved
7321 // 111 all other formats/drives
7322
7323 drive_type = inb_cmos(0x10);
7324 if (drive == 0)
7325 drive_type >>= 4;
7326 else
7327 drive_type &= 0x0f;
7328 if ( drive_type == 1 ) {
7329 // 360K 5.25" drive
7330 config_data = 0x00; // 0000 0000
7331 media_state = 0x25; // 0010 0101
7332 retval = 1;
7333 }
7334 else if ( drive_type == 2 ) {
7335 // 1.2 MB 5.25" drive
7336 config_data = 0x00; // 0000 0000
7337 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7338 retval = 1;
7339 }
7340 else if ( drive_type == 3 ) {
7341 // 720K 3.5" drive
7342 config_data = 0x00; // 0000 0000 ???
7343 media_state = 0x17; // 0001 0111
7344 retval = 1;
7345 }
7346 else if ( drive_type == 4 ) {
7347 // 1.44 MB 3.5" drive
7348 config_data = 0x00; // 0000 0000
7349 media_state = 0x17; // 0001 0111
7350 retval = 1;
7351 }
7352 else if ( drive_type == 5 ) {
7353 // 2.88 MB 3.5" drive
7354 config_data = 0xCC; // 1100 1100
7355 media_state = 0xD7; // 1101 0111
7356 retval = 1;
7357 }
7358 //
7359 // Extended floppy size uses special cmos setting
7360 else if ( drive_type == 6 ) {
7361 // 160k 5.25" drive
7362 config_data = 0x00; // 0000 0000
7363 media_state = 0x27; // 0010 0111
7364 retval = 1;
7365 }
7366 else if ( drive_type == 7 ) {
7367 // 180k 5.25" drive
7368 config_data = 0x00; // 0000 0000
7369 media_state = 0x27; // 0010 0111
7370 retval = 1;
7371 }
7372 else if ( drive_type == 8 ) {
7373 // 320k 5.25" drive
7374 config_data = 0x00; // 0000 0000
7375 media_state = 0x27; // 0010 0111
7376 retval = 1;
7377 }
7378
7379 else {
7380 // not recognized
7381 config_data = 0x00; // 0000 0000
7382 media_state = 0x00; // 0000 0000
7383 retval = 0;
7384 }
7385
7386 if (drive == 0)
7387 media_state_offset = 0x90;
7388 else
7389 media_state_offset = 0x91;
7390 write_byte(0x0040, 0x008B, config_data);
7391 write_byte(0x0040, media_state_offset, media_state);
7392
7393 return(retval);
7394}
7395
7396 bx_bool
7397floppy_drive_recal(drive)
7398 Bit16u drive;
7399{
7400 Bit8u val8;
7401 Bit16u curr_cyl_offset;
7402
7403 floppy_prepare_controller(drive);
7404
7405 // send Recalibrate command (2 bytes) to controller
7406 outb(0x03f5, 0x07); // 07: Recalibrate
7407 outb(0x03f5, drive); // 0=drive0, 1=drive1
7408
7409 // turn on interrupts
7410ASM_START
7411 sti
7412ASM_END
7413
7414 // wait on 40:3e bit 7 to become 1
7415 do {
7416 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7417 } while ( val8 == 0 );
7418
7419 val8 = 0; // separate asm from while() loop
7420 // turn off interrupts
7421ASM_START
7422 cli
7423ASM_END
7424
7425 // set 40:3e bit 7 to 0, and calibrated bit
7426 val8 = read_byte(0x0040, 0x003e);
7427 val8 &= 0x7f;
7428 if (drive) {
7429 val8 |= 0x02; // Drive 1 calibrated
7430 curr_cyl_offset = 0x0095;
7431 } else {
7432 val8 |= 0x01; // Drive 0 calibrated
7433 curr_cyl_offset = 0x0094;
7434 }
7435 write_byte(0x0040, 0x003e, val8);
7436 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7437
7438 return(1);
7439}
7440
7441
7442
7443 bx_bool
7444floppy_drive_exists(drive)
7445 Bit16u drive;
7446{
7447 Bit8u drive_type;
7448
7449 // check CMOS to see if drive exists
7450 drive_type = inb_cmos(0x10);
7451 if (drive == 0)
7452 drive_type >>= 4;
7453 else
7454 drive_type &= 0x0f;
7455 if ( drive_type == 0 )
7456 return(0);
7457 else
7458 return(1);
7459}
7460
7461#if BX_SUPPORT_FLOPPY
7462 void
7463int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7464 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7465{
7466 Bit8u drive, num_sectors, track, sector, head, status;
7467 Bit16u base_address, base_count, base_es;
7468 Bit8u page, mode_register, val8, dor;
7469 Bit8u return_status[7];
7470 Bit8u drive_type, num_floppies, ah;
7471 Bit16u es, last_addr;
7472
7473 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7474
7475 ah = GET_AH();
7476
7477 switch ( ah ) {
7478 case 0x00: // diskette controller reset
7479BX_DEBUG_INT13_FL("floppy f00\n");
7480 drive = GET_ELDL();
7481 if (drive > 1) {
7482 SET_AH(1); // invalid param
7483 set_diskette_ret_status(1);
7484 SET_CF();
7485 return;
7486 }
7487 drive_type = inb_cmos(0x10);
7488
7489 if (drive == 0)
7490 drive_type >>= 4;
7491 else
7492 drive_type &= 0x0f;
7493 if (drive_type == 0) {
7494 SET_AH(0x80); // drive not responding
7495 set_diskette_ret_status(0x80);
7496 SET_CF();
7497 return;
7498 }
7499 SET_AH(0);
7500 set_diskette_ret_status(0);
7501 CLEAR_CF(); // successful
7502 set_diskette_current_cyl(drive, 0); // current cylinder
7503 return;
7504
7505 case 0x01: // Read Diskette Status
7506 CLEAR_CF();
7507 val8 = read_byte(0x0000, 0x0441);
7508 SET_AH(val8);
7509 if (val8) {
7510 SET_CF();
7511 }
7512 return;
7513
7514 case 0x02: // Read Diskette Sectors
7515 case 0x03: // Write Diskette Sectors
7516 case 0x04: // Verify Diskette Sectors
7517 num_sectors = GET_AL();
7518 track = GET_CH();
7519 sector = GET_CL();
7520 head = GET_DH();
7521 drive = GET_ELDL();
7522
7523 if ( (drive > 1) || (head > 1) ||
7524 (num_sectors == 0) || (num_sectors > 72) ) {
7525BX_INFO("floppy: drive>1 || head>1 ...\n");
7526 SET_AH(1);
7527 set_diskette_ret_status(1);
7528 SET_AL(0); // no sectors read
7529 SET_CF(); // error occurred
7530 return;
7531 }
7532
7533 // see if drive exists
7534 if (floppy_drive_exists(drive) == 0) {
7535 SET_AH(0x80); // not responding
7536 set_diskette_ret_status(0x80);
7537 SET_AL(0); // no sectors read
7538 SET_CF(); // error occurred
7539 return;
7540 }
7541
7542 // see if media in drive, and type is known
7543 if (floppy_media_known(drive) == 0) {
7544 if (floppy_media_sense(drive) == 0) {
7545 SET_AH(0x0C); // Media type not found
7546 set_diskette_ret_status(0x0C);
7547 SET_AL(0); // no sectors read
7548 SET_CF(); // error occurred
7549 return;
7550 }
7551 }
7552
7553 if (ah == 0x02) {
7554 // Read Diskette Sectors
7555
7556 //-----------------------------------
7557 // set up DMA controller for transfer
7558 //-----------------------------------
7559
7560 // es:bx = pointer to where to place information from diskette
7561 // port 04: DMA-1 base and current address, channel 2
7562 // port 05: DMA-1 base and current count, channel 2
7563 page = (ES >> 12); // upper 4 bits
7564 base_es = (ES << 4); // lower 16bits contributed by ES
7565 base_address = base_es + BX; // lower 16 bits of address
7566 // contributed by ES:BX
7567 if ( base_address < base_es ) {
7568 // in case of carry, adjust page by 1
7569 page++;
7570 }
7571 base_count = (num_sectors * 512) - 1;
7572
7573 // check for 64K boundary overrun
7574 last_addr = base_address + base_count;
7575 if (last_addr < base_address) {
7576 SET_AH(0x09);
7577 set_diskette_ret_status(0x09);
7578 SET_AL(0); // no sectors read
7579 SET_CF(); // error occurred
7580 return;
7581 }
7582
7583 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7584 outb(0x000a, 0x06);
7585
7586 BX_DEBUG_INT13_FL("clear flip-flop\n");
7587 outb(0x000c, 0x00); // clear flip-flop
7588 outb(0x0004, base_address);
7589 outb(0x0004, base_address>>8);
7590 BX_DEBUG_INT13_FL("clear flip-flop\n");
7591 outb(0x000c, 0x00); // clear flip-flop
7592 outb(0x0005, base_count);
7593 outb(0x0005, base_count>>8);
7594
7595 // port 0b: DMA-1 Mode Register
7596 mode_register = 0x46; // single mode, increment, autoinit disable,
7597 // transfer type=write, channel 2
7598 BX_DEBUG_INT13_FL("setting mode register\n");
7599 outb(0x000b, mode_register);
7600
7601 BX_DEBUG_INT13_FL("setting page register\n");
7602 // port 81: DMA-1 Page Register, channel 2
7603 outb(0x0081, page);
7604
7605 BX_DEBUG_INT13_FL("unmask chan 2\n");
7606 outb(0x000a, 0x02); // unmask channel 2
7607
7608 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7609 outb(0x000a, 0x02);
7610
7611 //--------------------------------------
7612 // set up floppy controller for transfer
7613 //--------------------------------------
7614 floppy_prepare_controller(drive);
7615
7616 // send read-normal-data command (9 bytes) to controller
7617 outb(0x03f5, 0xe6); // e6: read normal data
7618 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7619 outb(0x03f5, track);
7620 outb(0x03f5, head);
7621 outb(0x03f5, sector);
7622 outb(0x03f5, 2); // 512 byte sector size
7623 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7624 outb(0x03f5, 0); // Gap length
7625 outb(0x03f5, 0xff); // Gap length
7626
7627 // turn on interrupts
7628 ASM_START
7629 sti
7630 ASM_END
7631
7632 // wait on 40:3e bit 7 to become 1
7633 do {
7634 val8 = read_byte(0x0040, 0x0040);
7635 if (val8 == 0) {
7636 floppy_reset_controller();
7637 SET_AH(0x80); // drive not ready (timeout)
7638 set_diskette_ret_status(0x80);
7639 SET_AL(0); // no sectors read
7640 SET_CF(); // error occurred
7641 return;
7642 }
7643 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7644 } while ( val8 == 0 );
7645
7646 val8 = 0; // separate asm from while() loop
7647 // turn off interrupts
7648 ASM_START
7649 cli
7650 ASM_END
7651
7652 // set 40:3e bit 7 to 0
7653 val8 = read_byte(0x0040, 0x003e);
7654 val8 &= 0x7f;
7655 write_byte(0x0040, 0x003e, val8);
7656
7657 // check port 3f4 for accessibility to status bytes
7658 val8 = inb(0x3f4);
7659 if ( (val8 & 0xc0) != 0xc0 )
7660 BX_PANIC("int13_diskette: ctrl not ready\n");
7661
7662 // read 7 return status bytes from controller
7663 // using loop index broken, have to unroll...
7664 return_status[0] = inb(0x3f5);
7665 return_status[1] = inb(0x3f5);
7666 return_status[2] = inb(0x3f5);
7667 return_status[3] = inb(0x3f5);
7668 return_status[4] = inb(0x3f5);
7669 return_status[5] = inb(0x3f5);
7670 return_status[6] = inb(0x3f5);
7671 // record in BIOS Data Area
7672 write_byte(0x0040, 0x0042, return_status[0]);
7673 write_byte(0x0040, 0x0043, return_status[1]);
7674 write_byte(0x0040, 0x0044, return_status[2]);
7675 write_byte(0x0040, 0x0045, return_status[3]);
7676 write_byte(0x0040, 0x0046, return_status[4]);
7677 write_byte(0x0040, 0x0047, return_status[5]);
7678 write_byte(0x0040, 0x0048, return_status[6]);
7679
7680 if ( (return_status[0] & 0xc0) != 0 ) {
7681 SET_AH(0x20);
7682 set_diskette_ret_status(0x20);
7683 SET_AL(0); // no sectors read
7684 SET_CF(); // error occurred
7685 return;
7686 }
7687
7688 // ??? should track be new val from return_status[3] ?
7689 set_diskette_current_cyl(drive, track);
7690 // AL = number of sectors read (same value as passed)
7691 SET_AH(0x00); // success
7692 CLEAR_CF(); // success
7693 return;
7694 } else if (ah == 0x03) {
7695 // Write Diskette Sectors
7696
7697 //-----------------------------------
7698 // set up DMA controller for transfer
7699 //-----------------------------------
7700
7701 // es:bx = pointer to where to place information from diskette
7702 // port 04: DMA-1 base and current address, channel 2
7703 // port 05: DMA-1 base and current count, channel 2
7704 page = (ES >> 12); // upper 4 bits
7705 base_es = (ES << 4); // lower 16bits contributed by ES
7706 base_address = base_es + BX; // lower 16 bits of address
7707 // contributed by ES:BX
7708 if ( base_address < base_es ) {
7709 // in case of carry, adjust page by 1
7710 page++;
7711 }
7712 base_count = (num_sectors * 512) - 1;
7713
7714 // check for 64K boundary overrun
7715 last_addr = base_address + base_count;
7716 if (last_addr < base_address) {
7717 SET_AH(0x09);
7718 set_diskette_ret_status(0x09);
7719 SET_AL(0); // no sectors read
7720 SET_CF(); // error occurred
7721 return;
7722 }
7723
7724 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7725 outb(0x000a, 0x06);
7726
7727 outb(0x000c, 0x00); // clear flip-flop
7728 outb(0x0004, base_address);
7729 outb(0x0004, base_address>>8);
7730 outb(0x000c, 0x00); // clear flip-flop
7731 outb(0x0005, base_count);
7732 outb(0x0005, base_count>>8);
7733
7734 // port 0b: DMA-1 Mode Register
7735 mode_register = 0x4a; // single mode, increment, autoinit disable,
7736 // transfer type=read, channel 2
7737 outb(0x000b, mode_register);
7738
7739 // port 81: DMA-1 Page Register, channel 2
7740 outb(0x0081, page);
7741
7742 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7743 outb(0x000a, 0x02);
7744
7745 //--------------------------------------
7746 // set up floppy controller for transfer
7747 //--------------------------------------
7748 floppy_prepare_controller(drive);
7749
7750 // send write-normal-data command (9 bytes) to controller
7751 outb(0x03f5, 0xc5); // c5: write normal data
7752 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7753 outb(0x03f5, track);
7754 outb(0x03f5, head);
7755 outb(0x03f5, sector);
7756 outb(0x03f5, 2); // 512 byte sector size
7757 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7758 outb(0x03f5, 0); // Gap length
7759 outb(0x03f5, 0xff); // Gap length
7760
7761 // turn on interrupts
7762 ASM_START
7763 sti
7764 ASM_END
7765
7766 // wait on 40:3e bit 7 to become 1
7767 do {
7768 val8 = read_byte(0x0040, 0x0040);
7769 if (val8 == 0) {
7770 floppy_reset_controller();
7771 SET_AH(0x80); // drive not ready (timeout)
7772 set_diskette_ret_status(0x80);
7773 SET_AL(0); // no sectors written
7774 SET_CF(); // error occurred
7775 return;
7776 }
7777 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7778 } while ( val8 == 0 );
7779
7780 val8 = 0; // separate asm from while() loop
7781 // turn off interrupts
7782 ASM_START
7783 cli
7784 ASM_END
7785
7786 // set 40:3e bit 7 to 0
7787 val8 = read_byte(0x0040, 0x003e);
7788 val8 &= 0x7f;
7789 write_byte(0x0040, 0x003e, val8);
7790
7791 // check port 3f4 for accessibility to status bytes
7792 val8 = inb(0x3f4);
7793 if ( (val8 & 0xc0) != 0xc0 )
7794 BX_PANIC("int13_diskette: ctrl not ready\n");
7795
7796 // read 7 return status bytes from controller
7797 // using loop index broken, have to unroll...
7798 return_status[0] = inb(0x3f5);
7799 return_status[1] = inb(0x3f5);
7800 return_status[2] = inb(0x3f5);
7801 return_status[3] = inb(0x3f5);
7802 return_status[4] = inb(0x3f5);
7803 return_status[5] = inb(0x3f5);
7804 return_status[6] = inb(0x3f5);
7805 // record in BIOS Data Area
7806 write_byte(0x0040, 0x0042, return_status[0]);
7807 write_byte(0x0040, 0x0043, return_status[1]);
7808 write_byte(0x0040, 0x0044, return_status[2]);
7809 write_byte(0x0040, 0x0045, return_status[3]);
7810 write_byte(0x0040, 0x0046, return_status[4]);
7811 write_byte(0x0040, 0x0047, return_status[5]);
7812 write_byte(0x0040, 0x0048, return_status[6]);
7813
7814 if ( (return_status[0] & 0xc0) != 0 ) {
7815 if ( (return_status[1] & 0x02) != 0 ) {
7816 // diskette not writable.
7817 // AH=status code=0x03 (tried to write on write-protected disk)
7818 // AL=number of sectors written=0
7819 AX = 0x0300;
7820 SET_CF();
7821 return;
7822 } else {
7823 BX_PANIC("int13_diskette_function: read error\n");
7824 }
7825 }
7826
7827 // ??? should track be new val from return_status[3] ?
7828 set_diskette_current_cyl(drive, track);
7829 // AL = number of sectors read (same value as passed)
7830 SET_AH(0x00); // success
7831 CLEAR_CF(); // success
7832 return;
7833 } else { // if (ah == 0x04)
7834 // Verify Diskette Sectors
7835
7836 // ??? should track be new val from return_status[3] ?
7837 set_diskette_current_cyl(drive, track);
7838 // AL = number of sectors verified (same value as passed)
7839 CLEAR_CF(); // success
7840 SET_AH(0x00); // success
7841 return;
7842 }
7843 break;
7844
7845 case 0x05: // format diskette track
7846BX_DEBUG_INT13_FL("floppy f05\n");
7847
7848 num_sectors = GET_AL();
7849 track = GET_CH();
7850 head = GET_DH();
7851 drive = GET_ELDL();
7852
7853 if ((drive > 1) || (head > 1) || (track > 79) ||
7854 (num_sectors == 0) || (num_sectors > 18)) {
7855 SET_AH(1);
7856 set_diskette_ret_status(1);
7857 SET_CF(); // error occurred
7858 }
7859
7860 // see if drive exists
7861 if (floppy_drive_exists(drive) == 0) {
7862 SET_AH(0x80); // drive not responding
7863 set_diskette_ret_status(0x80);
7864 SET_CF(); // error occurred
7865 return;
7866 }
7867
7868 // see if media in drive, and type is known
7869 if (floppy_media_known(drive) == 0) {
7870 if (floppy_media_sense(drive) == 0) {
7871 SET_AH(0x0C); // Media type not found
7872 set_diskette_ret_status(0x0C);
7873 SET_AL(0); // no sectors read
7874 SET_CF(); // error occurred
7875 return;
7876 }
7877 }
7878
7879 // set up DMA controller for transfer
7880 page = (ES >> 12); // upper 4 bits
7881 base_es = (ES << 4); // lower 16bits contributed by ES
7882 base_address = base_es + BX; // lower 16 bits of address
7883 // contributed by ES:BX
7884 if ( base_address < base_es ) {
7885 // in case of carry, adjust page by 1
7886 page++;
7887 }
7888 base_count = (num_sectors * 4) - 1;
7889
7890 // check for 64K boundary overrun
7891 last_addr = base_address + base_count;
7892 if (last_addr < base_address) {
7893 SET_AH(0x09);
7894 set_diskette_ret_status(0x09);
7895 SET_AL(0); // no sectors read
7896 SET_CF(); // error occurred
7897 return;
7898 }
7899
7900 outb(0x000a, 0x06);
7901 outb(0x000c, 0x00); // clear flip-flop
7902 outb(0x0004, base_address);
7903 outb(0x0004, base_address>>8);
7904 outb(0x000c, 0x00); // clear flip-flop
7905 outb(0x0005, base_count);
7906 outb(0x0005, base_count>>8);
7907 mode_register = 0x4a; // single mode, increment, autoinit disable,
7908 // transfer type=read, channel 2
7909 outb(0x000b, mode_register);
7910 // port 81: DMA-1 Page Register, channel 2
7911 outb(0x0081, page);
7912 outb(0x000a, 0x02);
7913
7914 // set up floppy controller for transfer
7915 floppy_prepare_controller(drive);
7916
7917 // send format-track command (6 bytes) to controller
7918 outb(0x03f5, 0x4d); // 4d: format track
7919 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7920 outb(0x03f5, 2); // 512 byte sector size
7921 outb(0x03f5, num_sectors); // number of sectors per track
7922 outb(0x03f5, 0); // Gap length
7923 outb(0x03f5, 0xf6); // Fill byte
7924 // turn on interrupts
7925 ASM_START
7926 sti
7927 ASM_END
7928
7929 // wait on 40:3e bit 7 to become 1
7930 do {
7931 val8 = read_byte(0x0040, 0x0040);
7932 if (val8 == 0) {
7933 floppy_reset_controller();
7934 SET_AH(0x80); // drive not ready (timeout)
7935 set_diskette_ret_status(0x80);
7936 SET_CF(); // error occurred
7937 return;
7938 }
7939 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7940 } while ( val8 == 0 );
7941
7942 val8 = 0; // separate asm from while() loop
7943 // turn off interrupts
7944 ASM_START
7945 cli
7946 ASM_END
7947 // set 40:3e bit 7 to 0
7948 val8 = read_byte(0x0040, 0x003e);
7949 val8 &= 0x7f;
7950 write_byte(0x0040, 0x003e, val8);
7951 // check port 3f4 for accessibility to status bytes
7952 val8 = inb(0x3f4);
7953 if ( (val8 & 0xc0) != 0xc0 )
7954 BX_PANIC("int13_diskette: ctrl not ready\n");
7955
7956 // read 7 return status bytes from controller
7957 // using loop index broken, have to unroll...
7958 return_status[0] = inb(0x3f5);
7959 return_status[1] = inb(0x3f5);
7960 return_status[2] = inb(0x3f5);
7961 return_status[3] = inb(0x3f5);
7962 return_status[4] = inb(0x3f5);
7963 return_status[5] = inb(0x3f5);
7964 return_status[6] = inb(0x3f5);
7965 // record in BIOS Data Area
7966 write_byte(0x0040, 0x0042, return_status[0]);
7967 write_byte(0x0040, 0x0043, return_status[1]);
7968 write_byte(0x0040, 0x0044, return_status[2]);
7969 write_byte(0x0040, 0x0045, return_status[3]);
7970 write_byte(0x0040, 0x0046, return_status[4]);
7971 write_byte(0x0040, 0x0047, return_status[5]);
7972 write_byte(0x0040, 0x0048, return_status[6]);
7973
7974 if ( (return_status[0] & 0xc0) != 0 ) {
7975 if ( (return_status[1] & 0x02) != 0 ) {
7976 // diskette not writable.
7977 // AH=status code=0x03 (tried to write on write-protected disk)
7978 // AL=number of sectors written=0
7979 AX = 0x0300;
7980 SET_CF();
7981 return;
7982 } else {
7983 BX_PANIC("int13_diskette_function: write error\n");
7984 }
7985 }
7986
7987 SET_AH(0);
7988 set_diskette_ret_status(0);
7989 set_diskette_current_cyl(drive, 0);
7990 CLEAR_CF(); // successful
7991 return;
7992
7993
7994 case 0x08: // read diskette drive parameters
7995BX_DEBUG_INT13_FL("floppy f08\n");
7996 drive = GET_ELDL();
7997
7998 if (drive > 1) {
7999 AX = 0;
8000 BX = 0;
8001 CX = 0;
8002 DX = 0;
8003 ES = 0;
8004 DI = 0;
8005 SET_DL(num_floppies);
8006 SET_CF();
8007 return;
8008 }
8009
8010 drive_type = inb_cmos(0x10);
8011 num_floppies = 0;
8012 if (drive_type & 0xf0)
8013 num_floppies++;
8014 if (drive_type & 0x0f)
8015 num_floppies++;
8016
8017 if (drive == 0)
8018 drive_type >>= 4;
8019 else
8020 drive_type &= 0x0f;
8021
8022 SET_BH(0);
8023 SET_BL(drive_type);
8024 SET_AH(0);
8025 SET_AL(0);
8026 SET_DL(num_floppies);
8027
8028 switch (drive_type) {
8029 case 0: // none
8030 CX = 0;
8031 SET_DH(0); // max head #
8032 break;
8033
8034 case 1: // 360KB, 5.25"
8035 CX = 0x2709; // 40 tracks, 9 sectors
8036 SET_DH(1); // max head #
8037 break;
8038
8039 case 2: // 1.2MB, 5.25"
8040 CX = 0x4f0f; // 80 tracks, 15 sectors
8041 SET_DH(1); // max head #
8042 break;
8043
8044 case 3: // 720KB, 3.5"
8045 CX = 0x4f09; // 80 tracks, 9 sectors
8046 SET_DH(1); // max head #
8047 break;
8048
8049 case 4: // 1.44MB, 3.5"
8050 CX = 0x4f12; // 80 tracks, 18 sectors
8051 SET_DH(1); // max head #
8052 break;
8053
8054 case 5: // 2.88MB, 3.5"
8055 CX = 0x4f24; // 80 tracks, 36 sectors
8056 SET_DH(1); // max head #
8057 break;
8058
8059 case 6: // 160k, 5.25"
8060 CX = 0x2708; // 40 tracks, 8 sectors
8061 SET_DH(0); // max head #
8062 break;
8063
8064 case 7: // 180k, 5.25"
8065 CX = 0x2709; // 40 tracks, 9 sectors
8066 SET_DH(0); // max head #
8067 break;
8068
8069 case 8: // 320k, 5.25"
8070 CX = 0x2708; // 40 tracks, 8 sectors
8071 SET_DH(1); // max head #
8072 break;
8073
8074 default: // ?
8075 BX_PANIC("floppy: int13: bad floppy type\n");
8076 }
8077
8078 /* set es & di to point to 11 byte diskette param table in ROM */
8079ASM_START
8080 push bp
8081 mov bp, sp
8082 mov ax, #diskette_param_table2
8083 mov _int13_diskette_function.DI+2[bp], ax
8084 mov _int13_diskette_function.ES+2[bp], cs
8085 pop bp
8086ASM_END
8087 CLEAR_CF(); // success
8088 /* disk status not changed upon success */
8089 return;
8090
8091
8092 case 0x15: // read diskette drive type
8093BX_DEBUG_INT13_FL("floppy f15\n");
8094 drive = GET_ELDL();
8095 if (drive > 1) {
8096 SET_AH(0); // only 2 drives supported
8097 // set_diskette_ret_status here ???
8098 SET_CF();
8099 return;
8100 }
8101 drive_type = inb_cmos(0x10);
8102
8103 if (drive == 0)
8104 drive_type >>= 4;
8105 else
8106 drive_type &= 0x0f;
8107 CLEAR_CF(); // successful, not present
8108 if (drive_type==0) {
8109 SET_AH(0); // drive not present
8110 }
8111 else {
8112 SET_AH(1); // drive present, does not support change line
8113 }
8114
8115 return;
8116
8117 case 0x16: // get diskette change line status
8118BX_DEBUG_INT13_FL("floppy f16\n");
8119 drive = GET_ELDL();
8120 if (drive > 1) {
8121 SET_AH(0x01); // invalid drive
8122 set_diskette_ret_status(0x01);
8123 SET_CF();
8124 return;
8125 }
8126
8127 SET_AH(0x06); // change line not supported
8128 set_diskette_ret_status(0x06);
8129 SET_CF();
8130 return;
8131
8132 case 0x17: // set diskette type for format(old)
8133BX_DEBUG_INT13_FL("floppy f17\n");
8134 /* not used for 1.44M floppies */
8135 SET_AH(0x01); // not supported
8136 set_diskette_ret_status(1); /* not supported */
8137 SET_CF();
8138 return;
8139
8140 case 0x18: // set diskette type for format(new)
8141BX_DEBUG_INT13_FL("floppy f18\n");
8142 SET_AH(0x01); // do later
8143 set_diskette_ret_status(1);
8144 SET_CF();
8145 return;
8146
8147 default:
8148 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8149
8150 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8151 SET_AH(0x01); // ???
8152 set_diskette_ret_status(1);
8153 SET_CF();
8154 return;
8155 // }
8156 }
8157}
8158#else // #if BX_SUPPORT_FLOPPY
8159 void
8160int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8161 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8162{
8163 Bit8u val8;
8164
8165 switch ( GET_AH() ) {
8166
8167 case 0x01: // Read Diskette Status
8168 CLEAR_CF();
8169 val8 = read_byte(0x0000, 0x0441);
8170 SET_AH(val8);
8171 if (val8) {
8172 SET_CF();
8173 }
8174 return;
8175
8176 default:
8177 SET_CF();
8178 write_byte(0x0000, 0x0441, 0x01);
8179 SET_AH(0x01);
8180 }
8181}
8182#endif // #if BX_SUPPORT_FLOPPY
8183
8184 void
8185set_diskette_ret_status(value)
8186 Bit8u value;
8187{
8188 write_byte(0x0040, 0x0041, value);
8189}
8190
8191 void
8192set_diskette_current_cyl(drive, cyl)
8193 Bit8u drive;
8194 Bit8u cyl;
8195{
8196 if (drive > 1)
8197 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8198 write_byte(0x0040, 0x0094+drive, cyl);
8199}
8200
8201 void
8202determine_floppy_media(drive)
8203 Bit16u drive;
8204{
8205#if 0
8206 Bit8u val8, DOR, ctrl_info;
8207
8208 ctrl_info = read_byte(0x0040, 0x008F);
8209 if (drive==1)
8210 ctrl_info >>= 4;
8211 else
8212 ctrl_info &= 0x0f;
8213
8214#if 0
8215 if (drive == 0) {
8216 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8217 }
8218 else {
8219 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8220 }
8221#endif
8222
8223 if ( (ctrl_info & 0x04) != 0x04 ) {
8224 // Drive not determined means no drive exists, done.
8225 return;
8226 }
8227
8228#if 0
8229 // check Main Status Register for readiness
8230 val8 = inb(0x03f4) & 0x80; // Main Status Register
8231 if (val8 != 0x80)
8232 BX_PANIC("d_f_m: MRQ bit not set\n");
8233
8234 // change line
8235
8236 // existing BDA values
8237
8238 // turn on drive motor
8239 outb(0x03f2, DOR); // Digital Output Register
8240 //
8241#endif
8242 BX_PANIC("d_f_m: OK so far\n");
8243#endif
8244}
8245
8246 void
8247int17_function(regs, ds, iret_addr)
8248 pusha_regs_t regs; // regs pushed from PUSHA instruction
8249 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8250 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8251{
8252 Bit16u addr,timeout;
8253 Bit8u val8;
8254
8255 ASM_START
8256 sti
8257 ASM_END
8258
8259 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8260 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8261 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8262 if (regs.u.r8.ah == 0) {
8263 outb(addr, regs.u.r8.al);
8264 val8 = inb(addr+2);
8265 outb(addr+2, val8 | 0x01); // send strobe
8266 ASM_START
8267 nop
8268 ASM_END
8269 outb(addr+2, val8 & ~0x01);
8270 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8271 timeout--;
8272 }
8273 }
8274 if (regs.u.r8.ah == 1) {
8275 val8 = inb(addr+2);
8276 outb(addr+2, val8 & ~0x04); // send init
8277 ASM_START
8278 nop
8279 ASM_END
8280 outb(addr+2, val8 | 0x04);
8281 }
8282 val8 = inb(addr+1);
8283 regs.u.r8.ah = (val8 ^ 0x48);
8284 if (!timeout) regs.u.r8.ah |= 0x01;
8285 ClearCF(iret_addr.flags);
8286 } else {
8287 SetCF(iret_addr.flags); // Unsupported
8288 }
8289}
8290
8291// returns bootsegment in ax, drive in bl
8292 Bit32u
8293int19_function(bseqnr)
8294Bit8u bseqnr;
8295{
8296 Bit16u ebda_seg=read_word(0x0040,0x000E);
8297 Bit16u bootseq;
8298 Bit8u bootdrv;
8299 Bit8u bootcd;
8300#ifdef VBOX
8301 Bit8u bootlan;
8302#endif /* VBOX */
8303 Bit8u bootchk;
8304 Bit16u bootseg;
8305 Bit16u status;
8306 Bit8u lastdrive=0;
8307
8308 // if BX_ELTORITO_BOOT is not defined, old behavior
8309 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8310 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8311 // 0: system boot sequence, first drive C: then A:
8312 // 1: system boot sequence, first drive A: then C:
8313 // else BX_ELTORITO_BOOT is defined
8314 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8315 // CMOS reg 0x3D & 0x0f : 1st boot device
8316 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8317 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8318#ifdef VBOX
8319 // CMOS reg 0x3C & 0x0f : 4th boot device
8320#endif /* VBOX */
8321 // boot device codes:
8322 // 0x00 : not defined
8323 // 0x01 : first floppy
8324 // 0x02 : first harddrive
8325 // 0x03 : first cdrom
8326#ifdef VBOX
8327 // 0x04 : local area network
8328#endif /* VBOX */
8329 // else : boot failure
8330
8331 // Get the boot sequence
8332#if BX_ELTORITO_BOOT
8333 bootseq=inb_cmos(0x3d);
8334 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8335#ifdef VBOX
8336 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8337 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8338 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8339 /* Boot delay hack. */
8340 if (bseqnr == 1)
8341 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8342#endif /* VBOX */
8343
8344 if (bseqnr==2) bootseq >>= 4;
8345 if (bseqnr==3) bootseq >>= 8;
8346#ifdef VBOX
8347 if (bseqnr==4) bootseq >>= 12;
8348#endif /* VBOX */
8349 if (bootseq<0x10) lastdrive = 1;
8350 bootdrv=0x00; bootcd=0;
8351#ifdef VBOX
8352 bootlan=0;
8353#endif /* VBOX */
8354
8355 switch(bootseq & 0x0f) {
8356 case 0x01:
8357 bootdrv=0x00;
8358 bootcd=0;
8359 break;
8360 case 0x02:
8361 {
8362 // Get the Boot drive.
8363 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8364
8365 bootdrv = boot_drive + 0x80;
8366 bootcd=0;
8367 break;
8368 }
8369 case 0x03:
8370 bootdrv=0x00;
8371 bootcd=1;
8372 break;
8373#ifdef VBOX
8374 case 0x04: bootlan=1; break;
8375#endif /* VBOX */
8376 default: return 0x00000000;
8377 }
8378#else
8379 bootseq=inb_cmos(0x2d);
8380
8381 if (bseqnr==2) {
8382 bootseq ^= 0x20;
8383 lastdrive = 1;
8384 }
8385 bootdrv=0x00; bootcd=0;
8386 if((bootseq&0x20)==0) bootdrv=0x80;
8387#endif // BX_ELTORITO_BOOT
8388
8389#if BX_ELTORITO_BOOT
8390 // We have to boot from cd
8391 if (bootcd != 0) {
8392 status = cdrom_boot();
8393
8394 // If failure
8395 if ( (status & 0x00ff) !=0 ) {
8396 print_cdromboot_failure(status);
8397#ifdef VBOX
8398 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8399#else /* !VBOX */
8400 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8401#endif /* !VBOX */
8402 return 0x00000000;
8403 }
8404
8405 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8406 bootdrv = (Bit8u)(status>>8);
8407 }
8408
8409#endif // BX_ELTORITO_BOOT
8410
8411#ifdef VBOX
8412 // Check for boot from LAN first
8413 if (bootlan == 1) {
8414 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8415 Bit16u pnpoff;
8416 Bit32u manuf;
8417 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8418 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8419 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8420 // Found PnP signature
8421 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8422 if (manuf == 0x65687445) {
8423 // Found Etherboot ROM
8424 print_boot_device(bootcd, bootlan, bootdrv);
8425ASM_START
8426 push ds
8427 push es
8428 pusha
8429 calli 0x0006,VBOX_LANBOOT_SEG
8430 popa
8431 pop es
8432 pop ds
8433ASM_END
8434 } else if (manuf == 0x65746E49) {
8435 // Found Intel PXE ROM
8436 print_boot_device(bootcd, bootlan, bootdrv);
8437ASM_START
8438 push ds
8439 push es
8440 pusha
8441 sti ; Why are interrupts disabled now? Because we were called through an INT!
8442 push #VBOX_LANBOOT_SEG
8443 pop ds
8444 mov bx,#0x1a ; PnP header offset
8445 mov bx,[bx]
8446 add bx,#0x1a ; BEV offset in PnP header
8447 mov ax,[bx]
8448 test ax,ax
8449 jz no_rom
8450bev_jump:
8451 push cs
8452 push #no_rom
8453 push #VBOX_LANBOOT_SEG
8454 push ax
8455 retf ; call Boot Entry Vector
8456no_rom:
8457 popa
8458 pop es
8459 pop ds
8460ASM_END
8461 }
8462 }
8463 }
8464
8465 // boot from LAN will not return if successful.
8466 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8467 return 0x00000000;
8468 }
8469#endif /* VBOX */
8470 // We have to boot from harddisk or floppy
8471#ifdef VBOX
8472 if (bootcd == 0 && bootlan == 0) {
8473#else /* !VBOX */
8474 if (bootcd == 0) {
8475#endif /* !VBOX */
8476 bootseg=0x07c0;
8477
8478ASM_START
8479 push bp
8480 mov bp, sp
8481
8482 xor ax, ax
8483 mov _int19_function.status + 2[bp], ax
8484 mov dl, _int19_function.bootdrv + 2[bp]
8485 mov ax, _int19_function.bootseg + 2[bp]
8486 mov es, ax ;; segment
8487 xor bx, bx ;; offset
8488 mov ah, #0x02 ;; function 2, read diskette sector
8489 mov al, #0x01 ;; read 1 sector
8490 mov ch, #0x00 ;; track 0
8491 mov cl, #0x01 ;; sector 1
8492 mov dh, #0x00 ;; head 0
8493 int #0x13 ;; read sector
8494 jnc int19_load_done
8495 mov ax, #0x0001
8496 mov _int19_function.status + 2[bp], ax
8497
8498int19_load_done:
8499 pop bp
8500ASM_END
8501
8502 if (status != 0) {
8503#ifdef VBOX
8504 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8505#else /* !VBOX */
8506 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8507#endif /* !VBOX */
8508 return 0x00000000;
8509 }
8510 }
8511
8512#ifdef VBOX
8513 // Don't check boot sectors on floppies and don't read CMOS - byte
8514 // 0x38 in CMOS always has the low bit clear.
8515 // There is *no* requirement whatsoever for a valid boot sector to
8516 // have a 55AAh signature. UNIX boot floppies typically have no such
8517 // signature. In general, it is impossible to tell a valid bootsector
8518 // from an invalid one.
8519 // NB: It is somewhat common for failed OS installs to have the
8520 // 0x55AA signature and a valid partition table but zeros in the
8521 // rest of the boot sector. We do a quick check by comparing the first
8522 // two words of boot sector; if identical, the boot sector is
8523 // extremely unlikely to be valid.
8524#endif
8525 // check signature if instructed by cmos reg 0x38, only for floppy
8526 // bootchk = 1 : signature check disabled
8527 // bootchk = 0 : signature check enabled
8528 if (bootdrv != 0) bootchk = 0;
8529#ifdef VBOX
8530 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8531#else
8532 else bootchk = inb_cmos(0x38) & 0x01;
8533#endif
8534
8535#if BX_ELTORITO_BOOT
8536 // if boot from cd, no signature check
8537 if (bootcd != 0)
8538 bootchk = 1;
8539#endif // BX_ELTORITO_BOOT
8540
8541 if (bootchk == 0) {
8542 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8543 read_word(bootseg,0) == read_word(bootseg,2)) {
8544#ifdef VBOX
8545 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8546#else /* !VBOX */
8547 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8548#endif /* VBOX */
8549 return 0x00000000;
8550 }
8551 }
8552
8553#if BX_ELTORITO_BOOT
8554 // Print out the boot string
8555#ifdef VBOX
8556 print_boot_device(bootcd, bootlan, bootdrv);
8557#else /* !VBOX */
8558 print_boot_device(bootcd, bootdrv);
8559#endif /* !VBOX */
8560#else // BX_ELTORITO_BOOT
8561#ifdef VBOX
8562 print_boot_device(0, bootlan, bootdrv);
8563#else /* !VBOX */
8564 print_boot_device(0, bootdrv);
8565#endif /* !VBOX */
8566#endif // BX_ELTORITO_BOOT
8567
8568 // return the boot segment
8569 return (((Bit32u)bootdrv) << 16) + bootseg;
8570}
8571
8572 void
8573int1a_function(regs, ds, iret_addr)
8574 pusha_regs_t regs; // regs pushed from PUSHA instruction
8575 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8576 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8577{
8578 Bit8u val8;
8579
8580 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);
8581
8582 ASM_START
8583 sti
8584 ASM_END
8585
8586 switch (regs.u.r8.ah) {
8587 case 0: // get current clock count
8588 ASM_START
8589 cli
8590 ASM_END
8591 regs.u.r16.cx = BiosData->ticks_high;
8592 regs.u.r16.dx = BiosData->ticks_low;
8593 regs.u.r8.al = BiosData->midnight_flag;
8594 BiosData->midnight_flag = 0; // reset flag
8595 ASM_START
8596 sti
8597 ASM_END
8598 // AH already 0
8599 ClearCF(iret_addr.flags); // OK
8600 break;
8601
8602 case 1: // Set Current Clock Count
8603 ASM_START
8604 cli
8605 ASM_END
8606 BiosData->ticks_high = regs.u.r16.cx;
8607 BiosData->ticks_low = regs.u.r16.dx;
8608 BiosData->midnight_flag = 0; // reset flag
8609 ASM_START
8610 sti
8611 ASM_END
8612 regs.u.r8.ah = 0;
8613 ClearCF(iret_addr.flags); // OK
8614 break;
8615
8616
8617 case 2: // Read CMOS Time
8618 if (rtc_updating()) {
8619 SetCF(iret_addr.flags);
8620 break;
8621 }
8622
8623 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8624 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8625 regs.u.r8.ch = inb_cmos(0x04); // Hours
8626 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8627 regs.u.r8.ah = 0;
8628 regs.u.r8.al = regs.u.r8.ch;
8629 ClearCF(iret_addr.flags); // OK
8630 break;
8631
8632 case 3: // Set CMOS Time
8633 // Using a debugger, I notice the following masking/setting
8634 // of bits in Status Register B, by setting Reg B to
8635 // a few values and getting its value after INT 1A was called.
8636 //
8637 // try#1 try#2 try#3
8638 // before 1111 1101 0111 1101 0000 0000
8639 // after 0110 0010 0110 0010 0000 0010
8640 //
8641 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8642 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8643 if (rtc_updating()) {
8644 init_rtc();
8645 // fall through as if an update were not in progress
8646 }
8647 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8648 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8649 outb_cmos(0x04, regs.u.r8.ch); // Hours
8650 // Set Daylight Savings time enabled bit to requested value
8651 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8652 // (reg B already selected)
8653 outb_cmos(0x0b, val8);
8654 regs.u.r8.ah = 0;
8655 regs.u.r8.al = val8; // val last written to Reg B
8656 ClearCF(iret_addr.flags); // OK
8657 break;
8658
8659 case 4: // Read CMOS Date
8660 regs.u.r8.ah = 0;
8661 if (rtc_updating()) {
8662 SetCF(iret_addr.flags);
8663 break;
8664 }
8665 regs.u.r8.cl = inb_cmos(0x09); // Year
8666 regs.u.r8.dh = inb_cmos(0x08); // Month
8667 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8668 regs.u.r8.ch = inb_cmos(0x32); // Century
8669 regs.u.r8.al = regs.u.r8.ch;
8670 ClearCF(iret_addr.flags); // OK
8671 break;
8672
8673 case 5: // Set CMOS Date
8674 // Using a debugger, I notice the following masking/setting
8675 // of bits in Status Register B, by setting Reg B to
8676 // a few values and getting its value after INT 1A was called.
8677 //
8678 // try#1 try#2 try#3 try#4
8679 // before 1111 1101 0111 1101 0000 0010 0000 0000
8680 // after 0110 1101 0111 1101 0000 0010 0000 0000
8681 //
8682 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8683 // My assumption: RegB = (RegB & 01111111b)
8684 if (rtc_updating()) {
8685 init_rtc();
8686 SetCF(iret_addr.flags);
8687 break;
8688 }
8689 outb_cmos(0x09, regs.u.r8.cl); // Year
8690 outb_cmos(0x08, regs.u.r8.dh); // Month
8691 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8692 outb_cmos(0x32, regs.u.r8.ch); // Century
8693 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8694 outb_cmos(0x0b, val8);
8695 regs.u.r8.ah = 0;
8696 regs.u.r8.al = val8; // AL = val last written to Reg B
8697 ClearCF(iret_addr.flags); // OK
8698 break;
8699
8700 case 6: // Set Alarm Time in CMOS
8701 // Using a debugger, I notice the following masking/setting
8702 // of bits in Status Register B, by setting Reg B to
8703 // a few values and getting its value after INT 1A was called.
8704 //
8705 // try#1 try#2 try#3
8706 // before 1101 1111 0101 1111 0000 0000
8707 // after 0110 1111 0111 1111 0010 0000
8708 //
8709 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8710 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8711 val8 = inb_cmos(0x0b); // Get Status Reg B
8712 regs.u.r16.ax = 0;
8713 if (val8 & 0x20) {
8714 // Alarm interrupt enabled already
8715 SetCF(iret_addr.flags); // Error: alarm in use
8716 break;
8717 }
8718 if (rtc_updating()) {
8719 init_rtc();
8720 // fall through as if an update were not in progress
8721 }
8722 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8723 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8724 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8725 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8726 // enable Status Reg B alarm bit, clear halt clock bit
8727 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8728 ClearCF(iret_addr.flags); // OK
8729 break;
8730
8731 case 7: // Turn off Alarm
8732 // Using a debugger, I notice the following masking/setting
8733 // of bits in Status Register B, by setting Reg B to
8734 // a few values and getting its value after INT 1A was called.
8735 //
8736 // try#1 try#2 try#3 try#4
8737 // before 1111 1101 0111 1101 0010 0000 0010 0010
8738 // after 0100 0101 0101 0101 0000 0000 0000 0010
8739 //
8740 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8741 // My assumption: RegB = (RegB & 01010111b)
8742 val8 = inb_cmos(0x0b); // Get Status Reg B
8743 // clear clock-halt bit, disable alarm bit
8744 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8745 regs.u.r8.ah = 0;
8746 regs.u.r8.al = val8; // val last written to Reg B
8747 ClearCF(iret_addr.flags); // OK
8748 break;
8749#if BX_PCIBIOS
8750 case 0xb1:
8751 // real mode PCI BIOS functions now handled in assembler code
8752 // this C code handles the error code for information only
8753 if (regs.u.r8.bl == 0xff) {
8754 BX_INFO("PCI BIOS: PCI not present\n");
8755 } else if (regs.u.r8.bl == 0x81) {
8756 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8757 } else if (regs.u.r8.bl == 0x83) {
8758 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8759 } else if (regs.u.r8.bl == 0x86) {
8760 if (regs.u.r8.al == 0x02) {
8761 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8762 } else {
8763 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);
8764 }
8765 }
8766 regs.u.r8.ah = regs.u.r8.bl;
8767 SetCF(iret_addr.flags);
8768 break;
8769#endif
8770
8771 default:
8772 SetCF(iret_addr.flags); // Unsupported
8773 }
8774}
8775
8776 void
8777int70_function(regs, ds, iret_addr)
8778 pusha_regs_t regs; // regs pushed from PUSHA instruction
8779 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8780 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8781{
8782 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8783 Bit8u registerB = 0, registerC = 0;
8784
8785 // Check which modes are enabled and have occurred.
8786 registerB = inb_cmos( 0xB );
8787 registerC = inb_cmos( 0xC );
8788
8789 if( ( registerB & 0x60 ) != 0 ) {
8790 if( ( registerC & 0x20 ) != 0 ) {
8791 // Handle Alarm Interrupt.
8792ASM_START
8793 sti
8794 int #0x4a
8795 cli
8796ASM_END
8797 }
8798 if( ( registerC & 0x40 ) != 0 ) {
8799 // Handle Periodic Interrupt.
8800
8801 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8802 // Wait Interval (Int 15, AH=83) active.
8803 Bit32u time, toggle;
8804
8805 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8806 if( time < 0x3D1 ) {
8807 // Done waiting.
8808 Bit16u segment, offset;
8809
8810 segment = read_word( 0x40, 0x98 );
8811 offset = read_word( 0x40, 0x9A );
8812 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8813 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8814 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8815 } else {
8816 // Continue waiting.
8817 time -= 0x3D1;
8818 write_dword( 0x40, 0x9C, time );
8819 }
8820 }
8821 }
8822 }
8823
8824ASM_START
8825 call eoi_both_pics
8826ASM_END
8827}
8828
8829 void
8830dummy_isr_function(regs, ds, iret_addr)
8831 pusha_regs_t regs; // regs pushed from PUSHA instruction
8832 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8833 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8834{
8835 // Interrupt handler for unexpected hardware interrupts. We have to clear
8836 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8837 // and all hell will break loose! This routine also masks the unexpected
8838 // interrupt so it will generally be called only once for each unexpected
8839 // interrupt level.
8840 Bit8u isrA, isrB, imr, last_int = 0xFF;
8841
8842 outb( 0x20, 0x0B );
8843 isrA = inb( 0x20 );
8844 if (isrA) {
8845 outb( 0xA0, 0x0B );
8846 isrB = inb( 0xA0 );
8847 if (isrB) {
8848 imr = inb( 0xA1 );
8849 outb( 0xA1, imr | isrB ); // Mask this interrupt
8850 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8851 } else {
8852 imr = inb( 0x21 );
8853 isrA &= 0xFB; // Never mask the cascade interrupt
8854 outb( 0x21, imr | isrA); // Mask this interrupt
8855 }
8856 outb( 0x20, 0x20 ); // Send EOI on master PIC
8857 last_int = isrA;
8858 }
8859 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8860}
8861
8862ASM_START
8863;------------------------------------------
8864;- INT74h : PS/2 mouse hardware interrupt -
8865;------------------------------------------
8866int74_handler:
8867 sti
8868 pusha
8869 push ds ;; save DS
8870 push #0x00 ;; placeholder for status
8871 push #0x00 ;; placeholder for X
8872 push #0x00 ;; placeholder for Y
8873 push #0x00 ;; placeholder for Z
8874 push #0x00 ;; placeholder for make_far_call boolean
8875 call _int74_function
8876 pop cx ;; remove make_far_call from stack
8877 jcxz int74_done
8878
8879 ;; make far call to EBDA:0022
8880 push #0x00
8881 pop ds
8882 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8883 pop ds
8884 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8885 call far ptr[0x22]
8886int74_done:
8887 cli
8888 call eoi_both_pics
8889 add sp, #8 ;; pop status, x, y, z
8890
8891 pop ds ;; restore DS
8892 popa
8893 iret
8894
8895
8896;; This will perform an IRET, but will retain value of current CF
8897;; by altering flags on stack. Better than RETF #02.
8898iret_modify_cf:
8899 jc carry_set
8900 push bp
8901 mov bp, sp
8902 and BYTE [bp + 0x06], #0xfe
8903 pop bp
8904 iret
8905carry_set:
8906 push bp
8907 mov bp, sp
8908 or BYTE [bp + 0x06], #0x01
8909 pop bp
8910 iret
8911
8912
8913;----------------------
8914;- INT13h (relocated) -
8915;----------------------
8916;
8917; int13_relocated is a little bit messed up since I played with it
8918; I have to rewrite it:
8919; - call a function that detect which function to call
8920; - make all called C function get the same parameters list
8921;
8922int13_relocated:
8923
8924#if BX_ELTORITO_BOOT
8925 ;; check for an eltorito function
8926 cmp ah,#0x4a
8927 jb int13_not_eltorito
8928 cmp ah,#0x4d
8929 ja int13_not_eltorito
8930
8931 pusha
8932 push es
8933 push ds
8934 push ss
8935 pop ds
8936
8937 push #int13_out
8938 jmp _int13_eltorito ;; ELDX not used
8939
8940int13_not_eltorito:
8941 push ax
8942 push bx
8943 push cx
8944 push dx
8945
8946 ;; check if emulation active
8947 call _cdemu_isactive
8948 cmp al,#0x00
8949 je int13_cdemu_inactive
8950
8951 ;; check if access to the emulated drive
8952 call _cdemu_emulated_drive
8953 pop dx
8954 push dx
8955 cmp al,dl ;; int13 on emulated drive
8956 jne int13_nocdemu
8957
8958 pop dx
8959 pop cx
8960 pop bx
8961 pop ax
8962
8963 pusha
8964 push es
8965 push ds
8966 push ss
8967 pop ds
8968
8969 push #int13_out
8970 jmp _int13_cdemu ;; ELDX not used
8971
8972int13_nocdemu:
8973 and dl,#0xE0 ;; mask to get device class, including cdroms
8974 cmp al,dl ;; al is 0x00 or 0x80
8975 jne int13_cdemu_inactive ;; inactive for device class
8976
8977 pop dx
8978 pop cx
8979 pop bx
8980 pop ax
8981
8982 push ax
8983 push cx
8984 push dx
8985 push bx
8986
8987 dec dl ;; real drive is dl - 1
8988 jmp int13_legacy
8989
8990int13_cdemu_inactive:
8991 pop dx
8992 pop cx
8993 pop bx
8994 pop ax
8995
8996#endif // BX_ELTORITO_BOOT
8997
8998int13_noeltorito:
8999
9000 push ax
9001 push cx
9002 push dx
9003 push bx
9004
9005int13_legacy:
9006
9007 push dx ;; push eltorito value of dx instead of sp
9008
9009 push bp
9010 push si
9011 push di
9012
9013 push es
9014 push ds
9015 push ss
9016 pop ds
9017
9018 ;; now the 16-bit registers can be restored with:
9019 ;; pop ds; pop es; popa; iret
9020 ;; arguments passed to functions should be
9021 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9022
9023 test dl, #0x80
9024 jnz int13_notfloppy
9025
9026 push #int13_out
9027 jmp _int13_diskette_function
9028
9029int13_notfloppy:
9030
9031#if BX_USE_ATADRV
9032
9033 cmp dl, #0xE0
9034 jb int13_notcdrom
9035
9036 // ebx is modified: BSD 5.2.1 boot loader problem
9037 // someone should figure out which 32 bit register that actually are used
9038
9039 shr ebx, #16
9040 push bx
9041
9042 call _int13_cdrom
9043
9044 pop bx
9045 shl ebx, #16
9046
9047 jmp int13_out
9048
9049int13_notcdrom:
9050
9051#endif
9052
9053int13_disk:
9054 ;; int13_harddisk modifies high word of EAX
9055 shr eax, #16
9056 push ax
9057 call _int13_harddisk
9058 pop ax
9059 shl eax, #16
9060
9061int13_out:
9062 pop ds
9063 pop es
9064 popa
9065 iret
9066
9067
9068;----------
9069;- INT18h -
9070;----------
9071int18_handler: ;; Boot Failure routing
9072 call _int18_panic_msg
9073 hlt
9074 iret
9075
9076;----------
9077;- INT19h -
9078;----------
9079int19_relocated: ;; Boot function, relocated
9080
9081#ifdef VBOX
9082 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9083 // just to try booting from the configured drives. All BIOS variables and
9084 // interrupt vectors need to be reset, otherwise strange things may happen.
9085 // The approach used is faking a warm reboot (which just skips showing the
9086 // logo), which is a bit more than what we need, but hey, it's fast.
9087 mov bp, sp
9088 mov ax, 2[bp]
9089 cmp ax, #0xf000
9090 jz bios_initiated_boot
9091 xor ax, ax
9092 mov ds, ax
9093 mov ax, #0x1234
9094 mov 0x472, ax
9095 jmp post
9096bios_initiated_boot:
9097#endif /* VBOX */
9098
9099 ;; int19 was beginning to be really complex, so now it
9100 ;; just calls an C function, that does the work
9101 ;; it returns in BL the boot drive, and in AX the boot segment
9102 ;; the boot segment will be 0x0000 if something has failed
9103
9104 push bp
9105 mov bp, sp
9106
9107 ;; drop ds
9108 xor ax, ax
9109 mov ds, ax
9110
9111 ;; 1st boot device
9112 mov ax, #0x0001
9113 push ax
9114 call _int19_function
9115 inc sp
9116 inc sp
9117 ;; bl contains the boot drive
9118 ;; ax contains the boot segment or 0 if failure
9119
9120 test ax, ax ;; if ax is 0 try next boot device
9121 jnz boot_setup
9122
9123 ;; 2nd boot device
9124 mov ax, #0x0002
9125 push ax
9126 call _int19_function
9127 inc sp
9128 inc sp
9129 test ax, ax ;; if ax is 0 try next boot device
9130 jnz boot_setup
9131
9132 ;; 3rd boot device
9133 mov ax, #0x0003
9134 push ax
9135 call _int19_function
9136 inc sp
9137 inc sp
9138#ifdef VBOX
9139 test ax, ax ;; if ax is 0 try next boot device
9140 jnz boot_setup
9141
9142 ;; 4th boot device
9143 mov ax, #0x0004
9144 push ax
9145 call _int19_function
9146 inc sp
9147 inc sp
9148#endif /* VBOX */
9149 test ax, ax ;; if ax is 0 call int18
9150 jz int18_handler
9151
9152boot_setup:
9153 mov dl, bl ;; set drive so guest os find it
9154 shl eax, #0x04 ;; convert seg to ip
9155 mov 2[bp], ax ;; set ip
9156
9157 shr eax, #0x04 ;; get cs back
9158 and ax, #0xF000 ;; remove what went in ip
9159 mov 4[bp], ax ;; set cs
9160 xor ax, ax
9161 mov es, ax ;; set es to zero fixes [ 549815 ]
9162 mov [bp], ax ;; set bp to zero
9163 mov ax, #0xaa55 ;; set ok flag
9164
9165 pop bp
9166 iret ;; Beam me up Scotty
9167
9168;----------
9169;- INT1Ch -
9170;----------
9171int1c_handler: ;; User Timer Tick
9172 iret
9173
9174
9175;----------------------
9176;- POST: Floppy Drive -
9177;----------------------
9178floppy_drive_post:
9179 xor ax, ax
9180 mov ds, ax
9181
9182 mov al, #0x00
9183 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9184
9185 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9186
9187 mov 0x0440, al ;; diskette motor timeout counter: not active
9188 mov 0x0441, al ;; diskette controller status return code
9189
9190 mov 0x0442, al ;; disk & diskette controller status register 0
9191 mov 0x0443, al ;; diskette controller status register 1
9192 mov 0x0444, al ;; diskette controller status register 2
9193 mov 0x0445, al ;; diskette controller cylinder number
9194 mov 0x0446, al ;; diskette controller head number
9195 mov 0x0447, al ;; diskette controller sector number
9196 mov 0x0448, al ;; diskette controller bytes written
9197
9198 mov 0x048b, al ;; diskette configuration data
9199
9200 ;; -----------------------------------------------------------------
9201 ;; (048F) diskette controller information
9202 ;;
9203 mov al, #0x10 ;; get CMOS diskette drive type
9204 out 0x70, AL
9205 in AL, 0x71
9206 mov ah, al ;; save byte to AH
9207
9208look_drive0:
9209 shr al, #4 ;; look at top 4 bits for drive 0
9210 jz f0_missing ;; jump if no drive0
9211 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9212 jmp look_drive1
9213f0_missing:
9214 mov bl, #0x00 ;; no drive0
9215
9216look_drive1:
9217 mov al, ah ;; restore from AH
9218 and al, #0x0f ;; look at bottom 4 bits for drive 1
9219 jz f1_missing ;; jump if no drive1
9220 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9221f1_missing:
9222 ;; leave high bits in BL zerod
9223 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9224 ;; -----------------------------------------------------------------
9225
9226 mov al, #0x00
9227 mov 0x0490, al ;; diskette 0 media state
9228 mov 0x0491, al ;; diskette 1 media state
9229
9230 ;; diskette 0,1 operational starting state
9231 ;; drive type has not been determined,
9232 ;; has no changed detection line
9233 mov 0x0492, al
9234 mov 0x0493, al
9235
9236 mov 0x0494, al ;; diskette 0 current cylinder
9237 mov 0x0495, al ;; diskette 1 current cylinder
9238
9239 mov al, #0x02
9240 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9241
9242 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9243 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9244 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9245
9246 ret
9247
9248
9249;--------------------
9250;- POST: HARD DRIVE -
9251;--------------------
9252; relocated here because the primary POST area isnt big enough.
9253hard_drive_post:
9254 // IRQ 14 = INT 76h
9255 // INT 76h calls INT 15h function ax=9100
9256
9257 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9258 mov dx, #0x03f6
9259 out dx, al
9260
9261 xor ax, ax
9262 mov ds, ax
9263 mov 0x0474, al /* hard disk status of last operation */
9264 mov 0x0477, al /* hard disk port offset (XT only ???) */
9265 mov 0x048c, al /* hard disk status register */
9266 mov 0x048d, al /* hard disk error register */
9267 mov 0x048e, al /* hard disk task complete flag */
9268 mov al, #0x01
9269 mov 0x0475, al /* hard disk number attached */
9270 mov al, #0xc0
9271 mov 0x0476, al /* hard disk control byte */
9272 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9273 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9274 ;; INT 41h: hard disk 0 configuration pointer
9275 ;; INT 46h: hard disk 1 configuration pointer
9276 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9277 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9278
9279#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9280 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9281 mov al, #0x12
9282 out #0x70, al
9283 in al, #0x71
9284 and al, #0xf0
9285 cmp al, #0xf0
9286 je post_d0_extended
9287 jmp check_for_hd1
9288post_d0_extended:
9289 mov al, #0x19
9290 out #0x70, al
9291 in al, #0x71
9292 cmp al, #47 ;; decimal 47 - user definable
9293 je post_d0_type47
9294 HALT(__LINE__)
9295post_d0_type47:
9296 ;; CMOS purpose param table offset
9297 ;; 1b cylinders low 0
9298 ;; 1c cylinders high 1
9299 ;; 1d heads 2
9300 ;; 1e write pre-comp low 5
9301 ;; 1f write pre-comp high 6
9302 ;; 20 retries/bad map/heads>8 8
9303 ;; 21 landing zone low C
9304 ;; 22 landing zone high D
9305 ;; 23 sectors/track E
9306
9307 mov ax, #EBDA_SEG
9308 mov ds, ax
9309
9310 ;;; Filling EBDA table for hard disk 0.
9311 mov al, #0x1f
9312 out #0x70, al
9313 in al, #0x71
9314 mov ah, al
9315 mov al, #0x1e
9316 out #0x70, al
9317 in al, #0x71
9318 mov (0x003d + 0x05), ax ;; write precomp word
9319
9320 mov al, #0x20
9321 out #0x70, al
9322 in al, #0x71
9323 mov (0x003d + 0x08), al ;; drive control byte
9324
9325 mov al, #0x22
9326 out #0x70, al
9327 in al, #0x71
9328 mov ah, al
9329 mov al, #0x21
9330 out #0x70, al
9331 in al, #0x71
9332 mov (0x003d + 0x0C), ax ;; landing zone word
9333
9334 mov al, #0x1c ;; get cylinders word in AX
9335 out #0x70, al
9336 in al, #0x71 ;; high byte
9337 mov ah, al
9338 mov al, #0x1b
9339 out #0x70, al
9340 in al, #0x71 ;; low byte
9341 mov bx, ax ;; BX = cylinders
9342
9343 mov al, #0x1d
9344 out #0x70, al
9345 in al, #0x71
9346 mov cl, al ;; CL = heads
9347
9348 mov al, #0x23
9349 out #0x70, al
9350 in al, #0x71
9351 mov dl, al ;; DL = sectors
9352
9353 cmp bx, #1024
9354 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9355
9356hd0_post_physical_chs:
9357 ;; no logical CHS mapping used, just physical CHS
9358 ;; use Standard Fixed Disk Parameter Table (FDPT)
9359 mov (0x003d + 0x00), bx ;; number of physical cylinders
9360 mov (0x003d + 0x02), cl ;; number of physical heads
9361 mov (0x003d + 0x0E), dl ;; number of physical sectors
9362 jmp check_for_hd1
9363
9364hd0_post_logical_chs:
9365 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9366 mov (0x003d + 0x09), bx ;; number of physical cylinders
9367 mov (0x003d + 0x0b), cl ;; number of physical heads
9368 mov (0x003d + 0x04), dl ;; number of physical sectors
9369 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9370 mov al, #0xa0
9371 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9372
9373 cmp bx, #2048
9374 jnbe hd0_post_above_2048
9375 ;; 1024 < c <= 2048 cylinders
9376 shr bx, #0x01
9377 shl cl, #0x01
9378 jmp hd0_post_store_logical
9379
9380hd0_post_above_2048:
9381 cmp bx, #4096
9382 jnbe hd0_post_above_4096
9383 ;; 2048 < c <= 4096 cylinders
9384 shr bx, #0x02
9385 shl cl, #0x02
9386 jmp hd0_post_store_logical
9387
9388hd0_post_above_4096:
9389 cmp bx, #8192
9390 jnbe hd0_post_above_8192
9391 ;; 4096 < c <= 8192 cylinders
9392 shr bx, #0x03
9393 shl cl, #0x03
9394 jmp hd0_post_store_logical
9395
9396hd0_post_above_8192:
9397 ;; 8192 < c <= 16384 cylinders
9398 shr bx, #0x04
9399 shl cl, #0x04
9400
9401hd0_post_store_logical:
9402 mov (0x003d + 0x00), bx ;; number of physical cylinders
9403 mov (0x003d + 0x02), cl ;; number of physical heads
9404 ;; checksum
9405 mov cl, #0x0f ;; repeat count
9406 mov si, #0x003d ;; offset to disk0 FDPT
9407 mov al, #0x00 ;; sum
9408hd0_post_checksum_loop:
9409 add al, [si]
9410 inc si
9411 dec cl
9412 jnz hd0_post_checksum_loop
9413 not al ;; now take 2s complement
9414 inc al
9415 mov [si], al
9416;;; Done filling EBDA table for hard disk 0.
9417
9418
9419check_for_hd1:
9420 ;; is there really a second hard disk? if not, return now
9421 mov al, #0x12
9422 out #0x70, al
9423 in al, #0x71
9424 and al, #0x0f
9425 jnz post_d1_exists
9426 ret
9427post_d1_exists:
9428 ;; check that the hd type is really 0x0f.
9429 cmp al, #0x0f
9430 jz post_d1_extended
9431 HALT(__LINE__)
9432post_d1_extended:
9433 ;; check that the extended type is 47 - user definable
9434 mov al, #0x1a
9435 out #0x70, al
9436 in al, #0x71
9437 cmp al, #47 ;; decimal 47 - user definable
9438 je post_d1_type47
9439 HALT(__LINE__)
9440post_d1_type47:
9441 ;; Table for disk1.
9442 ;; CMOS purpose param table offset
9443 ;; 0x24 cylinders low 0
9444 ;; 0x25 cylinders high 1
9445 ;; 0x26 heads 2
9446 ;; 0x27 write pre-comp low 5
9447 ;; 0x28 write pre-comp high 6
9448 ;; 0x29 heads>8 8
9449 ;; 0x2a landing zone low C
9450 ;; 0x2b landing zone high D
9451 ;; 0x2c sectors/track E
9452;;; Fill EBDA table for hard disk 1.
9453 mov ax, #EBDA_SEG
9454 mov ds, ax
9455 mov al, #0x28
9456 out #0x70, al
9457 in al, #0x71
9458 mov ah, al
9459 mov al, #0x27
9460 out #0x70, al
9461 in al, #0x71
9462 mov (0x004d + 0x05), ax ;; write precomp word
9463
9464 mov al, #0x29
9465 out #0x70, al
9466 in al, #0x71
9467 mov (0x004d + 0x08), al ;; drive control byte
9468
9469 mov al, #0x2b
9470 out #0x70, al
9471 in al, #0x71
9472 mov ah, al
9473 mov al, #0x2a
9474 out #0x70, al
9475 in al, #0x71
9476 mov (0x004d + 0x0C), ax ;; landing zone word
9477
9478 mov al, #0x25 ;; get cylinders word in AX
9479 out #0x70, al
9480 in al, #0x71 ;; high byte
9481 mov ah, al
9482 mov al, #0x24
9483 out #0x70, al
9484 in al, #0x71 ;; low byte
9485 mov bx, ax ;; BX = cylinders
9486
9487 mov al, #0x26
9488 out #0x70, al
9489 in al, #0x71
9490 mov cl, al ;; CL = heads
9491
9492 mov al, #0x2c
9493 out #0x70, al
9494 in al, #0x71
9495 mov dl, al ;; DL = sectors
9496
9497 cmp bx, #1024
9498 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9499
9500hd1_post_physical_chs:
9501 ;; no logical CHS mapping used, just physical CHS
9502 ;; use Standard Fixed Disk Parameter Table (FDPT)
9503 mov (0x004d + 0x00), bx ;; number of physical cylinders
9504 mov (0x004d + 0x02), cl ;; number of physical heads
9505 mov (0x004d + 0x0E), dl ;; number of physical sectors
9506 ret
9507
9508hd1_post_logical_chs:
9509 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9510 mov (0x004d + 0x09), bx ;; number of physical cylinders
9511 mov (0x004d + 0x0b), cl ;; number of physical heads
9512 mov (0x004d + 0x04), dl ;; number of physical sectors
9513 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9514 mov al, #0xa0
9515 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9516
9517 cmp bx, #2048
9518 jnbe hd1_post_above_2048
9519 ;; 1024 < c <= 2048 cylinders
9520 shr bx, #0x01
9521 shl cl, #0x01
9522 jmp hd1_post_store_logical
9523
9524hd1_post_above_2048:
9525 cmp bx, #4096
9526 jnbe hd1_post_above_4096
9527 ;; 2048 < c <= 4096 cylinders
9528 shr bx, #0x02
9529 shl cl, #0x02
9530 jmp hd1_post_store_logical
9531
9532hd1_post_above_4096:
9533 cmp bx, #8192
9534 jnbe hd1_post_above_8192
9535 ;; 4096 < c <= 8192 cylinders
9536 shr bx, #0x03
9537 shl cl, #0x03
9538 jmp hd1_post_store_logical
9539
9540hd1_post_above_8192:
9541 ;; 8192 < c <= 16384 cylinders
9542 shr bx, #0x04
9543 shl cl, #0x04
9544
9545hd1_post_store_logical:
9546 mov (0x004d + 0x00), bx ;; number of physical cylinders
9547 mov (0x004d + 0x02), cl ;; number of physical heads
9548 ;; checksum
9549 mov cl, #0x0f ;; repeat count
9550 mov si, #0x004d ;; offset to disk0 FDPT
9551 mov al, #0x00 ;; sum
9552hd1_post_checksum_loop:
9553 add al, [si]
9554 inc si
9555 dec cl
9556 jnz hd1_post_checksum_loop
9557 not al ;; now take 2s complement
9558 inc al
9559 mov [si], al
9560;;; Done filling EBDA table for hard disk 1.
9561#endif /* !VBOX */
9562
9563 ret
9564
9565;--------------------
9566;- POST: EBDA segment
9567;--------------------
9568; relocated here because the primary POST area isnt big enough.
9569; the SET_INT_VECTORs have nothing to do with EBDA but do not
9570; fit into the primary POST area either
9571ebda_post:
9572 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9573 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9574 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9575 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9576
9577#if BX_USE_EBDA
9578 mov ax, #EBDA_SEG
9579 mov ds, ax
9580 mov byte ptr [0x0], #EBDA_SIZE
9581#endif
9582 xor ax, ax ; mov EBDA seg into 40E
9583 mov ds, ax
9584 mov word ptr [0x40E], #EBDA_SEG
9585 ret;;
9586
9587;--------------------
9588;- POST: EOI + jmp via [0x40:67)
9589;--------------------
9590; relocated here because the primary POST area isnt big enough.
9591eoi_jmp_post:
9592 call eoi_both_pics
9593
9594 xor ax, ax
9595 mov ds, ax
9596
9597 jmp far ptr [0x467]
9598
9599
9600;--------------------
9601eoi_both_pics:
9602 mov al, #0x20
9603 out #0xA0, al ;; slave PIC EOI
9604eoi_master_pic:
9605 mov al, #0x20
9606 out #0x20, al ;; master PIC EOI
9607 ret
9608
9609;--------------------
9610BcdToBin:
9611 ;; in: AL in BCD format
9612 ;; out: AL in binary format, AH will always be 0
9613 ;; trashes BX
9614 mov bl, al
9615 and bl, #0x0f ;; bl has low digit
9616 shr al, #4 ;; al has high digit
9617 mov bh, #10
9618 mul al, bh ;; multiply high digit by 10 (result in AX)
9619 add al, bl ;; then add low digit
9620 ret
9621
9622;--------------------
9623timer_tick_post:
9624 ;; Setup the Timer Ticks Count (0x46C:dword) and
9625 ;; Timer Ticks Roller Flag (0x470:byte)
9626 ;; The Timer Ticks Count needs to be set according to
9627 ;; the current CMOS time, as if ticks have been occurring
9628 ;; at 18.2hz since midnight up to this point. Calculating
9629 ;; this is a little complicated. Here are the factors I gather
9630 ;; regarding this. 14,318,180 hz was the original clock speed,
9631 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9632 ;; at the time, or 4 to drive the CGA video adapter. The div3
9633 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9634 ;; the timer. With a maximum 16bit timer count, this is again
9635 ;; divided down by 65536 to 18.2hz.
9636 ;;
9637 ;; 14,318,180 Hz clock
9638 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9639 ;; /4 = 1,193,181 Hz fed to timer
9640 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9641 ;; 1 second = 18.20650736 ticks
9642 ;; 1 minute = 1092.390442 ticks
9643 ;; 1 hour = 65543.42651 ticks
9644 ;;
9645 ;; Given the values in the CMOS clock, one could calculate
9646 ;; the number of ticks by the following:
9647 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9648 ;; (BcdToBin(minutes) * 1092.3904)
9649 ;; (BcdToBin(hours) * 65543.427)
9650 ;; To get a little more accuracy, since Im using integer
9651 ;; arithmatic, I use:
9652 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9653 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9654 ;; (BcdToBin(hours) * 65543427) / 1000
9655
9656 ;; assuming DS=0000
9657
9658 ;; get CMOS seconds
9659 xor eax, eax ;; clear EAX
9660 mov al, #0x00
9661 out #0x70, al
9662 in al, #0x71 ;; AL has CMOS seconds in BCD
9663 call BcdToBin ;; EAX now has seconds in binary
9664 mov edx, #18206507
9665 mul eax, edx
9666 mov ebx, #1000000
9667 xor edx, edx
9668 div eax, ebx
9669 mov ecx, eax ;; ECX will accumulate total ticks
9670
9671 ;; get CMOS minutes
9672 xor eax, eax ;; clear EAX
9673 mov al, #0x02
9674 out #0x70, al
9675 in al, #0x71 ;; AL has CMOS minutes in BCD
9676 call BcdToBin ;; EAX now has minutes in binary
9677 mov edx, #10923904
9678 mul eax, edx
9679 mov ebx, #10000
9680 xor edx, edx
9681 div eax, ebx
9682 add ecx, eax ;; add to total ticks
9683
9684 ;; get CMOS hours
9685 xor eax, eax ;; clear EAX
9686 mov al, #0x04
9687 out #0x70, al
9688 in al, #0x71 ;; AL has CMOS hours in BCD
9689 call BcdToBin ;; EAX now has hours in binary
9690 mov edx, #65543427
9691 mul eax, edx
9692 mov ebx, #1000
9693 xor edx, edx
9694 div eax, ebx
9695 add ecx, eax ;; add to total ticks
9696
9697 mov 0x46C, ecx ;; Timer Ticks Count
9698 xor al, al
9699 mov 0x470, al ;; Timer Ticks Rollover Flag
9700 ret
9701
9702;--------------------
9703int76_handler:
9704 ;; record completion in BIOS task complete flag
9705 push ax
9706 push ds
9707 mov ax, #0x0040
9708 mov ds, ax
9709 mov 0x008E, #0xff
9710 call eoi_both_pics
9711 pop ds
9712 pop ax
9713 iret
9714
9715;--------------------
9716#ifdef VBOX
9717init_pic:
9718 ;; init PIC
9719 mov al, #0x11 ; send initialisation commands
9720 out 0x20, al
9721 out 0xa0, al
9722 mov al, #0x08
9723 out 0x21, al
9724 mov al, #0x70
9725 out 0xa1, al
9726 mov al, #0x04
9727 out 0x21, al
9728 mov al, #0x02
9729 out 0xa1, al
9730 mov al, #0x01
9731 out 0x21, al
9732 out 0xa1, al
9733 mov al, #0xb8
9734 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9735#if BX_USE_PS2_MOUSE
9736 mov al, #0x8f
9737#else
9738 mov al, #0x9f
9739#endif
9740 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9741 ret
9742#endif /* VBOX */
9743
9744;--------------------
9745#if BX_APM
9746
9747use32 386
9748#define APM_PROT32
9749#include "apmbios.S"
9750
9751use16 386
9752#define APM_PROT16
9753#include "apmbios.S"
9754
9755#define APM_REAL
9756#include "apmbios.S"
9757
9758#endif
9759
9760;--------------------
9761#if BX_PCIBIOS
9762use32 386
9763.align 16
9764bios32_structure:
9765 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9766 dw bios32_entry_point, 0xf ;; 32 bit physical address
9767 db 0 ;; revision level
9768 ;; length in paragraphs and checksum stored in a word to prevent errors
9769 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9770 & 0xff) << 8) + 0x01
9771 db 0,0,0,0,0 ;; reserved
9772
9773.align 16
9774bios32_entry_point:
9775 pushfd
9776 cmp eax, #0x49435024 ;; "$PCI"
9777 jne unknown_service
9778 mov eax, #0x80000000
9779 mov dx, #0x0cf8
9780 out dx, eax
9781 mov dx, #0x0cfc
9782 in eax, dx
9783#ifdef PCI_FIXED_HOST_BRIDGE
9784 cmp eax, #PCI_FIXED_HOST_BRIDGE
9785 jne unknown_service
9786#else
9787 ;; say ok if a device is present
9788 cmp eax, #0xffffffff
9789 je unknown_service
9790#endif
9791 mov ebx, #0x000f0000
9792 mov ecx, #0
9793 mov edx, #pcibios_protected
9794 xor al, al
9795 jmp bios32_end
9796unknown_service:
9797 mov al, #0x80
9798bios32_end:
9799#ifdef BX_QEMU
9800 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9801#endif
9802 popfd
9803 retf
9804
9805.align 16
9806pcibios_protected:
9807 pushfd
9808 cli
9809 push esi
9810 push edi
9811 cmp al, #0x01 ;; installation check
9812 jne pci_pro_f02
9813 mov bx, #0x0210
9814 mov cx, #0
9815 mov edx, #0x20494350 ;; "PCI "
9816 mov al, #0x01
9817 jmp pci_pro_ok
9818pci_pro_f02: ;; find pci device
9819 cmp al, #0x02
9820 jne pci_pro_f03
9821 shl ecx, #16
9822 mov cx, dx
9823 xor ebx, ebx
9824 mov di, #0x00
9825pci_pro_devloop:
9826 call pci_pro_select_reg
9827 mov dx, #0x0cfc
9828 in eax, dx
9829 cmp eax, ecx
9830 jne pci_pro_nextdev
9831 cmp si, #0
9832 je pci_pro_ok
9833 dec si
9834pci_pro_nextdev:
9835 inc ebx
9836 cmp ebx, #0x10000
9837 jne pci_pro_devloop
9838 mov ah, #0x86
9839 jmp pci_pro_fail
9840pci_pro_f03: ;; find class code
9841 cmp al, #0x03
9842 jne pci_pro_f08
9843 xor ebx, ebx
9844 mov di, #0x08
9845pci_pro_devloop2:
9846 call pci_pro_select_reg
9847 mov dx, #0x0cfc
9848 in eax, dx
9849 shr eax, #8
9850 cmp eax, ecx
9851 jne pci_pro_nextdev2
9852 cmp si, #0
9853 je pci_pro_ok
9854 dec si
9855pci_pro_nextdev2:
9856 inc ebx
9857 cmp ebx, #0x10000
9858 jne pci_pro_devloop2
9859 mov ah, #0x86
9860 jmp pci_pro_fail
9861pci_pro_f08: ;; read configuration byte
9862 cmp al, #0x08
9863 jne pci_pro_f09
9864 call pci_pro_select_reg
9865 push edx
9866 mov dx, di
9867 and dx, #0x03
9868 add dx, #0x0cfc
9869 in al, dx
9870 pop edx
9871 mov cl, al
9872 jmp pci_pro_ok
9873pci_pro_f09: ;; read configuration word
9874 cmp al, #0x09
9875 jne pci_pro_f0a
9876 call pci_pro_select_reg
9877 push edx
9878 mov dx, di
9879 and dx, #0x02
9880 add dx, #0x0cfc
9881 in ax, dx
9882 pop edx
9883 mov cx, ax
9884 jmp pci_pro_ok
9885pci_pro_f0a: ;; read configuration dword
9886 cmp al, #0x0a
9887 jne pci_pro_f0b
9888 call pci_pro_select_reg
9889 push edx
9890 mov dx, #0x0cfc
9891 in eax, dx
9892 pop edx
9893 mov ecx, eax
9894 jmp pci_pro_ok
9895pci_pro_f0b: ;; write configuration byte
9896 cmp al, #0x0b
9897 jne pci_pro_f0c
9898 call pci_pro_select_reg
9899 push edx
9900 mov dx, di
9901 and dx, #0x03
9902 add dx, #0x0cfc
9903 mov al, cl
9904 out dx, al
9905 pop edx
9906 jmp pci_pro_ok
9907pci_pro_f0c: ;; write configuration word
9908 cmp al, #0x0c
9909 jne pci_pro_f0d
9910 call pci_pro_select_reg
9911 push edx
9912 mov dx, di
9913 and dx, #0x02
9914 add dx, #0x0cfc
9915 mov ax, cx
9916 out dx, ax
9917 pop edx
9918 jmp pci_pro_ok
9919pci_pro_f0d: ;; write configuration dword
9920 cmp al, #0x0d
9921 jne pci_pro_unknown
9922 call pci_pro_select_reg
9923 push edx
9924 mov dx, #0x0cfc
9925 mov eax, ecx
9926 out dx, eax
9927 pop edx
9928 jmp pci_pro_ok
9929pci_pro_unknown:
9930 mov ah, #0x81
9931pci_pro_fail:
9932 pop edi
9933 pop esi
9934#ifdef BX_QEMU
9935 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9936#endif
9937 popfd
9938 stc
9939 retf
9940pci_pro_ok:
9941 xor ah, ah
9942 pop edi
9943 pop esi
9944#ifdef BX_QEMU
9945 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9946#endif
9947 popfd
9948 clc
9949 retf
9950
9951pci_pro_select_reg:
9952 push edx
9953 mov eax, #0x800000
9954 mov ax, bx
9955 shl eax, #8
9956 and di, #0xff
9957 or ax, di
9958 and al, #0xfc
9959 mov dx, #0x0cf8
9960 out dx, eax
9961 pop edx
9962 ret
9963
9964use16 386
9965
9966pcibios_real:
9967 push eax
9968 push dx
9969 mov eax, #0x80000000
9970 mov dx, #0x0cf8
9971 out dx, eax
9972 mov dx, #0x0cfc
9973 in eax, dx
9974#ifdef PCI_FIXED_HOST_BRIDGE
9975 cmp eax, #PCI_FIXED_HOST_BRIDGE
9976 je pci_present
9977#else
9978 ;; say ok if a device is present
9979 cmp eax, #0xffffffff
9980 jne pci_present
9981#endif
9982 pop dx
9983 pop eax
9984 mov ah, #0xff
9985 stc
9986 ret
9987pci_present:
9988 pop dx
9989 pop eax
9990 cmp al, #0x01 ;; installation check
9991 jne pci_real_f02
9992 mov ax, #0x0001
9993 mov bx, #0x0210
9994 mov cx, #0
9995 mov edx, #0x20494350 ;; "PCI "
9996 mov edi, #0xf0000
9997 mov di, #pcibios_protected
9998 clc
9999 ret
10000pci_real_f02: ;; find pci device
10001 push esi
10002 push edi
10003 cmp al, #0x02
10004 jne pci_real_f03
10005 shl ecx, #16
10006 mov cx, dx
10007 xor ebx, ebx
10008 mov di, #0x00
10009pci_real_devloop:
10010 call pci_real_select_reg
10011 mov dx, #0x0cfc
10012 in eax, dx
10013 cmp eax, ecx
10014 jne pci_real_nextdev
10015 cmp si, #0
10016 je pci_real_ok
10017 dec si
10018pci_real_nextdev:
10019 inc ebx
10020 cmp ebx, #0x10000
10021 jne pci_real_devloop
10022 mov dx, cx
10023 shr ecx, #16
10024 mov ax, #0x8602
10025 jmp pci_real_fail
10026pci_real_f03: ;; find class code
10027 cmp al, #0x03
10028 jne pci_real_f08
10029 xor ebx, ebx
10030 mov di, #0x08
10031pci_real_devloop2:
10032 call pci_real_select_reg
10033 mov dx, #0x0cfc
10034 in eax, dx
10035 shr eax, #8
10036 cmp eax, ecx
10037 jne pci_real_nextdev2
10038 cmp si, #0
10039 je pci_real_ok
10040 dec si
10041pci_real_nextdev2:
10042 inc ebx
10043 cmp ebx, #0x10000
10044 jne pci_real_devloop2
10045 mov dx, cx
10046 shr ecx, #16
10047 mov ax, #0x8603
10048 jmp pci_real_fail
10049pci_real_f08: ;; read configuration byte
10050 cmp al, #0x08
10051 jne pci_real_f09
10052 call pci_real_select_reg
10053 push dx
10054 mov dx, di
10055 and dx, #0x03
10056 add dx, #0x0cfc
10057 in al, dx
10058 pop dx
10059 mov cl, al
10060 jmp pci_real_ok
10061pci_real_f09: ;; read configuration word
10062 cmp al, #0x09
10063 jne pci_real_f0a
10064 call pci_real_select_reg
10065 push dx
10066 mov dx, di
10067 and dx, #0x02
10068 add dx, #0x0cfc
10069 in ax, dx
10070 pop dx
10071 mov cx, ax
10072 jmp pci_real_ok
10073pci_real_f0a: ;; read configuration dword
10074 cmp al, #0x0a
10075 jne pci_real_f0b
10076 call pci_real_select_reg
10077 push dx
10078 mov dx, #0x0cfc
10079 in eax, dx
10080 pop dx
10081 mov ecx, eax
10082 jmp pci_real_ok
10083pci_real_f0b: ;; write configuration byte
10084 cmp al, #0x0b
10085 jne pci_real_f0c
10086 call pci_real_select_reg
10087 push dx
10088 mov dx, di
10089 and dx, #0x03
10090 add dx, #0x0cfc
10091 mov al, cl
10092 out dx, al
10093 pop dx
10094 jmp pci_real_ok
10095pci_real_f0c: ;; write configuration word
10096 cmp al, #0x0c
10097 jne pci_real_f0d
10098 call pci_real_select_reg
10099 push dx
10100 mov dx, di
10101 and dx, #0x02
10102 add dx, #0x0cfc
10103 mov ax, cx
10104 out dx, ax
10105 pop dx
10106 jmp pci_real_ok
10107pci_real_f0d: ;; write configuration dword
10108 cmp al, #0x0d
10109 jne pci_real_f0e
10110 call pci_real_select_reg
10111 push dx
10112 mov dx, #0x0cfc
10113 mov eax, ecx
10114 out dx, eax
10115 pop dx
10116 jmp pci_real_ok
10117pci_real_f0e: ;; get irq routing options
10118 cmp al, #0x0e
10119 jne pci_real_unknown
10120 SEG ES
10121 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10122 jb pci_real_too_small
10123 SEG ES
10124 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10125 pushf
10126 push ds
10127 push es
10128 push cx
10129 push si
10130 push di
10131 cld
10132 mov si, #pci_routing_table_structure_start
10133 push cs
10134 pop ds
10135 SEG ES
10136 mov cx, [di+2]
10137 SEG ES
10138 mov es, [di+4]
10139 mov di, cx
10140 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10141 rep
10142 movsb
10143 pop di
10144 pop si
10145 pop cx
10146 pop es
10147 pop ds
10148 popf
10149 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10150 jmp pci_real_ok
10151pci_real_too_small:
10152 SEG ES
10153 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10154 mov ah, #0x89
10155 jmp pci_real_fail
10156
10157pci_real_unknown:
10158 mov ah, #0x81
10159pci_real_fail:
10160 pop edi
10161 pop esi
10162 stc
10163 ret
10164pci_real_ok:
10165 xor ah, ah
10166 pop edi
10167 pop esi
10168 clc
10169 ret
10170
10171pci_real_select_reg:
10172 push dx
10173 mov eax, #0x800000
10174 mov ax, bx
10175 shl eax, #8
10176 and di, #0xff
10177 or ax, di
10178 and al, #0xfc
10179 mov dx, #0x0cf8
10180 out dx, eax
10181 pop dx
10182 ret
10183
10184.align 16
10185pci_routing_table_structure:
10186 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10187 db 0, 1 ;; version
10188#ifdef VBOX
10189#if 0
10190 dw 32 + (30 * 16) ;; table size
10191#else
10192 dw 32 + (10 * 16) ;; table size
10193#endif
10194#else /* !VBOX */
10195 dw 32 + (6 * 16) ;; table size
10196#endif /* !VBOX */
10197 db 0 ;; PCI interrupt router bus
10198 db 0x08 ;; PCI interrupt router DevFunc
10199 dw 0x0000 ;; PCI exclusive IRQs
10200 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10201 dw 0x7000 ;; compatible PCI interrupt router device ID
10202 dw 0,0 ;; Miniport data
10203 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10204#ifdef VBOX
10205 db 0x00 ;; checksum (set by biossums)
10206#else /* !VBOX */
10207 db 0x07 ;; checksum
10208#endif /* !VBOX */
10209pci_routing_table_structure_start:
10210 ;; first slot entry PCI-to-ISA (embedded)
10211 db 0 ;; pci bus number
10212 db 0x08 ;; pci device number (bit 7-3)
10213 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10214 dw 0xdef8 ;; IRQ bitmap INTA#
10215 db 0x61 ;; link value INTB#
10216 dw 0xdef8 ;; IRQ bitmap INTB#
10217 db 0x62 ;; link value INTC#
10218 dw 0xdef8 ;; IRQ bitmap INTC#
10219 db 0x63 ;; link value INTD#
10220 dw 0xdef8 ;; IRQ bitmap INTD#
10221 db 0 ;; physical slot (0 = embedded)
10222 db 0 ;; reserved
10223 ;; second slot entry: 1st PCI slot
10224 db 0 ;; pci bus number
10225 db 0x10 ;; pci device number (bit 7-3)
10226 db 0x61 ;; link value INTA#
10227 dw 0xdef8 ;; IRQ bitmap INTA#
10228 db 0x62 ;; link value INTB#
10229 dw 0xdef8 ;; IRQ bitmap INTB#
10230 db 0x63 ;; link value INTC#
10231 dw 0xdef8 ;; IRQ bitmap INTC#
10232 db 0x60 ;; link value INTD#
10233 dw 0xdef8 ;; IRQ bitmap INTD#
10234 db 1 ;; physical slot (0 = embedded)
10235 db 0 ;; reserved
10236 ;; third slot entry: 2nd PCI slot
10237 db 0 ;; pci bus number
10238 db 0x18 ;; pci device number (bit 7-3)
10239 db 0x62 ;; link value INTA#
10240 dw 0xdef8 ;; IRQ bitmap INTA#
10241 db 0x63 ;; link value INTB#
10242 dw 0xdef8 ;; IRQ bitmap INTB#
10243 db 0x60 ;; link value INTC#
10244 dw 0xdef8 ;; IRQ bitmap INTC#
10245 db 0x61 ;; link value INTD#
10246 dw 0xdef8 ;; IRQ bitmap INTD#
10247 db 2 ;; physical slot (0 = embedded)
10248 db 0 ;; reserved
10249 ;; 4th slot entry: 3rd PCI slot
10250 db 0 ;; pci bus number
10251 db 0x20 ;; pci device number (bit 7-3)
10252 db 0x63 ;; link value INTA#
10253 dw 0xdef8 ;; IRQ bitmap INTA#
10254 db 0x60 ;; link value INTB#
10255 dw 0xdef8 ;; IRQ bitmap INTB#
10256 db 0x61 ;; link value INTC#
10257 dw 0xdef8 ;; IRQ bitmap INTC#
10258 db 0x62 ;; link value INTD#
10259 dw 0xdef8 ;; IRQ bitmap INTD#
10260 db 3 ;; physical slot (0 = embedded)
10261 db 0 ;; reserved
10262 ;; 5th slot entry: 4rd PCI slot
10263 db 0 ;; pci bus number
10264 db 0x28 ;; pci device number (bit 7-3)
10265 db 0x60 ;; link value INTA#
10266 dw 0xdef8 ;; IRQ bitmap INTA#
10267 db 0x61 ;; link value INTB#
10268 dw 0xdef8 ;; IRQ bitmap INTB#
10269 db 0x62 ;; link value INTC#
10270 dw 0xdef8 ;; IRQ bitmap INTC#
10271 db 0x63 ;; link value INTD#
10272 dw 0xdef8 ;; IRQ bitmap INTD#
10273 db 4 ;; physical slot (0 = embedded)
10274 db 0 ;; reserved
10275 ;; 6th slot entry: 5rd PCI slot
10276 db 0 ;; pci bus number
10277 db 0x30 ;; pci device number (bit 7-3)
10278 db 0x61 ;; link value INTA#
10279 dw 0xdef8 ;; IRQ bitmap INTA#
10280 db 0x62 ;; link value INTB#
10281 dw 0xdef8 ;; IRQ bitmap INTB#
10282 db 0x63 ;; link value INTC#
10283 dw 0xdef8 ;; IRQ bitmap INTC#
10284 db 0x60 ;; link value INTD#
10285 dw 0xdef8 ;; IRQ bitmap INTD#
10286 db 5 ;; physical slot (0 = embedded)
10287 db 0 ;; reserved
10288#ifdef VBOX
10289 ;; 7th slot entry: 6th PCI slot
10290 db 0 ;; pci bus number
10291 db 0x38 ;; pci device number (bit 7-3)
10292 db 0x62 ;; link value INTA#
10293 dw 0xdef8 ;; IRQ bitmap INTA#
10294 db 0x63 ;; link value INTB#
10295 dw 0xdef8 ;; IRQ bitmap INTB#
10296 db 0x60 ;; link value INTC#
10297 dw 0xdef8 ;; IRQ bitmap INTC#
10298 db 0x61 ;; link value INTD#
10299 dw 0xdef8 ;; IRQ bitmap INTD#
10300 db 6 ;; physical slot (0 = embedded)
10301 db 0 ;; reserved
10302 ;; 8th slot entry: 7th PCI slot
10303 db 0 ;; pci bus number
10304 db 0x40 ;; pci device number (bit 7-3)
10305 db 0x63 ;; link value INTA#
10306 dw 0xdef8 ;; IRQ bitmap INTA#
10307 db 0x60 ;; link value INTB#
10308 dw 0xdef8 ;; IRQ bitmap INTB#
10309 db 0x61 ;; link value INTC#
10310 dw 0xdef8 ;; IRQ bitmap INTC#
10311 db 0x62 ;; link value INTD#
10312 dw 0xdef8 ;; IRQ bitmap INTD#
10313 db 7 ;; physical slot (0 = embedded)
10314 db 0 ;; reserved
10315 ;; 9th slot entry: 8th PCI slot
10316 db 0 ;; pci bus number
10317 db 0x48 ;; pci device number (bit 7-3)
10318 db 0x60 ;; link value INTA#
10319 dw 0xdef8 ;; IRQ bitmap INTA#
10320 db 0x61 ;; link value INTB#
10321 dw 0xdef8 ;; IRQ bitmap INTB#
10322 db 0x62 ;; link value INTC#
10323 dw 0xdef8 ;; IRQ bitmap INTC#
10324 db 0x63 ;; link value INTD#
10325 dw 0xdef8 ;; IRQ bitmap INTD#
10326 db 8 ;; physical slot (0 = embedded)
10327 db 0 ;; reserved
10328 ;; 10th slot entry: 9th PCI slot
10329 db 0 ;; pci bus number
10330 db 0x50 ;; pci device number (bit 7-3)
10331 db 0x61 ;; link value INTA#
10332 dw 0xdef8 ;; IRQ bitmap INTA#
10333 db 0x62 ;; link value INTB#
10334 dw 0xdef8 ;; IRQ bitmap INTB#
10335 db 0x63 ;; link value INTC#
10336 dw 0xdef8 ;; IRQ bitmap INTC#
10337 db 0x60 ;; link value INTD#
10338 dw 0xdef8 ;; IRQ bitmap INTD#
10339 db 9 ;; physical slot (0 = embedded)
10340 db 0 ;; reserved
10341 ;; 11th slot entry: 10th PCI slot
10342 db 0 ;; pci bus number
10343 db 0x58 ;; pci device number (bit 7-3)
10344 db 0x61 ;; link value INTA#
10345 dw 0xdef8 ;; IRQ bitmap INTA#
10346 db 0x62 ;; link value INTB#
10347 dw 0xdef8 ;; IRQ bitmap INTB#
10348 db 0x63 ;; link value INTC#
10349 dw 0xdef8 ;; IRQ bitmap INTC#
10350 db 0x60 ;; link value INTD#
10351 dw 0xdef8 ;; IRQ bitmap INTD#
10352 db 10 ;; physical slot (0 = embedded)
10353 db 0 ;; reserved
10354 ;; 12th slot entry: 11th PCI slot
10355 db 0 ;; pci bus number
10356 db 0x60 ;; pci device number (bit 7-3)
10357 db 0x61 ;; link value INTA#
10358 dw 0xdef8 ;; IRQ bitmap INTA#
10359 db 0x62 ;; link value INTB#
10360 dw 0xdef8 ;; IRQ bitmap INTB#
10361 db 0x63 ;; link value INTC#
10362 dw 0xdef8 ;; IRQ bitmap INTC#
10363 db 0x60 ;; link value INTD#
10364 dw 0xdef8 ;; IRQ bitmap INTD#
10365 db 11 ;; physical slot (0 = embedded)
10366 db 0 ;; reserved
10367 ;; 13th slot entry: 12th PCI slot
10368 db 0 ;; pci bus number
10369 db 0x68 ;; pci device number (bit 7-3)
10370 db 0x61 ;; link value INTA#
10371 dw 0xdef8 ;; IRQ bitmap INTA#
10372 db 0x62 ;; link value INTB#
10373 dw 0xdef8 ;; IRQ bitmap INTB#
10374 db 0x63 ;; link value INTC#
10375 dw 0xdef8 ;; IRQ bitmap INTC#
10376 db 0x60 ;; link value INTD#
10377 dw 0xdef8 ;; IRQ bitmap INTD#
10378 db 12 ;; physical slot (0 = embedded)
10379 db 0 ;; reserved
10380 ;; 14th slot entry: 13th PCI slot
10381 db 0 ;; pci bus number
10382 db 0x70 ;; pci device number (bit 7-3)
10383 db 0x61 ;; link value INTA#
10384 dw 0xdef8 ;; IRQ bitmap INTA#
10385 db 0x62 ;; link value INTB#
10386 dw 0xdef8 ;; IRQ bitmap INTB#
10387 db 0x63 ;; link value INTC#
10388 dw 0xdef8 ;; IRQ bitmap INTC#
10389 db 0x60 ;; link value INTD#
10390 dw 0xdef8 ;; IRQ bitmap INTD#
10391 db 13 ;; physical slot (0 = embedded)
10392 db 0 ;; reserved
10393 ;; 15th slot entry: 14th PCI slot
10394 db 0 ;; pci bus number
10395 db 0x78 ;; pci device number (bit 7-3)
10396 db 0x61 ;; link value INTA#
10397 dw 0xdef8 ;; IRQ bitmap INTA#
10398 db 0x62 ;; link value INTB#
10399 dw 0xdef8 ;; IRQ bitmap INTB#
10400 db 0x63 ;; link value INTC#
10401 dw 0xdef8 ;; IRQ bitmap INTC#
10402 db 0x60 ;; link value INTD#
10403 dw 0xdef8 ;; IRQ bitmap INTD#
10404 db 14 ;; physical slot (0 = embedded)
10405 db 0 ;; reserved
10406 ;; 16th slot entry: 15th PCI slot
10407 db 0 ;; pci bus number
10408 db 0x80 ;; pci device number (bit 7-3)
10409 db 0x61 ;; link value INTA#
10410 dw 0xdef8 ;; IRQ bitmap INTA#
10411 db 0x62 ;; link value INTB#
10412 dw 0xdef8 ;; IRQ bitmap INTB#
10413 db 0x63 ;; link value INTC#
10414 dw 0xdef8 ;; IRQ bitmap INTC#
10415 db 0x60 ;; link value INTD#
10416 dw 0xdef8 ;; IRQ bitmap INTD#
10417 db 15 ;; physical slot (0 = embedded)
10418 db 0 ;; reserved
10419 ;; 17th slot entry: 16th PCI slot
10420 db 0 ;; pci bus number
10421 db 0x88 ;; pci device number (bit 7-3)
10422 db 0x61 ;; link value INTA#
10423 dw 0xdef8 ;; IRQ bitmap INTA#
10424 db 0x62 ;; link value INTB#
10425 dw 0xdef8 ;; IRQ bitmap INTB#
10426 db 0x63 ;; link value INTC#
10427 dw 0xdef8 ;; IRQ bitmap INTC#
10428 db 0x60 ;; link value INTD#
10429 dw 0xdef8 ;; IRQ bitmap INTD#
10430 db 16 ;; physical slot (0 = embedded)
10431 db 0 ;; reserved
10432 ;; 18th slot entry: 17th PCI slot
10433 db 0 ;; pci bus number
10434 db 0x90 ;; pci device number (bit 7-3)
10435 db 0x61 ;; link value INTA#
10436 dw 0xdef8 ;; IRQ bitmap INTA#
10437 db 0x62 ;; link value INTB#
10438 dw 0xdef8 ;; IRQ bitmap INTB#
10439 db 0x63 ;; link value INTC#
10440 dw 0xdef8 ;; IRQ bitmap INTC#
10441 db 0x60 ;; link value INTD#
10442 dw 0xdef8 ;; IRQ bitmap INTD#
10443 db 17 ;; physical slot (0 = embedded)
10444 db 0 ;; reserved
10445 ;; 19th slot entry: 18th PCI slot
10446 db 0 ;; pci bus number
10447 db 0x98 ;; pci device number (bit 7-3)
10448 db 0x61 ;; link value INTA#
10449 dw 0xdef8 ;; IRQ bitmap INTA#
10450 db 0x62 ;; link value INTB#
10451 dw 0xdef8 ;; IRQ bitmap INTB#
10452 db 0x63 ;; link value INTC#
10453 dw 0xdef8 ;; IRQ bitmap INTC#
10454 db 0x60 ;; link value INTD#
10455 dw 0xdef8 ;; IRQ bitmap INTD#
10456 db 18 ;; physical slot (0 = embedded)
10457 db 0 ;; reserved
10458 ;; 20th slot entry: 19th PCI slot
10459 db 0 ;; pci bus number
10460 db 0xa0 ;; pci device number (bit 7-3)
10461 db 0x61 ;; link value INTA#
10462 dw 0xdef8 ;; IRQ bitmap INTA#
10463 db 0x62 ;; link value INTB#
10464 dw 0xdef8 ;; IRQ bitmap INTB#
10465 db 0x63 ;; link value INTC#
10466 dw 0xdef8 ;; IRQ bitmap INTC#
10467 db 0x60 ;; link value INTD#
10468 dw 0xdef8 ;; IRQ bitmap INTD#
10469 db 19 ;; physical slot (0 = embedded)
10470 db 0 ;; reserved
10471 ;; 21th slot entry: 20th PCI slot
10472 db 0 ;; pci bus number
10473 db 0xa8 ;; pci device number (bit 7-3)
10474 db 0x61 ;; link value INTA#
10475 dw 0xdef8 ;; IRQ bitmap INTA#
10476 db 0x62 ;; link value INTB#
10477 dw 0xdef8 ;; IRQ bitmap INTB#
10478 db 0x63 ;; link value INTC#
10479 dw 0xdef8 ;; IRQ bitmap INTC#
10480 db 0x60 ;; link value INTD#
10481 dw 0xdef8 ;; IRQ bitmap INTD#
10482 db 20 ;; physical slot (0 = embedded)
10483 db 0 ;; reserved
10484 ;; 21th slot entry: 20th PCI slot
10485 db 0 ;; pci bus number
10486 db 0xb0 ;; pci device number (bit 7-3)
10487 db 0x61 ;; link value INTA#
10488 dw 0xdef8 ;; IRQ bitmap INTA#
10489 db 0x62 ;; link value INTB#
10490 dw 0xdef8 ;; IRQ bitmap INTB#
10491 db 0x63 ;; link value INTC#
10492 dw 0xdef8 ;; IRQ bitmap INTC#
10493 db 0x60 ;; link value INTD#
10494 dw 0xdef8 ;; IRQ bitmap INTD#
10495 db 20 ;; physical slot (0 = embedded)
10496 db 0 ;; reserved
10497 ;; 22th slot entry: 21th PCI slot
10498 db 0 ;; pci bus number
10499 db 0xb8 ;; pci device number (bit 7-3)
10500 db 0x61 ;; link value INTA#
10501 dw 0xdef8 ;; IRQ bitmap INTA#
10502 db 0x62 ;; link value INTB#
10503 dw 0xdef8 ;; IRQ bitmap INTB#
10504 db 0x63 ;; link value INTC#
10505 dw 0xdef8 ;; IRQ bitmap INTC#
10506 db 0x60 ;; link value INTD#
10507 dw 0xdef8 ;; IRQ bitmap INTD#
10508 db 21 ;; physical slot (0 = embedded)
10509 db 0 ;; reserved
10510 ;; 23th slot entry: 22th PCI slot
10511 db 0 ;; pci bus number
10512 db 0xc0 ;; pci device number (bit 7-3)
10513 db 0x61 ;; link value INTA#
10514 dw 0xdef8 ;; IRQ bitmap INTA#
10515 db 0x62 ;; link value INTB#
10516 dw 0xdef8 ;; IRQ bitmap INTB#
10517 db 0x63 ;; link value INTC#
10518 dw 0xdef8 ;; IRQ bitmap INTC#
10519 db 0x60 ;; link value INTD#
10520 dw 0xdef8 ;; IRQ bitmap INTD#
10521 db 22 ;; physical slot (0 = embedded)
10522 db 0 ;; reserved
10523 ;; 24th slot entry: 23th PCI slot
10524 db 0 ;; pci bus number
10525 db 0xc8 ;; pci device number (bit 7-3)
10526 db 0x61 ;; link value INTA#
10527 dw 0xdef8 ;; IRQ bitmap INTA#
10528 db 0x62 ;; link value INTB#
10529 dw 0xdef8 ;; IRQ bitmap INTB#
10530 db 0x63 ;; link value INTC#
10531 dw 0xdef8 ;; IRQ bitmap INTC#
10532 db 0x60 ;; link value INTD#
10533 dw 0xdef8 ;; IRQ bitmap INTD#
10534 db 23 ;; physical slot (0 = embedded)
10535 db 0 ;; reserved
10536 ;; 25th slot entry: 24th PCI slot
10537 db 0 ;; pci bus number
10538 db 0xd0 ;; pci device number (bit 7-3)
10539 db 0x61 ;; link value INTA#
10540 dw 0xdef8 ;; IRQ bitmap INTA#
10541 db 0x62 ;; link value INTB#
10542 dw 0xdef8 ;; IRQ bitmap INTB#
10543 db 0x63 ;; link value INTC#
10544 dw 0xdef8 ;; IRQ bitmap INTC#
10545 db 0x60 ;; link value INTD#
10546 dw 0xdef8 ;; IRQ bitmap INTD#
10547 db 24 ;; physical slot (0 = embedded)
10548 db 0 ;; reserved
10549 ;; 26th slot entry: 25th PCI slot
10550 db 0 ;; pci bus number
10551 db 0xd8 ;; pci device number (bit 7-3)
10552 db 0x61 ;; link value INTA#
10553 dw 0xdef8 ;; IRQ bitmap INTA#
10554 db 0x62 ;; link value INTB#
10555 dw 0xdef8 ;; IRQ bitmap INTB#
10556 db 0x63 ;; link value INTC#
10557 dw 0xdef8 ;; IRQ bitmap INTC#
10558 db 0x60 ;; link value INTD#
10559 dw 0xdef8 ;; IRQ bitmap INTD#
10560 db 25 ;; physical slot (0 = embedded)
10561 db 0 ;; reserved
10562 ;; 27th slot entry: 26th PCI slot
10563 db 0 ;; pci bus number
10564 db 0xe0 ;; pci device number (bit 7-3)
10565 db 0x61 ;; link value INTA#
10566 dw 0xdef8 ;; IRQ bitmap INTA#
10567 db 0x62 ;; link value INTB#
10568 dw 0xdef8 ;; IRQ bitmap INTB#
10569 db 0x63 ;; link value INTC#
10570 dw 0xdef8 ;; IRQ bitmap INTC#
10571 db 0x60 ;; link value INTD#
10572 dw 0xdef8 ;; IRQ bitmap INTD#
10573 db 26 ;; physical slot (0 = embedded)
10574 db 0 ;; reserved
10575 ;; 28th slot entry: 27th PCI slot
10576 db 0 ;; pci bus number
10577 db 0xe8 ;; pci device number (bit 7-3)
10578 db 0x61 ;; link value INTA#
10579 dw 0xdef8 ;; IRQ bitmap INTA#
10580 db 0x62 ;; link value INTB#
10581 dw 0xdef8 ;; IRQ bitmap INTB#
10582 db 0x63 ;; link value INTC#
10583 dw 0xdef8 ;; IRQ bitmap INTC#
10584 db 0x60 ;; link value INTD#
10585 dw 0xdef8 ;; IRQ bitmap INTD#
10586 db 27 ;; physical slot (0 = embedded)
10587 db 0 ;; reserved
10588 ;; 29th slot entry: 28th PCI slot
10589 db 0 ;; pci bus number
10590 db 0xf0 ;; pci device number (bit 7-3)
10591 db 0x61 ;; link value INTA#
10592 dw 0xdef8 ;; IRQ bitmap INTA#
10593 db 0x62 ;; link value INTB#
10594 dw 0xdef8 ;; IRQ bitmap INTB#
10595 db 0x63 ;; link value INTC#
10596 dw 0xdef8 ;; IRQ bitmap INTC#
10597 db 0x60 ;; link value INTD#
10598 dw 0xdef8 ;; IRQ bitmap INTD#
10599 db 28 ;; physical slot (0 = embedded)
10600 db 0 ;; reserved
10601 ;; 30th slot entry: 29th PCI slot
10602 db 0 ;; pci bus number
10603 db 0xf8 ;; pci device number (bit 7-3)
10604 db 0x61 ;; link value INTA#
10605 dw 0xdef8 ;; IRQ bitmap INTA#
10606 db 0x62 ;; link value INTB#
10607 dw 0xdef8 ;; IRQ bitmap INTB#
10608 db 0x63 ;; link value INTC#
10609 dw 0xdef8 ;; IRQ bitmap INTC#
10610 db 0x60 ;; link value INTD#
10611 dw 0xdef8 ;; IRQ bitmap INTD#
10612 db 29 ;; physical slot (0 = embedded)
10613 db 0 ;; reserved
10614#endif /* VBOX */
10615pci_routing_table_structure_end:
10616
10617#if !BX_ROMBIOS32
10618pci_irq_list:
10619 db 11, 10, 9, 5;
10620
10621pcibios_init_sel_reg:
10622 push eax
10623 mov eax, #0x800000
10624 mov ax, bx
10625 shl eax, #8
10626 and dl, #0xfc
10627 or al, dl
10628 mov dx, #0x0cf8
10629 out dx, eax
10630 pop eax
10631 ret
10632
10633pcibios_init_iomem_bases:
10634 push bp
10635 mov bp, sp
10636 mov eax, #0xe0000000 ;; base for memory init
10637 push eax
10638 mov ax, #0xc000 ;; base for i/o init
10639 push ax
10640 mov ax, #0x0010 ;; start at base address #0
10641 push ax
10642 mov bx, #0x0008
10643pci_init_io_loop1:
10644 mov dl, #0x00
10645 call pcibios_init_sel_reg
10646 mov dx, #0x0cfc
10647 in ax, dx
10648 cmp ax, #0xffff
10649 jz next_pci_dev
10650#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10651 mov dl, #0x04 ;; disable i/o and memory space access
10652 call pcibios_init_sel_reg
10653 mov dx, #0x0cfc
10654 in al, dx
10655 and al, #0xfc
10656 out dx, al
10657pci_init_io_loop2:
10658 mov dl, [bp-8]
10659 call pcibios_init_sel_reg
10660 mov dx, #0x0cfc
10661 in eax, dx
10662 test al, #0x01
10663 jnz init_io_base
10664 mov ecx, eax
10665 mov eax, #0xffffffff
10666 out dx, eax
10667 in eax, dx
10668 cmp eax, ecx
10669 je next_pci_base
10670 xor eax, #0xffffffff
10671 mov ecx, eax
10672 mov eax, [bp-4]
10673 out dx, eax
10674 add eax, ecx ;; calculate next free mem base
10675 add eax, #0x01000000
10676 and eax, #0xff000000
10677 mov [bp-4], eax
10678 jmp next_pci_base
10679init_io_base:
10680 mov cx, ax
10681 mov ax, #0xffff
10682 out dx, ax
10683 in ax, dx
10684 cmp ax, cx
10685 je next_pci_base
10686 xor ax, #0xfffe
10687 mov cx, ax
10688 mov ax, [bp-6]
10689 out dx, ax
10690 add ax, cx ;; calculate next free i/o base
10691 add ax, #0x0100
10692 and ax, #0xff00
10693 mov [bp-6], ax
10694next_pci_base:
10695 mov al, [bp-8]
10696 add al, #0x04
10697 cmp al, #0x28
10698 je enable_iomem_space
10699 mov byte ptr[bp-8], al
10700 jmp pci_init_io_loop2
10701#endif /* !VBOX */
10702enable_iomem_space:
10703 mov dl, #0x04 ;; enable i/o and memory space access if available
10704 call pcibios_init_sel_reg
10705 mov dx, #0x0cfc
10706 in al, dx
10707 or al, #0x07
10708 out dx, al
10709#ifdef VBOX
10710 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10711 call pcibios_init_sel_reg
10712 mov dx, #0x0cfc
10713 in eax, dx
10714 cmp eax, #0x20001022
10715 jne next_pci_dev
10716 mov dl, #0x10 ;; get I/O address
10717 call pcibios_init_sel_reg
10718 mov dx, #0x0cfc
10719 in ax, dx
10720 and ax, #0xfffc
10721 mov cx, ax
10722 mov dx, cx
10723 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10724 in ax, dx ;; reset is performed by reading the reset register
10725 mov dx, cx
10726 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10727 in eax, dx ;; reset is performed by reading the reset register
10728#endif /* VBOX */
10729next_pci_dev:
10730 mov byte ptr[bp-8], #0x10
10731 inc bx
10732 cmp bx, #0x0100
10733 jne pci_init_io_loop1
10734 mov sp, bp
10735 pop bp
10736 ret
10737
10738pcibios_init_set_elcr:
10739 push ax
10740 push cx
10741 mov dx, #0x04d0
10742 test al, #0x08
10743 jz is_master_pic
10744 inc dx
10745 and al, #0x07
10746is_master_pic:
10747 mov cl, al
10748 mov bl, #0x01
10749 shl bl, cl
10750 in al, dx
10751 or al, bl
10752 out dx, al
10753 pop cx
10754 pop ax
10755 ret
10756
10757pcibios_init_irqs:
10758 push ds
10759 push bp
10760 mov ax, #0xf000
10761 mov ds, ax
10762 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10763 mov al, #0x00
10764 out dx, al
10765 inc dx
10766 out dx, al
10767 mov si, #pci_routing_table_structure
10768 mov bh, [si+8]
10769 mov bl, [si+9]
10770 mov dl, #0x00
10771 call pcibios_init_sel_reg
10772 mov dx, #0x0cfc
10773 in eax, dx
10774 cmp eax, [si+12] ;; check irq router
10775 jne pci_init_end
10776 mov dl, [si+34]
10777 call pcibios_init_sel_reg
10778 push bx ;; save irq router bus + devfunc
10779 mov dx, #0x0cfc
10780 mov ax, #0x8080
10781 out dx, ax ;; reset PIRQ route control
10782 inc dx
10783 inc dx
10784 out dx, ax
10785 mov ax, [si+6]
10786 sub ax, #0x20
10787 shr ax, #4
10788 mov cx, ax
10789 add si, #0x20 ;; set pointer to 1st entry
10790 mov bp, sp
10791 mov ax, #pci_irq_list
10792 push ax
10793 xor ax, ax
10794 push ax
10795pci_init_irq_loop1:
10796 mov bh, [si]
10797 mov bl, [si+1]
10798pci_init_irq_loop2:
10799 mov dl, #0x00
10800 call pcibios_init_sel_reg
10801 mov dx, #0x0cfc
10802 in ax, dx
10803 cmp ax, #0xffff
10804 jnz pci_test_int_pin
10805 test bl, #0x07
10806 jz next_pir_entry
10807 jmp next_pci_func
10808pci_test_int_pin:
10809 mov dl, #0x3c
10810 call pcibios_init_sel_reg
10811 mov dx, #0x0cfd
10812 in al, dx
10813 and al, #0x07
10814 jz next_pci_func
10815 dec al ;; determine pirq reg
10816 mov dl, #0x03
10817 mul al, dl
10818 add al, #0x02
10819 xor ah, ah
10820 mov bx, ax
10821 mov al, [si+bx]
10822 mov dl, al
10823 mov bx, [bp]
10824 call pcibios_init_sel_reg
10825 mov dx, #0x0cfc
10826 and al, #0x03
10827 add dl, al
10828 in al, dx
10829 cmp al, #0x80
10830 jb pirq_found
10831 mov bx, [bp-2] ;; pci irq list pointer
10832 mov al, [bx]
10833 out dx, al
10834 inc bx
10835 mov [bp-2], bx
10836 call pcibios_init_set_elcr
10837pirq_found:
10838 mov bh, [si]
10839 mov bl, [si+1]
10840 add bl, [bp-3] ;; pci function number
10841 mov dl, #0x3c
10842 call pcibios_init_sel_reg
10843 mov dx, #0x0cfc
10844 out dx, al
10845next_pci_func:
10846 inc byte ptr[bp-3]
10847 inc bl
10848 test bl, #0x07
10849 jnz pci_init_irq_loop2
10850next_pir_entry:
10851 add si, #0x10
10852 mov byte ptr[bp-3], #0x00
10853 loop pci_init_irq_loop1
10854 mov sp, bp
10855 pop bx
10856pci_init_end:
10857 pop bp
10858 pop ds
10859 ret
10860#endif // BX_ROMBIOS32
10861#endif // BX_PCIBIOS
10862
10863#if BX_ROMBIOS32
10864rombios32_init:
10865 ;; save a20 and enable it
10866 in al, 0x92
10867 push ax
10868 or al, #0x02
10869 out 0x92, al
10870
10871 ;; save SS:SP to the BDA
10872 xor ax, ax
10873 mov ds, ax
10874 mov 0x0469, ss
10875 mov 0x0467, sp
10876
10877 SEG CS
10878 lidt [pmode_IDT_info]
10879 SEG CS
10880 lgdt [rombios32_gdt_48]
10881 ;; set PE bit in CR0
10882 mov eax, cr0
10883 or al, #0x01
10884 mov cr0, eax
10885 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10886 db 0x66, 0xea
10887 dw rombios32_05
10888 dw 0x000f ;; high 16 bit address
10889 dw 0x0010
10890
10891use32 386
10892rombios32_05:
10893 ;; init data segments
10894 mov eax, #0x18
10895 mov ds, ax
10896 mov es, ax
10897 mov ss, ax
10898 xor eax, eax
10899 mov fs, ax
10900 mov gs, ax
10901 cld
10902
10903 ;; copy rombios32 code to ram (ram offset = 1MB)
10904 mov esi, #0xfffe0000
10905 mov edi, #0x00040000
10906 mov ecx, #0x10000 / 4
10907 rep
10908 movsd
10909
10910 ;; init the stack pointer
10911 mov esp, #0x00080000
10912
10913 ;; call rombios32 code
10914 mov eax, #0x00040000
10915 call eax
10916
10917 ;; return to 16 bit protected mode first
10918 db 0xea
10919 dd rombios32_10
10920 dw 0x20
10921
10922use16 386
10923rombios32_10:
10924 ;; restore data segment limits to 0xffff
10925 mov ax, #0x28
10926 mov ds, ax
10927 mov es, ax
10928 mov ss, ax
10929 mov fs, ax
10930 mov gs, ax
10931
10932 ;; reset PE bit in CR0
10933 mov eax, cr0
10934 and al, #0xFE
10935 mov cr0, eax
10936
10937 ;; far jump to flush CPU queue after transition to real mode
10938 JMP_AP(0xf000, rombios32_real_mode)
10939
10940rombios32_real_mode:
10941 ;; restore IDT to normal real-mode defaults
10942 SEG CS
10943 lidt [rmode_IDT_info]
10944
10945 xor ax, ax
10946 mov ds, ax
10947 mov es, ax
10948 mov fs, ax
10949 mov gs, ax
10950
10951 ;; restore SS:SP from the BDA
10952 mov ss, 0x0469
10953 xor esp, esp
10954 mov sp, 0x0467
10955 ;; restore a20
10956 pop ax
10957 out 0x92, al
10958 ret
10959
10960rombios32_gdt_48:
10961 dw 0x30
10962 dw rombios32_gdt
10963 dw 0x000f
10964
10965rombios32_gdt:
10966 dw 0, 0, 0, 0
10967 dw 0, 0, 0, 0
10968 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
10969 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
10970 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
10971 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
10972#endif
10973
10974
10975; parallel port detection: base address in DX, index in BX, timeout in CL
10976detect_parport:
10977 push dx
10978 add dx, #2
10979 in al, dx
10980 and al, #0xdf ; clear input mode
10981 out dx, al
10982 pop dx
10983 mov al, #0xaa
10984 out dx, al
10985 in al, dx
10986 cmp al, #0xaa
10987 jne no_parport
10988 push bx
10989 shl bx, #1
10990 mov [bx+0x408], dx ; Parallel I/O address
10991 pop bx
10992 mov [bx+0x478], cl ; Parallel printer timeout
10993 inc bx
10994no_parport:
10995 ret
10996
10997; serial port detection: base address in DX, index in BX, timeout in CL
10998detect_serial:
10999 push dx
11000 inc dx
11001 mov al, #0x02
11002 out dx, al
11003 in al, dx
11004 cmp al, #0x02
11005 jne no_serial
11006 inc dx
11007 in al, dx
11008 cmp al, #0x02
11009 jne no_serial
11010 dec dx
11011 xor al, al
11012 out dx, al
11013 pop dx
11014 push bx
11015 shl bx, #1
11016 mov [bx+0x400], dx ; Serial I/O address
11017 pop bx
11018 mov [bx+0x47c], cl ; Serial timeout
11019 inc bx
11020 ret
11021no_serial:
11022 pop dx
11023 ret
11024
11025rom_checksum:
11026 push ax
11027 push bx
11028 push cx
11029 xor ax, ax
11030 xor bx, bx
11031 xor cx, cx
11032 mov ch, [2]
11033 shl cx, #1
11034checksum_loop:
11035 add al, [bx]
11036 inc bx
11037 loop checksum_loop
11038 and al, #0xff
11039 pop cx
11040 pop bx
11041 pop ax
11042 ret
11043
11044rom_scan:
11045 ;; Scan for existence of valid expansion ROMS.
11046 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11047 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11048 ;; System ROM: only 0xE0000
11049 ;;
11050 ;; Header:
11051 ;; Offset Value
11052 ;; 0 0x55
11053 ;; 1 0xAA
11054 ;; 2 ROM length in 512-byte blocks
11055 ;; 3 ROM initialization entry point (FAR CALL)
11056
11057 mov cx, #0xc000
11058rom_scan_loop:
11059 mov ds, cx
11060 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11061 cmp [0], #0xAA55 ;; look for signature
11062 jne rom_scan_increment
11063 call rom_checksum
11064 jnz rom_scan_increment
11065 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11066
11067 ;; We want our increment in 512-byte quantities, rounded to
11068 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11069 test al, #0x03
11070 jz block_count_rounded
11071 and al, #0xfc ;; needs rounding up
11072 add al, #0x04
11073block_count_rounded:
11074
11075 xor bx, bx ;; Restore DS back to 0000:
11076 mov ds, bx
11077 push ax ;; Save AX
11078 ;; Push addr of ROM entry point
11079 push cx ;; Push seg
11080 push #0x0003 ;; Push offset
11081 mov bp, sp ;; Call ROM init routine using seg:off on stack
11082 db 0xff ;; call_far ss:[bp+0]
11083 db 0x5e
11084 db 0
11085 cli ;; In case expansion ROM BIOS turns IF on
11086 add sp, #2 ;; Pop offset value
11087 pop cx ;; Pop seg value (restore CX)
11088 pop ax ;; Restore AX
11089rom_scan_increment:
11090 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11091 ;; because the segment selector is shifted left 4 bits.
11092 add cx, ax
11093 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11094 jbe rom_scan_loop
11095
11096 xor ax, ax ;; Restore DS back to 0000:
11097 mov ds, ax
11098 ret
11099
11100;; for 'C' strings and other data, insert them here with
11101;; a the following hack:
11102;; DATA_SEG_DEFS_HERE
11103
11104
11105;; the following area can be used to write dynamically generated tables
11106 .align 16
11107bios_table_area_start:
11108 dd 0xaafb4442
11109 dd bios_table_area_end - bios_table_area_start - 8;
11110
11111;--------
11112;- POST -
11113;--------
11114.org 0xe05b ; POST Entry Point
11115bios_table_area_end:
11116post:
11117
11118 xor ax, ax
11119
11120 ;; first reset the DMA controllers
11121 out 0x0d,al
11122 out 0xda,al
11123
11124 ;; then initialize the DMA controllers
11125 mov al, #0xC0
11126 out 0xD6, al ; cascade mode of channel 4 enabled
11127 mov al, #0x00
11128 out 0xD4, al ; unmask channel 4
11129
11130 ;; Examine CMOS shutdown status.
11131 mov AL, #0x0f
11132 out 0x70, AL
11133 in AL, 0x71
11134
11135 ;; backup status
11136 mov bl, al
11137
11138 ;; Reset CMOS shutdown status.
11139 mov AL, #0x0f
11140 out 0x70, AL ; select CMOS register Fh
11141 mov AL, #0x00
11142 out 0x71, AL ; set shutdown action to normal
11143
11144 ;; Examine CMOS shutdown status.
11145 mov al, bl
11146
11147 ;; 0x00, 0x09, 0x0D+ = normal startup
11148 cmp AL, #0x00
11149 jz normal_post
11150 cmp AL, #0x0d
11151 jae normal_post
11152 cmp AL, #0x09
11153 je normal_post
11154
11155 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11156 cmp al, #0x05
11157 je eoi_jmp_post
11158
11159 ;; Examine CMOS shutdown status.
11160 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11161 push bx
11162 call _shutdown_status_panic
11163
11164#if 0
11165 HALT(__LINE__)
11166 ;
11167 ;#if 0
11168 ; 0xb0, 0x20, /* mov al, #0x20 */
11169 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11170 ;#endif
11171 ;
11172 pop es
11173 pop ds
11174 popa
11175 iret
11176#endif
11177
11178normal_post:
11179 ; case 0: normal startup
11180
11181 cli
11182 mov ax, #0xfffe
11183 mov sp, ax
11184 xor ax, ax
11185 mov ds, ax
11186 mov ss, ax
11187
11188#ifndef VBOX
11189 ;; zero out BIOS data area (40:00..40:ff)
11190 mov es, ax
11191 mov cx, #0x0080 ;; 128 words
11192 mov di, #0x0400
11193 cld
11194 rep
11195 stosw
11196#else /* VBOX */
11197 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11198 mov es, ax
11199 xor di, di
11200 cld
11201 mov cx, #0x0239 ;; 569 words
11202 rep
11203 stosw
11204 inc di
11205 inc di
11206 mov cx, #0x7dc6 ;; 32198 words
11207 rep
11208 stosw
11209 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11210 ;; because we store the MP table there
11211 xor eax, eax
11212 xor bx, bx
11213memory_zero_loop:
11214 add bx, #0x1000
11215 cmp bx, #0x9000
11216 jae memory_cleared
11217 mov es, bx
11218 xor di, di
11219 mov cx, #0x4000
11220 rep
11221 stosd
11222 jmp memory_zero_loop
11223memory_cleared:
11224 mov es, bx
11225 xor di, di
11226 mov cx, #0x3f00
11227 rep
11228 stosd
11229 xor bx, bx
11230#endif
11231
11232 call _log_bios_start
11233
11234 ;; set all interrupts to default handler
11235 xor bx, bx ;; offset index
11236 mov cx, #0x0100 ;; counter (256 interrupts)
11237 mov ax, #dummy_iret_handler
11238 mov dx, #0xF000
11239
11240post_default_ints:
11241 mov [bx], ax
11242 inc bx
11243 inc bx
11244 mov [bx], dx
11245 inc bx
11246 inc bx
11247 loop post_default_ints
11248
11249 ;; set vector 0x79 to zero
11250 ;; this is used by 'gardian angel' protection system
11251 SET_INT_VECTOR(0x79, #0, #0)
11252
11253 ;; base memory in K 40:13 (word)
11254 mov ax, #BASE_MEM_IN_K
11255 mov 0x0413, ax
11256
11257
11258 ;; Manufacturing Test 40:12
11259 ;; zerod out above
11260
11261#ifndef VBOX
11262 ;; Warm Boot Flag 0040:0072
11263 ;; value of 1234h = skip memory checks
11264 ;; zerod out above
11265#endif /* !VBOX */
11266
11267
11268 ;; Printer Services vector
11269 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11270
11271 ;; Bootstrap failure vector
11272 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11273
11274 ;; Bootstrap Loader vector
11275 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11276
11277 ;; User Timer Tick vector
11278 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11279
11280 ;; Memory Size Check vector
11281 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11282
11283 ;; Equipment Configuration Check vector
11284 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11285
11286 ;; System Services
11287 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11288
11289 ;; EBDA setup
11290 call ebda_post
11291
11292 ;; PIT setup
11293 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11294 ;; int 1C already points at dummy_iret_handler (above)
11295 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11296 out 0x43, al
11297 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11298 out 0x40, al
11299 out 0x40, al
11300
11301 ;; Keyboard
11302 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11303 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11304
11305 xor ax, ax
11306 mov ds, ax
11307 mov 0x0417, al /* keyboard shift flags, set 1 */
11308 mov 0x0418, al /* keyboard shift flags, set 2 */
11309 mov 0x0419, al /* keyboard alt-numpad work area */
11310 mov 0x0471, al /* keyboard ctrl-break flag */
11311 mov 0x0497, al /* keyboard status flags 4 */
11312 mov al, #0x10
11313 mov 0x0496, al /* keyboard status flags 3 */
11314
11315
11316 /* keyboard head of buffer pointer */
11317 mov bx, #0x001E
11318 mov 0x041A, bx
11319
11320 /* keyboard end of buffer pointer */
11321 mov 0x041C, bx
11322
11323 /* keyboard pointer to start of buffer */
11324 mov bx, #0x001E
11325 mov 0x0480, bx
11326
11327 /* keyboard pointer to end of buffer */
11328 mov bx, #0x003E
11329 mov 0x0482, bx
11330
11331 /* init the keyboard */
11332 call _keyboard_init
11333
11334 ;; mov CMOS Equipment Byte to BDA Equipment Word
11335 mov ax, 0x0410
11336 mov al, #0x14
11337 out 0x70, al
11338 in al, 0x71
11339 mov 0x0410, ax
11340
11341
11342 ;; Parallel setup
11343 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11344 xor ax, ax
11345 mov ds, ax
11346 xor bx, bx
11347 mov cl, #0x14 ; timeout value
11348 mov dx, #0x378 ; Parallel I/O address, port 1
11349 call detect_parport
11350 mov dx, #0x278 ; Parallel I/O address, port 2
11351 call detect_parport
11352 shl bx, #0x0e
11353 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
11354 and ax, #0x3fff
11355 or ax, bx ; set number of parallel ports
11356 mov 0x410, ax
11357
11358 ;; Serial setup
11359 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11360 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11361 xor bx, bx
11362 mov cl, #0x0a ; timeout value
11363 mov dx, #0x03f8 ; Serial I/O address, port 1
11364 call detect_serial
11365 mov dx, #0x02f8 ; Serial I/O address, port 2
11366 call detect_serial
11367 mov dx, #0x03e8 ; Serial I/O address, port 3
11368 call detect_serial
11369 mov dx, #0x02e8 ; Serial I/O address, port 4
11370 call detect_serial
11371 shl bx, #0x09
11372 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11373 and ax, #0xf1ff
11374 or ax, bx ; set number of serial port
11375 mov 0x410, ax
11376
11377 ;; CMOS RTC
11378 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11379 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11380 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11381 ;; BIOS DATA AREA 0x4CE ???
11382 call timer_tick_post
11383
11384 ;; PS/2 mouse setup
11385 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11386
11387 ;; IRQ13 (FPU exception) setup
11388 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11389
11390 ;; Video setup
11391 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11392
11393#ifdef VBOX
11394 ;; moved the PIC initialization to another place as we need
11395 ;; some space for additions init calls. Otherwise this code
11396 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11397 call init_pic
11398#else /* !VBOX */
11399 ;; PIC
11400 mov al, #0x11 ; send initialisation commands
11401 out 0x20, al
11402 out 0xa0, al
11403 mov al, #0x08
11404 out 0x21, al
11405 mov al, #0x70
11406 out 0xa1, al
11407 mov al, #0x04
11408 out 0x21, al
11409 mov al, #0x02
11410 out 0xa1, al
11411 mov al, #0x01
11412 out 0x21, al
11413 out 0xa1, al
11414 mov al, #0xb8
11415 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11416#if BX_USE_PS2_MOUSE
11417 mov al, #0x8f
11418#else
11419 mov al, #0x9f
11420#endif
11421 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11422#endif /* !VBOX */
11423
11424#if BX_ROMBIOS32
11425 call rombios32_init
11426#else
11427 call pcibios_init_iomem_bases
11428 call pcibios_init_irqs
11429#endif
11430 call rom_scan
11431
11432#if BX_USE_ATADRV
11433 ;;
11434 ;; ATA/ATAPI driver setup
11435 ;;
11436 call _ata_init
11437 call _ata_detect
11438 ;;
11439#endif
11440
11441#ifdef VBOX_WITH_SCSI
11442 ;;
11443 ;; SCSI driver setup
11444 ;;
11445 call _scsi_init
11446 ;;
11447#endif
11448
11449 call _print_bios_banner
11450
11451 ;;
11452 ;; Floppy setup
11453 ;;
11454 call floppy_drive_post
11455
11456 ;;
11457 ;; Hard Drive setup
11458 ;;
11459 call hard_drive_post
11460
11461#if BX_ELTORITO_BOOT
11462 ;;
11463 ;; eltorito floppy/harddisk emulation from cd
11464 ;;
11465 call _cdemu_init
11466 ;;
11467#endif // BX_ELTORITO_BOOT
11468
11469 sti ;; enable interrupts
11470 int #0x19
11471
11472
11473.org 0xe2c3 ; NMI Handler Entry Point
11474nmi:
11475 ;; FIXME the NMI handler should not panic
11476 ;; but iret when called from int75 (fpu exception)
11477 call _nmi_handler_msg
11478 iret
11479
11480int75_handler:
11481 out 0xf0, al // clear irq13
11482 call eoi_both_pics // clear interrupt
11483 int 2 // legacy nmi call
11484 iret
11485
11486;-------------------------------------------
11487;- INT 13h Fixed Disk Services Entry Point -
11488;-------------------------------------------
11489.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11490int13_handler:
11491 //JMPL(int13_relocated)
11492 jmp int13_relocated
11493
11494.org 0xe401 ; Fixed Disk Parameter Table
11495
11496;----------
11497;- INT19h -
11498;----------
11499.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11500int19_handler:
11501
11502 jmp int19_relocated
11503;-------------------------------------------
11504;- System BIOS Configuration Data Table
11505;-------------------------------------------
11506.org BIOS_CONFIG_TABLE
11507db 0x08 ; Table size (bytes) -Lo
11508db 0x00 ; Table size (bytes) -Hi
11509db SYS_MODEL_ID
11510db SYS_SUBMODEL_ID
11511db BIOS_REVISION
11512; Feature byte 1
11513; b7: 1=DMA channel 3 used by hard disk
11514; b6: 1=2 interrupt controllers present
11515; b5: 1=RTC present
11516; b4: 1=BIOS calls int 15h/4Fh every key
11517; b3: 1=wait for extern event supported (Int 15h/41h)
11518; b2: 1=extended BIOS data area used
11519; b1: 0=AT or ESDI bus, 1=MicroChannel
11520; b0: 1=Dual bus (MicroChannel + ISA)
11521db (0 << 7) | \
11522 (1 << 6) | \
11523 (1 << 5) | \
11524 (BX_CALL_INT15_4F << 4) | \
11525 (0 << 3) | \
11526 (BX_USE_EBDA << 2) | \
11527 (0 << 1) | \
11528 (0 << 0)
11529; Feature byte 2
11530; b7: 1=32-bit DMA supported
11531; b6: 1=int16h, function 9 supported
11532; b5: 1=int15h/C6h (get POS data) supported
11533; b4: 1=int15h/C7h (get mem map info) supported
11534; b3: 1=int15h/C8h (en/dis CPU) supported
11535; b2: 1=non-8042 kb controller
11536; b1: 1=data streaming supported
11537; b0: reserved
11538db (0 << 7) | \
11539 (1 << 6) | \
11540 (0 << 5) | \
11541 (0 << 4) | \
11542 (0 << 3) | \
11543 (0 << 2) | \
11544 (0 << 1) | \
11545 (0 << 0)
11546; Feature byte 3
11547; b7: not used
11548; b6: reserved
11549; b5: reserved
11550; b4: POST supports ROM-to-RAM enable/disable
11551; b3: SCSI on system board
11552; b2: info panel installed
11553; b1: Initial Machine Load (IML) system - BIOS on disk
11554; b0: SCSI supported in IML
11555db 0x00
11556; Feature byte 4
11557; b7: IBM private
11558; b6: EEPROM present
11559; b5-3: ABIOS presence (011 = not supported)
11560; b2: private
11561; b1: memory split above 16Mb supported
11562; b0: POSTEXT directly supported by POST
11563db 0x00
11564; Feature byte 5 (IBM)
11565; b1: enhanced mouse
11566; b0: flash EPROM
11567db 0x00
11568
11569
11570
11571.org 0xe729 ; Baud Rate Generator Table
11572
11573;----------
11574;- INT14h -
11575;----------
11576.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11577int14_handler:
11578 push ds
11579 pusha
11580 xor ax, ax
11581 mov ds, ax
11582 call _int14_function
11583 popa
11584 pop ds
11585 iret
11586
11587
11588;----------------------------------------
11589;- INT 16h Keyboard Service Entry Point -
11590;----------------------------------------
11591.org 0xe82e
11592int16_handler:
11593
11594 sti
11595 push ds
11596 pushf
11597 pusha
11598
11599 cmp ah, #0x00
11600 je int16_F00
11601 cmp ah, #0x10
11602 je int16_F00
11603
11604 mov bx, #0xf000
11605 mov ds, bx
11606 call _int16_function
11607 popa
11608 popf
11609 pop ds
11610 jz int16_zero_set
11611
11612int16_zero_clear:
11613 push bp
11614 mov bp, sp
11615 //SEG SS
11616 and BYTE [bp + 0x06], #0xbf
11617 pop bp
11618 iret
11619
11620int16_zero_set:
11621 push bp
11622 mov bp, sp
11623 //SEG SS
11624 or BYTE [bp + 0x06], #0x40
11625 pop bp
11626 iret
11627
11628int16_F00:
11629 mov bx, #0x0040
11630 mov ds, bx
11631
11632int16_wait_for_key:
11633 cli
11634 mov bx, 0x001a
11635 cmp bx, 0x001c
11636 jne int16_key_found
11637 sti
11638 nop
11639#if 0
11640 /* no key yet, call int 15h, function AX=9002 */
11641 0x50, /* push AX */
11642 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11643 0xcd, 0x15, /* int 15h */
11644 0x58, /* pop AX */
11645 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11646#endif
11647 jmp int16_wait_for_key
11648
11649int16_key_found:
11650 mov bx, #0xf000
11651 mov ds, bx
11652 call _int16_function
11653 popa
11654 popf
11655 pop ds
11656#if 0
11657 /* notify int16 complete w/ int 15h, function AX=9102 */
11658 0x50, /* push AX */
11659 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11660 0xcd, 0x15, /* int 15h */
11661 0x58, /* pop AX */
11662#endif
11663 iret
11664
11665
11666
11667;-------------------------------------------------
11668;- INT09h : Keyboard Hardware Service Entry Point -
11669;-------------------------------------------------
11670.org 0xe987
11671int09_handler:
11672 cli
11673 push ax
11674
11675 mov al, #0xAD ;;disable keyboard
11676 out #0x64, al
11677
11678 mov al, #0x0B
11679 out #0x20, al
11680 in al, #0x20
11681 and al, #0x02
11682 jz int09_finish
11683
11684 in al, #0x60 ;;read key from keyboard controller
11685 sti
11686 push ds
11687 pusha
11688#ifdef BX_CALL_INT15_4F
11689 mov ah, #0x4f ;; allow for keyboard intercept
11690 stc
11691 int #0x15
11692 jnc int09_done
11693#endif
11694
11695 ;; check for extended key
11696 cmp al, #0xe0
11697 jne int09_check_pause
11698 xor ax, ax
11699 mov ds, ax
11700 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11701 or al, #0x02
11702 mov BYTE [0x496], al
11703 jmp int09_done
11704
11705int09_check_pause: ;; check for pause key
11706 cmp al, #0xe1
11707 jne int09_process_key
11708 xor ax, ax
11709 mov ds, ax
11710 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11711 or al, #0x01
11712 mov BYTE [0x496], al
11713 jmp int09_done
11714
11715int09_process_key:
11716 mov bx, #0xf000
11717 mov ds, bx
11718 call _int09_function
11719
11720int09_done:
11721 popa
11722 pop ds
11723 cli
11724 call eoi_master_pic
11725
11726int09_finish:
11727 mov al, #0xAE ;;enable keyboard
11728 out #0x64, al
11729 pop ax
11730 iret
11731
11732
11733;----------------------------------------
11734;- INT 13h Diskette Service Entry Point -
11735;----------------------------------------
11736.org 0xec59
11737int13_diskette:
11738 jmp int13_noeltorito
11739
11740;---------------------------------------------
11741;- INT 0Eh Diskette Hardware ISR Entry Point -
11742;---------------------------------------------
11743.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11744int0e_handler:
11745 push ax
11746 push dx
11747 mov dx, #0x03f4
11748 in al, dx
11749 and al, #0xc0
11750 cmp al, #0xc0
11751 je int0e_normal
11752 mov dx, #0x03f5
11753 mov al, #0x08 ; sense interrupt status
11754 out dx, al
11755int0e_loop1:
11756 mov dx, #0x03f4
11757 in al, dx
11758 and al, #0xc0
11759 cmp al, #0xc0
11760 jne int0e_loop1
11761int0e_loop2:
11762 mov dx, #0x03f5
11763 in al, dx
11764 mov dx, #0x03f4
11765 in al, dx
11766 and al, #0xc0
11767 cmp al, #0xc0
11768 je int0e_loop2
11769int0e_normal:
11770 push ds
11771 xor ax, ax ;; segment 0000
11772 mov ds, ax
11773 call eoi_master_pic
11774 mov al, 0x043e
11775 or al, #0x80 ;; diskette interrupt has occurred
11776 mov 0x043e, al
11777 pop ds
11778 pop dx
11779 pop ax
11780 iret
11781
11782
11783.org 0xefc7 ; Diskette Controller Parameter Table
11784diskette_param_table:
11785;; Since no provisions are made for multiple drive types, most
11786;; values in this table are ignored. I set parameters for 1.44M
11787;; floppy here
11788db 0xAF
11789db 0x02 ;; head load time 0000001, DMA used
11790db 0x25
11791db 0x02
11792db 18
11793db 0x1B
11794db 0xFF
11795db 0x6C
11796db 0xF6
11797db 0x0F
11798db 0x08
11799
11800
11801;----------------------------------------
11802;- INT17h : Printer Service Entry Point -
11803;----------------------------------------
11804.org 0xefd2
11805int17_handler:
11806 push ds
11807 pusha
11808 xor ax, ax
11809 mov ds, ax
11810 call _int17_function
11811 popa
11812 pop ds
11813 iret
11814
11815diskette_param_table2:
11816;; New diskette parameter table adding 3 parameters from IBM
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
11831db 79 ;; maximum track
11832db 0 ;; data transfer rate
11833db 4 ;; drive type in cmos
11834
11835.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11836 HALT(__LINE__)
11837 iret
11838
11839;----------
11840;- INT10h -
11841;----------
11842.org 0xf065 ; INT 10h Video Support Service Entry Point
11843int10_handler:
11844 ;; dont do anything, since the VGA BIOS handles int10h requests
11845 iret
11846
11847.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11848
11849;----------
11850;- INT12h -
11851;----------
11852.org 0xf841 ; INT 12h Memory Size Service Entry Point
11853; ??? different for Pentium (machine check)?
11854int12_handler:
11855 push ds
11856 mov ax, #0x0040
11857 mov ds, ax
11858 mov ax, 0x0013
11859 pop ds
11860 iret
11861
11862;----------
11863;- INT11h -
11864;----------
11865.org 0xf84d ; INT 11h Equipment List Service Entry Point
11866int11_handler:
11867 push ds
11868 mov ax, #0x0040
11869 mov ds, ax
11870 mov ax, 0x0010
11871 pop ds
11872 iret
11873
11874;----------
11875;- INT15h -
11876;----------
11877.org 0xf859 ; INT 15h System Services Entry Point
11878int15_handler:
11879 pushf
11880#if BX_APM
11881 cmp ah, #0x53
11882 je apm_call
11883#endif
11884 push ds
11885 push es
11886 cmp ah, #0x86
11887 je int15_handler32
11888 cmp ah, #0xE8
11889 je int15_handler32
11890 pusha
11891#if BX_USE_PS2_MOUSE
11892 cmp ah, #0xC2
11893 je int15_handler_mouse
11894#endif
11895 call _int15_function
11896int15_handler_mouse_ret:
11897 popa
11898int15_handler32_ret:
11899 pop es
11900 pop ds
11901 popf
11902 jmp iret_modify_cf
11903#if BX_APM
11904apm_call:
11905 jmp _apmreal_entry
11906#endif
11907
11908#if BX_USE_PS2_MOUSE
11909int15_handler_mouse:
11910 call _int15_function_mouse
11911 jmp int15_handler_mouse_ret
11912#endif
11913
11914int15_handler32:
11915 pushad
11916 call _int15_function32
11917 popad
11918 jmp int15_handler32_ret
11919
11920;; Protected mode IDT descriptor
11921;;
11922;; I just make the limit 0, so the machine will shutdown
11923;; if an exception occurs during protected mode memory
11924;; transfers.
11925;;
11926;; Set base to f0000 to correspond to beginning of BIOS,
11927;; in case I actually define an IDT later
11928;; Set limit to 0
11929
11930pmode_IDT_info:
11931dw 0x0000 ;; limit 15:00
11932dw 0x0000 ;; base 15:00
11933db 0x0f ;; base 23:16
11934
11935;; Real mode IDT descriptor
11936;;
11937;; Set to typical real-mode values.
11938;; base = 000000
11939;; limit = 03ff
11940
11941rmode_IDT_info:
11942dw 0x03ff ;; limit 15:00
11943dw 0x0000 ;; base 15:00
11944db 0x00 ;; base 23:16
11945
11946;;
11947;; Handler for unexpected hardware interrupts
11948;;
11949dummy_isr:
11950 push ds
11951 pushad
11952 xor ax, ax
11953 mov ds, ax
11954 call _dummy_isr_function
11955 popad
11956 pop ds
11957 iret
11958
11959;----------
11960;- INT1Ah -
11961;----------
11962.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
11963int1a_handler:
11964#if BX_PCIBIOS
11965 cmp ah, #0xb1
11966 jne int1a_normal
11967 call pcibios_real
11968 jc pcibios_error
11969 retf 2
11970pcibios_error:
11971 mov bl, ah
11972 mov ah, #0xb1
11973 push ds
11974 pusha
11975 mov ax, ss ; set readable descriptor to ds, for calling pcibios
11976 mov ds, ax ; on 16bit protected mode.
11977 jmp int1a_callfunction
11978int1a_normal:
11979#endif
11980 push ds
11981 pusha
11982 xor ax, ax
11983 mov ds, ax
11984int1a_callfunction:
11985 call _int1a_function
11986 popa
11987 pop ds
11988 iret
11989
11990;;
11991;; int70h: IRQ8 - CMOS RTC
11992;;
11993int70_handler:
11994 push ds
11995 pushad
11996 xor ax, ax
11997 mov ds, ax
11998 call _int70_function
11999 popad
12000 pop ds
12001 iret
12002
12003;---------
12004;- INT08 -
12005;---------
12006.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12007int08_handler:
12008 sti
12009 push eax
12010 push ds
12011 xor ax, ax
12012 mov ds, ax
12013
12014 ;; time to turn off drive(s)?
12015 mov al,0x0440
12016 or al,al
12017 jz int08_floppy_off
12018 dec al
12019 mov 0x0440,al
12020 jnz int08_floppy_off
12021 ;; turn motor(s) off
12022 push dx
12023 mov dx,#0x03f2
12024 in al,dx
12025 and al,#0xcf
12026 out dx,al
12027 pop dx
12028int08_floppy_off:
12029
12030 mov eax, 0x046c ;; get ticks dword
12031 inc eax
12032
12033 ;; compare eax to one days worth of timer ticks at 18.2 hz
12034 cmp eax, #0x001800B0
12035 jb int08_store_ticks
12036 ;; there has been a midnight rollover at this point
12037 xor eax, eax ;; zero out counter
12038 inc BYTE 0x0470 ;; increment rollover flag
12039
12040int08_store_ticks:
12041 mov 0x046c, eax ;; store new ticks dword
12042 ;; chain to user timer tick INT #0x1c
12043 //pushf
12044 //;; call_ep [ds:loc]
12045 //CALL_EP( 0x1c << 2 )
12046 int #0x1c
12047 cli
12048 call eoi_master_pic
12049 pop ds
12050 pop eax
12051 iret
12052
12053.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12054
12055
12056.org 0xff00
12057.ascii BIOS_COPYRIGHT_STRING
12058
12059#ifdef VBOX
12060// The SMBIOS header
12061.org 0xff30
12062.align 16
12063 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12064 db 0x00 ; checksum (set by biossums)
12065 db 0x1f ; EPS length, defined by standard
12066 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12067 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12068 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12069 db 0x00 ; Entry point revision
12070 db 0x00, 0x00, 0x00, 0x00, 0x00
12071
12072// The DMI header
12073 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12074 db 0x00 ; checksum (set by biossums)
12075 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12076 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12077 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12078 db VBOX_DMI_TABLE_VER ; DMI version
12079 db 0x00 ; Just for alignment
12080#endif
12081
12082;------------------------------------------------
12083;- IRET Instruction for Dummy Interrupt Handler -
12084;------------------------------------------------
12085.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12086dummy_iret_handler:
12087 iret
12088
12089.org 0xff54 ; INT 05h Print Screen Service Entry Point
12090 HALT(__LINE__)
12091 iret
12092
12093.org 0xfff0 ; Power-up Entry Point
12094 jmp 0xf000:post
12095
12096.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12097.ascii BIOS_BUILD_DATE
12098
12099.org 0xfffe ; System Model ID
12100db SYS_MODEL_ID
12101db 0x00 ; filler
12102
12103.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12104ASM_END
12105/*
12106 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12107 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12108 * This font is public domain
12109 */
12110static Bit8u vgafont8[128*8]=
12111{
12112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12113 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12114 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12115 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12116 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12117 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12118 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12119 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12120 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12121 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12122 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12123 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12124 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12125 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12126 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12127 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12128 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12129 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12130 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12131 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12132 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12133 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12134 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12135 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12136 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12137 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12138 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12139 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12140 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12141 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12142 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12143 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12145 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12146 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12147 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12148 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12149 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12150 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12151 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12152 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12153 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12154 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12155 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12156 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12157 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12158 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12159 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12160 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12161 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12162 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12163 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12164 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12165 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12166 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12167 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12168 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12169 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12170 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12171 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12172 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12173 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12174 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12175 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12176 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12177 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12178 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12179 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12180 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12181 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12182 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12183 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12184 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12185 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12186 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12187 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12188 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12189 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12190 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12191 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12192 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12193 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12194 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12195 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12196 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12197 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12198 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12199 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12200 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12201 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12202 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12203 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12204 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12205 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12206 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12208 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12209 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12210 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12211 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12212 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12213 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12214 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12215 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12216 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12217 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12218 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12219 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12220 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12221 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12222 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12223 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12224 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12225 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12226 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12227 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12228 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12229 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12230 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12231 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12232 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12233 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12234 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12235 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12236 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12237 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12238 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12239 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12240};
12241
12242ASM_START
12243.org 0xcc00
12244// bcc-generated data will be placed here
12245ASM_END
Note: See TracBrowser for help on using the repository browser.

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