VirtualBox

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

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

BIOS part to make Vista boot from the LsiLogic controller and boot speedup

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

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