VirtualBox

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

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

rombios.c: r=bird: INT 15 AX=EC00h should clear AH not AL (r59329).

  • Property svn:eol-style set to native
File size: 334.4 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
37
38
39// ROM BIOS compatability entry points:
40// ===================================
41// $e05b ; POST Entry Point
42// $e2c3 ; NMI Handler Entry Point
43// $e3fe ; INT 13h Fixed Disk Services Entry Point
44// $e401 ; Fixed Disk Parameter Table
45// $e6f2 ; INT 19h Boot Load Service Entry Point
46// $e6f5 ; Configuration Data Table
47// $e729 ; Baud Rate Generator Table
48// $e739 ; INT 14h Serial Communications Service Entry Point
49// $e82e ; INT 16h Keyboard Service Entry Point
50// $e987 ; INT 09h Keyboard Service Entry Point
51// $ec59 ; INT 13h Diskette Service Entry Point
52// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
53// $efc7 ; Diskette Controller Parameter Table
54// $efd2 ; INT 17h Printer Service Entry Point
55// $f045 ; INT 10 Functions 0-Fh Entry Point
56// $f065 ; INT 10h Video Support Service Entry Point
57// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
58// $f841 ; INT 12h Memory Size Service Entry Point
59// $f84d ; INT 11h Equipment List Service Entry Point
60// $f859 ; INT 15h System Services Entry Point
61// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
62// $fe6e ; INT 1Ah Time-of-day Service Entry Point
63// $fea5 ; INT 08h System Timer ISR Entry Point
64// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
65// $ff53 ; IRET Instruction for Dummy Interrupt Handler
66// $ff54 ; INT 05h Print Screen Service Entry Point
67// $fff0 ; Power-up Entry Point
68// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
69// $fffe ; System Model ID
70
71// NOTES for ATA/ATAPI driver ([email protected])
72// Features
73// - supports up to 4 ATA interfaces
74// - device/geometry detection
75// - 16bits/32bits device access
76// - pchs/lba access
77// - datain/dataout/packet command support
78//
79// NOTES for El-Torito Boot ([email protected])
80// - CD-ROM booting is only available if ATA/ATAPI Driver is available
81// - Current code is only able to boot mono-session cds
82// - Current code can not boot and emulate a hard-disk
83// the bios will panic otherwise
84// - Current code also use memory in EBDA segement.
85// - I used cmos byte 0x3D to store extended information on boot-device
86// - Code has to be modified modified to handle multiple cdrom drives
87// - Here are the cdrom boot failure codes:
88// 1 : no atapi device found
89// 2 : no atapi cdrom found
90// 3 : can not read cd - BRVD
91// 4 : cd is not eltorito (BRVD)
92// 5 : cd is not eltorito (ISO TAG)
93// 6 : cd is not eltorito (ELTORITO TAG)
94// 7 : can not read cd - boot catalog
95// 8 : boot catalog : bad header
96// 9 : boot catalog : bad platform
97// 10 : boot catalog : bad signature
98// 11 : boot catalog : bootable flag not set
99// 12 : can not read cd - boot image
100//
101// ATA driver
102// - EBDA segment.
103// I used memory starting at 0x121 in the segment
104#ifndef VBOX
105// - the translation policy is defined in cmos regs 0x39 & 0x3a
106#endif /* !VBOX */
107//
108// TODO :
109//
110// int74
111// - needs to be reworked. Uses direct [bp] offsets. (?)
112//
113// int13:
114// - f04 (verify sectors) isn't complete (?)
115// - f02/03/04 should set current cyl,etc in BDA (?)
116// - rewrite int13_relocated & clean up int13 entry code
117//
118// NOTES:
119// - NMI access (bit7 of addr written to 70h)
120//
121// ATA driver
122// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
123// - could send the multiple-sector read/write commands
124//
125// El-Torito
126// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
127// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
128// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
129// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
130// This is ok. But DL should be reincremented afterwards.
131// - Fix all "FIXME ElTorito Various"
132// - should be able to boot any cdrom instead of the first one
133//
134// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
135
136#ifdef VBOX
137#include "DevPcBios.h"
138#include <VBox/version.h>
139#endif
140
141#define BX_ROMBIOS32 0
142#define DEBUG_ROMBIOS 0
143
144#define DEBUG_ATA 0
145#define DEBUG_INT13_HD 0
146#define DEBUG_INT13_CD 0
147#define DEBUG_INT13_ET 0
148#define DEBUG_INT13_FL 0
149#define DEBUG_INT15 0
150#define DEBUG_INT16 0
151#define DEBUG_INT1A 0
152#define DEBUG_INT74 0
153#define DEBUG_APM 0
154
155#define BX_CPU 3
156#define BX_USE_PS2_MOUSE 1
157#define BX_CALL_INT15_4F 1
158#define BX_USE_EBDA 1
159#define BX_SUPPORT_FLOPPY 1
160#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
161#define BX_PCIBIOS 1
162#define BX_APM 1
163
164#define BX_USE_ATADRV 1
165#define BX_ELTORITO_BOOT 1
166
167#define BX_MAX_ATA_INTERFACES 4
168#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
169
170#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
171#define BX_DEBUG_SERIAL 0 /* output to COM1 */
172
173 /* model byte 0xFC = AT */
174#define SYS_MODEL_ID 0xFC
175#define SYS_SUBMODEL_ID 0x00
176#define BIOS_REVISION 1
177#define BIOS_CONFIG_TABLE 0xe6f5
178
179#ifndef BIOS_BUILD_DATE
180# define BIOS_BUILD_DATE "06/23/99"
181#endif
182
183 // 1K of base memory used for Extended Bios Data Area (EBDA)
184 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
185#define EBDA_SEG 0x9FC0
186#define EBDA_SIZE 1 // In KiB
187#define BASE_MEM_IN_K (640 - EBDA_SIZE)
188
189#define ACPI_DATA_SIZE 0x00010000L
190
191 // Define the application NAME
192#if defined(BX_QEMU)
193# define BX_APPNAME "QEMU"
194#elif defined(PLEX86)
195# define BX_APPNAME "Plex86"
196#else
197# define BX_APPNAME "Bochs"
198#endif
199
200 // Sanity Checks
201#if BX_USE_ATADRV && BX_CPU<3
202# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
203#endif
204#if BX_USE_ATADRV && !BX_USE_EBDA
205# error ATA/ATAPI Driver can only be used if EBDA is available
206#endif
207#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
208# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
209#endif
210#if BX_PCIBIOS && BX_CPU<3
211# error PCI BIOS can only be used with 386+ cpu
212#endif
213#if BX_APM && BX_CPU<3
214# error APM BIOS can only be used with 386+ cpu
215#endif
216
217#if defined(VBOX) && !BX_USE_ATADRV
218# error VBOX requires enabling the ATA/ATAPI driver
219#endif
220
221#ifdef VBOX_WITH_SCSI
222/* Enough for now */
223# define BX_MAX_SCSI_DEVICES 4
224# define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
225
226/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
227# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
228# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
229#endif
230
231#ifndef VBOX
232#define PANIC_PORT 0x400
233#define PANIC_PORT2 0x401
234#define INFO_PORT 0x402
235#define DEBUG_PORT 0x403
236#else /* VBOX */
237/* Redirect INFO output to backdoor logging port. */
238#define PANIC_PORT 0x400
239#define PANIC_PORT2 0x401
240#define INFO_PORT 0x504
241#define DEBUG_PORT 0x403
242#endif /* VBOX */
243
244// define this if you want to make PCIBIOS working on a specific bridge only
245// undef enables PCIBIOS when at least one PCI device is found
246// i440FX is emulated by Bochs and QEMU
247#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
248
249// #20 is dec 20
250// #$20 is hex 20 = 32
251// #0x20 is hex 20 = 32
252// LDA #$20
253// JSR $E820
254// LDD .i,S
255// JSR $C682
256// mov al, #$20
257
258// all hex literals should be prefixed with '0x'
259// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
260// no mov SEG-REG, #value, must mov register into seg-reg
261// grep -i "mov[ ]*.s" rombios.c
262
263// This is for compiling with gcc2 and gcc3
264#define ASM_START #asm
265#define ASM_END #endasm
266
267ASM_START
268.rom
269
270.org 0x0000
271
272#if BX_CPU >= 3
273use16 386
274#else
275use16 286
276#endif
277
278MACRO HALT
279 ;; the HALT macro is called with the line number of the HALT call.
280 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
281 ;; to print a BX_PANIC message. This will normally halt the simulation
282 ;; with a message such as "BIOS panic at rombios.c, line 4091".
283 ;; However, users can choose to make panics non-fatal and continue.
284#if BX_VIRTUAL_PORTS
285 mov dx,#PANIC_PORT
286 mov ax,#?1
287 out dx,ax
288#else
289 mov dx,#0x80
290 mov ax,#?1
291 out dx,al
292#endif
293MEND
294
295MACRO JMP_AP
296 db 0xea
297 dw ?2
298 dw ?1
299MEND
300
301MACRO SET_INT_VECTOR
302 mov ax, ?3
303 mov ?1*4, ax
304 mov ax, ?2
305 mov ?1*4+2, ax
306MEND
307
308ASM_END
309
310typedef unsigned char Bit8u;
311typedef unsigned short Bit16u;
312typedef unsigned short bx_bool;
313typedef unsigned long Bit32u;
314
315#if BX_USE_ATADRV
316
317 void memsetb(seg,offset,value,count);
318 void memcpyb(dseg,doffset,sseg,soffset,count);
319 void memcpyd(dseg,doffset,sseg,soffset,count);
320
321 // memset of count bytes
322 void
323 memsetb(seg,offset,value,count)
324 Bit16u seg;
325 Bit16u offset;
326 Bit16u value;
327 Bit16u count;
328 {
329 ASM_START
330 push bp
331 mov bp, sp
332
333 push ax
334 push cx
335 push es
336 push di
337
338 mov cx, 10[bp] ; count
339 test cx, cx
340 je memsetb_end
341 mov ax, 4[bp] ; segment
342 mov es, ax
343 mov ax, 6[bp] ; offset
344 mov di, ax
345 mov al, 8[bp] ; value
346 cld
347 rep
348 stosb
349
350 memsetb_end:
351 pop di
352 pop es
353 pop cx
354 pop ax
355
356 pop bp
357 ASM_END
358 }
359
360#if 0
361 // memcpy of count bytes
362 void
363 memcpyb(dseg,doffset,sseg,soffset,count)
364 Bit16u dseg;
365 Bit16u doffset;
366 Bit16u sseg;
367 Bit16u soffset;
368 Bit16u count;
369 {
370 ASM_START
371 push bp
372 mov bp, sp
373
374 push ax
375 push cx
376 push es
377 push di
378 push ds
379 push si
380
381 mov cx, 12[bp] ; count
382 cmp cx, #0x0000
383 je memcpyb_end
384 mov ax, 4[bp] ; dsegment
385 mov es, ax
386 mov ax, 6[bp] ; doffset
387 mov di, ax
388 mov ax, 8[bp] ; ssegment
389 mov ds, ax
390 mov ax, 10[bp] ; soffset
391 mov si, ax
392 cld
393 rep
394 movsb
395
396 memcpyb_end:
397 pop si
398 pop ds
399 pop di
400 pop es
401 pop cx
402 pop ax
403
404 pop bp
405 ASM_END
406 }
407
408 // memcpy of count dword
409 void
410 memcpyd(dseg,doffset,sseg,soffset,count)
411 Bit16u dseg;
412 Bit16u doffset;
413 Bit16u sseg;
414 Bit16u soffset;
415 Bit16u count;
416 {
417 ASM_START
418 push bp
419 mov bp, sp
420
421 push ax
422 push cx
423 push es
424 push di
425 push ds
426 push si
427
428 mov cx, 12[bp] ; count
429 test cx, cx
430 je memcpyd_end
431 mov ax, 4[bp] ; dsegment
432 mov es, ax
433 mov ax, 6[bp] ; doffset
434 mov di, ax
435 mov ax, 8[bp] ; ssegment
436 mov ds, ax
437 mov ax, 10[bp] ; soffset
438 mov si, ax
439 cld
440 rep
441 movsd
442
443 memcpyd_end:
444 pop si
445 pop ds
446 pop di
447 pop es
448 pop cx
449 pop ax
450
451 pop bp
452 ASM_END
453 }
454#endif
455#endif //BX_USE_ATADRV
456
457 // read_dword and write_dword functions
458 static Bit32u read_dword();
459 static void write_dword();
460
461 Bit32u
462 read_dword(seg, offset)
463 Bit16u seg;
464 Bit16u offset;
465 {
466 ASM_START
467 push bp
468 mov bp, sp
469
470 push bx
471 push ds
472 mov ax, 4[bp] ; segment
473 mov ds, ax
474 mov bx, 6[bp] ; offset
475 mov ax, [bx]
476 add bx, #2
477 mov dx, [bx]
478 ;; ax = return value (word)
479 ;; dx = return value (word)
480 pop ds
481 pop bx
482
483 pop bp
484 ASM_END
485 }
486
487 void
488 write_dword(seg, offset, data)
489 Bit16u seg;
490 Bit16u offset;
491 Bit32u data;
492 {
493 ASM_START
494 push bp
495 mov bp, sp
496
497 push ax
498 push bx
499 push ds
500 mov ax, 4[bp] ; segment
501 mov ds, ax
502 mov bx, 6[bp] ; offset
503 mov ax, 8[bp] ; data word
504 mov [bx], ax ; write data word
505 add bx, #2
506 mov ax, 10[bp] ; data word
507 mov [bx], ax ; write data word
508 pop ds
509 pop bx
510 pop ax
511
512 pop bp
513 ASM_END
514 }
515
516 // Bit32u (unsigned long) and long helper functions
517 ASM_START
518
519 ;; and function
520 landl:
521 landul:
522 SEG SS
523 and ax,[di]
524 SEG SS
525 and bx,2[di]
526 ret
527
528 ;; add function
529 laddl:
530 laddul:
531 SEG SS
532 add ax,[di]
533 SEG SS
534 adc bx,2[di]
535 ret
536
537 ;; cmp function
538 lcmpl:
539 lcmpul:
540 and eax, #0x0000FFFF
541 shl ebx, #16
542 or eax, ebx
543 shr ebx, #16
544 SEG SS
545 cmp eax, dword ptr [di]
546 ret
547
548 ;; sub function
549 lsubl:
550 lsubul:
551 SEG SS
552 sub ax,[di]
553 SEG SS
554 sbb bx,2[di]
555 ret
556
557 ;; mul function
558 lmull:
559 lmulul:
560 and eax, #0x0000FFFF
561 shl ebx, #16
562 or eax, ebx
563 SEG SS
564 mul eax, dword ptr [di]
565 mov ebx, eax
566 shr ebx, #16
567 ret
568
569 ;; dec function
570 ldecl:
571 ldecul:
572 SEG SS
573 dec dword ptr [bx]
574 ret
575
576 ;; or function
577 lorl:
578 lorul:
579 SEG SS
580 or ax,[di]
581 SEG SS
582 or bx,2[di]
583 ret
584
585 ;; inc function
586 lincl:
587 lincul:
588 SEG SS
589 inc dword ptr [bx]
590 ret
591
592 ;; tst function
593 ltstl:
594 ltstul:
595 and eax, #0x0000FFFF
596 shl ebx, #16
597 or eax, ebx
598 shr ebx, #16
599 test eax, eax
600 ret
601
602 ;; sr function
603 lsrul:
604 mov cx,di
605 jcxz lsr_exit
606 and eax, #0x0000FFFF
607 shl ebx, #16
608 or eax, ebx
609 lsr_loop:
610 shr eax, #1
611 loop lsr_loop
612 mov ebx, eax
613 shr ebx, #16
614 lsr_exit:
615 ret
616
617 ;; sl function
618 lsll:
619 lslul:
620 mov cx,di
621 jcxz lsl_exit
622 and eax, #0x0000FFFF
623 shl ebx, #16
624 or eax, ebx
625 lsl_loop:
626 shl eax, #1
627 loop lsl_loop
628 mov ebx, eax
629 shr ebx, #16
630 lsl_exit:
631 ret
632
633 idiv_:
634 cwd
635 idiv bx
636 ret
637
638 idiv_u:
639 xor dx,dx
640 div bx
641 ret
642
643 ldivul:
644 and eax, #0x0000FFFF
645 shl ebx, #16
646 or eax, ebx
647 xor edx, edx
648 SEG SS
649 mov bx, 2[di]
650 shl ebx, #16
651 SEG SS
652 mov bx, [di]
653 div ebx
654 mov ebx, eax
655 shr ebx, #16
656 ret
657
658 ASM_END
659
660// for access to RAM area which is used by interrupt vectors
661// and BIOS Data Area
662
663typedef struct {
664 unsigned char filler1[0x400];
665 unsigned char filler2[0x6c];
666 Bit16u ticks_low;
667 Bit16u ticks_high;
668 Bit8u midnight_flag;
669 } bios_data_t;
670
671#define BiosData ((bios_data_t *) 0)
672
673#if BX_USE_ATADRV
674 typedef struct {
675 Bit16u heads; // # heads
676 Bit16u cylinders; // # cylinders
677 Bit16u spt; // # sectors / track
678 } chs_t;
679
680 // DPTE definition
681 typedef struct {
682 Bit16u iobase1;
683 Bit16u iobase2;
684 Bit8u prefix;
685 Bit8u unused;
686 Bit8u irq;
687 Bit8u blkcount;
688 Bit8u dma;
689 Bit8u pio;
690 Bit16u options;
691 Bit16u reserved;
692 Bit8u revision;
693 Bit8u checksum;
694 } dpte_t;
695
696 typedef struct {
697 Bit8u iface; // ISA or PCI
698 Bit16u iobase1; // IO Base 1
699 Bit16u iobase2; // IO Base 2
700 Bit8u irq; // IRQ
701 } ata_channel_t;
702
703 typedef struct {
704 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
705 Bit8u device; // Detected type of attached devices (hd/cd/none)
706 Bit8u removable; // Removable device flag
707 Bit8u lock; // Locks for removable devices
708 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
709 Bit16u blksize; // block size
710
711 Bit8u translation; // type of translation
712 chs_t lchs; // Logical CHS
713 chs_t pchs; // Physical CHS
714
715 Bit32u sectors; // Total sectors count
716 } ata_device_t;
717
718 typedef struct {
719 // ATA channels info
720 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
721
722 // ATA devices info
723 ata_device_t devices[BX_MAX_ATA_DEVICES];
724 //
725 // map between (bios hd id - 0x80) and ata channels and scsi disks.
726#ifdef VBOX_WITH_SCSI
727 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
728#else
729 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
730#endif
731
732 // map between (bios cd id - 0xE0) and ata channels
733 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
734
735 // Buffer for DPTE table
736 dpte_t dpte;
737
738 // Count of transferred sectors and bytes
739 Bit16u trsfsectors;
740 Bit32u trsfbytes;
741
742 } ata_t;
743
744#if BX_ELTORITO_BOOT
745 // ElTorito Device Emulation data
746 typedef struct {
747 Bit8u active;
748 Bit8u media;
749 Bit8u emulated_drive;
750 Bit8u controller_index;
751 Bit16u device_spec;
752 Bit32u ilba;
753 Bit16u buffer_segment;
754 Bit16u load_segment;
755 Bit16u sector_count;
756
757 // Virtual device
758 chs_t vdevice;
759 } cdemu_t;
760#endif // BX_ELTORITO_BOOT
761
762#ifdef VBOX_WITH_SCSI
763 typedef struct {
764 // I/O port this device is attached to.
765 Bit16u io_base;
766 // Target Id.
767 Bit8u target_id;
768 // SCSI devices info
769 ata_device_t device_info;
770 } scsi_device_t;
771
772 typedef struct {
773 // SCSi device info
774 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
775 // Number of scsi disks.
776 Bit8u hdcount;
777 } scsi_t;
778#endif
779
780 // for access to EBDA area
781 // The EBDA structure should conform to
782 // http://www.frontiernet.net/~fys/rombios.htm document
783 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
784 typedef struct {
785 unsigned char filler1[0x3D];
786
787 // FDPT - Can be splitted in data members if needed
788 unsigned char fdpt0[0x10];
789 unsigned char fdpt1[0x10];
790
791 unsigned char filler2[0xC4];
792
793 // ATA Driver data
794 ata_t ata;
795
796#if BX_ELTORITO_BOOT
797 // El Torito Emulation data
798 cdemu_t cdemu;
799#endif // BX_ELTORITO_BOOT
800
801#ifdef VBOX
802
803#ifdef VBOX_WITH_SCSI
804 // SCSI Driver data
805 scsi_t scsi;
806# endif
807
808 unsigned char uForceBootDrive;
809 unsigned char uForceBootDevice;
810#endif /* VBOX */
811
812 } ebda_data_t;
813
814#ifdef VBOX
815 // the last 16 bytes of the EBDA segment are used for the MPS floating
816 // pointer structure (only if an IOAPIC is present)
817#endif
818
819 #define EbdaData ((ebda_data_t *) 0)
820
821 // for access to the int13ext structure
822 typedef struct {
823 Bit8u size;
824 Bit8u reserved;
825 Bit16u count;
826 Bit16u offset;
827 Bit16u segment;
828 Bit32u lba1;
829 Bit32u lba2;
830 } int13ext_t;
831
832 #define Int13Ext ((int13ext_t *) 0)
833
834 // Disk Physical Table definition
835 typedef struct {
836 Bit16u size;
837 Bit16u infos;
838 Bit32u cylinders;
839 Bit32u heads;
840 Bit32u spt;
841 Bit32u sector_count1;
842 Bit32u sector_count2;
843 Bit16u blksize;
844 Bit16u dpte_offset;
845 Bit16u dpte_segment;
846 Bit16u key;
847 Bit8u dpi_length;
848 Bit8u reserved1;
849 Bit16u reserved2;
850 Bit8u host_bus[4];
851 Bit8u iface_type[8];
852 Bit8u iface_path[8];
853 Bit8u device_path[8];
854 Bit8u reserved3;
855 Bit8u checksum;
856 } dpt_t;
857
858 #define Int13DPT ((dpt_t *) 0)
859
860#endif // BX_USE_ATADRV
861
862typedef struct {
863 union {
864 struct {
865 Bit16u di, si, bp, sp;
866 Bit16u bx, dx, cx, ax;
867 } r16;
868 struct {
869 Bit16u filler[4];
870 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
871 } r8;
872 } u;
873 } pusha_regs_t;
874
875typedef struct {
876 union {
877 struct {
878 Bit32u edi, esi, ebp, esp;
879 Bit32u ebx, edx, ecx, eax;
880 } r32;
881 struct {
882 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
883 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
884 } r16;
885 struct {
886 Bit32u filler[4];
887 Bit8u bl, bh;
888 Bit16u filler1;
889 Bit8u dl, dh;
890 Bit16u filler2;
891 Bit8u cl, ch;
892 Bit16u filler3;
893 Bit8u al, ah;
894 Bit16u filler4;
895 } r8;
896 } u;
897} pushad_regs_t;
898
899typedef struct {
900 union {
901 struct {
902 Bit16u flags;
903 } r16;
904 struct {
905 Bit8u flagsl;
906 Bit8u flagsh;
907 } r8;
908 } u;
909 } flags_t;
910
911#define SetCF(x) x.u.r8.flagsl |= 0x01
912#define SetZF(x) x.u.r8.flagsl |= 0x40
913#define ClearCF(x) x.u.r8.flagsl &= 0xfe
914#define ClearZF(x) x.u.r8.flagsl &= 0xbf
915#define GetCF(x) (x.u.r8.flagsl & 0x01)
916
917typedef struct {
918 Bit16u ip;
919 Bit16u cs;
920 flags_t flags;
921 } iret_addr_t;
922
923
924
925static Bit8u inb();
926static Bit8u inb_cmos();
927static void outb();
928static void outb_cmos();
929static Bit16u inw();
930static void outw();
931static void init_rtc();
932static bx_bool rtc_updating();
933
934static Bit8u read_byte();
935static Bit16u read_word();
936static void write_byte();
937static void write_word();
938static void bios_printf();
939
940static Bit8u send_to_mouse_ctrl();
941static Bit8u get_mouse_data();
942static void set_kbd_command_byte();
943
944static void int09_function();
945static void int13_harddisk();
946static void int13_cdrom();
947static void int13_cdemu();
948static void int13_eltorito();
949static void int13_diskette_function();
950static void int14_function();
951static void int15_function();
952static void int16_function();
953static void int17_function();
954static Bit32u int19_function();
955static void int1a_function();
956static void int70_function();
957static void int74_function();
958static void dummy_isr_function();
959static Bit16u get_CS();
960static Bit16u get_SS();
961static unsigned int enqueue_key();
962static unsigned int dequeue_key();
963static void get_hd_geometry();
964static void set_diskette_ret_status();
965static void set_diskette_current_cyl();
966static void determine_floppy_media();
967static bx_bool floppy_drive_exists();
968static bx_bool floppy_drive_recal();
969static bx_bool floppy_media_known();
970static bx_bool floppy_media_sense();
971static bx_bool set_enable_a20();
972static void debugger_on();
973static void debugger_off();
974static void keyboard_init();
975static void keyboard_panic();
976static void shutdown_status_panic();
977static void nmi_handler_msg();
978
979static void print_bios_banner();
980static void print_boot_device();
981static void print_boot_failure();
982static void print_cdromboot_failure();
983
984# if BX_USE_ATADRV
985
986// ATA / ATAPI driver
987void ata_init();
988void ata_detect();
989void ata_reset();
990
991Bit16u ata_cmd_non_data();
992Bit16u ata_cmd_data_in();
993Bit16u ata_cmd_data_out();
994Bit16u ata_cmd_packet();
995
996Bit16u atapi_get_sense();
997Bit16u atapi_is_ready();
998Bit16u atapi_is_cdrom();
999
1000#endif // BX_USE_ATADRV
1001
1002#if BX_ELTORITO_BOOT
1003
1004void cdemu_init();
1005Bit8u cdemu_isactive();
1006Bit8u cdemu_emulated_drive();
1007
1008Bit16u cdrom_boot();
1009
1010#endif // BX_ELTORITO_BOOT
1011
1012#ifdef VBOX
1013static char bios_prefix_string[] = "BIOS: ";
1014/* Do not use build timestamps in this string. Otherwise even rebuilding the
1015 * very same code will lead to compare errors when restoring saved state. */
1016static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1017#define BIOS_COPYRIGHT_STRING "Sun VirtualBox BIOS"
1018#else /* !VBOX */
1019static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1020
1021#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1022#endif /* !VBOX */
1023
1024#define BIOS_PRINTF_HALT 1
1025#define BIOS_PRINTF_SCREEN 2
1026#define BIOS_PRINTF_INFO 4
1027#define BIOS_PRINTF_DEBUG 8
1028#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1029#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1030
1031#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1032
1033// Defines the output macros.
1034// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1035// per-device basis. Debug info are sent only in debug mode
1036#if DEBUG_ROMBIOS
1037# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1038#else
1039# define BX_DEBUG(format, p...)
1040#endif
1041#ifdef VBOX
1042#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, get_CS(), bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
1043#else /* !VBOX */
1044#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1045#endif /* !VBOX */
1046#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1047
1048#if DEBUG_ATA
1049# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1050#else
1051# define BX_DEBUG_ATA(a...)
1052#endif
1053#if DEBUG_INT13_HD
1054# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1055#else
1056# define BX_DEBUG_INT13_HD(a...)
1057#endif
1058#if DEBUG_INT13_CD
1059# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1060#else
1061# define BX_DEBUG_INT13_CD(a...)
1062#endif
1063#if DEBUG_INT13_ET
1064# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1065#else
1066# define BX_DEBUG_INT13_ET(a...)
1067#endif
1068#if DEBUG_INT13_FL
1069# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1070#else
1071# define BX_DEBUG_INT13_FL(a...)
1072#endif
1073#if DEBUG_INT15
1074# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1075#else
1076# define BX_DEBUG_INT15(a...)
1077#endif
1078#if DEBUG_INT16
1079# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1080#else
1081# define BX_DEBUG_INT16(a...)
1082#endif
1083#if DEBUG_INT1A
1084# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1085#else
1086# define BX_DEBUG_INT1A(a...)
1087#endif
1088#if DEBUG_INT74
1089# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1090#else
1091# define BX_DEBUG_INT74(a...)
1092#endif
1093
1094#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1095#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1096#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1097#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1098#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1099#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1100#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1101#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1102
1103#define GET_AL() ( AX & 0x00ff )
1104#define GET_BL() ( BX & 0x00ff )
1105#define GET_CL() ( CX & 0x00ff )
1106#define GET_DL() ( DX & 0x00ff )
1107#define GET_AH() ( AX >> 8 )
1108#define GET_BH() ( BX >> 8 )
1109#define GET_CH() ( CX >> 8 )
1110#define GET_DH() ( DX >> 8 )
1111
1112#define GET_ELDL() ( ELDX & 0x00ff )
1113#define GET_ELDH() ( ELDX >> 8 )
1114
1115#define SET_CF() FLAGS |= 0x0001
1116#define CLEAR_CF() FLAGS &= 0xfffe
1117#define GET_CF() (FLAGS & 0x0001)
1118
1119#define SET_ZF() FLAGS |= 0x0040
1120#define CLEAR_ZF() FLAGS &= 0xffbf
1121#define GET_ZF() (FLAGS & 0x0040)
1122
1123#define UNSUPPORTED_FUNCTION 0x86
1124
1125#define none 0
1126#define MAX_SCAN_CODE 0x58
1127
1128static struct {
1129 Bit16u normal;
1130 Bit16u shift;
1131 Bit16u control;
1132 Bit16u alt;
1133 Bit8u lock_flags;
1134 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1135 { none, none, none, none, none },
1136 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1137 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1138 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1139 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1140 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1141 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1142 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1143 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1144 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1145 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1146 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1147 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1148 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1149 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1150 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1151 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1152 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1153 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1154 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1155 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1156 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1157 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1158 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1159 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1160 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1161 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1162 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1163 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1164 { none, none, none, none, none }, /* L Ctrl */
1165 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1166 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1167 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1168 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1169 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1170 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1171 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1172 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1173 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1174 { 0x273b, 0x273a, none, none, none }, /* ;: */
1175 { 0x2827, 0x2822, none, none, none }, /* '" */
1176 { 0x2960, 0x297e, none, none, none }, /* `~ */
1177 { none, none, none, none, none }, /* L shift */
1178 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1179 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1180 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1181 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1182 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1183 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1184 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1185 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1186 { 0x332c, 0x333c, none, none, none }, /* ,< */
1187 { 0x342e, 0x343e, none, none, none }, /* .> */
1188 { 0x352f, 0x353f, none, none, none }, /* /? */
1189 { none, none, none, none, none }, /* R Shift */
1190 { 0x372a, 0x372a, none, none, none }, /* * */
1191 { none, none, none, none, none }, /* L Alt */
1192 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1193 { none, none, none, none, none }, /* caps lock */
1194 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1195 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1196 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1197 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1198 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1199 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1200 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1201 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1202 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1203 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1204 { none, none, none, none, none }, /* Num Lock */
1205 { none, none, none, none, none }, /* Scroll Lock */
1206 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1207 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1208 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1209 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1210 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1211 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1212 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1213 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1214 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1215 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1216 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1217 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1218 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1219 { none, none, none, none, none },
1220 { none, none, none, none, none },
1221 { 0x565c, 0x567c, none, none, none }, /* \| */
1222#ifndef VBOX
1223 { 0x5700, 0x5700, none, none, none }, /* F11 */
1224 { 0x5800, 0x5800, none, none, none } /* F12 */
1225#else
1226 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1227 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1228#endif
1229 };
1230
1231 Bit8u
1232inb(port)
1233 Bit16u port;
1234{
1235ASM_START
1236 push bp
1237 mov bp, sp
1238
1239 push dx
1240 mov dx, 4[bp]
1241 in al, dx
1242 pop dx
1243
1244 pop bp
1245ASM_END
1246}
1247
1248#if BX_USE_ATADRV
1249 Bit16u
1250inw(port)
1251 Bit16u port;
1252{
1253ASM_START
1254 push bp
1255 mov bp, sp
1256
1257 push dx
1258 mov dx, 4[bp]
1259 in ax, dx
1260 pop dx
1261
1262 pop bp
1263ASM_END
1264}
1265#endif
1266
1267 void
1268outb(port, val)
1269 Bit16u port;
1270 Bit8u val;
1271{
1272ASM_START
1273 push bp
1274 mov bp, sp
1275
1276 push ax
1277 push dx
1278 mov dx, 4[bp]
1279 mov al, 6[bp]
1280 out dx, al
1281 pop dx
1282 pop ax
1283
1284 pop bp
1285ASM_END
1286}
1287
1288#if BX_USE_ATADRV
1289 void
1290outw(port, val)
1291 Bit16u port;
1292 Bit16u val;
1293{
1294ASM_START
1295 push bp
1296 mov bp, sp
1297
1298 push ax
1299 push dx
1300 mov dx, 4[bp]
1301 mov ax, 6[bp]
1302 out dx, ax
1303 pop dx
1304 pop ax
1305
1306 pop bp
1307ASM_END
1308}
1309#endif
1310
1311 void
1312outb_cmos(cmos_reg, val)
1313 Bit8u cmos_reg;
1314 Bit8u val;
1315{
1316ASM_START
1317 push bp
1318 mov bp, sp
1319
1320 mov al, 4[bp] ;; cmos_reg
1321 out 0x70, al
1322 mov al, 6[bp] ;; val
1323 out 0x71, al
1324
1325 pop bp
1326ASM_END
1327}
1328
1329 Bit8u
1330inb_cmos(cmos_reg)
1331 Bit8u cmos_reg;
1332{
1333ASM_START
1334 push bp
1335 mov bp, sp
1336
1337 mov al, 4[bp] ;; cmos_reg
1338 out 0x70, al
1339 in al, 0x71
1340
1341 pop bp
1342ASM_END
1343}
1344
1345 void
1346init_rtc()
1347{
1348 outb_cmos(0x0a, 0x26);
1349 outb_cmos(0x0b, 0x02);
1350 inb_cmos(0x0c);
1351 inb_cmos(0x0d);
1352}
1353
1354 bx_bool
1355rtc_updating()
1356{
1357 // This function checks to see if the update-in-progress bit
1358 // is set in CMOS Status Register A. If not, it returns 0.
1359 // If it is set, it tries to wait until there is a transition
1360 // to 0, and will return 0 if such a transition occurs. A 1
1361 // is returned only after timing out. The maximum period
1362 // that this bit should be set is constrained to 244useconds.
1363 // The count I use below guarantees coverage or more than
1364 // this time, with any reasonable IPS setting.
1365
1366 Bit16u count;
1367
1368 count = 25000;
1369 while (--count != 0) {
1370 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1371 return(0);
1372 }
1373 return(1); // update-in-progress never transitioned to 0
1374}
1375
1376
1377 Bit8u
1378read_byte(seg, offset)
1379 Bit16u seg;
1380 Bit16u offset;
1381{
1382ASM_START
1383 push bp
1384 mov bp, sp
1385
1386 push bx
1387 push ds
1388 mov ax, 4[bp] ; segment
1389 mov ds, ax
1390 mov bx, 6[bp] ; offset
1391 mov al, [bx]
1392 ;; al = return value (byte)
1393 pop ds
1394 pop bx
1395
1396 pop bp
1397ASM_END
1398}
1399
1400 Bit16u
1401read_word(seg, offset)
1402 Bit16u seg;
1403 Bit16u offset;
1404{
1405ASM_START
1406 push bp
1407 mov bp, sp
1408
1409 push bx
1410 push ds
1411 mov ax, 4[bp] ; segment
1412 mov ds, ax
1413 mov bx, 6[bp] ; offset
1414 mov ax, [bx]
1415 ;; ax = return value (word)
1416 pop ds
1417 pop bx
1418
1419 pop bp
1420ASM_END
1421}
1422
1423 void
1424write_byte(seg, offset, data)
1425 Bit16u seg;
1426 Bit16u offset;
1427 Bit8u data;
1428{
1429ASM_START
1430 push bp
1431 mov bp, sp
1432
1433 push ax
1434 push bx
1435 push ds
1436 mov ax, 4[bp] ; segment
1437 mov ds, ax
1438 mov bx, 6[bp] ; offset
1439 mov al, 8[bp] ; data byte
1440 mov [bx], al ; write data byte
1441 pop ds
1442 pop bx
1443 pop ax
1444
1445 pop bp
1446ASM_END
1447}
1448
1449 void
1450write_word(seg, offset, data)
1451 Bit16u seg;
1452 Bit16u offset;
1453 Bit16u data;
1454{
1455ASM_START
1456 push bp
1457 mov bp, sp
1458
1459 push ax
1460 push bx
1461 push ds
1462 mov ax, 4[bp] ; segment
1463 mov ds, ax
1464 mov bx, 6[bp] ; offset
1465 mov ax, 8[bp] ; data word
1466 mov [bx], ax ; write data word
1467 pop ds
1468 pop bx
1469 pop ax
1470
1471 pop bp
1472ASM_END
1473}
1474
1475 Bit16u
1476get_CS()
1477{
1478ASM_START
1479 mov ax, cs
1480ASM_END
1481}
1482
1483 Bit16u
1484get_SS()
1485{
1486ASM_START
1487 mov ax, ss
1488ASM_END
1489}
1490
1491#if BX_DEBUG_SERIAL
1492/* serial debug port*/
1493#define BX_DEBUG_PORT 0x03f8
1494
1495/* data */
1496#define UART_RBR 0x00
1497#define UART_THR 0x00
1498
1499/* control */
1500#define UART_IER 0x01
1501#define UART_IIR 0x02
1502#define UART_FCR 0x02
1503#define UART_LCR 0x03
1504#define UART_MCR 0x04
1505#define UART_DLL 0x00
1506#define UART_DLM 0x01
1507
1508/* status */
1509#define UART_LSR 0x05
1510#define UART_MSR 0x06
1511#define UART_SCR 0x07
1512
1513int uart_can_tx_byte(base_port)
1514 Bit16u base_port;
1515{
1516 return inb(base_port + UART_LSR) & 0x20;
1517}
1518
1519void uart_wait_to_tx_byte(base_port)
1520 Bit16u base_port;
1521{
1522 while (!uart_can_tx_byte(base_port));
1523}
1524
1525void uart_wait_until_sent(base_port)
1526 Bit16u base_port;
1527{
1528 while (!(inb(base_port + UART_LSR) & 0x40));
1529}
1530
1531void uart_tx_byte(base_port, data)
1532 Bit16u base_port;
1533 Bit8u data;
1534{
1535 uart_wait_to_tx_byte(base_port);
1536 outb(base_port + UART_THR, data);
1537 uart_wait_until_sent(base_port);
1538}
1539#endif
1540
1541 void
1542wrch(c)
1543 Bit8u c;
1544{
1545 ASM_START
1546 push bp
1547 mov bp, sp
1548
1549 push bx
1550 mov ah, #0x0e
1551 mov al, 4[bp]
1552 xor bx,bx
1553 int #0x10
1554 pop bx
1555
1556 pop bp
1557 ASM_END
1558}
1559
1560 void
1561send(action, c)
1562 Bit16u action;
1563 Bit8u c;
1564{
1565#if BX_DEBUG_SERIAL
1566 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1567 uart_tx_byte(BX_DEBUG_PORT, c);
1568#endif
1569#if BX_VIRTUAL_PORTS
1570 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1571 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1572#endif
1573 if (action & BIOS_PRINTF_SCREEN) {
1574 if (c == '\n') wrch('\r');
1575 wrch(c);
1576 }
1577}
1578
1579 void
1580put_int(action, val, width, neg)
1581 Bit16u action;
1582 short val, width;
1583 bx_bool neg;
1584{
1585 short nval = val / 10;
1586 if (nval)
1587 put_int(action, nval, width - 1, neg);
1588 else {
1589 while (--width > 0) send(action, ' ');
1590 if (neg) send(action, '-');
1591 }
1592 send(action, val - (nval * 10) + '0');
1593}
1594
1595 void
1596put_uint(action, val, width, neg)
1597 Bit16u action;
1598 unsigned short val;
1599 short width;
1600 bx_bool neg;
1601{
1602 unsigned short nval = val / 10;
1603 if (nval)
1604 put_uint(action, nval, width - 1, neg);
1605 else {
1606 while (--width > 0) send(action, ' ');
1607 if (neg) send(action, '-');
1608 }
1609 send(action, val - (nval * 10) + '0');
1610}
1611
1612 void
1613put_luint(action, val, width, neg)
1614 Bit16u action;
1615 unsigned long val;
1616 short width;
1617 bx_bool neg;
1618{
1619 unsigned long nval = val / 10;
1620 if (nval)
1621 put_luint(action, nval, width - 1, neg);
1622 else {
1623 while (--width > 0) send(action, ' ');
1624 if (neg) send(action, '-');
1625 }
1626 send(action, val - (nval * 10) + '0');
1627}
1628
1629void put_str(action, segment, offset)
1630 Bit16u action;
1631 Bit16u segment;
1632 Bit16u offset;
1633{
1634 Bit8u c;
1635
1636 while (c = read_byte(segment, offset)) {
1637 send(action, c);
1638 offset++;
1639 }
1640}
1641
1642
1643//--------------------------------------------------------------------------
1644// bios_printf()
1645// A compact variable argument printf function.
1646//
1647// Supports %[format_width][length]format
1648// where format can be x,X,u,d,s,S,c
1649// and the optional length modifier is l (ell)
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, hexadd;
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' || c == 'X') {
1688 if (format_width == 0)
1689 format_width = 4;
1690 if (c == 'x')
1691 hexadd = 'a';
1692 else
1693 hexadd = 'A';
1694 for (i=format_width-1; i>=0; i--) {
1695 nibble = (arg >> (4 * i)) & 0x000f;
1696 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1697 }
1698 }
1699 else if (c == 'u') {
1700 put_uint(action, arg, format_width, 0);
1701 }
1702 else if (c == 'l') {
1703 s++;
1704 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1705 arg_ptr++; /* increment to next arg */
1706 hibyte = read_word(arg_seg, arg_ptr);
1707 if (c == 'd') {
1708 if (hibyte & 0x8000)
1709 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1710 else
1711 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1712 }
1713 else if (c == 'u') {
1714 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1715 }
1716 else if (c == 'x' || c == 'X')
1717 {
1718 if (format_width == 0)
1719 format_width = 8;
1720 if (c == 'x')
1721 hexadd = 'a';
1722 else
1723 hexadd = 'A';
1724 for (i=format_width-1; i>=0; i--) {
1725 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1726 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1727 }
1728 }
1729 }
1730 else if (c == 'd') {
1731 if (arg & 0x8000)
1732 put_int(action, -arg, format_width - 1, 1);
1733 else
1734 put_int(action, arg, format_width, 0);
1735 }
1736 else if (c == 's') {
1737 put_str(action, get_CS(), arg);
1738 }
1739 else if (c == 'S') {
1740 hibyte = arg;
1741 arg_ptr++;
1742 arg = read_word(arg_seg, arg_ptr);
1743 put_str(action, hibyte, arg);
1744 }
1745 else if (c == 'c') {
1746 send(action, arg);
1747 }
1748 else
1749 BX_PANIC("bios_printf: unknown format\n");
1750 in_format = 0;
1751 }
1752 }
1753 else {
1754 send(action, c);
1755 }
1756 s ++;
1757 }
1758
1759 if (action & BIOS_PRINTF_HALT) {
1760 // freeze in a busy loop.
1761ASM_START
1762 cli
1763 halt2_loop:
1764 hlt
1765 jmp halt2_loop
1766ASM_END
1767 }
1768}
1769
1770//--------------------------------------------------------------------------
1771// keyboard_init
1772//--------------------------------------------------------------------------
1773// this file is based on LinuxBIOS implementation of keyboard.c
1774// could convert to #asm to gain space
1775 void
1776keyboard_init()
1777{
1778 Bit16u max;
1779
1780 /* ------------------- Flush buffers ------------------------*/
1781 /* Wait until buffer is empty */
1782 max=0xffff;
1783 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1784
1785 /* flush incoming keys */
1786 max=0x2000;
1787 while (--max > 0) {
1788 outb(0x80, 0x00);
1789 if (inb(0x64) & 0x01) {
1790 inb(0x60);
1791 max = 0x2000;
1792 }
1793 }
1794
1795 // Due to timer issues, and if the IPS setting is > 15000000,
1796 // the incoming keys might not be flushed here. That will
1797 // cause a panic a few lines below. See sourceforge bug report :
1798 // [ 642031 ] FATAL: Keyboard RESET error:993
1799
1800 /* ------------------- controller side ----------------------*/
1801 /* send cmd = 0xAA, self test 8042 */
1802 outb(0x64, 0xaa);
1803
1804 /* Wait until buffer is empty */
1805 max=0xffff;
1806 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1807 if (max==0x0) keyboard_panic(00);
1808
1809 /* Wait for data */
1810 max=0xffff;
1811 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1812 if (max==0x0) keyboard_panic(01);
1813
1814 /* read self-test result, 0x55 should be returned from 0x60 */
1815 if ((inb(0x60) != 0x55)){
1816 keyboard_panic(991);
1817 }
1818
1819 /* send cmd = 0xAB, keyboard interface test */
1820 outb(0x64,0xab);
1821
1822 /* Wait until buffer is empty */
1823 max=0xffff;
1824 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1825 if (max==0x0) keyboard_panic(10);
1826
1827 /* Wait for data */
1828 max=0xffff;
1829 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1830 if (max==0x0) keyboard_panic(11);
1831
1832 /* read keyboard interface test result, */
1833 /* 0x00 should be returned form 0x60 */
1834 if ((inb(0x60) != 0x00)) {
1835 keyboard_panic(992);
1836 }
1837
1838 /* Enable Keyboard clock */
1839 outb(0x64,0xae);
1840 outb(0x64,0xa8);
1841
1842 /* ------------------- keyboard side ------------------------*/
1843 /* reset kerboard and self test (keyboard side) */
1844 outb(0x60, 0xff);
1845
1846 /* Wait until buffer is empty */
1847 max=0xffff;
1848 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1849 if (max==0x0) keyboard_panic(20);
1850
1851 /* Wait for data */
1852 max=0xffff;
1853 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1854 if (max==0x0) keyboard_panic(21);
1855
1856 /* keyboard should return ACK */
1857 if ((inb(0x60) != 0xfa)) {
1858 keyboard_panic(993);
1859 }
1860
1861 /* Wait for data */
1862 max=0xffff;
1863 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1864 if (max==0x0) keyboard_panic(31);
1865
1866 if ((inb(0x60) != 0xaa)) {
1867 keyboard_panic(994);
1868 }
1869
1870 /* Disable keyboard */
1871 outb(0x60, 0xf5);
1872
1873 /* Wait until buffer is empty */
1874 max=0xffff;
1875 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1876 if (max==0x0) keyboard_panic(40);
1877
1878 /* Wait for data */
1879 max=0xffff;
1880 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1881 if (max==0x0) keyboard_panic(41);
1882
1883 /* keyboard should return ACK */
1884 if ((inb(0x60) != 0xfa)) {
1885 keyboard_panic(995);
1886 }
1887
1888 /* Write Keyboard Mode */
1889 outb(0x64, 0x60);
1890
1891 /* Wait until buffer is empty */
1892 max=0xffff;
1893 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1894 if (max==0x0) keyboard_panic(50);
1895
1896 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1897 outb(0x60, 0x65);
1898
1899 /* Wait until buffer is empty */
1900 max=0xffff;
1901 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1902 if (max==0x0) keyboard_panic(60);
1903
1904 /* Enable keyboard */
1905 outb(0x60, 0xf4);
1906
1907 /* Wait until buffer is empty */
1908 max=0xffff;
1909 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1910 if (max==0x0) keyboard_panic(70);
1911
1912 /* Wait for data */
1913 max=0xffff;
1914 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1915 if (max==0x0) keyboard_panic(70);
1916
1917 /* keyboard should return ACK */
1918 if ((inb(0x60) != 0xfa)) {
1919 keyboard_panic(996);
1920 }
1921
1922 outb(0x80, 0x77);
1923}
1924
1925//--------------------------------------------------------------------------
1926// keyboard_panic
1927//--------------------------------------------------------------------------
1928 void
1929keyboard_panic(status)
1930 Bit16u status;
1931{
1932 // If you're getting a 993 keyboard panic here,
1933 // please see the comment in keyboard_init
1934
1935 BX_PANIC("Keyboard error:%u\n",status);
1936}
1937
1938//--------------------------------------------------------------------------
1939// shutdown_status_panic
1940// called when the shutdown statsu is not implemented, displays the status
1941//--------------------------------------------------------------------------
1942 void
1943shutdown_status_panic(status)
1944 Bit16u status;
1945{
1946 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1947}
1948
1949#ifdef VBOX
1950#include "logo.c"
1951#endif /* VBOX */
1952
1953//--------------------------------------------------------------------------
1954// print_bios_banner
1955// displays a the bios version
1956//--------------------------------------------------------------------------
1957void
1958print_bios_banner()
1959{
1960#ifdef VBOX
1961 // Skip the logo if a warm boot is requested.
1962 Bit16u warm_boot = read_word(0x0040,0x0072);
1963 write_word(0x0040,0x0072, 0);
1964 if (warm_boot == 0x1234)
1965 return;
1966#if !defined(DEBUG) || defined(DEBUG_sunlover)
1967 /* show graphical logo */
1968 show_logo();
1969#else
1970 /* set text mode */
1971 ASM_START
1972 mov ax, #0x0003
1973 int #0x10
1974 ASM_END
1975#endif /* !DEBUG */
1976#else /* !VBOX */
1977 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1978 BIOS_BUILD_DATE, bios_cvs_version_string);
1979 printf(
1980#if BX_APM
1981 "apmbios "
1982#endif
1983#if BX_PCIBIOS
1984 "pcibios "
1985#endif
1986#if BX_ELTORITO_BOOT
1987 "eltorito "
1988#endif
1989#if BX_ROMBIOS32
1990 "rombios32 "
1991#endif
1992 "\n\n");
1993#endif /* VBOX */
1994}
1995
1996//--------------------------------------------------------------------------
1997// print_boot_device
1998// displays the boot device
1999//--------------------------------------------------------------------------
2000
2001#ifdef VBOX
2002static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
2003#else /* !VBOX */
2004static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
2005#endif /* !VBOX */
2006
2007#ifdef VBOX
2008void
2009print_boot_device(cdboot, lanboot, drive)
2010 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2011#else /* !VBOX */
2012void
2013print_boot_device(cdboot, drive)
2014 Bit8u cdboot; Bit16u drive;
2015#endif /* !VBOX */
2016{
2017 Bit8u i;
2018
2019#ifdef VBOX
2020 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2021 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2022#else /* !VBOX */
2023 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2024#endif /* !VBOX */
2025 // drive contains real/emulated boot drive
2026
2027 if(cdboot)i=2; // CD-Rom
2028#ifdef VBOX
2029 else if(lanboot)i=3; // LAN
2030#endif /* VBOX */
2031 else if((drive&0x0080)==0x00)i=0; // Floppy
2032 else if((drive&0x0080)==0x80)i=1; // Hard drive
2033 else return;
2034
2035#ifdef VBOX
2036 BX_INFO("Booting from %s...\n",drivetypes[i]);
2037#else /* !VBOX */
2038 printf("Booting from %s...\n",drivetypes[i]);
2039#endif /* !VBOX */
2040}
2041
2042//--------------------------------------------------------------------------
2043// print_boot_failure
2044// displays the reason why boot failed
2045//--------------------------------------------------------------------------
2046#ifdef VBOX
2047 void
2048print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2049 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2050#else /* !VBOX */
2051 void
2052print_boot_failure(cdboot, drive, reason, lastdrive)
2053 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2054#endif /* !VBOX */
2055{
2056 Bit16u drivenum = drive&0x7f;
2057
2058 // cdboot: 1 if boot from cd, 0 otherwise
2059#ifdef VBOX
2060 // lanboot: 1 if boot from lan, 0 otherwise
2061#endif /* VBOX */
2062 // drive : drive number
2063 // reason: 0 signature check failed, 1 read error
2064 // lastdrive: 1 boot drive is the last one in boot sequence
2065
2066 if (cdboot)
2067#ifndef VBOX
2068 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2069#else /* VBOX */
2070 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2071 else if (lanboot)
2072 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2073#endif /* VBOX */
2074 else if (drive & 0x80)
2075#ifndef VBOX
2076 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2077#else /* VBOX */
2078 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2079#endif /* VBOX */
2080 else
2081#ifndef VBOX
2082 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2083#else /* VBOX */
2084 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2085#endif /* VBOX */
2086
2087 if (lastdrive==1) {
2088 if (reason==0)
2089#ifndef VBOX
2090 BX_PANIC("Not a bootable disk\n");
2091#else /* VBOX */
2092 BX_PANIC("No bootable medium found! System halted.\n");
2093#endif /* VBOX */
2094 else
2095#ifndef VBOX
2096 BX_PANIC("Could not read the boot disk\n");
2097#else /* VBOX */
2098 BX_PANIC("Could not read from the boot medium! System halted.\n");
2099#endif /* VBOX */
2100 }
2101}
2102
2103//--------------------------------------------------------------------------
2104// print_cdromboot_failure
2105// displays the reason why boot failed
2106//--------------------------------------------------------------------------
2107 void
2108print_cdromboot_failure( code )
2109 Bit16u code;
2110{
2111#ifndef VBOX
2112 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2113#else /* VBOX */
2114 BX_INFO("CDROM boot failure code : %04x\n",code);
2115#endif /* VBOX */
2116
2117 return;
2118}
2119
2120void
2121nmi_handler_msg()
2122{
2123 BX_PANIC("NMI Handler called\n");
2124}
2125
2126void
2127int18_panic_msg()
2128{
2129 BX_PANIC("INT18: BOOT FAILURE\n");
2130}
2131
2132void
2133log_bios_start()
2134{
2135#if BX_DEBUG_SERIAL
2136 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2137#endif
2138 BX_INFO("%s\n", bios_cvs_version_string);
2139}
2140
2141 bx_bool
2142set_enable_a20(val)
2143 bx_bool val;
2144{
2145 Bit8u oldval;
2146
2147 // Use PS2 System Control port A to set A20 enable
2148
2149 // get current setting first
2150 oldval = inb(0x92);
2151
2152 // change A20 status
2153 if (val)
2154 outb(0x92, oldval | 0x02);
2155 else
2156 outb(0x92, oldval & 0xfd);
2157
2158 return((oldval & 0x02) != 0);
2159}
2160
2161 void
2162debugger_on()
2163{
2164 outb(0xfedc, 0x01);
2165}
2166
2167 void
2168debugger_off()
2169{
2170 outb(0xfedc, 0x00);
2171}
2172
2173#if BX_USE_ATADRV
2174
2175// ---------------------------------------------------------------------------
2176// Start of ATA/ATAPI Driver
2177// ---------------------------------------------------------------------------
2178
2179// Global defines -- ATA register and register bits.
2180// command block & control block regs
2181#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2182#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2183#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2184#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2185#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2186#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2187#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2188#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2189#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2190#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2191#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2192#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2193#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2194
2195#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2196#define ATA_CB_ER_BBK 0x80 // ATA bad block
2197#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2198#define ATA_CB_ER_MC 0x20 // ATA media change
2199#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2200#define ATA_CB_ER_MCR 0x08 // ATA media change request
2201#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2202#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2203#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2204
2205#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2206#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2207#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2208#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2209#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2210
2211// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2212#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2213#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2214#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2215#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2216
2217// bits 7-4 of the device/head (CB_DH) reg
2218#define ATA_CB_DH_DEV0 0xa0 // select device 0
2219#define ATA_CB_DH_DEV1 0xb0 // select device 1
2220
2221// status reg (CB_STAT and CB_ASTAT) bits
2222#define ATA_CB_STAT_BSY 0x80 // busy
2223#define ATA_CB_STAT_RDY 0x40 // ready
2224#define ATA_CB_STAT_DF 0x20 // device fault
2225#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2226#define ATA_CB_STAT_SKC 0x10 // seek complete
2227#define ATA_CB_STAT_SERV 0x10 // service
2228#define ATA_CB_STAT_DRQ 0x08 // data request
2229#define ATA_CB_STAT_CORR 0x04 // corrected
2230#define ATA_CB_STAT_IDX 0x02 // index
2231#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2232#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2233
2234// device control reg (CB_DC) bits
2235#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2236#define ATA_CB_DC_SRST 0x04 // soft reset
2237#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2238
2239// Most mandtory and optional ATA commands (from ATA-3),
2240#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2241#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2242#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2243#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2244#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2245#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2246#define ATA_CMD_CHECK_POWER_MODE2 0x98
2247#define ATA_CMD_DEVICE_RESET 0x08
2248#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2249#define ATA_CMD_FLUSH_CACHE 0xE7
2250#define ATA_CMD_FORMAT_TRACK 0x50
2251#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2252#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2253#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2254#define ATA_CMD_IDLE1 0xE3
2255#define ATA_CMD_IDLE2 0x97
2256#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2257#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2258#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2259#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2260#define ATA_CMD_NOP 0x00
2261#define ATA_CMD_PACKET 0xA0
2262#define ATA_CMD_READ_BUFFER 0xE4
2263#define ATA_CMD_READ_DMA 0xC8
2264#define ATA_CMD_READ_DMA_QUEUED 0xC7
2265#define ATA_CMD_READ_MULTIPLE 0xC4
2266#define ATA_CMD_READ_SECTORS 0x20
2267#ifdef VBOX
2268#define ATA_CMD_READ_SECTORS_EXT 0x24
2269#endif /* VBOX */
2270#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2271#define ATA_CMD_RECALIBRATE 0x10
2272#define ATA_CMD_SEEK 0x70
2273#define ATA_CMD_SET_FEATURES 0xEF
2274#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2275#define ATA_CMD_SLEEP1 0xE6
2276#define ATA_CMD_SLEEP2 0x99
2277#define ATA_CMD_STANDBY1 0xE2
2278#define ATA_CMD_STANDBY2 0x96
2279#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2280#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2281#define ATA_CMD_WRITE_BUFFER 0xE8
2282#define ATA_CMD_WRITE_DMA 0xCA
2283#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2284#define ATA_CMD_WRITE_MULTIPLE 0xC5
2285#define ATA_CMD_WRITE_SECTORS 0x30
2286#ifdef VBOX
2287#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2288#endif /* VBOX */
2289#define ATA_CMD_WRITE_VERIFY 0x3C
2290
2291#define ATA_IFACE_NONE 0x00
2292#define ATA_IFACE_ISA 0x00
2293#define ATA_IFACE_PCI 0x01
2294
2295#define ATA_TYPE_NONE 0x00
2296#define ATA_TYPE_UNKNOWN 0x01
2297#define ATA_TYPE_ATA 0x02
2298#define ATA_TYPE_ATAPI 0x03
2299#ifdef VBOX
2300#define ATA_TYPE_SCSI 0x04 // SCSI disk
2301#endif
2302
2303#define ATA_DEVICE_NONE 0x00
2304#define ATA_DEVICE_HD 0xFF
2305#define ATA_DEVICE_CDROM 0x05
2306
2307#define ATA_MODE_NONE 0x00
2308#define ATA_MODE_PIO16 0x00
2309#define ATA_MODE_PIO32 0x01
2310#define ATA_MODE_ISADMA 0x02
2311#define ATA_MODE_PCIDMA 0x03
2312#define ATA_MODE_USEIRQ 0x10
2313
2314#define ATA_TRANSLATION_NONE 0
2315#define ATA_TRANSLATION_LBA 1
2316#define ATA_TRANSLATION_LARGE 2
2317#define ATA_TRANSLATION_RECHS 3
2318
2319#define ATA_DATA_NO 0x00
2320#define ATA_DATA_IN 0x01
2321#define ATA_DATA_OUT 0x02
2322
2323// ---------------------------------------------------------------------------
2324// ATA/ATAPI driver : initialization
2325// ---------------------------------------------------------------------------
2326void ata_init( )
2327{
2328 Bit16u ebda_seg=read_word(0x0040,0x000E);
2329 Bit8u channel, device;
2330
2331 // Channels info init.
2332 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2333 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2334 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2335 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2336 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2337 }
2338
2339 // Devices info init.
2340 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2341 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2342 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2343 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2344 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2345 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2346 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2347 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2348 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2349 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2350 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2351 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2352 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2353 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2354
2355 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2356 }
2357
2358 // hdidmap and cdidmap init.
2359 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2360 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2361 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2362 }
2363
2364 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2365 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2366}
2367
2368// ---------------------------------------------------------------------------
2369// ATA/ATAPI driver : device detection
2370// ---------------------------------------------------------------------------
2371
2372void ata_detect( )
2373{
2374 Bit16u ebda_seg=read_word(0x0040,0x000E);
2375 Bit8u hdcount, cdcount, device, type;
2376 Bit8u buffer[0x0200];
2377
2378#if BX_MAX_ATA_INTERFACES > 0
2379 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2380 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2381 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2382 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2383#endif
2384#if BX_MAX_ATA_INTERFACES > 1
2385 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2386 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2387 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2388 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2389#endif
2390#if BX_MAX_ATA_INTERFACES > 2
2391 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2392 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2393 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2394 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2395#endif
2396#if BX_MAX_ATA_INTERFACES > 3
2397 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2398 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2399 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2400 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2401#endif
2402#if BX_MAX_ATA_INTERFACES > 4
2403#error Please fill the ATA interface informations
2404#endif
2405
2406 // Device detection
2407 hdcount=cdcount=0;
2408
2409 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2410 Bit16u iobase1, iobase2;
2411 Bit8u channel, slave, shift;
2412 Bit8u sc, sn, cl, ch, st;
2413
2414 channel = device / 2;
2415 slave = device % 2;
2416
2417 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2418 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2419
2420 // Disable interrupts
2421 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2422
2423 // Look for device
2424 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2425 outb(iobase1+ATA_CB_SC, 0x55);
2426 outb(iobase1+ATA_CB_SN, 0xaa);
2427 outb(iobase1+ATA_CB_SC, 0xaa);
2428 outb(iobase1+ATA_CB_SN, 0x55);
2429 outb(iobase1+ATA_CB_SC, 0x55);
2430 outb(iobase1+ATA_CB_SN, 0xaa);
2431
2432 // If we found something
2433 sc = inb(iobase1+ATA_CB_SC);
2434 sn = inb(iobase1+ATA_CB_SN);
2435
2436 if ( (sc == 0x55) && (sn == 0xaa) ) {
2437 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2438
2439 // reset the channel
2440 ata_reset(device);
2441
2442 // check for ATA or ATAPI
2443 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2444 sc = inb(iobase1+ATA_CB_SC);
2445 sn = inb(iobase1+ATA_CB_SN);
2446 if ((sc==0x01) && (sn==0x01)) {
2447 cl = inb(iobase1+ATA_CB_CL);
2448 ch = inb(iobase1+ATA_CB_CH);
2449 st = inb(iobase1+ATA_CB_STAT);
2450
2451 if ((cl==0x14) && (ch==0xeb)) {
2452 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2453 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2454 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2455 } else if ((cl==0xff) && (ch==0xff)) {
2456 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2457 }
2458 }
2459 }
2460
2461#ifdef VBOX
2462 // Enable interrupts
2463 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2464#endif /* VBOX */
2465
2466 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2467
2468 // Now we send a IDENTIFY command to ATA device
2469 if(type == ATA_TYPE_ATA) {
2470 Bit32u sectors;
2471 Bit16u cylinders, heads, spt, blksize;
2472#ifdef VBOX
2473 Bit16u lcylinders, lheads, lspt;
2474 Bit8u chsgeo_base;
2475#endif /* VBOX */
2476 Bit8u translation, removable, mode;
2477
2478 //Temporary values to do the transfer
2479 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2480 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2481
2482 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2483 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2484
2485 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2486 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2487#ifdef VBOX
2488 blksize = 512; /* There is no sector size field any more. */
2489#else /* !VBOX */
2490 blksize = read_word(get_SS(),buffer+10);
2491#endif /* !VBOX */
2492
2493 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2494 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2495 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2496
2497 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2498#ifdef VBOX
2499 /** @todo update sectors to be a 64 bit number (also lba...). */
2500 if (sectors == 268435455)
2501 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2502 switch (device)
2503 {
2504 case 0:
2505 chsgeo_base = 0x1e;
2506 break;
2507 case 1:
2508 chsgeo_base = 0x26;
2509 break;
2510 case 2:
2511 chsgeo_base = 0x67;
2512 break;
2513 case 3:
2514 chsgeo_base = 0x70;
2515 break;
2516 case 4:
2517 chsgeo_base = 0x40;
2518 break;
2519 case 5:
2520 chsgeo_base = 0x48;
2521 break;
2522 case 6:
2523 chsgeo_base = 0x50;
2524 break;
2525 case 7:
2526 chsgeo_base = 0x58;
2527 break;
2528 default:
2529 chsgeo_base = 0;
2530 }
2531 if (chsgeo_base != 0)
2532 {
2533 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2534 lheads = inb_cmos(chsgeo_base+2);
2535 lspt = inb_cmos(chsgeo_base+7);
2536 }
2537 else
2538 {
2539 lcylinders = 0;
2540 lheads = 0;
2541 lspt = 0;
2542 }
2543 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2544#endif /* VBOX */
2545
2546 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2547 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2548 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2551 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2552 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2553 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2554#ifdef VBOX
2555 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2556 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2557 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2558 if (device < 2)
2559 {
2560 Bit8u sum, i;
2561 unsigned char *fdpt;
2562 if (device == 0)
2563 fdpt = &EbdaData->fdpt0;
2564 else
2565 fdpt = &EbdaData->fdpt1;
2566
2567 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2568 * to be done at POST time with lots of ugly assembler code, which
2569 * isn't worth the effort of converting from AMI to Award CMOS
2570 * format. Just do it here. */
2571 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2572 write_byte(ebda_seg, fdpt + 0x02, lheads);
2573 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2574 write_word(ebda_seg, fdpt + 0x09, cylinders);
2575 write_byte(ebda_seg, fdpt + 0x0b, heads);
2576 write_byte(ebda_seg, fdpt + 0x04, spt);
2577 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2578 sum = 0;
2579 for (i = 0; i < 0xf; i++)
2580 sum += read_byte(ebda_seg, fdpt + i);
2581 sum = 1 - sum;
2582 write_byte(ebda_seg, fdpt + 0x0f, sum);
2583 }
2584#else /* !VBOX */
2585 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2586
2587 translation = inb_cmos(0x39 + channel/2);
2588 for (shift=device%4; shift>0; shift--) translation >>= 2;
2589 translation &= 0x03;
2590
2591 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2592
2593 switch (translation) {
2594 case ATA_TRANSLATION_NONE:
2595 BX_INFO("none");
2596 break;
2597 case ATA_TRANSLATION_LBA:
2598 BX_INFO("lba");
2599 break;
2600 case ATA_TRANSLATION_LARGE:
2601 BX_INFO("large");
2602 break;
2603 case ATA_TRANSLATION_RECHS:
2604 BX_INFO("r-echs");
2605 break;
2606 }
2607 switch (translation) {
2608 case ATA_TRANSLATION_NONE:
2609 break;
2610 case ATA_TRANSLATION_LBA:
2611 spt = 63;
2612 sectors /= 63;
2613 heads = sectors / 1024;
2614 if (heads>128) heads = 255;
2615 else if (heads>64) heads = 128;
2616 else if (heads>32) heads = 64;
2617 else if (heads>16) heads = 32;
2618 else heads=16;
2619 cylinders = sectors / heads;
2620 break;
2621 case ATA_TRANSLATION_RECHS:
2622 // Take care not to overflow
2623 if (heads==16) {
2624 if(cylinders>61439) cylinders=61439;
2625 heads=15;
2626 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2627 }
2628 // then go through the large bitshift process
2629 case ATA_TRANSLATION_LARGE:
2630 while(cylinders > 1024) {
2631 cylinders >>= 1;
2632 heads <<= 1;
2633
2634 // If we max out the head count
2635 if (heads > 127) break;
2636 }
2637 break;
2638 }
2639 // clip to 1024 cylinders in lchs
2640 if (cylinders > 1024) cylinders=1024;
2641 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2642
2643 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2644 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2645 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2646#endif /* VBOX */
2647
2648 // fill hdidmap
2649 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2650 hdcount++;
2651 }
2652
2653 // Now we send a IDENTIFY command to ATAPI device
2654 if(type == ATA_TYPE_ATAPI) {
2655
2656 Bit8u type, removable, mode;
2657 Bit16u blksize;
2658
2659 //Temporary values to do the transfer
2660 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2661 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2662
2663 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2664 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2665
2666 type = read_byte(get_SS(),buffer+1) & 0x1f;
2667 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2668 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2669 blksize = 2048;
2670
2671 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2672 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2673 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2674 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2675
2676 // fill cdidmap
2677 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2678 cdcount++;
2679 }
2680
2681 {
2682 Bit32u sizeinmb;
2683 Bit16u ataversion;
2684 Bit8u c, i, version, model[41];
2685
2686 switch (type) {
2687 case ATA_TYPE_ATA:
2688 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2689 sizeinmb >>= 11;
2690 case ATA_TYPE_ATAPI:
2691 // Read ATA/ATAPI version
2692 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2693 for(version=15;version>0;version--) {
2694 if((ataversion&(1<<version))!=0)
2695 break;
2696 }
2697
2698 // Read model name
2699 for(i=0;i<20;i++){
2700 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2701 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2702 }
2703
2704 // Reformat
2705 write_byte(get_SS(),model+40,0x00);
2706 for(i=39;i>0;i--){
2707 if(read_byte(get_SS(),model+i)==0x20)
2708 write_byte(get_SS(),model+i,0x00);
2709 else break;
2710 }
2711 break;
2712 }
2713
2714#ifdef VBOX
2715 // we don't want any noisy output for now
2716#else /* !VBOX */
2717 switch (type) {
2718 case ATA_TYPE_ATA:
2719 printf("ata%d %s: ",channel,slave?" slave":"master");
2720 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2721 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2722 break;
2723 case ATA_TYPE_ATAPI:
2724 printf("ata%d %s: ",channel,slave?" slave":"master");
2725 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2726 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2727 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2728 else
2729 printf(" ATAPI-%d Device\n",version);
2730 break;
2731 case ATA_TYPE_UNKNOWN:
2732 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2733 break;
2734 }
2735#endif /* !VBOX */
2736 }
2737 }
2738
2739 // Store the devices counts
2740 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2741 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2742 write_byte(0x40,0x75, hdcount);
2743
2744#ifdef VBOX
2745 // we don't want any noisy output for now
2746#else /* !VBOX */
2747 printf("\n");
2748#endif /* !VBOX */
2749
2750 // FIXME : should use bios=cmos|auto|disable bits
2751 // FIXME : should know about translation bits
2752 // FIXME : move hard_drive_post here
2753
2754}
2755
2756// ---------------------------------------------------------------------------
2757// ATA/ATAPI driver : software reset
2758// ---------------------------------------------------------------------------
2759// ATA-3
2760// 8.2.1 Software reset - Device 0
2761
2762void ata_reset(device)
2763Bit16u device;
2764{
2765 Bit16u ebda_seg=read_word(0x0040,0x000E);
2766 Bit16u iobase1, iobase2;
2767 Bit8u channel, slave, sn, sc;
2768 Bit16u max;
2769#ifdef VBOX
2770 Bit16u pdelay;
2771#endif /* VBOX */
2772
2773 channel = device / 2;
2774 slave = device % 2;
2775
2776 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2777 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2778
2779 // Reset
2780
2781// 8.2.1 (a) -- set SRST in DC
2782 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2783
2784// 8.2.1 (b) -- wait for BSY
2785 max=0xff;
2786 while(--max>0) {
2787 Bit8u status = inb(iobase1+ATA_CB_STAT);
2788 if ((status & ATA_CB_STAT_BSY) != 0) break;
2789 }
2790
2791// 8.2.1 (f) -- clear SRST
2792 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2793
2794 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2795
2796// 8.2.1 (g) -- check for sc==sn==0x01
2797 // select device
2798 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2799 sc = inb(iobase1+ATA_CB_SC);
2800 sn = inb(iobase1+ATA_CB_SN);
2801
2802 if ( (sc==0x01) && (sn==0x01) ) {
2803
2804// 8.2.1 (h) -- wait for not BSY
2805#ifdef VBOX
2806 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2807#else /* !VBOX */
2808 max=0xff;
2809#endif /* !VBOX */
2810 while(--max>0) {
2811 Bit8u status = inb(iobase1+ATA_CB_STAT);
2812 if ((status & ATA_CB_STAT_BSY) == 0) break;
2813#ifdef VBOX
2814 pdelay=0xffff;
2815 while (--pdelay>0) {
2816 /* nothing */
2817 }
2818#endif /* VBOX */
2819 }
2820 }
2821 }
2822
2823// 8.2.1 (i) -- wait for DRDY
2824#ifdef VBOX
2825 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2826#else /* !VBOX */
2827 max=0xfff;
2828#endif /* !VBOX */
2829 while(--max>0) {
2830 Bit8u status = inb(iobase1+ATA_CB_STAT);
2831 if ((status & ATA_CB_STAT_RDY) != 0) break;
2832 }
2833
2834 // Enable interrupts
2835 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2836}
2837
2838// ---------------------------------------------------------------------------
2839// ATA/ATAPI driver : execute a non data command
2840// ---------------------------------------------------------------------------
2841
2842Bit16u ata_cmd_non_data()
2843{return 0;}
2844
2845// ---------------------------------------------------------------------------
2846// ATA/ATAPI driver : execute a data-in command
2847// ---------------------------------------------------------------------------
2848 // returns
2849 // 0 : no error
2850 // 1 : BUSY bit set
2851 // 2 : read error
2852 // 3 : expected DRQ=1
2853 // 4 : no sectors left to read/verify
2854 // 5 : more sectors to read/verify
2855 // 6 : no sectors left to write
2856 // 7 : more sectors to write
2857Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2858Bit16u device, command, count, cylinder, head, sector, segment, offset;
2859Bit32u lba;
2860{
2861 Bit16u ebda_seg=read_word(0x0040,0x000E);
2862 Bit16u iobase1, iobase2, blksize;
2863 Bit8u channel, slave;
2864 Bit8u status, current, mode;
2865
2866 channel = device / 2;
2867 slave = device % 2;
2868
2869 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2870 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2871 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2872 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2873 if (mode == ATA_MODE_PIO32) blksize>>=2;
2874 else blksize>>=1;
2875
2876#ifdef VBOX
2877 status = inb(iobase1 + ATA_CB_STAT);
2878 if (status & ATA_CB_STAT_BSY)
2879 {
2880 // Enable interrupts
2881 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2882 return 1;
2883 }
2884#endif /* VBOX */
2885
2886 // sector will be 0 only on lba access. Convert to lba-chs
2887 if (sector == 0) {
2888#ifdef VBOX
2889 if (count >= 256 || lba + count >= 268435456)
2890 {
2891 sector = (lba & 0xff000000L) >> 24;
2892 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2893 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2894 outb(iobase1 + ATA_CB_SN, sector);
2895 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2896 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2897 /* Leave the bottom 24 bits as is, they are treated correctly by the
2898 * LBA28 code path. */
2899 lba &= 0xffffff;
2900 }
2901#endif /* VBOX */
2902 sector = (Bit16u) (lba & 0x000000ffL);
2903 lba >>= 8;
2904 cylinder = (Bit16u) (lba & 0x0000ffffL);
2905 lba >>= 16;
2906 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2907 }
2908
2909 // Reset count of transferred data
2910 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2911 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2912 current = 0;
2913
2914#ifndef VBOX
2915 status = inb(iobase1 + ATA_CB_STAT);
2916 if (status & ATA_CB_STAT_BSY) return 1;
2917#endif /* !VBOX */
2918
2919 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2920 outb(iobase1 + ATA_CB_FR, 0x00);
2921 outb(iobase1 + ATA_CB_SC, count);
2922 outb(iobase1 + ATA_CB_SN, sector);
2923 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2924 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2925 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2926 outb(iobase1 + ATA_CB_CMD, command);
2927
2928 while (1) {
2929 status = inb(iobase1 + ATA_CB_STAT);
2930 if ( !(status & ATA_CB_STAT_BSY) ) break;
2931 }
2932
2933 if (status & ATA_CB_STAT_ERR) {
2934 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2935#ifdef VBOX
2936 // Enable interrupts
2937 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2938#endif /* VBOX */
2939 return 2;
2940 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2941 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2942#ifdef VBOX
2943 // Enable interrupts
2944 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2945#endif /* VBOX */
2946 return 3;
2947 }
2948
2949 // FIXME : move seg/off translation here
2950
2951ASM_START
2952 sti ;; enable higher priority interrupts
2953ASM_END
2954
2955 while (1) {
2956
2957ASM_START
2958 push bp
2959 mov bp, sp
2960 mov di, _ata_cmd_data_in.offset + 2[bp]
2961 mov ax, _ata_cmd_data_in.segment + 2[bp]
2962 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2963
2964 ;; adjust if there will be an overrun. 2K max sector size
2965 cmp di, #0xf800 ;;
2966 jbe ata_in_no_adjust
2967
2968ata_in_adjust:
2969 sub di, #0x0800 ;; sub 2 kbytes from offset
2970 add ax, #0x0080 ;; add 2 Kbytes to segment
2971
2972ata_in_no_adjust:
2973 mov es, ax ;; segment in es
2974
2975 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2976
2977 mov ah, _ata_cmd_data_in.mode + 2[bp]
2978 cmp ah, #ATA_MODE_PIO32
2979 je ata_in_32
2980
2981ata_in_16:
2982 rep
2983 insw ;; CX words transfered from port(DX) to ES:[DI]
2984 jmp ata_in_done
2985
2986ata_in_32:
2987 rep
2988 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2989
2990ata_in_done:
2991 mov _ata_cmd_data_in.offset + 2[bp], di
2992 mov _ata_cmd_data_in.segment + 2[bp], es
2993 pop bp
2994ASM_END
2995
2996 current++;
2997 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2998 count--;
2999#ifdef VBOX
3000 while (1) {
3001 status = inb(iobase1 + ATA_CB_STAT);
3002 if ( !(status & ATA_CB_STAT_BSY) ) break;
3003 }
3004#else /* !VBOX */
3005 status = inb(iobase1 + ATA_CB_STAT);
3006#endif /* !VBOX */
3007 if (count == 0) {
3008 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3009 != ATA_CB_STAT_RDY ) {
3010 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3011#ifdef VBOX
3012 // Enable interrupts
3013 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3014#endif /* VBOX */
3015 return 4;
3016 }
3017 break;
3018 }
3019 else {
3020 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3021 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3022 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3023#ifdef VBOX
3024 // Enable interrupts
3025 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3026#endif /* VBOX */
3027 return 5;
3028 }
3029 continue;
3030 }
3031 }
3032 // Enable interrupts
3033 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3034 return 0;
3035}
3036
3037// ---------------------------------------------------------------------------
3038// ATA/ATAPI driver : execute a data-out command
3039// ---------------------------------------------------------------------------
3040 // returns
3041 // 0 : no error
3042 // 1 : BUSY bit set
3043 // 2 : read error
3044 // 3 : expected DRQ=1
3045 // 4 : no sectors left to read/verify
3046 // 5 : more sectors to read/verify
3047 // 6 : no sectors left to write
3048 // 7 : more sectors to write
3049Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3050Bit16u device, command, count, cylinder, head, sector, segment, offset;
3051Bit32u lba;
3052{
3053 Bit16u ebda_seg=read_word(0x0040,0x000E);
3054 Bit16u iobase1, iobase2, blksize;
3055 Bit8u channel, slave;
3056 Bit8u status, current, mode;
3057
3058 channel = device / 2;
3059 slave = device % 2;
3060
3061 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3062 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3063 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3064 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3065 if (mode == ATA_MODE_PIO32) blksize>>=2;
3066 else blksize>>=1;
3067
3068#ifdef VBOX
3069 status = inb(iobase1 + ATA_CB_STAT);
3070 if (status & ATA_CB_STAT_BSY)
3071 {
3072 // Enable interrupts
3073 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3074 return 1;
3075 }
3076#endif /* VBOX */
3077
3078 // sector will be 0 only on lba access. Convert to lba-chs
3079 if (sector == 0) {
3080#ifdef VBOX
3081 if (count >= 256 || lba + count >= 268435456)
3082 {
3083 sector = (lba & 0xff000000L) >> 24;
3084 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3085 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3086 outb(iobase1 + ATA_CB_SN, sector);
3087 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3088 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3089 /* Leave the bottom 24 bits as is, they are treated correctly by the
3090 * LBA28 code path. */
3091 lba &= 0xffffff;
3092 }
3093#endif /* VBOX */
3094 sector = (Bit16u) (lba & 0x000000ffL);
3095 lba >>= 8;
3096 cylinder = (Bit16u) (lba & 0x0000ffffL);
3097 lba >>= 16;
3098 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3099 }
3100
3101 // Reset count of transferred data
3102 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3103 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3104 current = 0;
3105
3106#ifndef VBOX
3107 status = inb(iobase1 + ATA_CB_STAT);
3108 if (status & ATA_CB_STAT_BSY) return 1;
3109#endif /* !VBOX */
3110
3111 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3112 outb(iobase1 + ATA_CB_FR, 0x00);
3113 outb(iobase1 + ATA_CB_SC, count);
3114 outb(iobase1 + ATA_CB_SN, sector);
3115 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3116 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3117 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3118 outb(iobase1 + ATA_CB_CMD, command);
3119
3120 while (1) {
3121 status = inb(iobase1 + ATA_CB_STAT);
3122 if ( !(status & ATA_CB_STAT_BSY) ) break;
3123 }
3124
3125 if (status & ATA_CB_STAT_ERR) {
3126 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3127#ifdef VBOX
3128 // Enable interrupts
3129 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3130#endif /* VBOX */
3131 return 2;
3132 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3133 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3134#ifdef VBOX
3135 // Enable interrupts
3136 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3137#endif /* VBOX */
3138 return 3;
3139 }
3140
3141 // FIXME : move seg/off translation here
3142
3143ASM_START
3144 sti ;; enable higher priority interrupts
3145ASM_END
3146
3147 while (1) {
3148
3149ASM_START
3150 push bp
3151 mov bp, sp
3152 mov si, _ata_cmd_data_out.offset + 2[bp]
3153 mov ax, _ata_cmd_data_out.segment + 2[bp]
3154 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3155
3156 ;; adjust if there will be an overrun. 2K max sector size
3157 cmp si, #0xf800 ;;
3158 jbe ata_out_no_adjust
3159
3160ata_out_adjust:
3161 sub si, #0x0800 ;; sub 2 kbytes from offset
3162 add ax, #0x0080 ;; add 2 Kbytes to segment
3163
3164ata_out_no_adjust:
3165 mov es, ax ;; segment in es
3166
3167 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3168
3169 mov ah, _ata_cmd_data_out.mode + 2[bp]
3170 cmp ah, #ATA_MODE_PIO32
3171 je ata_out_32
3172
3173ata_out_16:
3174 seg ES
3175 rep
3176 outsw ;; CX words transfered from port(DX) to ES:[SI]
3177 jmp ata_out_done
3178
3179ata_out_32:
3180 seg ES
3181 rep
3182 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3183
3184ata_out_done:
3185 mov _ata_cmd_data_out.offset + 2[bp], si
3186 mov _ata_cmd_data_out.segment + 2[bp], es
3187 pop bp
3188ASM_END
3189
3190 current++;
3191 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3192 count--;
3193#ifdef VBOX
3194 while (1) {
3195 status = inb(iobase1 + ATA_CB_STAT);
3196 if ( !(status & ATA_CB_STAT_BSY) ) break;
3197 }
3198#else /* !VBOX */
3199 status = inb(iobase1 + ATA_CB_STAT);
3200#endif /* VBOX */
3201 if (count == 0) {
3202 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3203 != ATA_CB_STAT_RDY ) {
3204 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3205#ifdef VBOX
3206 // Enable interrupts
3207 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3208#endif /* VBOX */
3209 return 6;
3210 }
3211 break;
3212 }
3213 else {
3214 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3215 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3216 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3217#ifdef VBOX
3218 // Enable interrupts
3219 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3220#endif /* VBOX */
3221 return 7;
3222 }
3223 continue;
3224 }
3225 }
3226 // Enable interrupts
3227 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3228 return 0;
3229}
3230
3231// ---------------------------------------------------------------------------
3232// ATA/ATAPI driver : execute a packet command
3233// ---------------------------------------------------------------------------
3234 // returns
3235 // 0 : no error
3236 // 1 : error in parameters
3237 // 2 : BUSY bit set
3238 // 3 : error
3239 // 4 : not ready
3240Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3241Bit8u cmdlen,inout;
3242Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3243Bit16u header;
3244Bit32u length;
3245{
3246 Bit16u ebda_seg=read_word(0x0040,0x000E);
3247 Bit16u iobase1, iobase2;
3248 Bit16u lcount, lbefore, lafter, count;
3249 Bit8u channel, slave;
3250 Bit8u status, mode, lmode;
3251 Bit32u total, transfer;
3252
3253 channel = device / 2;
3254 slave = device % 2;
3255
3256 // Data out is not supported yet
3257 if (inout == ATA_DATA_OUT) {
3258 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3259 return 1;
3260 }
3261
3262 // The header length must be even
3263 if (header & 1) {
3264 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3265 return 1;
3266 }
3267
3268 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3269 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3270 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3271 transfer= 0L;
3272
3273 if (cmdlen < 12) cmdlen=12;
3274 if (cmdlen > 12) cmdlen=16;
3275 cmdlen>>=1;
3276
3277 // Reset count of transferred data
3278 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3279 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3280
3281 status = inb(iobase1 + ATA_CB_STAT);
3282 if (status & ATA_CB_STAT_BSY) return 2;
3283
3284 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3285 // outb(iobase1 + ATA_CB_FR, 0x00);
3286 // outb(iobase1 + ATA_CB_SC, 0x00);
3287 // outb(iobase1 + ATA_CB_SN, 0x00);
3288 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3289 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3290 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3291 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3292
3293 // Device should ok to receive command
3294 while (1) {
3295 status = inb(iobase1 + ATA_CB_STAT);
3296 if ( !(status & ATA_CB_STAT_BSY) ) break;
3297 }
3298
3299 if (status & ATA_CB_STAT_ERR) {
3300 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3301#ifdef VBOX
3302 // Enable interrupts
3303 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3304#endif /* VBOX */
3305 return 3;
3306 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3307 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3308#ifdef VBOX
3309 // Enable interrupts
3310 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3311#endif /* VBOX */
3312 return 4;
3313 }
3314
3315 // Normalize address
3316 cmdseg += (cmdoff / 16);
3317 cmdoff %= 16;
3318
3319 // Send command to device
3320ASM_START
3321 sti ;; enable higher priority interrupts
3322
3323 push bp
3324 mov bp, sp
3325
3326 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3327 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3328 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3329 mov es, ax ;; segment in es
3330
3331 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3332
3333 seg ES
3334 rep
3335 outsw ;; CX words transfered from port(DX) to ES:[SI]
3336
3337 pop bp
3338ASM_END
3339
3340 if (inout == ATA_DATA_NO) {
3341 status = inb(iobase1 + ATA_CB_STAT);
3342 }
3343 else {
3344 while (1) {
3345
3346#ifdef VBOX
3347 while (1) {
3348 status = inb(iobase1 + ATA_CB_STAT);
3349 if ( !(status & ATA_CB_STAT_BSY) ) break;
3350 }
3351#else /* VBOX */
3352 status = inb(iobase1 + ATA_CB_STAT);
3353#endif /* VBOX */
3354
3355 // Check if command completed
3356 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3357
3358 if (status & ATA_CB_STAT_ERR) {
3359 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3360#ifdef VBOX
3361 // Enable interrupts
3362 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3363#endif /* VBOX */
3364 return 3;
3365 }
3366
3367 // Device must be ready to send data
3368 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3369 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3370 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3371#ifdef VBOX
3372 // Enable interrupts
3373 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3374#endif /* VBOX */
3375 return 4;
3376 }
3377
3378 // Normalize address
3379 bufseg += (bufoff / 16);
3380 bufoff %= 16;
3381
3382 // Get the byte count
3383 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3384
3385 // adjust to read what we want
3386 if(header>lcount) {
3387 lbefore=lcount;
3388 header-=lcount;
3389 lcount=0;
3390 }
3391 else {
3392 lbefore=header;
3393 header=0;
3394 lcount-=lbefore;
3395 }
3396
3397 if(lcount>length) {
3398 lafter=lcount-length;
3399 lcount=length;
3400 length=0;
3401 }
3402 else {
3403 lafter=0;
3404 length-=lcount;
3405 }
3406
3407 // Save byte count
3408 count = lcount;
3409
3410 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3411 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3412
3413 // If counts not dividable by 4, use 16bits mode
3414 lmode = mode;
3415 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3416 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3417 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3418
3419 // adds an extra byte if count are odd. before is always even
3420 if (lcount & 0x01) {
3421 lcount+=1;
3422 if ((lafter > 0) && (lafter & 0x01)) {
3423 lafter-=1;
3424 }
3425 }
3426
3427 if (lmode == ATA_MODE_PIO32) {
3428 lcount>>=2; lbefore>>=2; lafter>>=2;
3429 }
3430 else {
3431 lcount>>=1; lbefore>>=1; lafter>>=1;
3432 }
3433
3434 ; // FIXME bcc bug
3435
3436ASM_START
3437 push bp
3438 mov bp, sp
3439
3440 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3441
3442 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3443 jcxz ata_packet_no_before
3444
3445 mov ah, _ata_cmd_packet.lmode + 2[bp]
3446 cmp ah, #ATA_MODE_PIO32
3447 je ata_packet_in_before_32
3448
3449ata_packet_in_before_16:
3450 in ax, dx
3451 loop ata_packet_in_before_16
3452 jmp ata_packet_no_before
3453
3454ata_packet_in_before_32:
3455 push eax
3456ata_packet_in_before_32_loop:
3457 in eax, dx
3458 loop ata_packet_in_before_32_loop
3459 pop eax
3460
3461ata_packet_no_before:
3462 mov cx, _ata_cmd_packet.lcount + 2[bp]
3463 jcxz ata_packet_after
3464
3465 mov di, _ata_cmd_packet.bufoff + 2[bp]
3466 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3467 mov es, ax
3468
3469 mov ah, _ata_cmd_packet.lmode + 2[bp]
3470 cmp ah, #ATA_MODE_PIO32
3471 je ata_packet_in_32
3472
3473ata_packet_in_16:
3474 rep
3475 insw ;; CX words transfered tp port(DX) to ES:[DI]
3476 jmp ata_packet_after
3477
3478ata_packet_in_32:
3479 rep
3480 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3481
3482ata_packet_after:
3483 mov cx, _ata_cmd_packet.lafter + 2[bp]
3484 jcxz ata_packet_done
3485
3486 mov ah, _ata_cmd_packet.lmode + 2[bp]
3487 cmp ah, #ATA_MODE_PIO32
3488 je ata_packet_in_after_32
3489
3490ata_packet_in_after_16:
3491 in ax, dx
3492 loop ata_packet_in_after_16
3493 jmp ata_packet_done
3494
3495ata_packet_in_after_32:
3496 push eax
3497ata_packet_in_after_32_loop:
3498 in eax, dx
3499 loop ata_packet_in_after_32_loop
3500 pop eax
3501
3502ata_packet_done:
3503 pop bp
3504ASM_END
3505
3506 // Compute new buffer address
3507 bufoff += count;
3508
3509 // Save transferred bytes count
3510 transfer += count;
3511 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3512 }
3513 }
3514
3515 // Final check, device must be ready
3516 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3517 != ATA_CB_STAT_RDY ) {
3518 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3519#ifdef VBOX
3520 // Enable interrupts
3521 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3522#endif /* VBOX */
3523 return 4;
3524 }
3525
3526 // Enable interrupts
3527 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3528 return 0;
3529}
3530
3531// ---------------------------------------------------------------------------
3532// End of ATA/ATAPI Driver
3533// ---------------------------------------------------------------------------
3534
3535// ---------------------------------------------------------------------------
3536// Start of ATA/ATAPI generic functions
3537// ---------------------------------------------------------------------------
3538
3539 Bit16u
3540atapi_get_sense(device)
3541 Bit16u device;
3542{
3543 Bit8u atacmd[12];
3544 Bit8u buffer[16];
3545 Bit8u i;
3546
3547 memsetb(get_SS(),atacmd,0,12);
3548
3549 // Request SENSE
3550 atacmd[0]=0x03;
3551 atacmd[4]=0x20;
3552 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3553 return 0x0002;
3554
3555 if ((buffer[0] & 0x7e) == 0x70) {
3556 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3557 }
3558
3559 return 0;
3560}
3561
3562 Bit16u
3563atapi_is_ready(device)
3564 Bit16u device;
3565{
3566 Bit8u atacmd[12];
3567 Bit8u buffer[];
3568
3569 memsetb(get_SS(),atacmd,0,12);
3570
3571 // Test Unit Ready
3572 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3573 return 0x000f;
3574
3575 if (atapi_get_sense(device) !=0 ) {
3576 memsetb(get_SS(),atacmd,0,12);
3577
3578 // try to send Test Unit Ready again
3579 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3580 return 0x000f;
3581
3582 return atapi_get_sense(device);
3583 }
3584 return 0;
3585}
3586
3587 Bit16u
3588atapi_is_cdrom(device)
3589 Bit8u device;
3590{
3591 Bit16u ebda_seg=read_word(0x0040,0x000E);
3592
3593 if (device >= BX_MAX_ATA_DEVICES)
3594 return 0;
3595
3596 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3597 return 0;
3598
3599 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3600 return 0;
3601
3602 return 1;
3603}
3604
3605// ---------------------------------------------------------------------------
3606// End of ATA/ATAPI generic functions
3607// ---------------------------------------------------------------------------
3608
3609#endif // BX_USE_ATADRV
3610
3611#if BX_ELTORITO_BOOT
3612
3613// ---------------------------------------------------------------------------
3614// Start of El-Torito boot functions
3615// ---------------------------------------------------------------------------
3616
3617 void
3618cdemu_init()
3619{
3620 Bit16u ebda_seg=read_word(0x0040,0x000E);
3621
3622 // the only important data is this one for now
3623 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3624}
3625
3626 Bit8u
3627cdemu_isactive()
3628{
3629 Bit16u ebda_seg=read_word(0x0040,0x000E);
3630
3631 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3632}
3633
3634 Bit8u
3635cdemu_emulated_drive()
3636{
3637 Bit16u ebda_seg=read_word(0x0040,0x000E);
3638
3639 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3640}
3641
3642static char isotag[6]="CD001";
3643static char eltorito[24]="EL TORITO SPECIFICATION";
3644//
3645// Returns ah: emulated drive, al: error code
3646//
3647 Bit16u
3648cdrom_boot()
3649{
3650 Bit16u ebda_seg=read_word(0x0040,0x000E);
3651 Bit8u atacmd[12], buffer[2048];
3652 Bit32u lba;
3653 Bit16u boot_segment, nbsectors, i, error;
3654 Bit8u device;
3655#ifdef VBOX
3656 Bit8u read_try;
3657#endif /* VBOX */
3658
3659 // Find out the first cdrom
3660 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3661 if (atapi_is_cdrom(device)) break;
3662 }
3663
3664 // if not found
3665 if(device >= BX_MAX_ATA_DEVICES) return 2;
3666
3667 // Read the Boot Record Volume Descriptor
3668 memsetb(get_SS(),atacmd,0,12);
3669 atacmd[0]=0x28; // READ command
3670 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3671 atacmd[8]=(0x01 & 0x00ff); // Sectors
3672 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3673 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3674 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3675 atacmd[5]=(0x11 & 0x000000ff);
3676#ifdef VBOX
3677 for (read_try = 0; read_try <= 4; read_try++)
3678 {
3679 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3680 if (!error)
3681 break;
3682 }
3683 if (error)
3684 return 3;
3685#else /* !VBOX */
3686 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3687 return 3;
3688#endif /* !VBOX */
3689
3690 // Validity checks
3691 if(buffer[0]!=0)return 4;
3692 for(i=0;i<5;i++){
3693 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3694 }
3695 for(i=0;i<23;i++)
3696 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3697
3698 // ok, now we calculate the Boot catalog address
3699 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3700
3701 // And we read the Boot Catalog
3702 memsetb(get_SS(),atacmd,0,12);
3703 atacmd[0]=0x28; // READ command
3704 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3705 atacmd[8]=(0x01 & 0x00ff); // Sectors
3706 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3707 atacmd[3]=(lba & 0x00ff0000) >> 16;
3708 atacmd[4]=(lba & 0x0000ff00) >> 8;
3709 atacmd[5]=(lba & 0x000000ff);
3710 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3711 return 7;
3712
3713 // Validation entry
3714 if(buffer[0x00]!=0x01)return 8; // Header
3715 if(buffer[0x01]!=0x00)return 9; // Platform
3716 if(buffer[0x1E]!=0x55)return 10; // key 1
3717 if(buffer[0x1F]!=0xAA)return 10; // key 2
3718
3719 // Initial/Default Entry
3720 if(buffer[0x20]!=0x88)return 11; // Bootable
3721
3722 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3723 if(buffer[0x21]==0){
3724 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3725 // Win2000 cd boot needs to know it booted from cd
3726 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3727 }
3728 else if(buffer[0x21]<4)
3729 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3730 else
3731 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3732
3733 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3734 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3735
3736 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3737 if(boot_segment==0x0000)boot_segment=0x07C0;
3738
3739 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3740 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3741
3742 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3743 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3744
3745 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3746 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3747
3748 // And we read the image in memory
3749 memsetb(get_SS(),atacmd,0,12);
3750 atacmd[0]=0x28; // READ command
3751 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3752 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3753 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3754 atacmd[3]=(lba & 0x00ff0000) >> 16;
3755 atacmd[4]=(lba & 0x0000ff00) >> 8;
3756 atacmd[5]=(lba & 0x000000ff);
3757 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3758 return 12;
3759
3760 // Remember the media type
3761 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3762 case 0x01: // 1.2M floppy
3763 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3764 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3765 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3766 break;
3767 case 0x02: // 1.44M floppy
3768 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3769 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3770 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3771 break;
3772 case 0x03: // 2.88M floppy
3773 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3775 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3776 break;
3777 case 0x04: // Harddrive
3778 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3779 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3780 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3781 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3782 break;
3783 }
3784
3785 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3786 // Increase bios installed hardware number of devices
3787 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3788 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3789 else
3790 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3791 }
3792
3793
3794 // everything is ok, so from now on, the emulation is active
3795 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3796 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3797
3798 // return the boot drive + no error
3799 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3800}
3801
3802// ---------------------------------------------------------------------------
3803// End of El-Torito boot functions
3804// ---------------------------------------------------------------------------
3805#endif // BX_ELTORITO_BOOT
3806
3807#ifdef VBOX_WITH_SCSI
3808# include "scsi.c"
3809#endif
3810
3811 void
3812int14_function(regs, ds, iret_addr)
3813 pusha_regs_t regs; // regs pushed from PUSHA instruction
3814 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3815 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3816{
3817 Bit16u addr,timer,val16;
3818 Bit8u timeout;
3819
3820 ASM_START
3821 sti
3822 ASM_END
3823
3824 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3825 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3826 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3827 switch (regs.u.r8.ah) {
3828 case 0:
3829 outb(addr+3, inb(addr+3) | 0x80);
3830 if (regs.u.r8.al & 0xE0 == 0) {
3831 outb(addr, 0x17);
3832 outb(addr+1, 0x04);
3833 } else {
3834 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3835 outb(addr, val16 & 0xFF);
3836 outb(addr+1, val16 >> 8);
3837 }
3838 outb(addr+3, regs.u.r8.al & 0x1F);
3839 regs.u.r8.ah = inb(addr+5);
3840 regs.u.r8.al = inb(addr+6);
3841 ClearCF(iret_addr.flags);
3842 break;
3843 case 1:
3844 timer = read_word(0x0040, 0x006C);
3845 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3846 val16 = read_word(0x0040, 0x006C);
3847 if (val16 != timer) {
3848 timer = val16;
3849 timeout--;
3850 }
3851 }
3852 if (timeout) outb(addr, regs.u.r8.al);
3853 regs.u.r8.ah = inb(addr+5);
3854 if (!timeout) regs.u.r8.ah |= 0x80;
3855 ClearCF(iret_addr.flags);
3856 break;
3857 case 2:
3858 timer = read_word(0x0040, 0x006C);
3859 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3860 val16 = read_word(0x0040, 0x006C);
3861 if (val16 != timer) {
3862 timer = val16;
3863 timeout--;
3864 }
3865 }
3866 if (timeout) {
3867 regs.u.r8.ah = 0;
3868 regs.u.r8.al = inb(addr);
3869 } else {
3870 regs.u.r8.ah = inb(addr+5);
3871 }
3872 ClearCF(iret_addr.flags);
3873 break;
3874 case 3:
3875 regs.u.r8.ah = inb(addr+5);
3876 regs.u.r8.al = inb(addr+6);
3877 ClearCF(iret_addr.flags);
3878 break;
3879 default:
3880 SetCF(iret_addr.flags); // Unsupported
3881 }
3882 } else {
3883 SetCF(iret_addr.flags); // Unsupported
3884 }
3885}
3886
3887 void
3888int15_function(regs, ES, DS, FLAGS)
3889 pusha_regs_t regs; // REGS pushed via pusha
3890 Bit16u ES, DS, FLAGS;
3891{
3892 Bit16u ebda_seg=read_word(0x0040,0x000E);
3893 bx_bool prev_a20_enable;
3894 Bit16u base15_00;
3895 Bit8u base23_16;
3896 Bit16u ss;
3897 Bit16u BX,CX,DX;
3898
3899 Bit16u bRegister;
3900 Bit8u irqDisable;
3901
3902BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3903
3904 switch (regs.u.r8.ah) {
3905#ifdef VBOX
3906 case 0x00: /* assorted functions */
3907 if (regs.u.r8.al != 0xc0)
3908 goto undecoded;
3909 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3910 * which we don't support, but logging that event is annoying. In fact
3911 * it is likely that they just misread some specs, because there is a
3912 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3913 * wants to achieve. */
3914 SET_CF();
3915 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3916 break;
3917#endif
3918 case 0x24: /* A20 Control */
3919 switch (regs.u.r8.al) {
3920 case 0x00:
3921 set_enable_a20(0);
3922 CLEAR_CF();
3923 regs.u.r8.ah = 0;
3924 break;
3925 case 0x01:
3926 set_enable_a20(1);
3927 CLEAR_CF();
3928 regs.u.r8.ah = 0;
3929 break;
3930 case 0x02:
3931 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3932 CLEAR_CF();
3933 regs.u.r8.ah = 0;
3934 break;
3935 case 0x03:
3936 CLEAR_CF();
3937 regs.u.r8.ah = 0;
3938 regs.u.r16.bx = 3;
3939 break;
3940 default:
3941 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3942 SET_CF();
3943 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3944 }
3945 break;
3946
3947 case 0x41:
3948 SET_CF();
3949 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3950 break;
3951
3952 case 0x4f:
3953 /* keyboard intercept */
3954#if BX_CPU < 2
3955 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3956#else
3957 // nop
3958#endif
3959 SET_CF();
3960 break;
3961
3962 case 0x52: // removable media eject
3963 CLEAR_CF();
3964 regs.u.r8.ah = 0; // "ok ejection may proceed"
3965 break;
3966
3967 case 0x83: {
3968 if( regs.u.r8.al == 0 ) {
3969 // Set Interval requested.
3970 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3971 // Interval not already set.
3972 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3973 write_word( 0x40, 0x98, ES ); // Byte location, segment
3974 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3975 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3976 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3977 CLEAR_CF( );
3978 irqDisable = inb( 0xA1 );
3979 outb( 0xA1, irqDisable & 0xFE );
3980 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3981 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3982 } else {
3983 // Interval already set.
3984 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3985 SET_CF();
3986 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3987 }
3988 } else if( regs.u.r8.al == 1 ) {
3989 // Clear Interval requested
3990 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3991 CLEAR_CF( );
3992 bRegister = inb_cmos( 0xB );
3993 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3994 } else {
3995 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3996 SET_CF();
3997 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3998 regs.u.r8.al--;
3999 }
4000
4001 break;
4002 }
4003
4004 case 0x87:
4005#if BX_CPU < 3
4006# error "Int15 function 87h not supported on < 80386"
4007#endif
4008 // +++ should probably have descriptor checks
4009 // +++ should have exception handlers
4010
4011 // turn off interrupts
4012ASM_START
4013 cli
4014ASM_END
4015
4016 prev_a20_enable = set_enable_a20(1); // enable A20 line
4017
4018 // 128K max of transfer on 386+ ???
4019 // source == destination ???
4020
4021 // ES:SI points to descriptor table
4022 // offset use initially comments
4023 // ==============================================
4024 // 00..07 Unused zeros Null descriptor
4025 // 08..0f GDT zeros filled in by BIOS
4026 // 10..17 source ssssssss source of data
4027 // 18..1f dest dddddddd destination of data
4028 // 20..27 CS zeros filled in by BIOS
4029 // 28..2f SS zeros filled in by BIOS
4030
4031 //es:si
4032 //eeee0
4033 //0ssss
4034 //-----
4035
4036// check for access rights of source & dest here
4037
4038 // Initialize GDT descriptor
4039 base15_00 = (ES << 4) + regs.u.r16.si;
4040 base23_16 = ES >> 12;
4041 if (base15_00 < (ES<<4))
4042 base23_16++;
4043 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4044 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4045 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4046 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4047 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4048
4049 // Initialize CS descriptor
4050 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4051 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4052 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4053 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4054 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4055
4056 // Initialize SS descriptor
4057 ss = get_SS();
4058 base15_00 = ss << 4;
4059 base23_16 = ss >> 12;
4060 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4061 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4062 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4063 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4064 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4065
4066 CX = regs.u.r16.cx;
4067ASM_START
4068 // Compile generates locals offset info relative to SP.
4069 // Get CX (word count) from stack.
4070 mov bx, sp
4071 SEG SS
4072 mov cx, _int15_function.CX [bx]
4073
4074 // since we need to set SS:SP, save them to the BDA
4075 // for future restore
4076 push eax
4077 xor eax, eax
4078 mov ds, ax
4079 mov 0x0469, ss
4080 mov 0x0467, sp
4081
4082 SEG ES
4083 lgdt [si + 0x08]
4084 SEG CS
4085 lidt [pmode_IDT_info]
4086 ;; perhaps do something with IDT here
4087
4088 ;; set PE bit in CR0
4089 mov eax, cr0
4090 or al, #0x01
4091 mov cr0, eax
4092 ;; far jump to flush CPU queue after transition to protected mode
4093 JMP_AP(0x0020, protected_mode)
4094
4095protected_mode:
4096 ;; GDT points to valid descriptor table, now load SS, DS, ES
4097 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4098 mov ss, ax
4099 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4100 mov ds, ax
4101 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4102 mov es, ax
4103 xor si, si
4104 xor di, di
4105 cld
4106 rep
4107 movsw ;; move CX words from DS:SI to ES:DI
4108
4109 ;; make sure DS and ES limits are 64KB
4110 mov ax, #0x28
4111 mov ds, ax
4112 mov es, ax
4113
4114 ;; reset PG bit in CR0 ???
4115 mov eax, cr0
4116 and al, #0xFE
4117 mov cr0, eax
4118
4119 ;; far jump to flush CPU queue after transition to real mode
4120 JMP_AP(0xf000, real_mode)
4121
4122real_mode:
4123 ;; restore IDT to normal real-mode defaults
4124 SEG CS
4125 lidt [rmode_IDT_info]
4126
4127 // restore SS:SP from the BDA
4128 xor ax, ax
4129 mov ds, ax
4130 mov ss, 0x0469
4131 mov sp, 0x0467
4132 pop eax
4133ASM_END
4134
4135 set_enable_a20(prev_a20_enable);
4136
4137 // turn back on interrupts
4138ASM_START
4139 sti
4140ASM_END
4141
4142 regs.u.r8.ah = 0;
4143 CLEAR_CF();
4144 break;
4145
4146
4147 case 0x88:
4148 // Get the amount of extended memory (above 1M)
4149#if BX_CPU < 2
4150 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4151 SET_CF();
4152#else
4153 regs.u.r8.al = inb_cmos(0x30);
4154 regs.u.r8.ah = inb_cmos(0x31);
4155
4156 // According to Ralf Brown's interrupt the limit should be 15M,
4157 // but real machines mostly return max. 63M.
4158 if(regs.u.r16.ax > 0xffc0)
4159 regs.u.r16.ax = 0xffc0;
4160
4161 CLEAR_CF();
4162#endif
4163 break;
4164
4165#ifdef VBOX
4166 case 0x89:
4167 // Switch to Protected Mode.
4168 // ES:DI points to user-supplied GDT
4169 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4170 // This subfunction does not return!
4171
4172// turn off interrupts
4173ASM_START
4174 cli
4175ASM_END
4176
4177 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4178
4179 // Initialize CS descriptor for BIOS
4180 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4181 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4182 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4183 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4184 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4185
4186 BX = regs.u.r16.bx;
4187ASM_START
4188 // Compiler generates locals offset info relative to SP.
4189 // Get BX (PIC offsets) from stack.
4190 mov bx, sp
4191 SEG SS
4192 mov bx, _int15_function.BX [bx]
4193
4194 // Program PICs
4195 mov al, #0x11 ; send initialisation commands
4196 out 0x20, al
4197 out 0xa0, al
4198 mov al, bh
4199 out 0x21, al
4200 mov al, bl
4201 out 0xa1, al
4202 mov al, #0x04
4203 out 0x21, al
4204 mov al, #0x02
4205 out 0xa1, al
4206 mov al, #0x01
4207 out 0x21, al
4208 out 0xa1, al
4209 mov al, #0xff ; mask all IRQs, user must re-enable
4210 out 0x21, al
4211 out 0xa1, al
4212
4213 // Load GDT and IDT from supplied data
4214 SEG ES
4215 lgdt [si + 0x08]
4216 SEG ES
4217 lidt [si + 0x10]
4218
4219 // set PE bit in CR0
4220 mov eax, cr0
4221 or al, #0x01
4222 mov cr0, eax
4223 // far jump to flush CPU queue after transition to protected mode
4224 JMP_AP(0x0038, protmode_switch)
4225
4226protmode_switch:
4227 ;; GDT points to valid descriptor table, now load SS, DS, ES
4228 mov ax, #0x28
4229 mov ss, ax
4230 mov ax, #0x18
4231 mov ds, ax
4232 mov ax, #0x20
4233 mov es, ax
4234
4235 // unwind the stack - this will break if calling sequence changes!
4236 mov sp,bp
4237 add sp,#4 ; skip return address
4238 popa ; restore regs
4239 pop ax ; skip saved es
4240 pop ax ; skip saved ds
4241 pop ax ; skip saved flags
4242
4243 // return to caller - note that we do not use IRET because
4244 // we cannot enable interrupts
4245 pop cx ; get return offset
4246 pop ax ; skip return segment
4247 pop ax ; skip flags
4248 mov ax, #0x30 ; ah must be 0 on successful exit
4249 push ax
4250 push cx ; re-create modified ret address on stack
4251 retf
4252
4253ASM_END
4254
4255 break;
4256#endif /* VBOX */
4257
4258 case 0x90:
4259 /* Device busy interrupt. Called by Int 16h when no key available */
4260 break;
4261
4262 case 0x91:
4263 /* Interrupt complete. Called by Int 16h when key becomes available */
4264 break;
4265
4266 case 0xbf:
4267 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4268 SET_CF();
4269 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4270 break;
4271
4272 case 0xC0:
4273#if 0
4274 SET_CF();
4275 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4276 break;
4277#endif
4278 CLEAR_CF();
4279 regs.u.r8.ah = 0;
4280 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4281 ES = 0xF000;
4282 break;
4283
4284 case 0xc1:
4285 ES = ebda_seg;
4286 CLEAR_CF();
4287 break;
4288
4289 case 0xd8:
4290 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4291 SET_CF();
4292 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4293 break;
4294
4295#ifdef VBOX
4296 /* Make the BIOS warning for pretty much every Linux kernel start
4297 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4298 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4299 SET_CF();
4300 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4301 break;
4302 case 0xec: /* AMD64 target operating mode callback */
4303 if (regs.u.r8.al != 0)
4304 goto undecoded;
4305 regs.u.r8.ah = 0;
4306 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4307 CLEAR_CF(); /* Accepted value. */
4308 else
4309 SET_CF(); /* Reserved, error. */
4310 break;
4311undecoded:
4312#endif /* VBOX */
4313 default:
4314 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4315 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4316 SET_CF();
4317 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4318 break;
4319 }
4320}
4321
4322#if BX_USE_PS2_MOUSE
4323 void
4324int15_function_mouse(regs, ES, DS, FLAGS)
4325 pusha_regs_t regs; // REGS pushed via pusha
4326 Bit16u ES, DS, FLAGS;
4327{
4328 Bit16u ebda_seg=read_word(0x0040,0x000E);
4329 Bit8u mouse_flags_1, mouse_flags_2;
4330 Bit16u mouse_driver_seg;
4331 Bit16u mouse_driver_offset;
4332 Bit8u mouse_cmd;
4333 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4334
4335BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4336
4337 switch (regs.u.r8.ah) {
4338 case 0xC2:
4339 // Return Codes status in AH
4340 // =========================
4341 // 00: success
4342 // 01: invalid subfunction (AL > 7)
4343 // 02: invalid input value (out of allowable range)
4344 // 03: interface error
4345 // 04: resend command received from mouse controller,
4346 // device driver should attempt command again
4347 // 05: cannot enable mouse, since no far call has been installed
4348 // 80/86: mouse service not implemented
4349
4350 if (regs.u.r8.al > 7) {
4351BX_DEBUG_INT15("unsupported subfn\n");
4352 // invalid function
4353 SET_CF();
4354 regs.u.r8.ah = 1;
4355 break;
4356 }
4357
4358 // Valid subfn; disable AUX input and IRQ12, assume no error
4359 set_kbd_command_byte(0x65);
4360 CLEAR_CF();
4361 regs.u.r8.ah = 0;
4362
4363 switch (regs.u.r8.al) {
4364 case 0: // Disable/Enable Mouse
4365BX_DEBUG_INT15("case 0: ");
4366 if (regs.u.r8.bh > 1) {
4367 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4368 // invalid subfunction
4369 SET_CF();
4370 regs.u.r8.ah = 1;
4371 break;
4372 }
4373 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4374 if ( (mouse_flags_2 & 0x80) == 0 ) {
4375 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4376 SET_CF();
4377 regs.u.r8.ah = 5; // no far call installed
4378 break;
4379 }
4380 if (regs.u.r8.bh == 0) {
4381BX_DEBUG_INT15("Disable Mouse\n");
4382 mouse_cmd = 0xF5; // disable mouse command
4383 } else {
4384BX_DEBUG_INT15("Enable Mouse\n");
4385 mouse_cmd = 0xF4; // enable mouse command
4386 }
4387
4388 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4389 if (ret == 0) {
4390 ret = get_mouse_data(&mouse_data1);
4391 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4392 // success
4393 break;
4394 }
4395 }
4396
4397 // interface error
4398 SET_CF();
4399 regs.u.r8.ah = 3;
4400 break;
4401
4402 case 5: // Initialize Mouse
4403 // Valid package sizes are 1 to 8
4404 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4405 SET_CF();
4406 regs.u.r8.ah = 2; // invalid input
4407 break;
4408 }
4409 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4410 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4411 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4412 // fall through!
4413
4414 case 1: // Reset Mouse
4415BX_DEBUG_INT15("case 1 or 5:\n");
4416 // clear current package byte index
4417 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4418 mouse_flags_1 = mouse_flags_1 & 0xf8;
4419 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4420 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4421 if (ret == 0) {
4422 ret = get_mouse_data(&mouse_data3);
4423 // if no mouse attached, it will return RESEND
4424 if (mouse_data3 == 0xfe) {
4425 SET_CF();
4426 regs.u.r8.ah = 4; // resend
4427 break;
4428 }
4429 if (mouse_data3 != 0xfa)
4430 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4431 if ( ret == 0 ) {
4432 ret = get_mouse_data(&mouse_data1);
4433 if ( ret == 0 ) {
4434 ret = get_mouse_data(&mouse_data2);
4435 if ( ret == 0 ) {
4436 // success
4437 regs.u.r8.bl = mouse_data1;
4438 regs.u.r8.bh = mouse_data2;
4439 break;
4440 }
4441 }
4442 }
4443 }
4444
4445 // interface error
4446 SET_CF();
4447 regs.u.r8.ah = 3;
4448 break;
4449
4450 case 2: // Set Sample Rate
4451BX_DEBUG_INT15("case 2:\n");
4452 switch (regs.u.r8.bh) {
4453 case 0: mouse_data1 = 10; break; // 10 reports/sec
4454 case 1: mouse_data1 = 20; break; // 20 reports/sec
4455 case 2: mouse_data1 = 40; break; // 40 reports/sec
4456 case 3: mouse_data1 = 60; break; // 60 reports/sec
4457 case 4: mouse_data1 = 80; break; // 80 reports/sec
4458 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4459 case 6: mouse_data1 = 200; break; // 200 reports/sec
4460 default: mouse_data1 = 0;
4461 }
4462 if (mouse_data1 > 0) {
4463 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4464 if (ret == 0) {
4465 ret = get_mouse_data(&mouse_data2);
4466 ret = send_to_mouse_ctrl(mouse_data1);
4467 ret = get_mouse_data(&mouse_data2);
4468 // success
4469 } else {
4470 // interface error
4471 SET_CF();
4472 regs.u.r8.ah = 3;
4473 }
4474 } else {
4475 // invalid input
4476 SET_CF();
4477 regs.u.r8.ah = 2;
4478 }
4479 break;
4480
4481 case 3: // Set Resolution
4482BX_DEBUG_INT15("case 3:\n");
4483 // BX:
4484 // 0 = 25 dpi, 1 count per millimeter
4485 // 1 = 50 dpi, 2 counts per millimeter
4486 // 2 = 100 dpi, 4 counts per millimeter
4487 // 3 = 200 dpi, 8 counts per millimeter
4488 if (regs.u.r8.bh < 4) {
4489 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4490 if (ret == 0) {
4491 ret = get_mouse_data(&mouse_data1);
4492 if (mouse_data1 != 0xfa)
4493 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4494 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4495 ret = get_mouse_data(&mouse_data1);
4496 if (mouse_data1 != 0xfa)
4497 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4498 // success
4499 } else {
4500 // interface error
4501 SET_CF();
4502 regs.u.r8.ah = 3;
4503 }
4504 } else {
4505 // invalid input
4506 SET_CF();
4507 regs.u.r8.ah = 2;
4508 }
4509 break;
4510
4511 case 4: // Get Device ID
4512BX_DEBUG_INT15("case 4:\n");
4513 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4514 if (ret == 0) {
4515 ret = get_mouse_data(&mouse_data1);
4516 ret = get_mouse_data(&mouse_data2);
4517 regs.u.r8.bh = mouse_data2;
4518 // success
4519 } else {
4520 // interface error
4521 SET_CF();
4522 regs.u.r8.ah = 3;
4523 }
4524 break;
4525
4526 case 6: // Return Status & Set Scaling Factor...
4527BX_DEBUG_INT15("case 6:\n");
4528 switch (regs.u.r8.bh) {
4529 case 0: // Return Status
4530 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4531 if (ret == 0) {
4532 ret = get_mouse_data(&mouse_data1);
4533 if (mouse_data1 != 0xfa)
4534 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4535 if (ret == 0) {
4536 ret = get_mouse_data(&mouse_data1);
4537 if ( ret == 0 ) {
4538 ret = get_mouse_data(&mouse_data2);
4539 if ( ret == 0 ) {
4540 ret = get_mouse_data(&mouse_data3);
4541 if ( ret == 0 ) {
4542 regs.u.r8.bl = mouse_data1;
4543 regs.u.r8.cl = mouse_data2;
4544 regs.u.r8.dl = mouse_data3;
4545 // success
4546 break;
4547 }
4548 }
4549 }
4550 }
4551 }
4552
4553 // interface error
4554 SET_CF();
4555 regs.u.r8.ah = 3;
4556 break;
4557
4558 case 1: // Set Scaling Factor to 1:1
4559 case 2: // Set Scaling Factor to 2:1
4560 if (regs.u.r8.bh == 1) {
4561 ret = send_to_mouse_ctrl(0xE6);
4562 } else {
4563 ret = send_to_mouse_ctrl(0xE7);
4564 }
4565 if (ret == 0) {
4566 get_mouse_data(&mouse_data1);
4567 ret = (mouse_data1 != 0xFA);
4568 }
4569 if (ret != 0) {
4570 // interface error
4571 SET_CF();
4572 regs.u.r8.ah = 3;
4573 }
4574 break;
4575
4576 default:
4577 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4578 // invalid subfunction
4579 SET_CF();
4580 regs.u.r8.ah = 1;
4581 }
4582 break;
4583
4584 case 7: // Set Mouse Handler Address
4585BX_DEBUG_INT15("case 7:\n");
4586 mouse_driver_seg = ES;
4587 mouse_driver_offset = regs.u.r16.bx;
4588 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4589 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4590 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4591 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4592 /* remove handler */
4593 if ( (mouse_flags_2 & 0x80) != 0 ) {
4594 mouse_flags_2 &= ~0x80;
4595 }
4596 }
4597 else {
4598 /* install handler */
4599 mouse_flags_2 |= 0x80;
4600 }
4601 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4602 break;
4603
4604 default:
4605 BX_PANIC("INT 15h C2 default case entered\n");
4606 // invalid subfunction
4607 SET_CF();
4608 regs.u.r8.ah = 1;
4609 }
4610BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4611 // Re-enable AUX input and IRQ12
4612 set_kbd_command_byte(0x47);
4613 break;
4614
4615 default:
4616 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4617 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4618 SET_CF();
4619 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4620 break;
4621 }
4622}
4623#endif // BX_USE_PS2_MOUSE
4624
4625
4626void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4627 Bit16u ES;
4628 Bit16u DI;
4629 Bit32u start;
4630 Bit32u end;
4631 Bit8u extra_start;
4632 Bit8u extra_end;
4633 Bit16u type;
4634{
4635 write_word(ES, DI, start);
4636 write_word(ES, DI+2, start >> 16);
4637 write_word(ES, DI+4, extra_start);
4638 write_word(ES, DI+6, 0x00);
4639
4640 end -= start;
4641 extra_end -= extra_start;
4642 write_word(ES, DI+8, end);
4643 write_word(ES, DI+10, end >> 16);
4644 write_word(ES, DI+12, extra_end);
4645 write_word(ES, DI+14, 0x0000);
4646
4647 write_word(ES, DI+16, type);
4648 write_word(ES, DI+18, 0x0);
4649}
4650
4651 void
4652int15_function32(regs, ES, DS, FLAGS)
4653 pushad_regs_t regs; // REGS pushed via pushad
4654 Bit16u ES, DS, FLAGS;
4655{
4656 Bit32u extended_memory_size=0; // 64bits long
4657 Bit32u extra_lowbits_memory_size=0;
4658 Bit16u CX,DX;
4659 Bit8u extra_highbits_memory_size=0;
4660
4661BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4662
4663 switch (regs.u.r8.ah) {
4664 case 0x86:
4665 // Wait for CX:DX microseconds. currently using the
4666 // refresh request port 0x61 bit4, toggling every 15usec
4667
4668 CX = regs.u.r16.cx;
4669 DX = regs.u.r16.dx;
4670
4671ASM_START
4672 sti
4673
4674 ;; Get the count in eax
4675 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4676 mov bx, sp
4677 SEG SS
4678 mov ax, _int15_function32.CX [bx]
4679 shl eax, #16
4680 SEG SS
4681 mov ax, _int15_function32.DX [bx]
4682
4683 ;; convert to numbers of 15usec ticks
4684 mov ebx, #15
4685 xor edx, edx
4686 div eax, ebx
4687 mov ecx, eax
4688
4689 ;; wait for ecx number of refresh requests
4690 in al, #0x61
4691 and al,#0x10
4692 mov ah, al
4693
4694 or ecx, ecx
4695 je int1586_tick_end
4696int1586_tick:
4697 in al, #0x61
4698 and al,#0x10
4699 cmp al, ah
4700 je int1586_tick
4701 mov ah, al
4702 dec ecx
4703 jnz int1586_tick
4704int1586_tick_end:
4705ASM_END
4706
4707 break;
4708
4709 case 0xe8:
4710 switch(regs.u.r8.al)
4711 {
4712 case 0x20: // coded by osmaker aka K.J.
4713 if(regs.u.r32.edx == 0x534D4150)
4714 {
4715 extended_memory_size = inb_cmos(0x35);
4716 extended_memory_size <<= 8;
4717 extended_memory_size |= inb_cmos(0x34);
4718 extended_memory_size *= 64;
4719#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4720 // greater than EFF00000???
4721 if(extended_memory_size > 0x3bc000) {
4722 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4723 }
4724#endif /* !VBOX */
4725 extended_memory_size *= 1024;
4726 extended_memory_size += (16L * 1024 * 1024);
4727
4728 if(extended_memory_size <= (16L * 1024 * 1024)) {
4729 extended_memory_size = inb_cmos(0x31);
4730 extended_memory_size <<= 8;
4731 extended_memory_size |= inb_cmos(0x30);
4732 extended_memory_size *= 1024;
4733 extended_memory_size += (1L * 1024 * 1024);
4734 }
4735
4736#ifdef VBOX /* We've already used the CMOS entries for SATA.
4737 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4738 extra_lowbits_memory_size = inb_cmos(0x62);
4739 extra_lowbits_memory_size <<= 8;
4740 extra_lowbits_memory_size |= inb_cmos(0x61);
4741 extra_lowbits_memory_size <<= 16;
4742 extra_highbits_memory_size = inb_cmos(0x63);
4743 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4744#else
4745 extra_lowbits_memory_size = inb_cmos(0x5c);
4746 extra_lowbits_memory_size <<= 8;
4747 extra_lowbits_memory_size |= inb_cmos(0x5b);
4748 extra_lowbits_memory_size *= 64;
4749 extra_lowbits_memory_size *= 1024;
4750 extra_highbits_memory_size = inb_cmos(0x5d);
4751#endif /* !VBOX */
4752
4753 switch(regs.u.r16.bx)
4754 {
4755 case 0:
4756 set_e820_range(ES, regs.u.r16.di,
4757#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4758 0x0000000L, 0x0009f000L, 0, 0, 1);
4759#else
4760 0x0000000L, 0x0009fc00L, 0, 0, 1);
4761#endif
4762 regs.u.r32.ebx = 1;
4763 break;
4764 case 1:
4765 set_e820_range(ES, regs.u.r16.di,
4766#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4767 0x0009f000L, 0x000a0000L, 0, 0, 2);
4768#else
4769 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4770#endif
4771 regs.u.r32.ebx = 2;
4772 break;
4773 case 2:
4774#ifdef VBOX
4775 /* Mark the BIOS as reserved. VBox doesn't currently
4776 * use the 0xe0000-0xeffff area. It does use the
4777 * 0xd0000-0xdffff area for the BIOS logo, but it's
4778 * not worth marking it as reserved. Note that various
4779 * Windows versions don't accept (read: in debug builds
4780 * they trigger the "Too many similar traps" assertion)
4781 * a single reserved range from 0xd0000 to 0xffffff.
4782 * A 128K area starting from 0xd0000 works. */
4783 set_e820_range(ES, regs.u.r16.di,
4784 0x000f0000L, 0x00100000L, 0, 0, 2);
4785#else /* !VBOX */
4786 set_e820_range(ES, regs.u.r16.di,
4787 0x000e8000L, 0x00100000L, 0, 0, 2);
4788#endif /* !VBOX */
4789 regs.u.r32.ebx = 3;
4790 break;
4791 case 3:
4792#if BX_ROMBIOS32 || defined(VBOX)
4793 set_e820_range(ES, regs.u.r16.di,
4794 0x00100000L,
4795 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4796 regs.u.r32.ebx = 4;
4797#else
4798 set_e820_range(ES, regs.u.r16.di,
4799 0x00100000L,
4800 extended_memory_size, 1);
4801 regs.u.r32.ebx = 5;
4802#endif
4803 break;
4804 case 4:
4805 set_e820_range(ES, regs.u.r16.di,
4806 extended_memory_size - ACPI_DATA_SIZE,
4807 extended_memory_size, 0, 0, 3); // ACPI RAM
4808 regs.u.r32.ebx = 5;
4809 break;
4810 case 5:
4811 /* 256KB BIOS area at the end of 4 GB */
4812#ifdef VBOX
4813 /* We don't set the end to 1GB here and rely on the 32-bit
4814 unsigned wrap around effect (0-0xfffc0000L). */
4815#endif
4816 set_e820_range(ES, regs.u.r16.di,
4817 0xfffc0000L, 0x00000000L, 0, 0, 2);
4818 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4819 regs.u.r32.ebx = 6;
4820 else
4821 regs.u.r32.ebx = 0;
4822 break;
4823 case 6:
4824#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4825 /* Mapping of memory above 4 GB if present.
4826 Note: set_e820_range needs do no borrowing in the
4827 subtraction because of the nice numbers. */
4828 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4829 {
4830 set_e820_range(ES, regs.u.r16.di,
4831 0x00000000L, extra_lowbits_memory_size,
4832 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4833 regs.u.r32.ebx = 0;
4834 break;
4835 }
4836 /* fall thru */
4837#else /* !VBOX */
4838 /* Maping of memory above 4 GB */
4839 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4840 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4841 + 1, 1);
4842 regs.u.r32.ebx = 0;
4843 break;
4844#endif /* !VBOX */
4845 default: /* AX=E820, DX=534D4150, BX unrecognized */
4846 goto int15_unimplemented;
4847 break;
4848 }
4849 regs.u.r32.eax = 0x534D4150;
4850 regs.u.r32.ecx = 0x14;
4851 CLEAR_CF();
4852 } else {
4853 // if DX != 0x534D4150)
4854 goto int15_unimplemented;
4855 }
4856 break;
4857
4858 case 0x01:
4859 // do we have any reason to fail here ?
4860 CLEAR_CF();
4861
4862 // my real system sets ax and bx to 0
4863 // this is confirmed by Ralph Brown list
4864 // but syslinux v1.48 is known to behave
4865 // strangely if ax is set to 0
4866 // regs.u.r16.ax = 0;
4867 // regs.u.r16.bx = 0;
4868
4869 // Get the amount of extended memory (above 1M)
4870 regs.u.r8.cl = inb_cmos(0x30);
4871 regs.u.r8.ch = inb_cmos(0x31);
4872
4873 // limit to 15M
4874 if(regs.u.r16.cx > 0x3c00)
4875 {
4876 regs.u.r16.cx = 0x3c00;
4877 }
4878
4879 // Get the amount of extended memory above 16M in 64k blocs
4880 regs.u.r8.dl = inb_cmos(0x34);
4881 regs.u.r8.dh = inb_cmos(0x35);
4882
4883 // Set configured memory equal to extended memory
4884 regs.u.r16.ax = regs.u.r16.cx;
4885 regs.u.r16.bx = regs.u.r16.dx;
4886 break;
4887 default: /* AH=0xE8?? but not implemented */
4888 goto int15_unimplemented;
4889 }
4890 break;
4891 int15_unimplemented:
4892 // fall into the default
4893 default:
4894 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4895 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4896 SET_CF();
4897 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4898 break;
4899 }
4900}
4901
4902 void
4903int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4904 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4905{
4906 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4907 Bit16u kbd_code, max;
4908
4909 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4910
4911 shift_flags = read_byte(0x0040, 0x17);
4912 led_flags = read_byte(0x0040, 0x97);
4913 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4914ASM_START
4915 cli
4916ASM_END
4917 outb(0x60, 0xed);
4918 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4919 if ((inb(0x60) == 0xfa)) {
4920 led_flags &= 0xf8;
4921 led_flags |= ((shift_flags >> 4) & 0x07);
4922 outb(0x60, led_flags & 0x07);
4923 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4924 inb(0x60);
4925 write_byte(0x0040, 0x97, led_flags);
4926 }
4927ASM_START
4928 sti
4929ASM_END
4930 }
4931
4932 switch (GET_AH()) {
4933 case 0x00: /* read keyboard input */
4934
4935 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4936 BX_PANIC("KBD: int16h: out of keyboard input\n");
4937 }
4938 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4939 else if (ascii_code == 0xE0) ascii_code = 0;
4940 AX = (scan_code << 8) | ascii_code;
4941 break;
4942
4943 case 0x01: /* check keyboard status */
4944 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4945 SET_ZF();
4946 return;
4947 }
4948 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4949 else if (ascii_code == 0xE0) ascii_code = 0;
4950 AX = (scan_code << 8) | ascii_code;
4951 CLEAR_ZF();
4952 break;
4953
4954 case 0x02: /* get shift flag status */
4955 shift_flags = read_byte(0x0040, 0x17);
4956 SET_AL(shift_flags);
4957 break;
4958
4959 case 0x05: /* store key-stroke into buffer */
4960 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4961 SET_AL(1);
4962 }
4963 else {
4964 SET_AL(0);
4965 }
4966 break;
4967
4968 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4969 // bit Bochs Description
4970 // 7 0 reserved
4971 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4972 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4973 // 4 1 INT 16/AH=0Ah supported
4974 // 3 0 INT 16/AX=0306h supported
4975 // 2 0 INT 16/AX=0305h supported
4976 // 1 0 INT 16/AX=0304h supported
4977 // 0 0 INT 16/AX=0300h supported
4978 //
4979 SET_AL(0x30);
4980 break;
4981
4982 case 0x0A: /* GET KEYBOARD ID */
4983 count = 2;
4984 kbd_code = 0x0;
4985 outb(0x60, 0xf2);
4986 /* Wait for data */
4987 max=0xffff;
4988 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4989 if (max>0x0) {
4990 if ((inb(0x60) == 0xfa)) {
4991 do {
4992 max=0xffff;
4993 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4994 if (max>0x0) {
4995 kbd_code >>= 8;
4996 kbd_code |= (inb(0x60) << 8);
4997 }
4998 } while (--count>0);
4999 }
5000 }
5001 BX=kbd_code;
5002 break;
5003
5004 case 0x10: /* read MF-II keyboard input */
5005
5006 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5007 BX_PANIC("KBD: int16h: out of keyboard input\n");
5008 }
5009 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5010 AX = (scan_code << 8) | ascii_code;
5011 break;
5012
5013 case 0x11: /* check MF-II keyboard status */
5014 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5015 SET_ZF();
5016 return;
5017 }
5018 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5019 AX = (scan_code << 8) | ascii_code;
5020 CLEAR_ZF();
5021 break;
5022
5023 case 0x12: /* get extended keyboard status */
5024 shift_flags = read_byte(0x0040, 0x17);
5025 SET_AL(shift_flags);
5026 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5027 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5028 SET_AH(shift_flags);
5029 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5030 break;
5031
5032 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5033 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5034 break;
5035
5036 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5037 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5038 break;
5039
5040 case 0x6F:
5041 if (GET_AL() == 0x08)
5042 SET_AH(0x02); // unsupported, aka normal keyboard
5043
5044 default:
5045 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5046 }
5047}
5048
5049 unsigned int
5050dequeue_key(scan_code, ascii_code, incr)
5051 Bit8u *scan_code;
5052 Bit8u *ascii_code;
5053 unsigned int incr;
5054{
5055 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5056 Bit16u ss;
5057 Bit8u acode, scode;
5058
5059#if BX_CPU < 2
5060 buffer_start = 0x001E;
5061 buffer_end = 0x003E;
5062#else
5063 buffer_start = read_word(0x0040, 0x0080);
5064 buffer_end = read_word(0x0040, 0x0082);
5065#endif
5066
5067 buffer_head = read_word(0x0040, 0x001a);
5068 buffer_tail = read_word(0x0040, 0x001c);
5069
5070 if (buffer_head != buffer_tail) {
5071 ss = get_SS();
5072 acode = read_byte(0x0040, buffer_head);
5073 scode = read_byte(0x0040, buffer_head+1);
5074 write_byte(ss, ascii_code, acode);
5075 write_byte(ss, scan_code, scode);
5076
5077 if (incr) {
5078 buffer_head += 2;
5079 if (buffer_head >= buffer_end)
5080 buffer_head = buffer_start;
5081 write_word(0x0040, 0x001a, buffer_head);
5082 }
5083 return(1);
5084 }
5085 else {
5086 return(0);
5087 }
5088}
5089
5090static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5091
5092 Bit8u
5093send_to_mouse_ctrl(sendbyte)
5094 Bit8u sendbyte;
5095{
5096 Bit8u response;
5097
5098 // wait for chance to write to ctrl
5099 if ( inb(0x64) & 0x02 )
5100 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5101 outb(0x64, 0xD4);
5102 outb(0x60, sendbyte);
5103 return(0);
5104}
5105
5106
5107 Bit8u
5108get_mouse_data(data)
5109 Bit8u *data;
5110{
5111 Bit8u response;
5112 Bit16u ss;
5113
5114 while ( (inb(0x64) & 0x21) != 0x21 ) {
5115 }
5116
5117 response = inb(0x60);
5118
5119 ss = get_SS();
5120 write_byte(ss, data, response);
5121 return(0);
5122}
5123
5124 void
5125set_kbd_command_byte(command_byte)
5126 Bit8u command_byte;
5127{
5128 if ( inb(0x64) & 0x02 )
5129 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5130
5131 outb(0x64, 0x60); // write command byte
5132 outb(0x60, command_byte);
5133}
5134
5135 void
5136int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5137 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5138{
5139 Bit8u scancode, asciicode, shift_flags;
5140 Bit8u mf2_flags, mf2_state;
5141
5142 //
5143 // DS has been set to F000 before call
5144 //
5145
5146
5147 scancode = GET_AL();
5148
5149 if (scancode == 0) {
5150 BX_INFO("KBD: int09 handler: AL=0\n");
5151 return;
5152 }
5153
5154
5155 shift_flags = read_byte(0x0040, 0x17);
5156 mf2_flags = read_byte(0x0040, 0x18);
5157 mf2_state = read_byte(0x0040, 0x96);
5158 asciicode = 0;
5159
5160 switch (scancode) {
5161 case 0x3a: /* Caps Lock press */
5162 shift_flags ^= 0x40;
5163 write_byte(0x0040, 0x17, shift_flags);
5164 mf2_flags |= 0x40;
5165 write_byte(0x0040, 0x18, mf2_flags);
5166 break;
5167 case 0xba: /* Caps Lock release */
5168 mf2_flags &= ~0x40;
5169 write_byte(0x0040, 0x18, mf2_flags);
5170 break;
5171
5172 case 0x2a: /* L Shift press */
5173 shift_flags |= 0x02;
5174 write_byte(0x0040, 0x17, shift_flags);
5175 break;
5176 case 0xaa: /* L Shift release */
5177 shift_flags &= ~0x02;
5178 write_byte(0x0040, 0x17, shift_flags);
5179 break;
5180
5181 case 0x36: /* R Shift press */
5182 shift_flags |= 0x01;
5183 write_byte(0x0040, 0x17, shift_flags);
5184 break;
5185 case 0xb6: /* R Shift release */
5186 shift_flags &= ~0x01;
5187 write_byte(0x0040, 0x17, shift_flags);
5188 break;
5189
5190 case 0x1d: /* Ctrl press */
5191 if ((mf2_state & 0x01) == 0) {
5192 shift_flags |= 0x04;
5193 write_byte(0x0040, 0x17, shift_flags);
5194 if (mf2_state & 0x02) {
5195 mf2_state |= 0x04;
5196 write_byte(0x0040, 0x96, mf2_state);
5197 } else {
5198 mf2_flags |= 0x01;
5199 write_byte(0x0040, 0x18, mf2_flags);
5200 }
5201 }
5202 break;
5203 case 0x9d: /* Ctrl release */
5204 if ((mf2_state & 0x01) == 0) {
5205 shift_flags &= ~0x04;
5206 write_byte(0x0040, 0x17, shift_flags);
5207 if (mf2_state & 0x02) {
5208 mf2_state &= ~0x04;
5209 write_byte(0x0040, 0x96, mf2_state);
5210 } else {
5211 mf2_flags &= ~0x01;
5212 write_byte(0x0040, 0x18, mf2_flags);
5213 }
5214 }
5215 break;
5216
5217 case 0x38: /* Alt press */
5218 shift_flags |= 0x08;
5219 write_byte(0x0040, 0x17, shift_flags);
5220 if (mf2_state & 0x02) {
5221 mf2_state |= 0x08;
5222 write_byte(0x0040, 0x96, mf2_state);
5223 } else {
5224 mf2_flags |= 0x02;
5225 write_byte(0x0040, 0x18, mf2_flags);
5226 }
5227 break;
5228 case 0xb8: /* Alt release */
5229 shift_flags &= ~0x08;
5230 write_byte(0x0040, 0x17, shift_flags);
5231 if (mf2_state & 0x02) {
5232 mf2_state &= ~0x08;
5233 write_byte(0x0040, 0x96, mf2_state);
5234 } else {
5235 mf2_flags &= ~0x02;
5236 write_byte(0x0040, 0x18, mf2_flags);
5237 }
5238 break;
5239
5240 case 0x45: /* Num Lock press */
5241 if ((mf2_state & 0x03) == 0) {
5242 mf2_flags |= 0x20;
5243 write_byte(0x0040, 0x18, mf2_flags);
5244 shift_flags ^= 0x20;
5245 write_byte(0x0040, 0x17, shift_flags);
5246 }
5247 break;
5248 case 0xc5: /* Num Lock release */
5249 if ((mf2_state & 0x03) == 0) {
5250 mf2_flags &= ~0x20;
5251 write_byte(0x0040, 0x18, mf2_flags);
5252 }
5253 break;
5254
5255 case 0x46: /* Scroll Lock press */
5256 mf2_flags |= 0x10;
5257 write_byte(0x0040, 0x18, mf2_flags);
5258 shift_flags ^= 0x10;
5259 write_byte(0x0040, 0x17, shift_flags);
5260 break;
5261
5262 case 0xc6: /* Scroll Lock release */
5263 mf2_flags &= ~0x10;
5264 write_byte(0x0040, 0x18, mf2_flags);
5265 break;
5266
5267#ifdef VBOX
5268 case 0x53: /* Del press */
5269 if ((shift_flags & 0x0f) == 0x0c)
5270 {
5271ASM_START
5272 /* Ctrl+Alt+Del => Reboot */
5273 jmp 0xf000:post
5274ASM_END
5275 }
5276 /* fall through */
5277#endif
5278
5279 default:
5280 if (scancode & 0x80) {
5281 break; /* toss key releases ... */
5282 }
5283 if (scancode > MAX_SCAN_CODE) {
5284 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5285 return;
5286 }
5287 if (shift_flags & 0x08) { /* ALT */
5288 asciicode = scan_to_scanascii[scancode].alt;
5289 scancode = scan_to_scanascii[scancode].alt >> 8;
5290 } else if (shift_flags & 0x04) { /* CONTROL */
5291 asciicode = scan_to_scanascii[scancode].control;
5292 scancode = scan_to_scanascii[scancode].control >> 8;
5293 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5294 /* extended keys handling */
5295 asciicode = 0xe0;
5296 scancode = scan_to_scanascii[scancode].normal >> 8;
5297 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5298 /* check if lock state should be ignored
5299 * because a SHIFT key are pressed */
5300
5301 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5302 asciicode = scan_to_scanascii[scancode].normal;
5303 scancode = scan_to_scanascii[scancode].normal >> 8;
5304 } else {
5305 asciicode = scan_to_scanascii[scancode].shift;
5306 scancode = scan_to_scanascii[scancode].shift >> 8;
5307 }
5308 } else {
5309 /* check if lock is on */
5310 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5311 asciicode = scan_to_scanascii[scancode].shift;
5312 scancode = scan_to_scanascii[scancode].shift >> 8;
5313 } else {
5314 asciicode = scan_to_scanascii[scancode].normal;
5315 scancode = scan_to_scanascii[scancode].normal >> 8;
5316 }
5317 }
5318 if (scancode==0 && asciicode==0) {
5319 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5320 }
5321 enqueue_key(scancode, asciicode);
5322 break;
5323 }
5324 if ((scancode & 0x7f) != 0x1d) {
5325 mf2_state &= ~0x01;
5326 }
5327 mf2_state &= ~0x02;
5328 write_byte(0x0040, 0x96, mf2_state);
5329}
5330
5331 unsigned int
5332enqueue_key(scan_code, ascii_code)
5333 Bit8u scan_code, ascii_code;
5334{
5335 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5336
5337#if BX_CPU < 2
5338 buffer_start = 0x001E;
5339 buffer_end = 0x003E;
5340#else
5341 buffer_start = read_word(0x0040, 0x0080);
5342 buffer_end = read_word(0x0040, 0x0082);
5343#endif
5344
5345 buffer_head = read_word(0x0040, 0x001A);
5346 buffer_tail = read_word(0x0040, 0x001C);
5347
5348 temp_tail = buffer_tail;
5349 buffer_tail += 2;
5350 if (buffer_tail >= buffer_end)
5351 buffer_tail = buffer_start;
5352
5353 if (buffer_tail == buffer_head) {
5354 return(0);
5355 }
5356
5357 write_byte(0x0040, temp_tail, ascii_code);
5358 write_byte(0x0040, temp_tail+1, scan_code);
5359 write_word(0x0040, 0x001C, buffer_tail);
5360 return(1);
5361}
5362
5363
5364 void
5365int74_function(make_farcall, Z, Y, X, status)
5366 Bit16u make_farcall, Z, Y, X, status;
5367{
5368 Bit16u ebda_seg=read_word(0x0040,0x000E);
5369 Bit8u in_byte, index, package_count;
5370 Bit8u mouse_flags_1, mouse_flags_2;
5371
5372BX_DEBUG_INT74("entering int74_function\n");
5373 make_farcall = 0;
5374
5375 in_byte = inb(0x64);
5376 if ( (in_byte & 0x21) != 0x21 ) {
5377 return;
5378 }
5379 in_byte = inb(0x60);
5380BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5381
5382 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5383 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5384
5385 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5386 return;
5387 }
5388
5389 package_count = mouse_flags_2 & 0x07;
5390 index = mouse_flags_1 & 0x07;
5391 write_byte(ebda_seg, 0x28 + index, in_byte);
5392
5393 if ( index >= package_count ) {
5394BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5395 status = read_byte(ebda_seg, 0x0028 + 0);
5396 X = read_byte(ebda_seg, 0x0028 + 1);
5397 Y = read_byte(ebda_seg, 0x0028 + 2);
5398 Z = 0;
5399 mouse_flags_1 = 0;
5400 // check if far call handler installed
5401 if (mouse_flags_2 & 0x80)
5402 make_farcall = 1;
5403 }
5404 else {
5405 mouse_flags_1++;
5406 }
5407 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5408}
5409
5410#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5411
5412#if BX_USE_ATADRV
5413
5414 void
5415int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5416 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5417{
5418 Bit32u lba;
5419 Bit16u ebda_seg=read_word(0x0040,0x000E);
5420 Bit16u cylinder, head, sector;
5421 Bit16u segment, offset;
5422 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5423 Bit16u size, count;
5424 Bit8u device, status;
5425
5426 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5427
5428 write_byte(0x0040, 0x008e, 0); // clear completion flag
5429
5430#ifdef VBOX_WITH_SCSI
5431 // basic check : device has to be defined
5432 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5433 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5434 goto int13_fail;
5435 }
5436#else
5437 // basic check : device has to be defined
5438 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5439 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5440 goto int13_fail;
5441 }
5442#endif
5443
5444 // Get the ata channel
5445 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5446
5447#ifdef VBOX_WITH_SCSI
5448 // basic check : device has to be valid
5449 if (device >= BX_MAX_STORAGE_DEVICES) {
5450 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5451 goto int13_fail;
5452 }
5453#else
5454 // basic check : device has to be valid
5455 if (device >= BX_MAX_ATA_DEVICES) {
5456 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5457 goto int13_fail;
5458 }
5459#endif
5460
5461 switch (GET_AH()) {
5462
5463 case 0x00: /* disk controller reset */
5464#ifdef VBOX_WITH_SCSI
5465 /* SCSI controller does not need a reset. */
5466 if (!VBOX_IS_SCSI_DEVICE(device))
5467#endif
5468 ata_reset (device);
5469 goto int13_success;
5470 break;
5471
5472 case 0x01: /* read disk status */
5473 status = read_byte(0x0040, 0x0074);
5474 SET_AH(status);
5475 SET_DISK_RET_STATUS(0);
5476 /* set CF if error status read */
5477 if (status) goto int13_fail_nostatus;
5478 else goto int13_success_noah;
5479 break;
5480
5481 case 0x02: // read disk sectors
5482 case 0x03: // write disk sectors
5483 case 0x04: // verify disk sectors
5484
5485 count = GET_AL();
5486 cylinder = GET_CH();
5487 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5488 sector = (GET_CL() & 0x3f);
5489 head = GET_DH();
5490
5491 segment = ES;
5492 offset = BX;
5493
5494 if ( (count > 128) || (count == 0) ) {
5495 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5496 goto int13_fail;
5497 }
5498
5499#ifdef VBOX_WITH_SCSI
5500 if (!VBOX_IS_SCSI_DEVICE(device))
5501#endif
5502 {
5503 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5504 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5505 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5506 }
5507#ifdef VBOX_WITH_SCSI
5508 else
5509 {
5510 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5511
5512 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5513 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5514 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5515 }
5516#endif
5517
5518 // sanity check on cyl heads, sec
5519 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5520 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5521 goto int13_fail;
5522 }
5523
5524 // FIXME verify
5525 if ( GET_AH() == 0x04 ) goto int13_success;
5526
5527#ifdef VBOX_WITH_SCSI
5528 if (!VBOX_IS_SCSI_DEVICE(device))
5529#endif
5530 {
5531 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5532 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5533 }
5534#ifdef VBOX_WITH_SCSI
5535 else
5536 {
5537 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5538 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5539 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5540 }
5541#endif
5542
5543 // if needed, translate lchs to lba, and execute command
5544#ifdef VBOX_WITH_SCSI
5545 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5546 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5547 sector = 0; // this forces the command to be lba
5548 }
5549#else
5550 if (( (nph != nlh) || (npspt != nlspt)) ) {
5551 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5552 sector = 0; // this forces the command to be lba
5553 }
5554#endif
5555
5556 if ( GET_AH() == 0x02 )
5557 {
5558#ifdef VBOX_WITH_SCSI
5559 if (VBOX_IS_SCSI_DEVICE(device))
5560 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5561 else
5562#endif
5563 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5564 }
5565 else
5566 {
5567#ifdef VBOX_WITH_SCSI
5568 if (VBOX_IS_SCSI_DEVICE(device))
5569 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5570 else
5571#endif
5572 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5573 }
5574
5575 // Set nb of sector transferred
5576 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5577
5578 if (status != 0) {
5579 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5580 SET_AH(0x0c);
5581 goto int13_fail_noah;
5582 }
5583
5584 goto int13_success;
5585 break;
5586
5587 case 0x05: /* format disk track */
5588 BX_INFO("format disk track called\n");
5589 goto int13_success;
5590 return;
5591 break;
5592
5593 case 0x08: /* read disk drive parameters */
5594
5595 // Get logical geometry from table
5596#ifdef VBOX_WITH_SCSI
5597 if (!VBOX_IS_SCSI_DEVICE(device))
5598#endif
5599 {
5600 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5601 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5602 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5603 }
5604#ifdef VBOX_WITH_SCSI
5605 else
5606 {
5607 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5608 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5609 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5610 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5611 }
5612#endif
5613
5614 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5615#ifndef VBOX
5616 nlc = nlc - 2; /* 0 based , last sector not used */
5617#else /* VBOX */
5618 /* Maximum cylinder number is just one less than the number of cylinders. */
5619 nlc = nlc - 1; /* 0 based , last sector not used */
5620#endif /* VBOX */
5621 SET_AL(0);
5622 SET_CH(nlc & 0xff);
5623 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5624 SET_DH(nlh - 1);
5625 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5626
5627 // FIXME should set ES & DI
5628
5629 goto int13_success;
5630 break;
5631
5632 case 0x10: /* check drive ready */
5633 // should look at 40:8E also???
5634
5635 // Read the status from controller
5636 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5637 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5638 goto int13_success;
5639 }
5640 else {
5641 SET_AH(0xAA);
5642 goto int13_fail_noah;
5643 }
5644 break;
5645
5646 case 0x15: /* read disk drive size */
5647
5648 // Get physical geometry from table
5649#ifdef VBOX_WITH_SCSI
5650 if (!VBOX_IS_SCSI_DEVICE(device))
5651#endif
5652 {
5653 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5654 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5655 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5656 }
5657#ifdef VBOX_WITH_SCSI
5658 else
5659 {
5660 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5661 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5662 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5663 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5664 }
5665#endif
5666
5667 // Compute sector count seen by int13
5668#ifndef VBOX
5669 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5670#else /* VBOX */
5671 /* Is it so hard to multiply a couple of counts (without introducing
5672 * arbitrary off by one errors)? */
5673 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5674#endif /* VBOX */
5675 CX = lba >> 16;
5676 DX = lba & 0xffff;
5677
5678 SET_AH(3); // hard disk accessible
5679 goto int13_success_noah;
5680 break;
5681
5682 case 0x41: // IBM/MS installation check
5683 BX=0xaa55; // install check
5684 SET_AH(0x30); // EDD 3.0
5685 CX=0x0007; // ext disk access and edd, removable supported
5686 goto int13_success_noah;
5687 break;
5688
5689 case 0x42: // IBM/MS extended read
5690 case 0x43: // IBM/MS extended write
5691 case 0x44: // IBM/MS verify
5692 case 0x47: // IBM/MS extended seek
5693
5694 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5695 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5696 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5697
5698 // Can't use 64 bits lba
5699 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5700 if (lba != 0L) {
5701 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5702 goto int13_fail;
5703 }
5704
5705 // Get 32 bits lba and check
5706 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5707
5708#ifdef VBOX_WITH_SCSI
5709 if (VBOX_IS_SCSI_DEVICE(device))
5710 {
5711 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5712 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5713 goto int13_fail;
5714 }
5715 }
5716 else
5717#endif
5718 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5719 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5720 goto int13_fail;
5721 }
5722
5723
5724 // If verify or seek
5725 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5726 goto int13_success;
5727
5728 // Execute the command
5729 if ( GET_AH() == 0x42 )
5730#ifdef VBOX
5731 {
5732#ifdef VBOX_WITH_SCSI
5733 if (VBOX_IS_SCSI_DEVICE(device))
5734 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5735 else
5736#endif
5737 {
5738 if (count >= 256 || lba + count >= 268435456)
5739 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5740 else
5741 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5742 }
5743 }
5744#else /* !VBOX */
5745 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5746#endif /* VBOX */
5747 else
5748#ifdef VBOX
5749 {
5750#ifdef VBOX_WITH_SCSI
5751 if (VBOX_IS_SCSI_DEVICE(device))
5752 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5753 else
5754#endif
5755 {
5756 if (count >= 256 || lba + count >= 268435456)
5757 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5758 else
5759 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5760 }
5761 }
5762#else /* !VBOX */
5763 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5764#endif /* VBOX */
5765
5766 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5767 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5768
5769 if (status != 0) {
5770 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5771 SET_AH(0x0c);
5772 goto int13_fail_noah;
5773 }
5774
5775 goto int13_success;
5776 break;
5777
5778 case 0x45: // IBM/MS lock/unlock drive
5779 case 0x49: // IBM/MS extended media change
5780 goto int13_success; // Always success for HD
5781 break;
5782
5783 case 0x46: // IBM/MS eject media
5784 SET_AH(0xb2); // Volume Not Removable
5785 goto int13_fail_noah; // Always fail for HD
5786 break;
5787
5788 case 0x48: // IBM/MS get drive parameters
5789 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5790
5791 // Buffer is too small
5792 if(size < 0x1a)
5793 goto int13_fail;
5794
5795 // EDD 1.x
5796 if(size >= 0x1a) {
5797 Bit16u blksize;
5798
5799#ifdef VBOX_WITH_SCSI
5800 if (!VBOX_IS_SCSI_DEVICE(device))
5801#endif
5802 {
5803 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5804 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5805 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5806 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5807 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5808 }
5809#ifdef VBOX_WITH_SCSI
5810 else
5811 {
5812 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5813 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5814 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5815 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5816 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5817 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5818 }
5819#endif
5820
5821 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5822 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5823 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5824 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5825 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5826 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5827 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5828 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5829 }
5830
5831 // EDD 2.x
5832 if(size >= 0x1e) {
5833 Bit8u channel, dev, irq, mode, checksum, i, translation;
5834 Bit16u iobase1, iobase2, options;
5835
5836 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5837
5838 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5839 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5840
5841 // Fill in dpte
5842 channel = device / 2;
5843 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5844 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5845 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5846 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5847 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5848
5849 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5850 options |= (1<<4); // lba translation
5851 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5852 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5853 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5854
5855 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5856 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5857 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5858 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5859 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5860 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5861 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5862 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5863 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5864 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5865 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5866
5867 checksum=0;
5868 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5869 checksum = ~checksum;
5870 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5871 }
5872
5873 // EDD 3.x
5874 if(size >= 0x42) {
5875 Bit8u channel, iface, checksum, i;
5876 Bit16u iobase1;
5877
5878 channel = device / 2;
5879 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5880 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5881
5882 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5883 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5884 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5885 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5886 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5887
5888 if (iface==ATA_IFACE_ISA) {
5889 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5890 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5891 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5892 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5893 }
5894 else {
5895 // FIXME PCI
5896 }
5897 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5898 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5899 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5900 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5901
5902 if (iface==ATA_IFACE_ISA) {
5903 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5904 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5905 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5906 }
5907 else {
5908 // FIXME PCI
5909 }
5910 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5911 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5912 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5913 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5914
5915 checksum=0;
5916 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5917 checksum = ~checksum;
5918 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5919 }
5920
5921 goto int13_success;
5922 break;
5923
5924 case 0x4e: // // IBM/MS set hardware configuration
5925 // DMA, prefetch, PIO maximum not supported
5926 switch (GET_AL()) {
5927 case 0x01:
5928 case 0x03:
5929 case 0x04:
5930 case 0x06:
5931 goto int13_success;
5932 break;
5933 default :
5934 goto int13_fail;
5935 }
5936 break;
5937
5938 case 0x09: /* initialize drive parameters */
5939 case 0x0c: /* seek to specified cylinder */
5940 case 0x0d: /* alternate disk reset */
5941 case 0x11: /* recalibrate */
5942 case 0x14: /* controller internal diagnostic */
5943 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5944 goto int13_success;
5945 break;
5946
5947 case 0x0a: /* read disk sectors with ECC */
5948 case 0x0b: /* write disk sectors with ECC */
5949 case 0x18: // set media type for format
5950 case 0x50: // IBM/MS send packet command
5951 default:
5952 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5953 goto int13_fail;
5954 break;
5955 }
5956
5957int13_fail:
5958 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5959int13_fail_noah:
5960 SET_DISK_RET_STATUS(GET_AH());
5961int13_fail_nostatus:
5962 SET_CF(); // error occurred
5963 return;
5964
5965int13_success:
5966 SET_AH(0x00); // no error
5967int13_success_noah:
5968 SET_DISK_RET_STATUS(0x00);
5969 CLEAR_CF(); // no error
5970 return;
5971}
5972
5973// ---------------------------------------------------------------------------
5974// Start of int13 for cdrom
5975// ---------------------------------------------------------------------------
5976
5977 void
5978int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5979 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5980{
5981 Bit16u ebda_seg=read_word(0x0040,0x000E);
5982 Bit8u device, status, locks;
5983 Bit8u atacmd[12];
5984 Bit32u lba;
5985 Bit16u count, segment, offset, i, size;
5986
5987 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5988
5989 SET_DISK_RET_STATUS(0x00);
5990
5991 /* basic check : device should be 0xE0+ */
5992 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5993 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5994 goto int13_fail;
5995 }
5996
5997 // Get the ata channel
5998 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5999
6000 /* basic check : device has to be valid */
6001 if (device >= BX_MAX_ATA_DEVICES) {
6002 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
6003 goto int13_fail;
6004 }
6005
6006 switch (GET_AH()) {
6007
6008 // all those functions return SUCCESS
6009 case 0x00: /* disk controller reset */
6010 case 0x09: /* initialize drive parameters */
6011 case 0x0c: /* seek to specified cylinder */
6012 case 0x0d: /* alternate disk reset */
6013 case 0x10: /* check drive ready */
6014 case 0x11: /* recalibrate */
6015 case 0x14: /* controller internal diagnostic */
6016 case 0x16: /* detect disk change */
6017 goto int13_success;
6018 break;
6019
6020 // all those functions return disk write-protected
6021 case 0x03: /* write disk sectors */
6022 case 0x05: /* format disk track */
6023 case 0x43: // IBM/MS extended write
6024 SET_AH(0x03);
6025 goto int13_fail_noah;
6026 break;
6027
6028 case 0x01: /* read disk status */
6029 status = read_byte(0x0040, 0x0074);
6030 SET_AH(status);
6031 SET_DISK_RET_STATUS(0);
6032
6033 /* set CF if error status read */
6034 if (status) goto int13_fail_nostatus;
6035 else goto int13_success_noah;
6036 break;
6037
6038 case 0x15: /* read disk drive size */
6039 SET_AH(0x02);
6040 goto int13_fail_noah;
6041 break;
6042
6043 case 0x41: // IBM/MS installation check
6044 BX=0xaa55; // install check
6045 SET_AH(0x30); // EDD 2.1
6046 CX=0x0007; // ext disk access, removable and edd
6047 goto int13_success_noah;
6048 break;
6049
6050 case 0x42: // IBM/MS extended read
6051 case 0x44: // IBM/MS verify sectors
6052 case 0x47: // IBM/MS extended seek
6053
6054 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6055 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6056 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6057
6058 // Can't use 64 bits lba
6059 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6060 if (lba != 0L) {
6061 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6062 goto int13_fail;
6063 }
6064
6065 // Get 32 bits lba
6066 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6067
6068 // If verify or seek
6069 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6070 goto int13_success;
6071
6072 memsetb(get_SS(),atacmd,0,12);
6073 atacmd[0]=0x28; // READ command
6074 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6075 atacmd[8]=(count & 0x00ff); // Sectors
6076 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6077 atacmd[3]=(lba & 0x00ff0000) >> 16;
6078 atacmd[4]=(lba & 0x0000ff00) >> 8;
6079 atacmd[5]=(lba & 0x000000ff);
6080 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6081
6082 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6083 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6084
6085 if (status != 0) {
6086 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6087 SET_AH(0x0c);
6088 goto int13_fail_noah;
6089 }
6090
6091 goto int13_success;
6092 break;
6093
6094 case 0x45: // IBM/MS lock/unlock drive
6095 if (GET_AL() > 2) goto int13_fail;
6096
6097 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6098
6099 switch (GET_AL()) {
6100 case 0 : // lock
6101 if (locks == 0xff) {
6102 SET_AH(0xb4);
6103 SET_AL(1);
6104 goto int13_fail_noah;
6105 }
6106 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6107 SET_AL(1);
6108 break;
6109 case 1 : // unlock
6110 if (locks == 0x00) {
6111 SET_AH(0xb0);
6112 SET_AL(0);
6113 goto int13_fail_noah;
6114 }
6115 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6116 SET_AL(locks==0?0:1);
6117 break;
6118 case 2 : // status
6119 SET_AL(locks==0?0:1);
6120 break;
6121 }
6122 goto int13_success;
6123 break;
6124
6125 case 0x46: // IBM/MS eject media
6126 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6127
6128 if (locks != 0) {
6129 SET_AH(0xb1); // media locked
6130 goto int13_fail_noah;
6131 }
6132 // FIXME should handle 0x31 no media in device
6133 // FIXME should handle 0xb5 valid request failed
6134
6135 // Call removable media eject
6136 ASM_START
6137 push bp
6138 mov bp, sp
6139
6140 mov ah, #0x52
6141 int #0x15
6142 mov _int13_cdrom.status + 2[bp], ah
6143 jnc int13_cdrom_rme_end
6144 mov _int13_cdrom.status, #1
6145int13_cdrom_rme_end:
6146 pop bp
6147 ASM_END
6148
6149 if (status != 0) {
6150 SET_AH(0xb1); // media locked
6151 goto int13_fail_noah;
6152 }
6153
6154 goto int13_success;
6155 break;
6156
6157 case 0x48: // IBM/MS get drive parameters
6158 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6159
6160 // Buffer is too small
6161 if(size < 0x1a)
6162 goto int13_fail;
6163
6164 // EDD 1.x
6165 if(size >= 0x1a) {
6166 Bit16u cylinders, heads, spt, blksize;
6167
6168 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6169
6170 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6171 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6172 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6173 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6174 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6175 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6176 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6177 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6178 }
6179
6180 // EDD 2.x
6181 if(size >= 0x1e) {
6182 Bit8u channel, dev, irq, mode, checksum, i;
6183 Bit16u iobase1, iobase2, options;
6184
6185 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6186
6187 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6188 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6189
6190 // Fill in dpte
6191 channel = device / 2;
6192 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6193 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6194 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6195 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6196
6197 // FIXME atapi device
6198 options = (1<<4); // lba translation
6199 options |= (1<<5); // removable device
6200 options |= (1<<6); // atapi device
6201 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6202
6203 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6204 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6205 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6206 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6207 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6208 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6209 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6210 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6211 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6212 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6213 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6214
6215 checksum=0;
6216 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6217 checksum = ~checksum;
6218 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6219 }
6220
6221 // EDD 3.x
6222 if(size >= 0x42) {
6223 Bit8u channel, iface, checksum, i;
6224 Bit16u iobase1;
6225
6226 channel = device / 2;
6227 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6228 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6229
6230 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6231 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6232 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6233 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6234 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6235
6236 if (iface==ATA_IFACE_ISA) {
6237 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6238 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6239 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6240 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6241 }
6242 else {
6243 // FIXME PCI
6244 }
6245 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6246 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6247 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6248 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6249
6250 if (iface==ATA_IFACE_ISA) {
6251 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6252 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6253 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6254 }
6255 else {
6256 // FIXME PCI
6257 }
6258 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6259 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6260 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6261 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6262
6263 checksum=0;
6264 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6265 checksum = ~checksum;
6266 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6267 }
6268
6269 goto int13_success;
6270 break;
6271
6272 case 0x49: // IBM/MS extended media change
6273 // always send changed ??
6274 SET_AH(06);
6275 goto int13_fail_nostatus;
6276 break;
6277
6278 case 0x4e: // // IBM/MS set hardware configuration
6279 // DMA, prefetch, PIO maximum not supported
6280 switch (GET_AL()) {
6281 case 0x01:
6282 case 0x03:
6283 case 0x04:
6284 case 0x06:
6285 goto int13_success;
6286 break;
6287 default :
6288 goto int13_fail;
6289 }
6290 break;
6291
6292 // all those functions return unimplemented
6293 case 0x02: /* read sectors */
6294 case 0x04: /* verify sectors */
6295 case 0x08: /* read disk drive parameters */
6296 case 0x0a: /* read disk sectors with ECC */
6297 case 0x0b: /* write disk sectors with ECC */
6298 case 0x18: /* set media type for format */
6299 case 0x50: // ? - send packet command
6300 default:
6301 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6302 goto int13_fail;
6303 break;
6304 }
6305
6306int13_fail:
6307 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6308int13_fail_noah:
6309 SET_DISK_RET_STATUS(GET_AH());
6310int13_fail_nostatus:
6311 SET_CF(); // error occurred
6312 return;
6313
6314int13_success:
6315 SET_AH(0x00); // no error
6316int13_success_noah:
6317 SET_DISK_RET_STATUS(0x00);
6318 CLEAR_CF(); // no error
6319 return;
6320}
6321
6322// ---------------------------------------------------------------------------
6323// End of int13 for cdrom
6324// ---------------------------------------------------------------------------
6325
6326#if BX_ELTORITO_BOOT
6327// ---------------------------------------------------------------------------
6328// Start of int13 for eltorito functions
6329// ---------------------------------------------------------------------------
6330
6331 void
6332int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6333 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6334{
6335 Bit16u ebda_seg=read_word(0x0040,0x000E);
6336
6337 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6338 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6339
6340 switch (GET_AH()) {
6341
6342 // FIXME ElTorito Various. Should be implemented
6343 case 0x4a: // ElTorito - Initiate disk emu
6344 case 0x4c: // ElTorito - Initiate disk emu and boot
6345 case 0x4d: // ElTorito - Return Boot catalog
6346 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6347 goto int13_fail;
6348 break;
6349
6350 case 0x4b: // ElTorito - Terminate disk emu
6351 // FIXME ElTorito Hardcoded
6352 write_byte(DS,SI+0x00,0x13);
6353 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6354 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6355 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6356 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6357 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6358 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6359 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6360 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6361 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6362 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6363 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6364
6365 // If we have to terminate emulation
6366 if(GET_AL() == 0x00) {
6367 // FIXME ElTorito Various. Should be handled accordingly to spec
6368 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6369 }
6370
6371 goto int13_success;
6372 break;
6373
6374 default:
6375 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6376 goto int13_fail;
6377 break;
6378 }
6379
6380int13_fail:
6381 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6382 SET_DISK_RET_STATUS(GET_AH());
6383 SET_CF(); // error occurred
6384 return;
6385
6386int13_success:
6387 SET_AH(0x00); // no error
6388 SET_DISK_RET_STATUS(0x00);
6389 CLEAR_CF(); // no error
6390 return;
6391}
6392
6393// ---------------------------------------------------------------------------
6394// End of int13 for eltorito functions
6395// ---------------------------------------------------------------------------
6396
6397// ---------------------------------------------------------------------------
6398// Start of int13 when emulating a device from the cd
6399// ---------------------------------------------------------------------------
6400
6401 void
6402int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6403 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6404{
6405 Bit16u ebda_seg=read_word(0x0040,0x000E);
6406 Bit8u device, status;
6407 Bit16u vheads, vspt, vcylinders;
6408 Bit16u head, sector, cylinder, nbsectors;
6409 Bit32u vlba, ilba, slba, elba;
6410 Bit16u before, segment, offset;
6411 Bit8u atacmd[12];
6412
6413 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6414
6415 /* at this point, we are emulating a floppy/harddisk */
6416
6417 // Recompute the device number
6418 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6419 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6420
6421 SET_DISK_RET_STATUS(0x00);
6422
6423 /* basic checks : emulation should be active, dl should equal the emulated drive */
6424 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6425 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6426 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6427 goto int13_fail;
6428 }
6429
6430 switch (GET_AH()) {
6431
6432 // all those functions return SUCCESS
6433 case 0x00: /* disk controller reset */
6434 case 0x09: /* initialize drive parameters */
6435 case 0x0c: /* seek to specified cylinder */
6436 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6437 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6438 case 0x11: /* recalibrate */
6439 case 0x14: /* controller internal diagnostic */
6440 case 0x16: /* detect disk change */
6441 goto int13_success;
6442 break;
6443
6444 // all those functions return disk write-protected
6445 case 0x03: /* write disk sectors */
6446 case 0x05: /* format disk track */
6447 SET_AH(0x03);
6448 goto int13_fail_noah;
6449 break;
6450
6451 case 0x01: /* read disk status */
6452 status=read_byte(0x0040, 0x0074);
6453 SET_AH(status);
6454 SET_DISK_RET_STATUS(0);
6455
6456 /* set CF if error status read */
6457 if (status) goto int13_fail_nostatus;
6458 else goto int13_success_noah;
6459 break;
6460
6461 case 0x02: // read disk sectors
6462 case 0x04: // verify disk sectors
6463 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6464 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6465 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6466
6467 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6468
6469 sector = GET_CL() & 0x003f;
6470 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6471 head = GET_DH();
6472 nbsectors = GET_AL();
6473 segment = ES;
6474 offset = BX;
6475
6476 // no sector to read ?
6477 if(nbsectors==0) goto int13_success;
6478
6479 // sanity checks sco openserver needs this!
6480 if ((sector > vspt)
6481 || (cylinder >= vcylinders)
6482 || (head >= vheads)) {
6483 goto int13_fail;
6484 }
6485
6486 // After controls, verify do nothing
6487 if (GET_AH() == 0x04) goto int13_success;
6488
6489 segment = ES+(BX / 16);
6490 offset = BX % 16;
6491
6492 // calculate the virtual lba inside the image
6493 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6494
6495 // In advance so we don't loose the count
6496 SET_AL(nbsectors);
6497
6498 // start lba on cd
6499 slba = (Bit32u)vlba/4;
6500 before= (Bit16u)vlba%4;
6501
6502 // end lba on cd
6503 elba = (Bit32u)(vlba+nbsectors-1)/4;
6504
6505 memsetb(get_SS(),atacmd,0,12);
6506 atacmd[0]=0x28; // READ command
6507 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6508 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6509 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6510 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6511 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6512 atacmd[5]=(ilba+slba & 0x000000ff);
6513 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6514 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6515 SET_AH(0x02);
6516 SET_AL(0);
6517 goto int13_fail_noah;
6518 }
6519
6520 goto int13_success;
6521 break;
6522
6523 case 0x08: /* read disk drive parameters */
6524 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6525 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6526 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6527
6528 SET_AL( 0x00 );
6529 SET_BL( 0x00 );
6530 SET_CH( vcylinders & 0xff );
6531 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6532 SET_DH( vheads );
6533 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6534 // FIXME ElTorito Harddisk. should send the HD count
6535
6536 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6537 case 0x01: SET_BL( 0x02 ); break;
6538 case 0x02: SET_BL( 0x04 ); break;
6539 case 0x03: SET_BL( 0x06 ); break;
6540 }
6541
6542ASM_START
6543 push bp
6544 mov bp, sp
6545 mov ax, #diskette_param_table2
6546 mov _int13_cdemu.DI+2[bp], ax
6547 mov _int13_cdemu.ES+2[bp], cs
6548 pop bp
6549ASM_END
6550 goto int13_success;
6551 break;
6552
6553 case 0x15: /* read disk drive size */
6554 // FIXME ElTorito Harddisk. What geometry to send ?
6555 SET_AH(0x03);
6556 goto int13_success_noah;
6557 break;
6558
6559 // all those functions return unimplemented
6560 case 0x0a: /* read disk sectors with ECC */
6561 case 0x0b: /* write disk sectors with ECC */
6562 case 0x18: /* set media type for format */
6563 case 0x41: // IBM/MS installation check
6564 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6565 case 0x42: // IBM/MS extended read
6566 case 0x43: // IBM/MS extended write
6567 case 0x44: // IBM/MS verify sectors
6568 case 0x45: // IBM/MS lock/unlock drive
6569 case 0x46: // IBM/MS eject media
6570 case 0x47: // IBM/MS extended seek
6571 case 0x48: // IBM/MS get drive parameters
6572 case 0x49: // IBM/MS extended media change
6573 case 0x4e: // ? - set hardware configuration
6574 case 0x50: // ? - send packet command
6575 default:
6576 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6577 goto int13_fail;
6578 break;
6579 }
6580
6581int13_fail:
6582 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6583int13_fail_noah:
6584 SET_DISK_RET_STATUS(GET_AH());
6585int13_fail_nostatus:
6586 SET_CF(); // error occurred
6587 return;
6588
6589int13_success:
6590 SET_AH(0x00); // no error
6591int13_success_noah:
6592 SET_DISK_RET_STATUS(0x00);
6593 CLEAR_CF(); // no error
6594 return;
6595}
6596
6597// ---------------------------------------------------------------------------
6598// End of int13 when emulating a device from the cd
6599// ---------------------------------------------------------------------------
6600
6601#endif // BX_ELTORITO_BOOT
6602
6603#else //BX_USE_ATADRV
6604
6605 void
6606outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6607 Bit16u cylinder;
6608 Bit16u hd_heads;
6609 Bit16u head;
6610 Bit16u hd_sectors;
6611 Bit16u sector;
6612 Bit16u dl;
6613{
6614ASM_START
6615 push bp
6616 mov bp, sp
6617 push eax
6618 push ebx
6619 push edx
6620 xor eax,eax
6621 mov ax,4[bp] // cylinder
6622 xor ebx,ebx
6623 mov bl,6[bp] // hd_heads
6624 imul ebx
6625
6626 mov bl,8[bp] // head
6627 add eax,ebx
6628 mov bl,10[bp] // hd_sectors
6629 imul ebx
6630 mov bl,12[bp] // sector
6631 add eax,ebx
6632
6633 dec eax
6634 mov dx,#0x1f3
6635 out dx,al
6636 mov dx,#0x1f4
6637 mov al,ah
6638 out dx,al
6639 shr eax,#16
6640 mov dx,#0x1f5
6641 out dx,al
6642 and ah,#0xf
6643 mov bl,14[bp] // dl
6644 and bl,#1
6645 shl bl,#4
6646 or ah,bl
6647 or ah,#0xe0
6648 mov al,ah
6649 mov dx,#0x01f6
6650 out dx,al
6651 pop edx
6652 pop ebx
6653 pop eax
6654 pop bp
6655ASM_END
6656}
6657
6658 void
6659int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6660 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6661{
6662 Bit8u drive, num_sectors, sector, head, status, mod;
6663 Bit8u drive_map;
6664 Bit8u n_drives;
6665 Bit16u cyl_mod, ax;
6666 Bit16u max_cylinder, cylinder, total_sectors;
6667 Bit16u hd_cylinders;
6668 Bit8u hd_heads, hd_sectors;
6669 Bit16u val16;
6670 Bit8u sector_count;
6671 unsigned int i;
6672 Bit16u tempbx;
6673 Bit16u dpsize;
6674
6675 Bit16u count, segment, offset;
6676 Bit32u lba;
6677 Bit16u error;
6678
6679 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6680
6681 write_byte(0x0040, 0x008e, 0); // clear completion flag
6682
6683 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6684 handler code */
6685 /* check how many disks first (cmos reg 0x12), return an error if
6686 drive not present */
6687 drive_map = inb_cmos(0x12);
6688 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6689 (((drive_map & 0x0f)==0) ? 0 : 2);
6690 n_drives = (drive_map==0) ? 0 :
6691 ((drive_map==3) ? 2 : 1);
6692
6693 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6694 SET_AH(0x01);
6695 SET_DISK_RET_STATUS(0x01);
6696 SET_CF(); /* error occurred */
6697 return;
6698 }
6699
6700 switch (GET_AH()) {
6701
6702 case 0x00: /* disk controller reset */
6703BX_DEBUG_INT13_HD("int13_f00\n");
6704
6705 SET_AH(0);
6706 SET_DISK_RET_STATUS(0);
6707 set_diskette_ret_status(0);
6708 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6709 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6710 CLEAR_CF(); /* successful */
6711 return;
6712 break;
6713
6714 case 0x01: /* read disk status */
6715BX_DEBUG_INT13_HD("int13_f01\n");
6716 status = read_byte(0x0040, 0x0074);
6717 SET_AH(status);
6718 SET_DISK_RET_STATUS(0);
6719 /* set CF if error status read */
6720 if (status) SET_CF();
6721 else CLEAR_CF();
6722 return;
6723 break;
6724
6725 case 0x04: // verify disk sectors
6726 case 0x02: // read disk sectors
6727 drive = GET_ELDL();
6728 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6729
6730 num_sectors = GET_AL();
6731 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6732 sector = (GET_CL() & 0x3f);
6733 head = GET_DH();
6734
6735
6736 if (hd_cylinders > 1024) {
6737 if (hd_cylinders <= 2048) {
6738 cylinder <<= 1;
6739 }
6740 else if (hd_cylinders <= 4096) {
6741 cylinder <<= 2;
6742 }
6743 else if (hd_cylinders <= 8192) {
6744 cylinder <<= 3;
6745 }
6746 else { // hd_cylinders <= 16384
6747 cylinder <<= 4;
6748 }
6749
6750 ax = head / hd_heads;
6751 cyl_mod = ax & 0xff;
6752 head = ax >> 8;
6753 cylinder |= cyl_mod;
6754 }
6755
6756 if ( (cylinder >= hd_cylinders) ||
6757 (sector > hd_sectors) ||
6758 (head >= hd_heads) ) {
6759 SET_AH(1);
6760 SET_DISK_RET_STATUS(1);
6761 SET_CF(); /* error occurred */
6762 return;
6763 }
6764
6765 if ( (num_sectors > 128) || (num_sectors == 0) )
6766 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6767
6768 if (head > 15)
6769 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6770
6771 if ( GET_AH() == 0x04 ) {
6772 SET_AH(0);
6773 SET_DISK_RET_STATUS(0);
6774 CLEAR_CF();
6775 return;
6776 }
6777
6778 status = inb(0x1f7);
6779 if (status & 0x80) {
6780 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6781 }
6782 outb(0x01f2, num_sectors);
6783 /* activate LBA? (tomv) */
6784 if (hd_heads > 16) {
6785BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6786 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6787 }
6788 else {
6789 outb(0x01f3, sector);
6790 outb(0x01f4, cylinder & 0x00ff);
6791 outb(0x01f5, cylinder >> 8);
6792 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6793 }
6794 outb(0x01f7, 0x20);
6795
6796 while (1) {
6797 status = inb(0x1f7);
6798 if ( !(status & 0x80) ) break;
6799 }
6800
6801 if (status & 0x01) {
6802 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6803 } else if ( !(status & 0x08) ) {
6804 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6805 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6806 }
6807
6808 sector_count = 0;
6809 tempbx = BX;
6810
6811ASM_START
6812 sti ;; enable higher priority interrupts
6813ASM_END
6814
6815 while (1) {
6816ASM_START
6817 ;; store temp bx in real DI register
6818 push bp
6819 mov bp, sp
6820 mov di, _int13_harddisk.tempbx + 2 [bp]
6821 pop bp
6822
6823 ;; adjust if there will be an overrun
6824 cmp di, #0xfe00
6825 jbe i13_f02_no_adjust
6826i13_f02_adjust:
6827 sub di, #0x0200 ; sub 512 bytes from offset
6828 mov ax, es
6829 add ax, #0x0020 ; add 512 to segment
6830 mov es, ax
6831
6832i13_f02_no_adjust:
6833 mov cx, #0x0100 ;; counter (256 words = 512b)
6834 mov dx, #0x01f0 ;; AT data read port
6835
6836 rep
6837 insw ;; CX words transfered from port(DX) to ES:[DI]
6838
6839i13_f02_done:
6840 ;; store real DI register back to temp bx
6841 push bp
6842 mov bp, sp
6843 mov _int13_harddisk.tempbx + 2 [bp], di
6844 pop bp
6845ASM_END
6846
6847 sector_count++;
6848 num_sectors--;
6849 if (num_sectors == 0) {
6850 status = inb(0x1f7);
6851 if ( (status & 0xc9) != 0x40 )
6852 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6853 break;
6854 }
6855 else {
6856 status = inb(0x1f7);
6857 if ( (status & 0xc9) != 0x48 )
6858 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6859 continue;
6860 }
6861 }
6862
6863 SET_AH(0);
6864 SET_DISK_RET_STATUS(0);
6865 SET_AL(sector_count);
6866 CLEAR_CF(); /* successful */
6867 return;
6868 break;
6869
6870
6871 case 0x03: /* write disk sectors */
6872BX_DEBUG_INT13_HD("int13_f03\n");
6873 drive = GET_ELDL ();
6874 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6875
6876 num_sectors = GET_AL();
6877 cylinder = GET_CH();
6878 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6879 sector = (GET_CL() & 0x3f);
6880 head = GET_DH();
6881
6882 if (hd_cylinders > 1024) {
6883 if (hd_cylinders <= 2048) {
6884 cylinder <<= 1;
6885 }
6886 else if (hd_cylinders <= 4096) {
6887 cylinder <<= 2;
6888 }
6889 else if (hd_cylinders <= 8192) {
6890 cylinder <<= 3;
6891 }
6892 else { // hd_cylinders <= 16384
6893 cylinder <<= 4;
6894 }
6895
6896 ax = head / hd_heads;
6897 cyl_mod = ax & 0xff;
6898 head = ax >> 8;
6899 cylinder |= cyl_mod;
6900 }
6901
6902 if ( (cylinder >= hd_cylinders) ||
6903 (sector > hd_sectors) ||
6904 (head >= hd_heads) ) {
6905 SET_AH( 1);
6906 SET_DISK_RET_STATUS(1);
6907 SET_CF(); /* error occurred */
6908 return;
6909 }
6910
6911 if ( (num_sectors > 128) || (num_sectors == 0) )
6912 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6913
6914 if (head > 15)
6915 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6916
6917 status = inb(0x1f7);
6918 if (status & 0x80) {
6919 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6920 }
6921// should check for Drive Ready Bit also in status reg
6922 outb(0x01f2, num_sectors);
6923
6924 /* activate LBA? (tomv) */
6925 if (hd_heads > 16) {
6926BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6927 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6928 }
6929 else {
6930 outb(0x01f3, sector);
6931 outb(0x01f4, cylinder & 0x00ff);
6932 outb(0x01f5, cylinder >> 8);
6933 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6934 }
6935 outb(0x01f7, 0x30);
6936
6937 // wait for busy bit to turn off after seeking
6938 while (1) {
6939 status = inb(0x1f7);
6940 if ( !(status & 0x80) ) break;
6941 }
6942
6943 if ( !(status & 0x08) ) {
6944 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6945 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6946 }
6947
6948 sector_count = 0;
6949 tempbx = BX;
6950
6951ASM_START
6952 sti ;; enable higher priority interrupts
6953ASM_END
6954
6955 while (1) {
6956ASM_START
6957 ;; store temp bx in real SI register
6958 push bp
6959 mov bp, sp
6960 mov si, _int13_harddisk.tempbx + 2 [bp]
6961 pop bp
6962
6963 ;; adjust if there will be an overrun
6964 cmp si, #0xfe00
6965 jbe i13_f03_no_adjust
6966i13_f03_adjust:
6967 sub si, #0x0200 ; sub 512 bytes from offset
6968 mov ax, es
6969 add ax, #0x0020 ; add 512 to segment
6970 mov es, ax
6971
6972i13_f03_no_adjust:
6973 mov cx, #0x0100 ;; counter (256 words = 512b)
6974 mov dx, #0x01f0 ;; AT data read port
6975
6976 seg ES
6977 rep
6978 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6979
6980 ;; store real SI register back to temp bx
6981 push bp
6982 mov bp, sp
6983 mov _int13_harddisk.tempbx + 2 [bp], si
6984 pop bp
6985ASM_END
6986
6987 sector_count++;
6988 num_sectors--;
6989 if (num_sectors == 0) {
6990 status = inb(0x1f7);
6991 if ( (status & 0xe9) != 0x40 )
6992 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6993 break;
6994 }
6995 else {
6996 status = inb(0x1f7);
6997 if ( (status & 0xc9) != 0x48 )
6998 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6999 continue;
7000 }
7001 }
7002
7003 SET_AH(0);
7004 SET_DISK_RET_STATUS(0);
7005 SET_AL(sector_count);
7006 CLEAR_CF(); /* successful */
7007 return;
7008 break;
7009
7010 case 0x05: /* format disk track */
7011BX_DEBUG_INT13_HD("int13_f05\n");
7012 BX_PANIC("format disk track called\n");
7013 /* nop */
7014 SET_AH(0);
7015 SET_DISK_RET_STATUS(0);
7016 CLEAR_CF(); /* successful */
7017 return;
7018 break;
7019
7020 case 0x08: /* read disk drive parameters */
7021BX_DEBUG_INT13_HD("int13_f08\n");
7022
7023 drive = GET_ELDL ();
7024 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7025
7026 // translate CHS
7027 //
7028 if (hd_cylinders <= 1024) {
7029 // hd_cylinders >>= 0;
7030 // hd_heads <<= 0;
7031 }
7032 else if (hd_cylinders <= 2048) {
7033 hd_cylinders >>= 1;
7034 hd_heads <<= 1;
7035 }
7036 else if (hd_cylinders <= 4096) {
7037 hd_cylinders >>= 2;
7038 hd_heads <<= 2;
7039 }
7040 else if (hd_cylinders <= 8192) {
7041 hd_cylinders >>= 3;
7042 hd_heads <<= 3;
7043 }
7044 else { // hd_cylinders <= 16384
7045 hd_cylinders >>= 4;
7046 hd_heads <<= 4;
7047 }
7048
7049 max_cylinder = hd_cylinders - 2; /* 0 based */
7050 SET_AL(0);
7051 SET_CH(max_cylinder & 0xff);
7052 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7053 SET_DH(hd_heads - 1);
7054 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7055 SET_AH(0);
7056 SET_DISK_RET_STATUS(0);
7057 CLEAR_CF(); /* successful */
7058
7059 return;
7060 break;
7061
7062 case 0x09: /* initialize drive parameters */
7063BX_DEBUG_INT13_HD("int13_f09\n");
7064 SET_AH(0);
7065 SET_DISK_RET_STATUS(0);
7066 CLEAR_CF(); /* successful */
7067 return;
7068 break;
7069
7070 case 0x0a: /* read disk sectors with ECC */
7071BX_DEBUG_INT13_HD("int13_f0a\n");
7072 case 0x0b: /* write disk sectors with ECC */
7073BX_DEBUG_INT13_HD("int13_f0b\n");
7074 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7075 return;
7076 break;
7077
7078 case 0x0c: /* seek to specified cylinder */
7079BX_DEBUG_INT13_HD("int13_f0c\n");
7080 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7081 SET_AH(0);
7082 SET_DISK_RET_STATUS(0);
7083 CLEAR_CF(); /* successful */
7084 return;
7085 break;
7086
7087 case 0x0d: /* alternate disk reset */
7088BX_DEBUG_INT13_HD("int13_f0d\n");
7089 SET_AH(0);
7090 SET_DISK_RET_STATUS(0);
7091 CLEAR_CF(); /* successful */
7092 return;
7093 break;
7094
7095 case 0x10: /* check drive ready */
7096BX_DEBUG_INT13_HD("int13_f10\n");
7097 //SET_AH(0);
7098 //SET_DISK_RET_STATUS(0);
7099 //CLEAR_CF(); /* successful */
7100 //return;
7101 //break;
7102
7103 // should look at 40:8E also???
7104 status = inb(0x01f7);
7105 if ( (status & 0xc0) == 0x40 ) {
7106 SET_AH(0);
7107 SET_DISK_RET_STATUS(0);
7108 CLEAR_CF(); // drive ready
7109 return;
7110 }
7111 else {
7112 SET_AH(0xAA);
7113 SET_DISK_RET_STATUS(0xAA);
7114 SET_CF(); // not ready
7115 return;
7116 }
7117 break;
7118
7119 case 0x11: /* recalibrate */
7120BX_DEBUG_INT13_HD("int13_f11\n");
7121 SET_AH(0);
7122 SET_DISK_RET_STATUS(0);
7123 CLEAR_CF(); /* successful */
7124 return;
7125 break;
7126
7127 case 0x14: /* controller internal diagnostic */
7128BX_DEBUG_INT13_HD("int13_f14\n");
7129 SET_AH(0);
7130 SET_DISK_RET_STATUS(0);
7131 CLEAR_CF(); /* successful */
7132 SET_AL(0);
7133 return;
7134 break;
7135
7136 case 0x15: /* read disk drive size */
7137 drive = GET_ELDL();
7138 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7139ASM_START
7140 push bp
7141 mov bp, sp
7142 mov al, _int13_harddisk.hd_heads + 2 [bp]
7143 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7144 mul al, ah ;; ax = heads * sectors
7145 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7146 dec bx ;; use (cylinders - 1) ???
7147 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7148 ;; now we need to move the 32bit result dx:ax to what the
7149 ;; BIOS wants which is cx:dx.
7150 ;; and then into CX:DX on the stack
7151 mov _int13_harddisk.CX + 2 [bp], dx
7152 mov _int13_harddisk.DX + 2 [bp], ax
7153 pop bp
7154ASM_END
7155 SET_AH(3); // hard disk accessible
7156 SET_DISK_RET_STATUS(0); // ??? should this be 0
7157 CLEAR_CF(); // successful
7158 return;
7159 break;
7160
7161 case 0x18: // set media type for format
7162 case 0x41: // IBM/MS
7163 case 0x42: // IBM/MS
7164 case 0x43: // IBM/MS
7165 case 0x44: // IBM/MS
7166 case 0x45: // IBM/MS lock/unlock drive
7167 case 0x46: // IBM/MS eject media
7168 case 0x47: // IBM/MS extended seek
7169 case 0x49: // IBM/MS extended media change
7170 case 0x50: // IBM/MS send packet command
7171 default:
7172 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7173
7174 SET_AH(1); // code=invalid function in AH or invalid parameter
7175 SET_DISK_RET_STATUS(1);
7176 SET_CF(); /* unsuccessful */
7177 return;
7178 break;
7179 }
7180}
7181
7182static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7183static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7184
7185 void
7186get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7187 Bit8u drive;
7188 Bit16u *hd_cylinders;
7189 Bit8u *hd_heads;
7190 Bit8u *hd_sectors;
7191{
7192 Bit8u hd_type;
7193 Bit16u ss;
7194 Bit16u cylinders;
7195 Bit8u iobase;
7196
7197 ss = get_SS();
7198 if (drive == 0x80) {
7199 hd_type = inb_cmos(0x12) & 0xf0;
7200 if (hd_type != 0xf0)
7201 BX_INFO(panic_msg_reg12h,0);
7202 hd_type = inb_cmos(0x19); // HD0: extended type
7203 if (hd_type != 47)
7204 BX_INFO(panic_msg_reg19h,0,0x19);
7205 iobase = 0x1b;
7206 } else {
7207 hd_type = inb_cmos(0x12) & 0x0f;
7208 if (hd_type != 0x0f)
7209 BX_INFO(panic_msg_reg12h,1);
7210 hd_type = inb_cmos(0x1a); // HD1: extended type
7211 if (hd_type != 47)
7212 BX_INFO(panic_msg_reg19h,0,0x1a);
7213 iobase = 0x24;
7214 }
7215
7216 // cylinders
7217 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7218 write_word(ss, hd_cylinders, cylinders);
7219
7220 // heads
7221 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7222
7223 // sectors per track
7224 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7225}
7226
7227#endif //else BX_USE_ATADRV
7228
7229#if BX_SUPPORT_FLOPPY
7230
7231//////////////////////
7232// FLOPPY functions //
7233//////////////////////
7234
7235void floppy_reset_controller()
7236{
7237 Bit8u val8;
7238
7239 // Reset controller
7240 val8 = inb(0x03f2);
7241 outb(0x03f2, val8 & ~0x04);
7242 outb(0x03f2, val8 | 0x04);
7243
7244 // Wait for controller to come out of reset
7245 do {
7246 val8 = inb(0x3f4);
7247 } while ( (val8 & 0xc0) != 0x80 );
7248}
7249
7250void floppy_prepare_controller(drive)
7251 Bit16u drive;
7252{
7253 Bit8u val8, dor, prev_reset;
7254
7255 // set 40:3e bit 7 to 0
7256 val8 = read_byte(0x0040, 0x003e);
7257 val8 &= 0x7f;
7258 write_byte(0x0040, 0x003e, val8);
7259
7260 // turn on motor of selected drive, DMA & int enabled, normal operation
7261 prev_reset = inb(0x03f2) & 0x04;
7262 if (drive)
7263 dor = 0x20;
7264 else
7265 dor = 0x10;
7266 dor |= 0x0c;
7267 dor |= drive;
7268 outb(0x03f2, dor);
7269
7270 // reset the disk motor timeout value of INT 08
7271 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7272
7273#ifdef VBOX
7274 // program data rate
7275 val8 = read_byte(0x0040, 0x008b);
7276 val8 >>= 6;
7277 outb(0x03f7, val8);
7278#endif
7279
7280 // wait for drive readiness
7281 do {
7282 val8 = inb(0x3f4);
7283 } while ( (val8 & 0xc0) != 0x80 );
7284
7285 if (prev_reset == 0) {
7286 // turn on interrupts
7287ASM_START
7288 sti
7289ASM_END
7290 // wait on 40:3e bit 7 to become 1
7291 do {
7292 val8 = read_byte(0x0040, 0x003e);
7293 } while ( (val8 & 0x80) == 0 );
7294 val8 &= 0x7f;
7295ASM_START
7296 cli
7297ASM_END
7298 write_byte(0x0040, 0x003e, val8);
7299 }
7300}
7301
7302 bx_bool
7303floppy_media_known(drive)
7304 Bit16u drive;
7305{
7306 Bit8u val8;
7307 Bit16u media_state_offset;
7308
7309 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7310 if (drive)
7311 val8 >>= 1;
7312 val8 &= 0x01;
7313 if (val8 == 0)
7314 return(0);
7315
7316 media_state_offset = 0x0090;
7317 if (drive)
7318 media_state_offset += 1;
7319
7320 val8 = read_byte(0x0040, media_state_offset);
7321 val8 = (val8 >> 4) & 0x01;
7322 if (val8 == 0)
7323 return(0);
7324
7325 // check pass, return KNOWN
7326 return(1);
7327}
7328
7329 bx_bool
7330floppy_media_sense(drive)
7331 Bit16u drive;
7332{
7333 bx_bool retval;
7334 Bit16u media_state_offset;
7335 Bit8u drive_type, config_data, media_state;
7336
7337 if (floppy_drive_recal(drive) == 0) {
7338 return(0);
7339 }
7340
7341 // for now cheat and get drive type from CMOS,
7342 // assume media is same as drive type
7343
7344 // ** config_data **
7345 // Bitfields for diskette media control:
7346 // Bit(s) Description (Table M0028)
7347 // 7-6 last data rate set by controller
7348 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7349 // 5-4 last diskette drive step rate selected
7350 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7351 // 3-2 {data rate at start of operation}
7352 // 1-0 reserved
7353
7354 // ** media_state **
7355 // Bitfields for diskette drive media state:
7356 // Bit(s) Description (Table M0030)
7357 // 7-6 data rate
7358 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7359 // 5 double stepping required (e.g. 360kB in 1.2MB)
7360 // 4 media type established
7361 // 3 drive capable of supporting 4MB media
7362 // 2-0 on exit from BIOS, contains
7363 // 000 trying 360kB in 360kB
7364 // 001 trying 360kB in 1.2MB
7365 // 010 trying 1.2MB in 1.2MB
7366 // 011 360kB in 360kB established
7367 // 100 360kB in 1.2MB established
7368 // 101 1.2MB in 1.2MB established
7369 // 110 reserved
7370 // 111 all other formats/drives
7371
7372 drive_type = inb_cmos(0x10);
7373 if (drive == 0)
7374 drive_type >>= 4;
7375 else
7376 drive_type &= 0x0f;
7377 if ( drive_type == 1 ) {
7378 // 360K 5.25" drive
7379 config_data = 0x00; // 0000 0000
7380 media_state = 0x25; // 0010 0101
7381 retval = 1;
7382 }
7383 else if ( drive_type == 2 ) {
7384 // 1.2 MB 5.25" drive
7385 config_data = 0x00; // 0000 0000
7386 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7387 retval = 1;
7388 }
7389 else if ( drive_type == 3 ) {
7390 // 720K 3.5" drive
7391 config_data = 0x00; // 0000 0000 ???
7392 media_state = 0x17; // 0001 0111
7393 retval = 1;
7394 }
7395 else if ( drive_type == 4 ) {
7396 // 1.44 MB 3.5" drive
7397 config_data = 0x00; // 0000 0000
7398 media_state = 0x17; // 0001 0111
7399 retval = 1;
7400 }
7401 else if ( drive_type == 5 ) {
7402 // 2.88 MB 3.5" drive
7403 config_data = 0xCC; // 1100 1100
7404 media_state = 0xD7; // 1101 0111
7405 retval = 1;
7406 }
7407 //
7408 // Extended floppy size uses special cmos setting
7409 else if ( drive_type == 6 ) {
7410 // 160k 5.25" drive
7411 config_data = 0x00; // 0000 0000
7412 media_state = 0x27; // 0010 0111
7413 retval = 1;
7414 }
7415 else if ( drive_type == 7 ) {
7416 // 180k 5.25" drive
7417 config_data = 0x00; // 0000 0000
7418 media_state = 0x27; // 0010 0111
7419 retval = 1;
7420 }
7421 else if ( drive_type == 8 ) {
7422 // 320k 5.25" drive
7423 config_data = 0x00; // 0000 0000
7424 media_state = 0x27; // 0010 0111
7425 retval = 1;
7426 }
7427
7428 else {
7429 // not recognized
7430 config_data = 0x00; // 0000 0000
7431 media_state = 0x00; // 0000 0000
7432 retval = 0;
7433 }
7434
7435 if (drive == 0)
7436 media_state_offset = 0x90;
7437 else
7438 media_state_offset = 0x91;
7439 write_byte(0x0040, 0x008B, config_data);
7440 write_byte(0x0040, media_state_offset, media_state);
7441
7442 return(retval);
7443}
7444
7445 bx_bool
7446floppy_drive_recal(drive)
7447 Bit16u drive;
7448{
7449 Bit8u val8;
7450 Bit16u curr_cyl_offset;
7451
7452 floppy_prepare_controller(drive);
7453
7454 // send Recalibrate command (2 bytes) to controller
7455 outb(0x03f5, 0x07); // 07: Recalibrate
7456 outb(0x03f5, drive); // 0=drive0, 1=drive1
7457
7458 // turn on interrupts
7459ASM_START
7460 sti
7461ASM_END
7462
7463 // wait on 40:3e bit 7 to become 1
7464 do {
7465 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7466 } while ( val8 == 0 );
7467
7468 val8 = 0; // separate asm from while() loop
7469 // turn off interrupts
7470ASM_START
7471 cli
7472ASM_END
7473
7474 // set 40:3e bit 7 to 0, and calibrated bit
7475 val8 = read_byte(0x0040, 0x003e);
7476 val8 &= 0x7f;
7477 if (drive) {
7478 val8 |= 0x02; // Drive 1 calibrated
7479 curr_cyl_offset = 0x0095;
7480 } else {
7481 val8 |= 0x01; // Drive 0 calibrated
7482 curr_cyl_offset = 0x0094;
7483 }
7484 write_byte(0x0040, 0x003e, val8);
7485 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7486
7487 return(1);
7488}
7489
7490
7491
7492 bx_bool
7493floppy_drive_exists(drive)
7494 Bit16u drive;
7495{
7496 Bit8u drive_type;
7497
7498 // check CMOS to see if drive exists
7499 drive_type = inb_cmos(0x10);
7500 if (drive == 0)
7501 drive_type >>= 4;
7502 else
7503 drive_type &= 0x0f;
7504 if ( drive_type == 0 )
7505 return(0);
7506 else
7507 return(1);
7508}
7509
7510 void
7511int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7512 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7513{
7514 Bit8u drive, num_sectors, track, sector, head, status;
7515 Bit16u base_address, base_count, base_es;
7516 Bit8u page, mode_register, val8, dor;
7517 Bit8u return_status[7];
7518 Bit8u drive_type, num_floppies, ah;
7519 Bit16u es, last_addr;
7520
7521 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7522
7523 ah = GET_AH();
7524
7525 switch ( ah ) {
7526 case 0x00: // diskette controller reset
7527BX_DEBUG_INT13_FL("floppy f00\n");
7528 drive = GET_ELDL();
7529 if (drive > 1) {
7530 SET_AH(1); // invalid param
7531 set_diskette_ret_status(1);
7532 SET_CF();
7533 return;
7534 }
7535 drive_type = inb_cmos(0x10);
7536
7537 if (drive == 0)
7538 drive_type >>= 4;
7539 else
7540 drive_type &= 0x0f;
7541 if (drive_type == 0) {
7542 SET_AH(0x80); // drive not responding
7543 set_diskette_ret_status(0x80);
7544 SET_CF();
7545 return;
7546 }
7547 SET_AH(0);
7548 set_diskette_ret_status(0);
7549 CLEAR_CF(); // successful
7550 set_diskette_current_cyl(drive, 0); // current cylinder
7551 return;
7552
7553 case 0x01: // Read Diskette Status
7554 CLEAR_CF();
7555 val8 = read_byte(0x0000, 0x0441);
7556 SET_AH(val8);
7557 if (val8) {
7558 SET_CF();
7559 }
7560 return;
7561
7562 case 0x02: // Read Diskette Sectors
7563 case 0x03: // Write Diskette Sectors
7564 case 0x04: // Verify Diskette Sectors
7565 num_sectors = GET_AL();
7566 track = GET_CH();
7567 sector = GET_CL();
7568 head = GET_DH();
7569 drive = GET_ELDL();
7570
7571 if ( (drive > 1) || (head > 1) ||
7572 (num_sectors == 0) || (num_sectors > 72) ) {
7573BX_INFO("floppy: drive>1 || head>1 ...\n");
7574 SET_AH(1);
7575 set_diskette_ret_status(1);
7576 SET_AL(0); // no sectors read
7577 SET_CF(); // error occurred
7578 return;
7579 }
7580
7581 // see if drive exists
7582 if (floppy_drive_exists(drive) == 0) {
7583 SET_AH(0x80); // not responding
7584 set_diskette_ret_status(0x80);
7585 SET_AL(0); // no sectors read
7586 SET_CF(); // error occurred
7587 return;
7588 }
7589
7590 // see if media in drive, and type is known
7591 if (floppy_media_known(drive) == 0) {
7592 if (floppy_media_sense(drive) == 0) {
7593 SET_AH(0x0C); // Media type not found
7594 set_diskette_ret_status(0x0C);
7595 SET_AL(0); // no sectors read
7596 SET_CF(); // error occurred
7597 return;
7598 }
7599 }
7600
7601 if (ah == 0x02) {
7602 // Read Diskette Sectors
7603
7604 //-----------------------------------
7605 // set up DMA controller for transfer
7606 //-----------------------------------
7607
7608 // es:bx = pointer to where to place information from diskette
7609 // port 04: DMA-1 base and current address, channel 2
7610 // port 05: DMA-1 base and current count, channel 2
7611 page = (ES >> 12); // upper 4 bits
7612 base_es = (ES << 4); // lower 16bits contributed by ES
7613 base_address = base_es + BX; // lower 16 bits of address
7614 // contributed by ES:BX
7615 if ( base_address < base_es ) {
7616 // in case of carry, adjust page by 1
7617 page++;
7618 }
7619 base_count = (num_sectors * 512) - 1;
7620
7621 // check for 64K boundary overrun
7622 last_addr = base_address + base_count;
7623 if (last_addr < base_address) {
7624 SET_AH(0x09);
7625 set_diskette_ret_status(0x09);
7626 SET_AL(0); // no sectors read
7627 SET_CF(); // error occurred
7628 return;
7629 }
7630
7631 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7632 outb(0x000a, 0x06);
7633
7634 BX_DEBUG_INT13_FL("clear flip-flop\n");
7635 outb(0x000c, 0x00); // clear flip-flop
7636 outb(0x0004, base_address);
7637 outb(0x0004, base_address>>8);
7638 BX_DEBUG_INT13_FL("clear flip-flop\n");
7639 outb(0x000c, 0x00); // clear flip-flop
7640 outb(0x0005, base_count);
7641 outb(0x0005, base_count>>8);
7642
7643 // port 0b: DMA-1 Mode Register
7644 mode_register = 0x46; // single mode, increment, autoinit disable,
7645 // transfer type=write, channel 2
7646 BX_DEBUG_INT13_FL("setting mode register\n");
7647 outb(0x000b, mode_register);
7648
7649 BX_DEBUG_INT13_FL("setting page register\n");
7650 // port 81: DMA-1 Page Register, channel 2
7651 outb(0x0081, page);
7652
7653 BX_DEBUG_INT13_FL("unmask chan 2\n");
7654 outb(0x000a, 0x02); // unmask channel 2
7655
7656 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7657 outb(0x000a, 0x02);
7658
7659 //--------------------------------------
7660 // set up floppy controller for transfer
7661 //--------------------------------------
7662 floppy_prepare_controller(drive);
7663
7664 // send read-normal-data command (9 bytes) to controller
7665 outb(0x03f5, 0xe6); // e6: read normal data
7666 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7667 outb(0x03f5, track);
7668 outb(0x03f5, head);
7669 outb(0x03f5, sector);
7670 outb(0x03f5, 2); // 512 byte sector size
7671 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7672 outb(0x03f5, 0); // Gap length
7673 outb(0x03f5, 0xff); // Gap length
7674
7675 // turn on interrupts
7676 ASM_START
7677 sti
7678 ASM_END
7679
7680 // wait on 40:3e bit 7 to become 1
7681 do {
7682 val8 = read_byte(0x0040, 0x0040);
7683 if (val8 == 0) {
7684 floppy_reset_controller();
7685 SET_AH(0x80); // drive not ready (timeout)
7686 set_diskette_ret_status(0x80);
7687 SET_AL(0); // no sectors read
7688 SET_CF(); // error occurred
7689 return;
7690 }
7691 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7692 } while ( val8 == 0 );
7693
7694 val8 = 0; // separate asm from while() loop
7695 // turn off interrupts
7696 ASM_START
7697 cli
7698 ASM_END
7699
7700 // set 40:3e bit 7 to 0
7701 val8 = read_byte(0x0040, 0x003e);
7702 val8 &= 0x7f;
7703 write_byte(0x0040, 0x003e, val8);
7704
7705 // check port 3f4 for accessibility to status bytes
7706 val8 = inb(0x3f4);
7707 if ( (val8 & 0xc0) != 0xc0 )
7708 BX_PANIC("int13_diskette: ctrl not ready\n");
7709
7710 // read 7 return status bytes from controller
7711 // using loop index broken, have to unroll...
7712 return_status[0] = inb(0x3f5);
7713 return_status[1] = inb(0x3f5);
7714 return_status[2] = inb(0x3f5);
7715 return_status[3] = inb(0x3f5);
7716 return_status[4] = inb(0x3f5);
7717 return_status[5] = inb(0x3f5);
7718 return_status[6] = inb(0x3f5);
7719 // record in BIOS Data Area
7720 write_byte(0x0040, 0x0042, return_status[0]);
7721 write_byte(0x0040, 0x0043, return_status[1]);
7722 write_byte(0x0040, 0x0044, return_status[2]);
7723 write_byte(0x0040, 0x0045, return_status[3]);
7724 write_byte(0x0040, 0x0046, return_status[4]);
7725 write_byte(0x0040, 0x0047, return_status[5]);
7726 write_byte(0x0040, 0x0048, return_status[6]);
7727
7728 if ( (return_status[0] & 0xc0) != 0 ) {
7729 SET_AH(0x20);
7730 set_diskette_ret_status(0x20);
7731 SET_AL(0); // no sectors read
7732 SET_CF(); // error occurred
7733 return;
7734 }
7735
7736 // ??? should track be new val from return_status[3] ?
7737 set_diskette_current_cyl(drive, track);
7738 // AL = number of sectors read (same value as passed)
7739 SET_AH(0x00); // success
7740 CLEAR_CF(); // success
7741 return;
7742 } else if (ah == 0x03) {
7743 // Write Diskette Sectors
7744
7745 //-----------------------------------
7746 // set up DMA controller for transfer
7747 //-----------------------------------
7748
7749 // es:bx = pointer to where to place information from diskette
7750 // port 04: DMA-1 base and current address, channel 2
7751 // port 05: DMA-1 base and current count, channel 2
7752 page = (ES >> 12); // upper 4 bits
7753 base_es = (ES << 4); // lower 16bits contributed by ES
7754 base_address = base_es + BX; // lower 16 bits of address
7755 // contributed by ES:BX
7756 if ( base_address < base_es ) {
7757 // in case of carry, adjust page by 1
7758 page++;
7759 }
7760 base_count = (num_sectors * 512) - 1;
7761
7762 // check for 64K boundary overrun
7763 last_addr = base_address + base_count;
7764 if (last_addr < base_address) {
7765 SET_AH(0x09);
7766 set_diskette_ret_status(0x09);
7767 SET_AL(0); // no sectors read
7768 SET_CF(); // error occurred
7769 return;
7770 }
7771
7772 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7773 outb(0x000a, 0x06);
7774
7775 outb(0x000c, 0x00); // clear flip-flop
7776 outb(0x0004, base_address);
7777 outb(0x0004, base_address>>8);
7778 outb(0x000c, 0x00); // clear flip-flop
7779 outb(0x0005, base_count);
7780 outb(0x0005, base_count>>8);
7781
7782 // port 0b: DMA-1 Mode Register
7783 mode_register = 0x4a; // single mode, increment, autoinit disable,
7784 // transfer type=read, channel 2
7785 outb(0x000b, mode_register);
7786
7787 // port 81: DMA-1 Page Register, channel 2
7788 outb(0x0081, page);
7789
7790 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7791 outb(0x000a, 0x02);
7792
7793 //--------------------------------------
7794 // set up floppy controller for transfer
7795 //--------------------------------------
7796 floppy_prepare_controller(drive);
7797
7798 // send write-normal-data command (9 bytes) to controller
7799 outb(0x03f5, 0xc5); // c5: write normal data
7800 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7801 outb(0x03f5, track);
7802 outb(0x03f5, head);
7803 outb(0x03f5, sector);
7804 outb(0x03f5, 2); // 512 byte sector size
7805 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7806 outb(0x03f5, 0); // Gap length
7807 outb(0x03f5, 0xff); // Gap length
7808
7809 // turn on interrupts
7810 ASM_START
7811 sti
7812 ASM_END
7813
7814 // wait on 40:3e bit 7 to become 1
7815 do {
7816 val8 = read_byte(0x0040, 0x0040);
7817 if (val8 == 0) {
7818 floppy_reset_controller();
7819 SET_AH(0x80); // drive not ready (timeout)
7820 set_diskette_ret_status(0x80);
7821 SET_AL(0); // no sectors written
7822 SET_CF(); // error occurred
7823 return;
7824 }
7825 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7826 } while ( val8 == 0 );
7827
7828 val8 = 0; // separate asm from while() loop
7829 // turn off interrupts
7830 ASM_START
7831 cli
7832 ASM_END
7833
7834 // set 40:3e bit 7 to 0
7835 val8 = read_byte(0x0040, 0x003e);
7836 val8 &= 0x7f;
7837 write_byte(0x0040, 0x003e, val8);
7838
7839 // check port 3f4 for accessibility to status bytes
7840 val8 = inb(0x3f4);
7841 if ( (val8 & 0xc0) != 0xc0 )
7842 BX_PANIC("int13_diskette: ctrl not ready\n");
7843
7844 // read 7 return status bytes from controller
7845 // using loop index broken, have to unroll...
7846 return_status[0] = inb(0x3f5);
7847 return_status[1] = inb(0x3f5);
7848 return_status[2] = inb(0x3f5);
7849 return_status[3] = inb(0x3f5);
7850 return_status[4] = inb(0x3f5);
7851 return_status[5] = inb(0x3f5);
7852 return_status[6] = inb(0x3f5);
7853 // record in BIOS Data Area
7854 write_byte(0x0040, 0x0042, return_status[0]);
7855 write_byte(0x0040, 0x0043, return_status[1]);
7856 write_byte(0x0040, 0x0044, return_status[2]);
7857 write_byte(0x0040, 0x0045, return_status[3]);
7858 write_byte(0x0040, 0x0046, return_status[4]);
7859 write_byte(0x0040, 0x0047, return_status[5]);
7860 write_byte(0x0040, 0x0048, return_status[6]);
7861
7862 if ( (return_status[0] & 0xc0) != 0 ) {
7863 if ( (return_status[1] & 0x02) != 0 ) {
7864 // diskette not writable.
7865 // AH=status code=0x03 (tried to write on write-protected disk)
7866 // AL=number of sectors written=0
7867 AX = 0x0300;
7868 SET_CF();
7869 return;
7870 } else {
7871 BX_PANIC("int13_diskette_function: read error\n");
7872 }
7873 }
7874
7875 // ??? should track be new val from return_status[3] ?
7876 set_diskette_current_cyl(drive, track);
7877 // AL = number of sectors read (same value as passed)
7878 SET_AH(0x00); // success
7879 CLEAR_CF(); // success
7880 return;
7881 } else { // if (ah == 0x04)
7882 // Verify Diskette Sectors
7883
7884 // ??? should track be new val from return_status[3] ?
7885 set_diskette_current_cyl(drive, track);
7886 // AL = number of sectors verified (same value as passed)
7887 CLEAR_CF(); // success
7888 SET_AH(0x00); // success
7889 return;
7890 }
7891 break;
7892
7893 case 0x05: // format diskette track
7894BX_DEBUG_INT13_FL("floppy f05\n");
7895
7896 num_sectors = GET_AL();
7897 track = GET_CH();
7898 head = GET_DH();
7899 drive = GET_ELDL();
7900
7901 if ((drive > 1) || (head > 1) || (track > 79) ||
7902 (num_sectors == 0) || (num_sectors > 18)) {
7903 SET_AH(1);
7904 set_diskette_ret_status(1);
7905 SET_CF(); // error occurred
7906 }
7907
7908 // see if drive exists
7909 if (floppy_drive_exists(drive) == 0) {
7910 SET_AH(0x80); // drive not responding
7911 set_diskette_ret_status(0x80);
7912 SET_CF(); // error occurred
7913 return;
7914 }
7915
7916 // see if media in drive, and type is known
7917 if (floppy_media_known(drive) == 0) {
7918 if (floppy_media_sense(drive) == 0) {
7919 SET_AH(0x0C); // Media type not found
7920 set_diskette_ret_status(0x0C);
7921 SET_AL(0); // no sectors read
7922 SET_CF(); // error occurred
7923 return;
7924 }
7925 }
7926
7927 // set up DMA controller for transfer
7928 page = (ES >> 12); // upper 4 bits
7929 base_es = (ES << 4); // lower 16bits contributed by ES
7930 base_address = base_es + BX; // lower 16 bits of address
7931 // contributed by ES:BX
7932 if ( base_address < base_es ) {
7933 // in case of carry, adjust page by 1
7934 page++;
7935 }
7936 base_count = (num_sectors * 4) - 1;
7937
7938 // check for 64K boundary overrun
7939 last_addr = base_address + base_count;
7940 if (last_addr < base_address) {
7941 SET_AH(0x09);
7942 set_diskette_ret_status(0x09);
7943 SET_AL(0); // no sectors read
7944 SET_CF(); // error occurred
7945 return;
7946 }
7947
7948 outb(0x000a, 0x06);
7949 outb(0x000c, 0x00); // clear flip-flop
7950 outb(0x0004, base_address);
7951 outb(0x0004, base_address>>8);
7952 outb(0x000c, 0x00); // clear flip-flop
7953 outb(0x0005, base_count);
7954 outb(0x0005, base_count>>8);
7955 mode_register = 0x4a; // single mode, increment, autoinit disable,
7956 // transfer type=read, channel 2
7957 outb(0x000b, mode_register);
7958 // port 81: DMA-1 Page Register, channel 2
7959 outb(0x0081, page);
7960 outb(0x000a, 0x02);
7961
7962 // set up floppy controller for transfer
7963 floppy_prepare_controller(drive);
7964
7965 // send format-track command (6 bytes) to controller
7966 outb(0x03f5, 0x4d); // 4d: format track
7967 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7968 outb(0x03f5, 2); // 512 byte sector size
7969 outb(0x03f5, num_sectors); // number of sectors per track
7970 outb(0x03f5, 0); // Gap length
7971 outb(0x03f5, 0xf6); // Fill byte
7972 // turn on interrupts
7973 ASM_START
7974 sti
7975 ASM_END
7976
7977 // wait on 40:3e bit 7 to become 1
7978 do {
7979 val8 = read_byte(0x0040, 0x0040);
7980 if (val8 == 0) {
7981 floppy_reset_controller();
7982 SET_AH(0x80); // drive not ready (timeout)
7983 set_diskette_ret_status(0x80);
7984 SET_CF(); // error occurred
7985 return;
7986 }
7987 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7988 } while ( val8 == 0 );
7989
7990 val8 = 0; // separate asm from while() loop
7991 // turn off interrupts
7992 ASM_START
7993 cli
7994 ASM_END
7995 // set 40:3e bit 7 to 0
7996 val8 = read_byte(0x0040, 0x003e);
7997 val8 &= 0x7f;
7998 write_byte(0x0040, 0x003e, val8);
7999 // check port 3f4 for accessibility to status bytes
8000 val8 = inb(0x3f4);
8001 if ( (val8 & 0xc0) != 0xc0 )
8002 BX_PANIC("int13_diskette: ctrl not ready\n");
8003
8004 // read 7 return status bytes from controller
8005 // using loop index broken, have to unroll...
8006 return_status[0] = inb(0x3f5);
8007 return_status[1] = inb(0x3f5);
8008 return_status[2] = inb(0x3f5);
8009 return_status[3] = inb(0x3f5);
8010 return_status[4] = inb(0x3f5);
8011 return_status[5] = inb(0x3f5);
8012 return_status[6] = inb(0x3f5);
8013 // record in BIOS Data Area
8014 write_byte(0x0040, 0x0042, return_status[0]);
8015 write_byte(0x0040, 0x0043, return_status[1]);
8016 write_byte(0x0040, 0x0044, return_status[2]);
8017 write_byte(0x0040, 0x0045, return_status[3]);
8018 write_byte(0x0040, 0x0046, return_status[4]);
8019 write_byte(0x0040, 0x0047, return_status[5]);
8020 write_byte(0x0040, 0x0048, return_status[6]);
8021
8022 if ( (return_status[0] & 0xc0) != 0 ) {
8023 if ( (return_status[1] & 0x02) != 0 ) {
8024 // diskette not writable.
8025 // AH=status code=0x03 (tried to write on write-protected disk)
8026 // AL=number of sectors written=0
8027 AX = 0x0300;
8028 SET_CF();
8029 return;
8030 } else {
8031 BX_PANIC("int13_diskette_function: write error\n");
8032 }
8033 }
8034
8035 SET_AH(0);
8036 set_diskette_ret_status(0);
8037 set_diskette_current_cyl(drive, 0);
8038 CLEAR_CF(); // successful
8039 return;
8040
8041
8042 case 0x08: // read diskette drive parameters
8043BX_DEBUG_INT13_FL("floppy f08\n");
8044 drive = GET_ELDL();
8045
8046 if (drive > 1) {
8047 AX = 0;
8048 BX = 0;
8049 CX = 0;
8050 DX = 0;
8051 ES = 0;
8052 DI = 0;
8053 SET_DL(num_floppies);
8054 SET_CF();
8055 return;
8056 }
8057
8058 drive_type = inb_cmos(0x10);
8059 num_floppies = 0;
8060 if (drive_type & 0xf0)
8061 num_floppies++;
8062 if (drive_type & 0x0f)
8063 num_floppies++;
8064
8065 if (drive == 0)
8066 drive_type >>= 4;
8067 else
8068 drive_type &= 0x0f;
8069
8070 SET_BH(0);
8071 SET_BL(drive_type);
8072 SET_AH(0);
8073 SET_AL(0);
8074 SET_DL(num_floppies);
8075
8076 switch (drive_type) {
8077 case 0: // none
8078 CX = 0;
8079 SET_DH(0); // max head #
8080 break;
8081
8082 case 1: // 360KB, 5.25"
8083 CX = 0x2709; // 40 tracks, 9 sectors
8084 SET_DH(1); // max head #
8085 break;
8086
8087 case 2: // 1.2MB, 5.25"
8088 CX = 0x4f0f; // 80 tracks, 15 sectors
8089 SET_DH(1); // max head #
8090 break;
8091
8092 case 3: // 720KB, 3.5"
8093 CX = 0x4f09; // 80 tracks, 9 sectors
8094 SET_DH(1); // max head #
8095 break;
8096
8097 case 4: // 1.44MB, 3.5"
8098 CX = 0x4f12; // 80 tracks, 18 sectors
8099 SET_DH(1); // max head #
8100 break;
8101
8102 case 5: // 2.88MB, 3.5"
8103 CX = 0x4f24; // 80 tracks, 36 sectors
8104 SET_DH(1); // max head #
8105 break;
8106
8107 case 6: // 160k, 5.25"
8108 CX = 0x2708; // 40 tracks, 8 sectors
8109 SET_DH(0); // max head #
8110 break;
8111
8112 case 7: // 180k, 5.25"
8113 CX = 0x2709; // 40 tracks, 9 sectors
8114 SET_DH(0); // max head #
8115 break;
8116
8117 case 8: // 320k, 5.25"
8118 CX = 0x2708; // 40 tracks, 8 sectors
8119 SET_DH(1); // max head #
8120 break;
8121
8122 default: // ?
8123 BX_PANIC("floppy: int13: bad floppy type\n");
8124 }
8125
8126 /* set es & di to point to 11 byte diskette param table in ROM */
8127ASM_START
8128 push bp
8129 mov bp, sp
8130 mov ax, #diskette_param_table2
8131 mov _int13_diskette_function.DI+2[bp], ax
8132 mov _int13_diskette_function.ES+2[bp], cs
8133 pop bp
8134ASM_END
8135 CLEAR_CF(); // success
8136 /* disk status not changed upon success */
8137 return;
8138
8139
8140 case 0x15: // read diskette drive type
8141BX_DEBUG_INT13_FL("floppy f15\n");
8142 drive = GET_ELDL();
8143 if (drive > 1) {
8144 SET_AH(0); // only 2 drives supported
8145 // set_diskette_ret_status here ???
8146 SET_CF();
8147 return;
8148 }
8149 drive_type = inb_cmos(0x10);
8150
8151 if (drive == 0)
8152 drive_type >>= 4;
8153 else
8154 drive_type &= 0x0f;
8155 CLEAR_CF(); // successful, not present
8156 if (drive_type==0) {
8157 SET_AH(0); // drive not present
8158 }
8159 else {
8160 SET_AH(1); // drive present, does not support change line
8161 }
8162
8163 return;
8164
8165 case 0x16: // get diskette change line status
8166BX_DEBUG_INT13_FL("floppy f16\n");
8167 drive = GET_ELDL();
8168 if (drive > 1) {
8169 SET_AH(0x01); // invalid drive
8170 set_diskette_ret_status(0x01);
8171 SET_CF();
8172 return;
8173 }
8174
8175 SET_AH(0x06); // change line not supported
8176 set_diskette_ret_status(0x06);
8177 SET_CF();
8178 return;
8179
8180 case 0x17: // set diskette type for format(old)
8181BX_DEBUG_INT13_FL("floppy f17\n");
8182 /* not used for 1.44M floppies */
8183 SET_AH(0x01); // not supported
8184 set_diskette_ret_status(1); /* not supported */
8185 SET_CF();
8186 return;
8187
8188 case 0x18: // set diskette type for format(new)
8189BX_DEBUG_INT13_FL("floppy f18\n");
8190 SET_AH(0x01); // do later
8191 set_diskette_ret_status(1);
8192 SET_CF();
8193 return;
8194
8195 default:
8196 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8197
8198 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8199 SET_AH(0x01); // ???
8200 set_diskette_ret_status(1);
8201 SET_CF();
8202 return;
8203 // }
8204 }
8205}
8206#else // #if BX_SUPPORT_FLOPPY
8207 void
8208int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8209 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8210{
8211 Bit8u val8;
8212
8213 switch ( GET_AH() ) {
8214
8215 case 0x01: // Read Diskette Status
8216 CLEAR_CF();
8217 val8 = read_byte(0x0000, 0x0441);
8218 SET_AH(val8);
8219 if (val8) {
8220 SET_CF();
8221 }
8222 return;
8223
8224 default:
8225 SET_CF();
8226 write_byte(0x0000, 0x0441, 0x01);
8227 SET_AH(0x01);
8228 }
8229}
8230#endif // #if BX_SUPPORT_FLOPPY
8231
8232 void
8233set_diskette_ret_status(value)
8234 Bit8u value;
8235{
8236 write_byte(0x0040, 0x0041, value);
8237}
8238
8239 void
8240set_diskette_current_cyl(drive, cyl)
8241 Bit8u drive;
8242 Bit8u cyl;
8243{
8244 if (drive > 1)
8245 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8246 write_byte(0x0040, 0x0094+drive, cyl);
8247}
8248
8249 void
8250determine_floppy_media(drive)
8251 Bit16u drive;
8252{
8253#if 0
8254 Bit8u val8, DOR, ctrl_info;
8255
8256 ctrl_info = read_byte(0x0040, 0x008F);
8257 if (drive==1)
8258 ctrl_info >>= 4;
8259 else
8260 ctrl_info &= 0x0f;
8261
8262#if 0
8263 if (drive == 0) {
8264 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8265 }
8266 else {
8267 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8268 }
8269#endif
8270
8271 if ( (ctrl_info & 0x04) != 0x04 ) {
8272 // Drive not determined means no drive exists, done.
8273 return;
8274 }
8275
8276#if 0
8277 // check Main Status Register for readiness
8278 val8 = inb(0x03f4) & 0x80; // Main Status Register
8279 if (val8 != 0x80)
8280 BX_PANIC("d_f_m: MRQ bit not set\n");
8281
8282 // change line
8283
8284 // existing BDA values
8285
8286 // turn on drive motor
8287 outb(0x03f2, DOR); // Digital Output Register
8288 //
8289#endif
8290 BX_PANIC("d_f_m: OK so far\n");
8291#endif
8292}
8293
8294 void
8295int17_function(regs, ds, iret_addr)
8296 pusha_regs_t regs; // regs pushed from PUSHA instruction
8297 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8298 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8299{
8300 Bit16u addr,timeout;
8301 Bit8u val8;
8302
8303 ASM_START
8304 sti
8305 ASM_END
8306
8307 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8308 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8309 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8310 if (regs.u.r8.ah == 0) {
8311 outb(addr, regs.u.r8.al);
8312 val8 = inb(addr+2);
8313 outb(addr+2, val8 | 0x01); // send strobe
8314 ASM_START
8315 nop
8316 ASM_END
8317 outb(addr+2, val8 & ~0x01);
8318 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8319 timeout--;
8320 }
8321 }
8322 if (regs.u.r8.ah == 1) {
8323 val8 = inb(addr+2);
8324 outb(addr+2, val8 & ~0x04); // send init
8325 ASM_START
8326 nop
8327 ASM_END
8328 outb(addr+2, val8 | 0x04);
8329 }
8330 val8 = inb(addr+1);
8331 regs.u.r8.ah = (val8 ^ 0x48);
8332 if (!timeout) regs.u.r8.ah |= 0x01;
8333 ClearCF(iret_addr.flags);
8334 } else {
8335 SetCF(iret_addr.flags); // Unsupported
8336 }
8337}
8338
8339// returns bootsegment in ax, drive in bl
8340 Bit32u
8341int19_function(bseqnr)
8342Bit8u bseqnr;
8343{
8344 Bit16u ebda_seg=read_word(0x0040,0x000E);
8345 Bit16u bootseq;
8346 Bit8u bootdrv;
8347 Bit8u bootcd;
8348#ifdef VBOX
8349 Bit8u bootlan;
8350#endif /* VBOX */
8351 Bit8u bootchk;
8352 Bit16u bootseg;
8353 Bit16u status;
8354 Bit8u lastdrive=0;
8355
8356 // if BX_ELTORITO_BOOT is not defined, old behavior
8357 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8358 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8359 // 0: system boot sequence, first drive C: then A:
8360 // 1: system boot sequence, first drive A: then C:
8361 // else BX_ELTORITO_BOOT is defined
8362 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8363 // CMOS reg 0x3D & 0x0f : 1st boot device
8364 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8365 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8366#ifdef VBOX
8367 // CMOS reg 0x3C & 0x0f : 4th boot device
8368#endif /* VBOX */
8369 // boot device codes:
8370 // 0x00 : not defined
8371 // 0x01 : first floppy
8372 // 0x02 : first harddrive
8373 // 0x03 : first cdrom
8374#ifdef VBOX
8375 // 0x04 : local area network
8376#endif /* VBOX */
8377 // else : boot failure
8378
8379 // Get the boot sequence
8380#if BX_ELTORITO_BOOT
8381 bootseq=inb_cmos(0x3d);
8382 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8383#ifdef VBOX
8384 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8385 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8386 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8387 /* Boot delay hack. */
8388 if (bseqnr == 1)
8389 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8390#endif /* VBOX */
8391
8392 if (bseqnr==2) bootseq >>= 4;
8393 if (bseqnr==3) bootseq >>= 8;
8394#ifdef VBOX
8395 if (bseqnr==4) bootseq >>= 12;
8396#endif /* VBOX */
8397 if (bootseq<0x10) lastdrive = 1;
8398 bootdrv=0x00; bootcd=0;
8399#ifdef VBOX
8400 bootlan=0;
8401#endif /* VBOX */
8402
8403 switch(bootseq & 0x0f) {
8404 case 0x01:
8405 bootdrv=0x00;
8406 bootcd=0;
8407 break;
8408 case 0x02:
8409 {
8410 // Get the Boot drive.
8411 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8412
8413 bootdrv = boot_drive + 0x80;
8414 bootcd=0;
8415 break;
8416 }
8417 case 0x03:
8418 bootdrv=0x00;
8419 bootcd=1;
8420 break;
8421#ifdef VBOX
8422 case 0x04: bootlan=1; break;
8423#endif /* VBOX */
8424 default: return 0x00000000;
8425 }
8426#else
8427 bootseq=inb_cmos(0x2d);
8428
8429 if (bseqnr==2) {
8430 bootseq ^= 0x20;
8431 lastdrive = 1;
8432 }
8433 bootdrv=0x00; bootcd=0;
8434 if((bootseq&0x20)==0) bootdrv=0x80;
8435#endif // BX_ELTORITO_BOOT
8436
8437#if BX_ELTORITO_BOOT
8438 // We have to boot from cd
8439 if (bootcd != 0) {
8440 status = cdrom_boot();
8441
8442 // If failure
8443 if ( (status & 0x00ff) !=0 ) {
8444 print_cdromboot_failure(status);
8445#ifdef VBOX
8446 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8447#else /* !VBOX */
8448 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8449#endif /* !VBOX */
8450 return 0x00000000;
8451 }
8452
8453 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8454 bootdrv = (Bit8u)(status>>8);
8455 }
8456
8457#endif // BX_ELTORITO_BOOT
8458
8459#ifdef VBOX
8460 // Check for boot from LAN first
8461 if (bootlan == 1) {
8462 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8463 Bit16u pnpoff;
8464 Bit32u manuf;
8465 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8466 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8467 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8468 // Found PnP signature
8469 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8470 if (manuf == 0x65687445) {
8471 // Found Etherboot ROM
8472 print_boot_device(bootcd, bootlan, bootdrv);
8473ASM_START
8474 push ds
8475 push es
8476 pusha
8477 calli 0x0006,VBOX_LANBOOT_SEG
8478 popa
8479 pop es
8480 pop ds
8481ASM_END
8482 } else if (manuf == 0x65746E49) {
8483 // Found Intel PXE ROM
8484 print_boot_device(bootcd, bootlan, bootdrv);
8485ASM_START
8486 push ds
8487 push es
8488 pusha
8489 sti ; Why are interrupts disabled now? Because we were called through an INT!
8490 push #VBOX_LANBOOT_SEG
8491 pop ds
8492 mov bx,#0x1a ; PnP header offset
8493 mov bx,[bx]
8494 add bx,#0x1a ; BEV offset in PnP header
8495 mov ax,[bx]
8496 test ax,ax
8497 jz no_rom
8498bev_jump:
8499 push cs
8500 push #no_rom
8501 push #VBOX_LANBOOT_SEG
8502 push ax
8503 retf ; call Boot Entry Vector
8504no_rom:
8505 popa
8506 pop es
8507 pop ds
8508ASM_END
8509 }
8510 }
8511 }
8512
8513 // boot from LAN will not return if successful.
8514 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8515 return 0x00000000;
8516 }
8517#endif /* VBOX */
8518 // We have to boot from harddisk or floppy
8519#ifdef VBOX
8520 if (bootcd == 0 && bootlan == 0) {
8521#else /* !VBOX */
8522 if (bootcd == 0) {
8523#endif /* !VBOX */
8524 bootseg=0x07c0;
8525
8526ASM_START
8527 push bp
8528 mov bp, sp
8529
8530 xor ax, ax
8531 mov _int19_function.status + 2[bp], ax
8532 mov dl, _int19_function.bootdrv + 2[bp]
8533 mov ax, _int19_function.bootseg + 2[bp]
8534 mov es, ax ;; segment
8535 xor bx, bx ;; offset
8536 mov ah, #0x02 ;; function 2, read diskette sector
8537 mov al, #0x01 ;; read 1 sector
8538 mov ch, #0x00 ;; track 0
8539 mov cl, #0x01 ;; sector 1
8540 mov dh, #0x00 ;; head 0
8541 int #0x13 ;; read sector
8542 jnc int19_load_done
8543 mov ax, #0x0001
8544 mov _int19_function.status + 2[bp], ax
8545
8546int19_load_done:
8547 pop bp
8548ASM_END
8549
8550 if (status != 0) {
8551#ifdef VBOX
8552 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8553#else /* !VBOX */
8554 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8555#endif /* !VBOX */
8556 return 0x00000000;
8557 }
8558 }
8559
8560#ifdef VBOX
8561 // Don't check boot sectors on floppies and don't read CMOS - byte
8562 // 0x38 in CMOS always has the low bit clear.
8563 // There is *no* requirement whatsoever for a valid boot sector to
8564 // have a 55AAh signature. UNIX boot floppies typically have no such
8565 // signature. In general, it is impossible to tell a valid bootsector
8566 // from an invalid one.
8567 // NB: It is somewhat common for failed OS installs to have the
8568 // 0x55AA signature and a valid partition table but zeros in the
8569 // rest of the boot sector. We do a quick check by comparing the first
8570 // two words of boot sector; if identical, the boot sector is
8571 // extremely unlikely to be valid.
8572#endif
8573 // check signature if instructed by cmos reg 0x38, only for floppy
8574 // bootchk = 1 : signature check disabled
8575 // bootchk = 0 : signature check enabled
8576 if (bootdrv != 0) bootchk = 0;
8577#ifdef VBOX
8578 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8579#else
8580 else bootchk = inb_cmos(0x38) & 0x01;
8581#endif
8582
8583#if BX_ELTORITO_BOOT
8584 // if boot from cd, no signature check
8585 if (bootcd != 0)
8586 bootchk = 1;
8587#endif // BX_ELTORITO_BOOT
8588
8589 if (bootchk == 0) {
8590 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8591 read_word(bootseg,0) == read_word(bootseg,2)) {
8592#ifdef VBOX
8593 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8594#else /* !VBOX */
8595 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8596#endif /* VBOX */
8597 return 0x00000000;
8598 }
8599 }
8600
8601#if BX_ELTORITO_BOOT
8602 // Print out the boot string
8603#ifdef VBOX
8604 print_boot_device(bootcd, bootlan, bootdrv);
8605#else /* !VBOX */
8606 print_boot_device(bootcd, bootdrv);
8607#endif /* !VBOX */
8608#else // BX_ELTORITO_BOOT
8609#ifdef VBOX
8610 print_boot_device(0, bootlan, bootdrv);
8611#else /* !VBOX */
8612 print_boot_device(0, bootdrv);
8613#endif /* !VBOX */
8614#endif // BX_ELTORITO_BOOT
8615
8616 // return the boot segment
8617 return (((Bit32u)bootdrv) << 16) + bootseg;
8618}
8619
8620 void
8621int1a_function(regs, ds, iret_addr)
8622 pusha_regs_t regs; // regs pushed from PUSHA instruction
8623 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8624 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8625{
8626 Bit8u val8;
8627
8628 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);
8629
8630 ASM_START
8631 sti
8632 ASM_END
8633
8634 switch (regs.u.r8.ah) {
8635 case 0: // get current clock count
8636 ASM_START
8637 cli
8638 ASM_END
8639 regs.u.r16.cx = BiosData->ticks_high;
8640 regs.u.r16.dx = BiosData->ticks_low;
8641 regs.u.r8.al = BiosData->midnight_flag;
8642 BiosData->midnight_flag = 0; // reset flag
8643 ASM_START
8644 sti
8645 ASM_END
8646 // AH already 0
8647 ClearCF(iret_addr.flags); // OK
8648 break;
8649
8650 case 1: // Set Current Clock Count
8651 ASM_START
8652 cli
8653 ASM_END
8654 BiosData->ticks_high = regs.u.r16.cx;
8655 BiosData->ticks_low = regs.u.r16.dx;
8656 BiosData->midnight_flag = 0; // reset flag
8657 ASM_START
8658 sti
8659 ASM_END
8660 regs.u.r8.ah = 0;
8661 ClearCF(iret_addr.flags); // OK
8662 break;
8663
8664
8665 case 2: // Read CMOS Time
8666 if (rtc_updating()) {
8667 SetCF(iret_addr.flags);
8668 break;
8669 }
8670
8671 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8672 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8673 regs.u.r8.ch = inb_cmos(0x04); // Hours
8674 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8675 regs.u.r8.ah = 0;
8676 regs.u.r8.al = regs.u.r8.ch;
8677 ClearCF(iret_addr.flags); // OK
8678 break;
8679
8680 case 3: // Set CMOS Time
8681 // Using a debugger, I notice the following masking/setting
8682 // of bits in Status Register B, by setting Reg B to
8683 // a few values and getting its value after INT 1A was called.
8684 //
8685 // try#1 try#2 try#3
8686 // before 1111 1101 0111 1101 0000 0000
8687 // after 0110 0010 0110 0010 0000 0010
8688 //
8689 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8690 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8691 if (rtc_updating()) {
8692 init_rtc();
8693 // fall through as if an update were not in progress
8694 }
8695 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8696 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8697 outb_cmos(0x04, regs.u.r8.ch); // Hours
8698 // Set Daylight Savings time enabled bit to requested value
8699 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8700 // (reg B already selected)
8701 outb_cmos(0x0b, val8);
8702 regs.u.r8.ah = 0;
8703 regs.u.r8.al = val8; // val last written to Reg B
8704 ClearCF(iret_addr.flags); // OK
8705 break;
8706
8707 case 4: // Read CMOS Date
8708 regs.u.r8.ah = 0;
8709 if (rtc_updating()) {
8710 SetCF(iret_addr.flags);
8711 break;
8712 }
8713 regs.u.r8.cl = inb_cmos(0x09); // Year
8714 regs.u.r8.dh = inb_cmos(0x08); // Month
8715 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8716 regs.u.r8.ch = inb_cmos(0x32); // Century
8717 regs.u.r8.al = regs.u.r8.ch;
8718 ClearCF(iret_addr.flags); // OK
8719 break;
8720
8721 case 5: // Set CMOS Date
8722 // Using a debugger, I notice the following masking/setting
8723 // of bits in Status Register B, by setting Reg B to
8724 // a few values and getting its value after INT 1A was called.
8725 //
8726 // try#1 try#2 try#3 try#4
8727 // before 1111 1101 0111 1101 0000 0010 0000 0000
8728 // after 0110 1101 0111 1101 0000 0010 0000 0000
8729 //
8730 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8731 // My assumption: RegB = (RegB & 01111111b)
8732 if (rtc_updating()) {
8733 init_rtc();
8734 SetCF(iret_addr.flags);
8735 break;
8736 }
8737 outb_cmos(0x09, regs.u.r8.cl); // Year
8738 outb_cmos(0x08, regs.u.r8.dh); // Month
8739 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8740 outb_cmos(0x32, regs.u.r8.ch); // Century
8741 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8742 outb_cmos(0x0b, val8);
8743 regs.u.r8.ah = 0;
8744 regs.u.r8.al = val8; // AL = val last written to Reg B
8745 ClearCF(iret_addr.flags); // OK
8746 break;
8747
8748 case 6: // Set Alarm Time in CMOS
8749 // Using a debugger, I notice the following masking/setting
8750 // of bits in Status Register B, by setting Reg B to
8751 // a few values and getting its value after INT 1A was called.
8752 //
8753 // try#1 try#2 try#3
8754 // before 1101 1111 0101 1111 0000 0000
8755 // after 0110 1111 0111 1111 0010 0000
8756 //
8757 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8758 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8759 val8 = inb_cmos(0x0b); // Get Status Reg B
8760 regs.u.r16.ax = 0;
8761 if (val8 & 0x20) {
8762 // Alarm interrupt enabled already
8763 SetCF(iret_addr.flags); // Error: alarm in use
8764 break;
8765 }
8766 if (rtc_updating()) {
8767 init_rtc();
8768 // fall through as if an update were not in progress
8769 }
8770 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8771 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8772 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8773 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8774 // enable Status Reg B alarm bit, clear halt clock bit
8775 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8776 ClearCF(iret_addr.flags); // OK
8777 break;
8778
8779 case 7: // Turn off Alarm
8780 // Using a debugger, I notice the following masking/setting
8781 // of bits in Status Register B, by setting Reg B to
8782 // a few values and getting its value after INT 1A was called.
8783 //
8784 // try#1 try#2 try#3 try#4
8785 // before 1111 1101 0111 1101 0010 0000 0010 0010
8786 // after 0100 0101 0101 0101 0000 0000 0000 0010
8787 //
8788 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8789 // My assumption: RegB = (RegB & 01010111b)
8790 val8 = inb_cmos(0x0b); // Get Status Reg B
8791 // clear clock-halt bit, disable alarm bit
8792 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8793 regs.u.r8.ah = 0;
8794 regs.u.r8.al = val8; // val last written to Reg B
8795 ClearCF(iret_addr.flags); // OK
8796 break;
8797#if BX_PCIBIOS
8798 case 0xb1:
8799 // real mode PCI BIOS functions now handled in assembler code
8800 // this C code handles the error code for information only
8801 if (regs.u.r8.bl == 0xff) {
8802 BX_INFO("PCI BIOS: PCI not present\n");
8803 } else if (regs.u.r8.bl == 0x81) {
8804 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8805 } else if (regs.u.r8.bl == 0x83) {
8806 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8807 } else if (regs.u.r8.bl == 0x86) {
8808 if (regs.u.r8.al == 0x02) {
8809 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8810 } else {
8811 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);
8812 }
8813 }
8814 regs.u.r8.ah = regs.u.r8.bl;
8815 SetCF(iret_addr.flags);
8816 break;
8817#endif
8818
8819 default:
8820 SetCF(iret_addr.flags); // Unsupported
8821 }
8822}
8823
8824 void
8825int70_function(regs, ds, iret_addr)
8826 pusha_regs_t regs; // regs pushed from PUSHA instruction
8827 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8828 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8829{
8830 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8831 Bit8u registerB = 0, registerC = 0;
8832
8833 // Check which modes are enabled and have occurred.
8834 registerB = inb_cmos( 0xB );
8835 registerC = inb_cmos( 0xC );
8836
8837 if( ( registerB & 0x60 ) != 0 ) {
8838 if( ( registerC & 0x20 ) != 0 ) {
8839 // Handle Alarm Interrupt.
8840ASM_START
8841 sti
8842 int #0x4a
8843 cli
8844ASM_END
8845 }
8846 if( ( registerC & 0x40 ) != 0 ) {
8847 // Handle Periodic Interrupt.
8848
8849 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8850 // Wait Interval (Int 15, AH=83) active.
8851 Bit32u time, toggle;
8852
8853 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8854 if( time < 0x3D1 ) {
8855 // Done waiting.
8856 Bit16u segment, offset;
8857
8858 segment = read_word( 0x40, 0x98 );
8859 offset = read_word( 0x40, 0x9A );
8860 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8861 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8862 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8863 } else {
8864 // Continue waiting.
8865 time -= 0x3D1;
8866 write_dword( 0x40, 0x9C, time );
8867 }
8868 }
8869 }
8870 }
8871
8872ASM_START
8873 call eoi_both_pics
8874ASM_END
8875}
8876
8877 void
8878dummy_isr_function(regs, ds, iret_addr)
8879 pusha_regs_t regs; // regs pushed from PUSHA instruction
8880 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8881 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8882{
8883 // Interrupt handler for unexpected hardware interrupts. We have to clear
8884 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8885 // and all hell will break loose! This routine also masks the unexpected
8886 // interrupt so it will generally be called only once for each unexpected
8887 // interrupt level.
8888 Bit8u isrA, isrB, imr, last_int = 0xFF;
8889
8890 outb( 0x20, 0x0B );
8891 isrA = inb( 0x20 );
8892 if (isrA) {
8893 outb( 0xA0, 0x0B );
8894 isrB = inb( 0xA0 );
8895 if (isrB) {
8896 imr = inb( 0xA1 );
8897 outb( 0xA1, imr | isrB ); // Mask this interrupt
8898 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8899 } else {
8900 imr = inb( 0x21 );
8901 isrA &= 0xFB; // Never mask the cascade interrupt
8902 outb( 0x21, imr | isrA); // Mask this interrupt
8903 }
8904 outb( 0x20, 0x20 ); // Send EOI on master PIC
8905 last_int = isrA;
8906 }
8907 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8908}
8909
8910ASM_START
8911;------------------------------------------
8912;- INT74h : PS/2 mouse hardware interrupt -
8913;------------------------------------------
8914int74_handler:
8915 sti
8916 pusha
8917 push ds ;; save DS
8918 push #0x00 ;; placeholder for status
8919 push #0x00 ;; placeholder for X
8920 push #0x00 ;; placeholder for Y
8921 push #0x00 ;; placeholder for Z
8922 push #0x00 ;; placeholder for make_far_call boolean
8923 call _int74_function
8924 pop cx ;; remove make_far_call from stack
8925 jcxz int74_done
8926
8927 ;; make far call to EBDA:0022
8928 push #0x00
8929 pop ds
8930 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8931 pop ds
8932 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8933 call far ptr[0x22]
8934int74_done:
8935 cli
8936 call eoi_both_pics
8937 add sp, #8 ;; pop status, x, y, z
8938
8939 pop ds ;; restore DS
8940 popa
8941 iret
8942
8943
8944;; This will perform an IRET, but will retain value of current CF
8945;; by altering flags on stack. Better than RETF #02.
8946iret_modify_cf:
8947 jc carry_set
8948 push bp
8949 mov bp, sp
8950 and BYTE [bp + 0x06], #0xfe
8951 pop bp
8952 iret
8953carry_set:
8954 push bp
8955 mov bp, sp
8956 or BYTE [bp + 0x06], #0x01
8957 pop bp
8958 iret
8959
8960
8961;----------------------
8962;- INT13h (relocated) -
8963;----------------------
8964;
8965; int13_relocated is a little bit messed up since I played with it
8966; I have to rewrite it:
8967; - call a function that detect which function to call
8968; - make all called C function get the same parameters list
8969;
8970int13_relocated:
8971
8972#if BX_ELTORITO_BOOT
8973 ;; check for an eltorito function
8974 cmp ah,#0x4a
8975 jb int13_not_eltorito
8976 cmp ah,#0x4d
8977 ja int13_not_eltorito
8978
8979 pusha
8980 push es
8981 push ds
8982 push ss
8983 pop ds
8984
8985 push #int13_out
8986 jmp _int13_eltorito ;; ELDX not used
8987
8988int13_not_eltorito:
8989 push ax
8990 push bx
8991 push cx
8992 push dx
8993
8994 ;; check if emulation active
8995 call _cdemu_isactive
8996 cmp al,#0x00
8997 je int13_cdemu_inactive
8998
8999 ;; check if access to the emulated drive
9000 call _cdemu_emulated_drive
9001 pop dx
9002 push dx
9003 cmp al,dl ;; int13 on emulated drive
9004 jne int13_nocdemu
9005
9006 pop dx
9007 pop cx
9008 pop bx
9009 pop ax
9010
9011 pusha
9012 push es
9013 push ds
9014 push ss
9015 pop ds
9016
9017 push #int13_out
9018 jmp _int13_cdemu ;; ELDX not used
9019
9020int13_nocdemu:
9021 and dl,#0xE0 ;; mask to get device class, including cdroms
9022 cmp al,dl ;; al is 0x00 or 0x80
9023 jne int13_cdemu_inactive ;; inactive for device class
9024
9025 pop dx
9026 pop cx
9027 pop bx
9028 pop ax
9029
9030 push ax
9031 push cx
9032 push dx
9033 push bx
9034
9035 dec dl ;; real drive is dl - 1
9036 jmp int13_legacy
9037
9038int13_cdemu_inactive:
9039 pop dx
9040 pop cx
9041 pop bx
9042 pop ax
9043
9044#endif // BX_ELTORITO_BOOT
9045
9046int13_noeltorito:
9047
9048 push ax
9049 push cx
9050 push dx
9051 push bx
9052
9053int13_legacy:
9054
9055 push dx ;; push eltorito value of dx instead of sp
9056
9057 push bp
9058 push si
9059 push di
9060
9061 push es
9062 push ds
9063 push ss
9064 pop ds
9065
9066 ;; now the 16-bit registers can be restored with:
9067 ;; pop ds; pop es; popa; iret
9068 ;; arguments passed to functions should be
9069 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9070
9071 test dl, #0x80
9072 jnz int13_notfloppy
9073
9074 push #int13_out
9075 jmp _int13_diskette_function
9076
9077int13_notfloppy:
9078
9079#if BX_USE_ATADRV
9080
9081 cmp dl, #0xE0
9082 jb int13_notcdrom
9083
9084 // ebx is modified: BSD 5.2.1 boot loader problem
9085 // someone should figure out which 32 bit register that actually are used
9086
9087 shr ebx, #16
9088 push bx
9089
9090 call _int13_cdrom
9091
9092 pop bx
9093 shl ebx, #16
9094
9095 jmp int13_out
9096
9097int13_notcdrom:
9098
9099#endif
9100
9101int13_disk:
9102 ;; int13_harddisk modifies high word of EAX and EBX
9103 shr eax, #16
9104 push ax
9105 shr ebx, #16
9106 push bx
9107 call _int13_harddisk
9108 pop bx
9109 shl ebx, #16
9110 pop ax
9111 shl eax, #16
9112
9113int13_out:
9114 pop ds
9115 pop es
9116 popa
9117 iret
9118
9119;----------
9120;- INT18h -
9121;----------
9122int18_handler: ;; Boot Failure routing
9123 call _int18_panic_msg
9124 hlt
9125 iret
9126
9127;----------
9128;- INT19h -
9129;----------
9130int19_relocated: ;; Boot function, relocated
9131
9132#ifdef VBOX
9133 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9134 // just to try booting from the configured drives. All BIOS variables and
9135 // interrupt vectors need to be reset, otherwise strange things may happen.
9136 // The approach used is faking a warm reboot (which just skips showing the
9137 // logo), which is a bit more than what we need, but hey, it's fast.
9138 mov bp, sp
9139 mov ax, 2[bp]
9140 cmp ax, #0xf000
9141 jz bios_initiated_boot
9142 xor ax, ax
9143 mov ds, ax
9144 mov ax, #0x1234
9145 mov 0x472, ax
9146 jmp post
9147bios_initiated_boot:
9148#endif /* VBOX */
9149
9150 ;; int19 was beginning to be really complex, so now it
9151 ;; just calls a C function that does the work
9152 ;; it returns in BL the boot drive, and in AX the boot segment
9153 ;; the boot segment will be 0x0000 if something has failed
9154
9155 push bp
9156 mov bp, sp
9157
9158 ;; drop ds
9159 xor ax, ax
9160 mov ds, ax
9161
9162 ;; 1st boot device
9163 mov ax, #0x0001
9164 push ax
9165 call _int19_function
9166 inc sp
9167 inc sp
9168 ;; bl contains the boot drive
9169 ;; ax contains the boot segment or 0 if failure
9170
9171 test ax, ax ;; if ax is 0 try next boot device
9172 jnz boot_setup
9173
9174 ;; 2nd boot device
9175 mov ax, #0x0002
9176 push ax
9177 call _int19_function
9178 inc sp
9179 inc sp
9180 test ax, ax ;; if ax is 0 try next boot device
9181 jnz boot_setup
9182
9183 ;; 3rd boot device
9184 mov ax, #0x0003
9185 push ax
9186 call _int19_function
9187 inc sp
9188 inc sp
9189#ifdef VBOX
9190 test ax, ax ;; if ax is 0 try next boot device
9191 jnz boot_setup
9192
9193 ;; 4th boot device
9194 mov ax, #0x0004
9195 push ax
9196 call _int19_function
9197 inc sp
9198 inc sp
9199#endif /* VBOX */
9200 test ax, ax ;; if ax is 0 call int18
9201 jz int18_handler
9202
9203boot_setup:
9204 mov dl, bl ;; set drive so guest os find it
9205 shl eax, #0x04 ;; convert seg to ip
9206 mov 2[bp], ax ;; set ip
9207
9208 shr eax, #0x04 ;; get cs back
9209 and ax, #0xF000 ;; remove what went in ip
9210 mov 4[bp], ax ;; set cs
9211 xor ax, ax
9212 mov es, ax ;; set es to zero fixes [ 549815 ]
9213 mov [bp], ax ;; set bp to zero
9214 mov ax, #0xaa55 ;; set ok flag
9215
9216 pop bp
9217 iret ;; Beam me up Scotty
9218
9219;----------
9220;- INT1Ch -
9221;----------
9222int1c_handler: ;; User Timer Tick
9223 iret
9224
9225
9226;----------------------
9227;- POST: Floppy Drive -
9228;----------------------
9229floppy_drive_post:
9230 xor ax, ax
9231 mov ds, ax
9232
9233 mov al, #0x00
9234 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9235
9236 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9237
9238 mov 0x0440, al ;; diskette motor timeout counter: not active
9239 mov 0x0441, al ;; diskette controller status return code
9240
9241 mov 0x0442, al ;; disk & diskette controller status register 0
9242 mov 0x0443, al ;; diskette controller status register 1
9243 mov 0x0444, al ;; diskette controller status register 2
9244 mov 0x0445, al ;; diskette controller cylinder number
9245 mov 0x0446, al ;; diskette controller head number
9246 mov 0x0447, al ;; diskette controller sector number
9247 mov 0x0448, al ;; diskette controller bytes written
9248
9249 mov 0x048b, al ;; diskette configuration data
9250
9251 ;; -----------------------------------------------------------------
9252 ;; (048F) diskette controller information
9253 ;;
9254 mov al, #0x10 ;; get CMOS diskette drive type
9255 out 0x70, AL
9256 in AL, 0x71
9257 mov ah, al ;; save byte to AH
9258
9259look_drive0:
9260 shr al, #4 ;; look at top 4 bits for drive 0
9261 jz f0_missing ;; jump if no drive0
9262 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9263 jmp look_drive1
9264f0_missing:
9265 mov bl, #0x00 ;; no drive0
9266
9267look_drive1:
9268 mov al, ah ;; restore from AH
9269 and al, #0x0f ;; look at bottom 4 bits for drive 1
9270 jz f1_missing ;; jump if no drive1
9271 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9272f1_missing:
9273 ;; leave high bits in BL zerod
9274 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9275 ;; -----------------------------------------------------------------
9276
9277 mov al, #0x00
9278 mov 0x0490, al ;; diskette 0 media state
9279 mov 0x0491, al ;; diskette 1 media state
9280
9281 ;; diskette 0,1 operational starting state
9282 ;; drive type has not been determined,
9283 ;; has no changed detection line
9284 mov 0x0492, al
9285 mov 0x0493, al
9286
9287 mov 0x0494, al ;; diskette 0 current cylinder
9288 mov 0x0495, al ;; diskette 1 current cylinder
9289
9290 mov al, #0x02
9291 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9292
9293 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9294 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9295 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9296
9297 ret
9298
9299
9300;--------------------
9301;- POST: HARD DRIVE -
9302;--------------------
9303; relocated here because the primary POST area isnt big enough.
9304hard_drive_post:
9305 // IRQ 14 = INT 76h
9306 // INT 76h calls INT 15h function ax=9100
9307
9308 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9309 mov dx, #0x03f6
9310 out dx, al
9311
9312 xor ax, ax
9313 mov ds, ax
9314 mov 0x0474, al /* hard disk status of last operation */
9315 mov 0x0477, al /* hard disk port offset (XT only ???) */
9316 mov 0x048c, al /* hard disk status register */
9317 mov 0x048d, al /* hard disk error register */
9318 mov 0x048e, al /* hard disk task complete flag */
9319 mov al, #0x01
9320 mov 0x0475, al /* hard disk number attached */
9321 mov al, #0xc0
9322 mov 0x0476, al /* hard disk control byte */
9323 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9324 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9325 ;; INT 41h: hard disk 0 configuration pointer
9326 ;; INT 46h: hard disk 1 configuration pointer
9327 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9328 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9329
9330#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9331 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9332 mov al, #0x12
9333 out #0x70, al
9334 in al, #0x71
9335 and al, #0xf0
9336 cmp al, #0xf0
9337 je post_d0_extended
9338 jmp check_for_hd1
9339post_d0_extended:
9340 mov al, #0x19
9341 out #0x70, al
9342 in al, #0x71
9343 cmp al, #47 ;; decimal 47 - user definable
9344 je post_d0_type47
9345 HALT(__LINE__)
9346post_d0_type47:
9347 ;; CMOS purpose param table offset
9348 ;; 1b cylinders low 0
9349 ;; 1c cylinders high 1
9350 ;; 1d heads 2
9351 ;; 1e write pre-comp low 5
9352 ;; 1f write pre-comp high 6
9353 ;; 20 retries/bad map/heads>8 8
9354 ;; 21 landing zone low C
9355 ;; 22 landing zone high D
9356 ;; 23 sectors/track E
9357
9358 mov ax, #EBDA_SEG
9359 mov ds, ax
9360
9361 ;;; Filling EBDA table for hard disk 0.
9362 mov al, #0x1f
9363 out #0x70, al
9364 in al, #0x71
9365 mov ah, al
9366 mov al, #0x1e
9367 out #0x70, al
9368 in al, #0x71
9369 mov (0x003d + 0x05), ax ;; write precomp word
9370
9371 mov al, #0x20
9372 out #0x70, al
9373 in al, #0x71
9374 mov (0x003d + 0x08), al ;; drive control byte
9375
9376 mov al, #0x22
9377 out #0x70, al
9378 in al, #0x71
9379 mov ah, al
9380 mov al, #0x21
9381 out #0x70, al
9382 in al, #0x71
9383 mov (0x003d + 0x0C), ax ;; landing zone word
9384
9385 mov al, #0x1c ;; get cylinders word in AX
9386 out #0x70, al
9387 in al, #0x71 ;; high byte
9388 mov ah, al
9389 mov al, #0x1b
9390 out #0x70, al
9391 in al, #0x71 ;; low byte
9392 mov bx, ax ;; BX = cylinders
9393
9394 mov al, #0x1d
9395 out #0x70, al
9396 in al, #0x71
9397 mov cl, al ;; CL = heads
9398
9399 mov al, #0x23
9400 out #0x70, al
9401 in al, #0x71
9402 mov dl, al ;; DL = sectors
9403
9404 cmp bx, #1024
9405 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9406
9407hd0_post_physical_chs:
9408 ;; no logical CHS mapping used, just physical CHS
9409 ;; use Standard Fixed Disk Parameter Table (FDPT)
9410 mov (0x003d + 0x00), bx ;; number of physical cylinders
9411 mov (0x003d + 0x02), cl ;; number of physical heads
9412 mov (0x003d + 0x0E), dl ;; number of physical sectors
9413 jmp check_for_hd1
9414
9415hd0_post_logical_chs:
9416 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9417 mov (0x003d + 0x09), bx ;; number of physical cylinders
9418 mov (0x003d + 0x0b), cl ;; number of physical heads
9419 mov (0x003d + 0x04), dl ;; number of physical sectors
9420 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9421 mov al, #0xa0
9422 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9423
9424 cmp bx, #2048
9425 jnbe hd0_post_above_2048
9426 ;; 1024 < c <= 2048 cylinders
9427 shr bx, #0x01
9428 shl cl, #0x01
9429 jmp hd0_post_store_logical
9430
9431hd0_post_above_2048:
9432 cmp bx, #4096
9433 jnbe hd0_post_above_4096
9434 ;; 2048 < c <= 4096 cylinders
9435 shr bx, #0x02
9436 shl cl, #0x02
9437 jmp hd0_post_store_logical
9438
9439hd0_post_above_4096:
9440 cmp bx, #8192
9441 jnbe hd0_post_above_8192
9442 ;; 4096 < c <= 8192 cylinders
9443 shr bx, #0x03
9444 shl cl, #0x03
9445 jmp hd0_post_store_logical
9446
9447hd0_post_above_8192:
9448 ;; 8192 < c <= 16384 cylinders
9449 shr bx, #0x04
9450 shl cl, #0x04
9451
9452hd0_post_store_logical:
9453 mov (0x003d + 0x00), bx ;; number of physical cylinders
9454 mov (0x003d + 0x02), cl ;; number of physical heads
9455 ;; checksum
9456 mov cl, #0x0f ;; repeat count
9457 mov si, #0x003d ;; offset to disk0 FDPT
9458 mov al, #0x00 ;; sum
9459hd0_post_checksum_loop:
9460 add al, [si]
9461 inc si
9462 dec cl
9463 jnz hd0_post_checksum_loop
9464 not al ;; now take 2s complement
9465 inc al
9466 mov [si], al
9467;;; Done filling EBDA table for hard disk 0.
9468
9469
9470check_for_hd1:
9471 ;; is there really a second hard disk? if not, return now
9472 mov al, #0x12
9473 out #0x70, al
9474 in al, #0x71
9475 and al, #0x0f
9476 jnz post_d1_exists
9477 ret
9478post_d1_exists:
9479 ;; check that the hd type is really 0x0f.
9480 cmp al, #0x0f
9481 jz post_d1_extended
9482 HALT(__LINE__)
9483post_d1_extended:
9484 ;; check that the extended type is 47 - user definable
9485 mov al, #0x1a
9486 out #0x70, al
9487 in al, #0x71
9488 cmp al, #47 ;; decimal 47 - user definable
9489 je post_d1_type47
9490 HALT(__LINE__)
9491post_d1_type47:
9492 ;; Table for disk1.
9493 ;; CMOS purpose param table offset
9494 ;; 0x24 cylinders low 0
9495 ;; 0x25 cylinders high 1
9496 ;; 0x26 heads 2
9497 ;; 0x27 write pre-comp low 5
9498 ;; 0x28 write pre-comp high 6
9499 ;; 0x29 heads>8 8
9500 ;; 0x2a landing zone low C
9501 ;; 0x2b landing zone high D
9502 ;; 0x2c sectors/track E
9503;;; Fill EBDA table for hard disk 1.
9504 mov ax, #EBDA_SEG
9505 mov ds, ax
9506 mov al, #0x28
9507 out #0x70, al
9508 in al, #0x71
9509 mov ah, al
9510 mov al, #0x27
9511 out #0x70, al
9512 in al, #0x71
9513 mov (0x004d + 0x05), ax ;; write precomp word
9514
9515 mov al, #0x29
9516 out #0x70, al
9517 in al, #0x71
9518 mov (0x004d + 0x08), al ;; drive control byte
9519
9520 mov al, #0x2b
9521 out #0x70, al
9522 in al, #0x71
9523 mov ah, al
9524 mov al, #0x2a
9525 out #0x70, al
9526 in al, #0x71
9527 mov (0x004d + 0x0C), ax ;; landing zone word
9528
9529 mov al, #0x25 ;; get cylinders word in AX
9530 out #0x70, al
9531 in al, #0x71 ;; high byte
9532 mov ah, al
9533 mov al, #0x24
9534 out #0x70, al
9535 in al, #0x71 ;; low byte
9536 mov bx, ax ;; BX = cylinders
9537
9538 mov al, #0x26
9539 out #0x70, al
9540 in al, #0x71
9541 mov cl, al ;; CL = heads
9542
9543 mov al, #0x2c
9544 out #0x70, al
9545 in al, #0x71
9546 mov dl, al ;; DL = sectors
9547
9548 cmp bx, #1024
9549 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9550
9551hd1_post_physical_chs:
9552 ;; no logical CHS mapping used, just physical CHS
9553 ;; use Standard Fixed Disk Parameter Table (FDPT)
9554 mov (0x004d + 0x00), bx ;; number of physical cylinders
9555 mov (0x004d + 0x02), cl ;; number of physical heads
9556 mov (0x004d + 0x0E), dl ;; number of physical sectors
9557 ret
9558
9559hd1_post_logical_chs:
9560 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9561 mov (0x004d + 0x09), bx ;; number of physical cylinders
9562 mov (0x004d + 0x0b), cl ;; number of physical heads
9563 mov (0x004d + 0x04), dl ;; number of physical sectors
9564 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9565 mov al, #0xa0
9566 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9567
9568 cmp bx, #2048
9569 jnbe hd1_post_above_2048
9570 ;; 1024 < c <= 2048 cylinders
9571 shr bx, #0x01
9572 shl cl, #0x01
9573 jmp hd1_post_store_logical
9574
9575hd1_post_above_2048:
9576 cmp bx, #4096
9577 jnbe hd1_post_above_4096
9578 ;; 2048 < c <= 4096 cylinders
9579 shr bx, #0x02
9580 shl cl, #0x02
9581 jmp hd1_post_store_logical
9582
9583hd1_post_above_4096:
9584 cmp bx, #8192
9585 jnbe hd1_post_above_8192
9586 ;; 4096 < c <= 8192 cylinders
9587 shr bx, #0x03
9588 shl cl, #0x03
9589 jmp hd1_post_store_logical
9590
9591hd1_post_above_8192:
9592 ;; 8192 < c <= 16384 cylinders
9593 shr bx, #0x04
9594 shl cl, #0x04
9595
9596hd1_post_store_logical:
9597 mov (0x004d + 0x00), bx ;; number of physical cylinders
9598 mov (0x004d + 0x02), cl ;; number of physical heads
9599 ;; checksum
9600 mov cl, #0x0f ;; repeat count
9601 mov si, #0x004d ;; offset to disk0 FDPT
9602 mov al, #0x00 ;; sum
9603hd1_post_checksum_loop:
9604 add al, [si]
9605 inc si
9606 dec cl
9607 jnz hd1_post_checksum_loop
9608 not al ;; now take 2s complement
9609 inc al
9610 mov [si], al
9611;;; Done filling EBDA table for hard disk 1.
9612#endif /* !VBOX */
9613
9614 ret
9615
9616;--------------------
9617;- POST: EBDA segment
9618;--------------------
9619; relocated here because the primary POST area isnt big enough.
9620; the SET_INT_VECTORs have nothing to do with EBDA but do not
9621; fit into the primary POST area either
9622ebda_post:
9623 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9624 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9625 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9626 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9627
9628#if BX_USE_EBDA
9629 mov ax, #EBDA_SEG
9630 mov ds, ax
9631 mov byte ptr [0x0], #EBDA_SIZE
9632#endif
9633 xor ax, ax ; mov EBDA seg into 40E
9634 mov ds, ax
9635 mov word ptr [0x40E], #EBDA_SEG
9636 ret;;
9637
9638;--------------------
9639;- POST: EOI + jmp via [0x40:67)
9640;--------------------
9641; relocated here because the primary POST area isnt big enough.
9642eoi_jmp_post:
9643 call eoi_both_pics
9644
9645 xor ax, ax
9646 mov ds, ax
9647
9648 jmp far ptr [0x467]
9649
9650
9651;--------------------
9652eoi_both_pics:
9653 mov al, #0x20
9654 out #0xA0, al ;; slave PIC EOI
9655eoi_master_pic:
9656 mov al, #0x20
9657 out #0x20, al ;; master PIC EOI
9658 ret
9659
9660;--------------------
9661BcdToBin:
9662 ;; in: AL in BCD format
9663 ;; out: AL in binary format, AH will always be 0
9664 ;; trashes BX
9665 mov bl, al
9666 and bl, #0x0f ;; bl has low digit
9667 shr al, #4 ;; al has high digit
9668 mov bh, #10
9669 mul al, bh ;; multiply high digit by 10 (result in AX)
9670 add al, bl ;; then add low digit
9671 ret
9672
9673;--------------------
9674timer_tick_post:
9675 ;; Setup the Timer Ticks Count (0x46C:dword) and
9676 ;; Timer Ticks Roller Flag (0x470:byte)
9677 ;; The Timer Ticks Count needs to be set according to
9678 ;; the current CMOS time, as if ticks have been occurring
9679 ;; at 18.2hz since midnight up to this point. Calculating
9680 ;; this is a little complicated. Here are the factors I gather
9681 ;; regarding this. 14,318,180 hz was the original clock speed,
9682 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9683 ;; at the time, or 4 to drive the CGA video adapter. The div3
9684 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9685 ;; the timer. With a maximum 16bit timer count, this is again
9686 ;; divided down by 65536 to 18.2hz.
9687 ;;
9688 ;; 14,318,180 Hz clock
9689 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9690 ;; /4 = 1,193,181 Hz fed to timer
9691 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9692 ;; 1 second = 18.20650736 ticks
9693 ;; 1 minute = 1092.390442 ticks
9694 ;; 1 hour = 65543.42651 ticks
9695 ;;
9696 ;; Given the values in the CMOS clock, one could calculate
9697 ;; the number of ticks by the following:
9698 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9699 ;; (BcdToBin(minutes) * 1092.3904)
9700 ;; (BcdToBin(hours) * 65543.427)
9701 ;; To get a little more accuracy, since Im using integer
9702 ;; arithmatic, I use:
9703 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9704 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9705 ;; (BcdToBin(hours) * 65543427) / 1000
9706
9707 ;; assuming DS=0000
9708
9709 ;; get CMOS seconds
9710 xor eax, eax ;; clear EAX
9711 mov al, #0x00
9712 out #0x70, al
9713 in al, #0x71 ;; AL has CMOS seconds in BCD
9714 call BcdToBin ;; EAX now has seconds in binary
9715 mov edx, #18206507
9716 mul eax, edx
9717 mov ebx, #1000000
9718 xor edx, edx
9719 div eax, ebx
9720 mov ecx, eax ;; ECX will accumulate total ticks
9721
9722 ;; get CMOS minutes
9723 xor eax, eax ;; clear EAX
9724 mov al, #0x02
9725 out #0x70, al
9726 in al, #0x71 ;; AL has CMOS minutes in BCD
9727 call BcdToBin ;; EAX now has minutes in binary
9728 mov edx, #10923904
9729 mul eax, edx
9730 mov ebx, #10000
9731 xor edx, edx
9732 div eax, ebx
9733 add ecx, eax ;; add to total ticks
9734
9735 ;; get CMOS hours
9736 xor eax, eax ;; clear EAX
9737 mov al, #0x04
9738 out #0x70, al
9739 in al, #0x71 ;; AL has CMOS hours in BCD
9740 call BcdToBin ;; EAX now has hours in binary
9741 mov edx, #65543427
9742 mul eax, edx
9743 mov ebx, #1000
9744 xor edx, edx
9745 div eax, ebx
9746 add ecx, eax ;; add to total ticks
9747
9748 mov 0x46C, ecx ;; Timer Ticks Count
9749 xor al, al
9750 mov 0x470, al ;; Timer Ticks Rollover Flag
9751 ret
9752
9753;--------------------
9754int76_handler:
9755 ;; record completion in BIOS task complete flag
9756 push ax
9757 push ds
9758 mov ax, #0x0040
9759 mov ds, ax
9760 mov 0x008E, #0xff
9761 call eoi_both_pics
9762 pop ds
9763 pop ax
9764 iret
9765
9766
9767;--------------------
9768#ifdef VBOX
9769init_pic:
9770 ;; init PIC
9771 mov al, #0x11 ; send initialisation commands
9772 out 0x20, al
9773 out 0xa0, al
9774 mov al, #0x08
9775 out 0x21, al
9776 mov al, #0x70
9777 out 0xa1, al
9778 mov al, #0x04
9779 out 0x21, al
9780 mov al, #0x02
9781 out 0xa1, al
9782 mov al, #0x01
9783 out 0x21, al
9784 out 0xa1, al
9785 mov al, #0xb8
9786 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9787#if BX_USE_PS2_MOUSE
9788 mov al, #0x8f
9789#else
9790 mov al, #0x9f
9791#endif
9792 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9793 ret
9794#endif /* VBOX */
9795
9796;--------------------
9797#if BX_APM
9798
9799use32 386
9800#define APM_PROT32
9801#include "apmbios.S"
9802
9803use16 386
9804#define APM_PROT16
9805#include "apmbios.S"
9806
9807#define APM_REAL
9808#include "apmbios.S"
9809
9810#endif
9811
9812;--------------------
9813#if BX_PCIBIOS
9814use32 386
9815.align 16
9816bios32_structure:
9817 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9818 dw bios32_entry_point, 0xf ;; 32 bit physical address
9819 db 0 ;; revision level
9820 ;; length in paragraphs and checksum stored in a word to prevent errors
9821 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9822 & 0xff) << 8) + 0x01
9823 db 0,0,0,0,0 ;; reserved
9824
9825.align 16
9826bios32_entry_point:
9827 pushfd
9828 cmp eax, #0x49435024 ;; "$PCI"
9829 jne unknown_service
9830 mov eax, #0x80000000
9831 mov dx, #0x0cf8
9832 out dx, eax
9833 mov dx, #0x0cfc
9834 in eax, dx
9835#ifdef PCI_FIXED_HOST_BRIDGE
9836 cmp eax, #PCI_FIXED_HOST_BRIDGE
9837 jne unknown_service
9838#else
9839 ;; say ok if a device is present
9840 cmp eax, #0xffffffff
9841 je unknown_service
9842#endif
9843 mov ebx, #0x000f0000
9844 mov ecx, #0
9845 mov edx, #pcibios_protected
9846 xor al, al
9847 jmp bios32_end
9848unknown_service:
9849 mov al, #0x80
9850bios32_end:
9851#ifdef BX_QEMU
9852 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9853#endif
9854 popfd
9855 retf
9856
9857.align 16
9858pcibios_protected:
9859 pushfd
9860 cli
9861 push esi
9862 push edi
9863 cmp al, #0x01 ;; installation check
9864 jne pci_pro_f02
9865 mov bx, #0x0210
9866 mov cx, #0
9867 mov edx, #0x20494350 ;; "PCI "
9868 mov al, #0x01
9869 jmp pci_pro_ok
9870pci_pro_f02: ;; find pci device
9871 cmp al, #0x02
9872 jne pci_pro_f03
9873 shl ecx, #16
9874 mov cx, dx
9875 xor ebx, ebx
9876 mov di, #0x00
9877pci_pro_devloop:
9878 call pci_pro_select_reg
9879 mov dx, #0x0cfc
9880 in eax, dx
9881 cmp eax, ecx
9882 jne pci_pro_nextdev
9883 cmp si, #0
9884 je pci_pro_ok
9885 dec si
9886pci_pro_nextdev:
9887 inc ebx
9888 cmp ebx, #0x10000
9889 jne pci_pro_devloop
9890 mov ah, #0x86
9891 jmp pci_pro_fail
9892pci_pro_f03: ;; find class code
9893 cmp al, #0x03
9894 jne pci_pro_f08
9895 xor ebx, ebx
9896 mov di, #0x08
9897pci_pro_devloop2:
9898 call pci_pro_select_reg
9899 mov dx, #0x0cfc
9900 in eax, dx
9901 shr eax, #8
9902 cmp eax, ecx
9903 jne pci_pro_nextdev2
9904 cmp si, #0
9905 je pci_pro_ok
9906 dec si
9907pci_pro_nextdev2:
9908 inc ebx
9909 cmp ebx, #0x10000
9910 jne pci_pro_devloop2
9911 mov ah, #0x86
9912 jmp pci_pro_fail
9913pci_pro_f08: ;; read configuration byte
9914 cmp al, #0x08
9915 jne pci_pro_f09
9916 call pci_pro_select_reg
9917 push edx
9918 mov dx, di
9919 and dx, #0x03
9920 add dx, #0x0cfc
9921 in al, dx
9922 pop edx
9923 mov cl, al
9924 jmp pci_pro_ok
9925pci_pro_f09: ;; read configuration word
9926 cmp al, #0x09
9927 jne pci_pro_f0a
9928 call pci_pro_select_reg
9929 push edx
9930 mov dx, di
9931 and dx, #0x02
9932 add dx, #0x0cfc
9933 in ax, dx
9934 pop edx
9935 mov cx, ax
9936 jmp pci_pro_ok
9937pci_pro_f0a: ;; read configuration dword
9938 cmp al, #0x0a
9939 jne pci_pro_f0b
9940 call pci_pro_select_reg
9941 push edx
9942 mov dx, #0x0cfc
9943 in eax, dx
9944 pop edx
9945 mov ecx, eax
9946 jmp pci_pro_ok
9947pci_pro_f0b: ;; write configuration byte
9948 cmp al, #0x0b
9949 jne pci_pro_f0c
9950 call pci_pro_select_reg
9951 push edx
9952 mov dx, di
9953 and dx, #0x03
9954 add dx, #0x0cfc
9955 mov al, cl
9956 out dx, al
9957 pop edx
9958 jmp pci_pro_ok
9959pci_pro_f0c: ;; write configuration word
9960 cmp al, #0x0c
9961 jne pci_pro_f0d
9962 call pci_pro_select_reg
9963 push edx
9964 mov dx, di
9965 and dx, #0x02
9966 add dx, #0x0cfc
9967 mov ax, cx
9968 out dx, ax
9969 pop edx
9970 jmp pci_pro_ok
9971pci_pro_f0d: ;; write configuration dword
9972 cmp al, #0x0d
9973 jne pci_pro_unknown
9974 call pci_pro_select_reg
9975 push edx
9976 mov dx, #0x0cfc
9977 mov eax, ecx
9978 out dx, eax
9979 pop edx
9980 jmp pci_pro_ok
9981pci_pro_unknown:
9982 mov ah, #0x81
9983pci_pro_fail:
9984 pop edi
9985 pop esi
9986#ifdef BX_QEMU
9987 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9988#endif
9989 popfd
9990 stc
9991 retf
9992pci_pro_ok:
9993 xor ah, ah
9994 pop edi
9995 pop esi
9996#ifdef BX_QEMU
9997 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9998#endif
9999 popfd
10000 clc
10001 retf
10002
10003pci_pro_select_reg:
10004 push edx
10005 mov eax, #0x800000
10006 mov ax, bx
10007 shl eax, #8
10008 and di, #0xff
10009 or ax, di
10010 and al, #0xfc
10011 mov dx, #0x0cf8
10012 out dx, eax
10013 pop edx
10014 ret
10015
10016use16 386
10017
10018pcibios_real:
10019 push eax
10020 push dx
10021 mov eax, #0x80000000
10022 mov dx, #0x0cf8
10023 out dx, eax
10024 mov dx, #0x0cfc
10025 in eax, dx
10026#ifdef PCI_FIXED_HOST_BRIDGE
10027 cmp eax, #PCI_FIXED_HOST_BRIDGE
10028 je pci_present
10029#else
10030 ;; say ok if a device is present
10031 cmp eax, #0xffffffff
10032 jne pci_present
10033#endif
10034 pop dx
10035 pop eax
10036 mov ah, #0xff
10037 stc
10038 ret
10039pci_present:
10040 pop dx
10041 pop eax
10042 cmp al, #0x01 ;; installation check
10043 jne pci_real_f02
10044 mov ax, #0x0001
10045 mov bx, #0x0210
10046 mov cx, #0
10047 mov edx, #0x20494350 ;; "PCI "
10048 mov edi, #0xf0000
10049 mov di, #pcibios_protected
10050 clc
10051 ret
10052pci_real_f02: ;; find pci device
10053 push esi
10054 push edi
10055 push edx
10056 cmp al, #0x02
10057 jne pci_real_f03
10058 shl ecx, #16
10059 mov cx, dx
10060 xor ebx, ebx
10061 mov di, #0x00
10062pci_real_devloop:
10063 call pci_real_select_reg
10064 mov dx, #0x0cfc
10065 in eax, dx
10066 cmp eax, ecx
10067 jne pci_real_nextdev
10068 cmp si, #0
10069 je pci_real_ok
10070 dec si
10071pci_real_nextdev:
10072 inc ebx
10073 cmp ebx, #0x10000
10074 jne pci_real_devloop
10075 mov dx, cx
10076 shr ecx, #16
10077 mov ax, #0x8602
10078 jmp pci_real_fail
10079pci_real_f03: ;; find class code
10080 cmp al, #0x03
10081 jne pci_real_f08
10082 xor ebx, ebx
10083 mov di, #0x08
10084pci_real_devloop2:
10085 call pci_real_select_reg
10086 mov dx, #0x0cfc
10087 in eax, dx
10088 shr eax, #8
10089 cmp eax, ecx
10090 jne pci_real_nextdev2
10091 cmp si, #0
10092 je pci_real_ok
10093 dec si
10094pci_real_nextdev2:
10095 inc ebx
10096 cmp ebx, #0x10000
10097 jne pci_real_devloop2
10098 mov ax, #0x8603
10099 jmp pci_real_fail
10100pci_real_f08: ;; read configuration byte
10101 cmp al, #0x08
10102 jne pci_real_f09
10103 call pci_real_select_reg
10104 push dx
10105 mov dx, di
10106 and dx, #0x03
10107 add dx, #0x0cfc
10108 in al, dx
10109 pop dx
10110 mov cl, al
10111 jmp pci_real_ok
10112pci_real_f09: ;; read configuration word
10113 cmp al, #0x09
10114 jne pci_real_f0a
10115 call pci_real_select_reg
10116 push dx
10117 mov dx, di
10118 and dx, #0x02
10119 add dx, #0x0cfc
10120 in ax, dx
10121 pop dx
10122 mov cx, ax
10123 jmp pci_real_ok
10124pci_real_f0a: ;; read configuration dword
10125 cmp al, #0x0a
10126 jne pci_real_f0b
10127 call pci_real_select_reg
10128 push dx
10129 mov dx, #0x0cfc
10130 in eax, dx
10131 pop dx
10132 mov ecx, eax
10133 jmp pci_real_ok
10134pci_real_f0b: ;; write configuration byte
10135 cmp al, #0x0b
10136 jne pci_real_f0c
10137 call pci_real_select_reg
10138 push dx
10139 mov dx, di
10140 and dx, #0x03
10141 add dx, #0x0cfc
10142 mov al, cl
10143 out dx, al
10144 pop dx
10145 jmp pci_real_ok
10146pci_real_f0c: ;; write configuration word
10147 cmp al, #0x0c
10148 jne pci_real_f0d
10149 call pci_real_select_reg
10150 push dx
10151 mov dx, di
10152 and dx, #0x02
10153 add dx, #0x0cfc
10154 mov ax, cx
10155 out dx, ax
10156 pop dx
10157 jmp pci_real_ok
10158pci_real_f0d: ;; write configuration dword
10159 cmp al, #0x0d
10160 jne pci_real_f0e
10161 call pci_real_select_reg
10162 push dx
10163 mov dx, #0x0cfc
10164 mov eax, ecx
10165 out dx, eax
10166 pop dx
10167 jmp pci_real_ok
10168pci_real_f0e: ;; get irq routing options
10169 cmp al, #0x0e
10170 jne pci_real_unknown
10171 SEG ES
10172 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10173 jb pci_real_too_small
10174 SEG ES
10175 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10176 pushf
10177 push ds
10178 push es
10179 push cx
10180 push si
10181 push di
10182 cld
10183 mov si, #pci_routing_table_structure_start
10184 push cs
10185 pop ds
10186 SEG ES
10187 mov cx, [di+2]
10188 SEG ES
10189 mov es, [di+4]
10190 mov di, cx
10191 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10192 rep
10193 movsb
10194 pop di
10195 pop si
10196 pop cx
10197 pop es
10198 pop ds
10199 popf
10200 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10201 jmp pci_real_ok
10202pci_real_too_small:
10203 SEG ES
10204 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10205 mov ah, #0x89
10206 jmp pci_real_fail
10207
10208pci_real_unknown:
10209 mov ah, #0x81
10210pci_real_fail:
10211 pop edx
10212 pop edi
10213 pop esi
10214 stc
10215 ret
10216pci_real_ok:
10217 xor ah, ah
10218 pop edx
10219 pop edi
10220 pop esi
10221 clc
10222 ret
10223
10224;; prepare from reading the PCI config space; on input:
10225;; bx = bus/dev/fn
10226;; di = offset into config space header
10227;; destroys eax and may modify di
10228pci_real_select_reg:
10229 push dx
10230 mov eax, #0x800000
10231 mov ax, bx
10232 shl eax, #8
10233 and di, #0xff
10234 or ax, di
10235 and al, #0xfc
10236 mov dx, #0x0cf8
10237 out dx, eax
10238 pop dx
10239 ret
10240
10241.align 16
10242pci_routing_table_structure:
10243 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10244 db 0, 1 ;; version
10245#ifdef VBOX
10246#if 0
10247 dw 32 + (30 * 16) ;; table size
10248#else
10249 dw 32 + (20 * 16) ;; table size
10250#endif
10251#else /* !VBOX */
10252 dw 32 + (6 * 16) ;; table size
10253#endif /* !VBOX */
10254 db 0 ;; PCI interrupt router bus
10255 db 0x08 ;; PCI interrupt router DevFunc
10256 dw 0x0000 ;; PCI exclusive IRQs
10257 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10258 dw 0x7000 ;; compatible PCI interrupt router device ID
10259 dw 0,0 ;; Miniport data
10260 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10261#ifdef VBOX
10262 db 0x00 ;; checksum (set by biossums)
10263#else /* !VBOX */
10264 db 0x07 ;; checksum
10265#endif /* !VBOX */
10266pci_routing_table_structure_start:
10267 ;; first slot entry PCI-to-ISA (embedded)
10268 db 0 ;; pci bus number
10269 db 0x08 ;; pci device number (bit 7-3)
10270 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10271 dw 0xdef8 ;; IRQ bitmap INTA#
10272 db 0x61 ;; link value INTB#
10273 dw 0xdef8 ;; IRQ bitmap INTB#
10274 db 0x62 ;; link value INTC#
10275 dw 0xdef8 ;; IRQ bitmap INTC#
10276 db 0x63 ;; link value INTD#
10277 dw 0xdef8 ;; IRQ bitmap INTD#
10278 db 0 ;; physical slot (0 = embedded)
10279 db 0 ;; reserved
10280 ;; second slot entry: 1st PCI slot
10281 db 0 ;; pci bus number
10282 db 0x10 ;; pci device number (bit 7-3)
10283 db 0x61 ;; link value INTA#
10284 dw 0xdef8 ;; IRQ bitmap INTA#
10285 db 0x62 ;; link value INTB#
10286 dw 0xdef8 ;; IRQ bitmap INTB#
10287 db 0x63 ;; link value INTC#
10288 dw 0xdef8 ;; IRQ bitmap INTC#
10289 db 0x60 ;; link value INTD#
10290 dw 0xdef8 ;; IRQ bitmap INTD#
10291 db 1 ;; physical slot (0 = embedded)
10292 db 0 ;; reserved
10293 ;; third slot entry: 2nd PCI slot
10294 db 0 ;; pci bus number
10295 db 0x18 ;; pci device number (bit 7-3)
10296 db 0x62 ;; link value INTA#
10297 dw 0xdef8 ;; IRQ bitmap INTA#
10298 db 0x63 ;; link value INTB#
10299 dw 0xdef8 ;; IRQ bitmap INTB#
10300 db 0x60 ;; link value INTC#
10301 dw 0xdef8 ;; IRQ bitmap INTC#
10302 db 0x61 ;; link value INTD#
10303 dw 0xdef8 ;; IRQ bitmap INTD#
10304 db 2 ;; physical slot (0 = embedded)
10305 db 0 ;; reserved
10306 ;; 4th slot entry: 3rd PCI slot
10307 db 0 ;; pci bus number
10308 db 0x20 ;; pci device number (bit 7-3)
10309 db 0x63 ;; link value INTA#
10310 dw 0xdef8 ;; IRQ bitmap INTA#
10311 db 0x60 ;; link value INTB#
10312 dw 0xdef8 ;; IRQ bitmap INTB#
10313 db 0x61 ;; link value INTC#
10314 dw 0xdef8 ;; IRQ bitmap INTC#
10315 db 0x62 ;; link value INTD#
10316 dw 0xdef8 ;; IRQ bitmap INTD#
10317 db 3 ;; physical slot (0 = embedded)
10318 db 0 ;; reserved
10319 ;; 5th slot entry: 4rd PCI slot
10320 db 0 ;; pci bus number
10321 db 0x28 ;; pci device number (bit 7-3)
10322 db 0x60 ;; link value INTA#
10323 dw 0xdef8 ;; IRQ bitmap INTA#
10324 db 0x61 ;; link value INTB#
10325 dw 0xdef8 ;; IRQ bitmap INTB#
10326 db 0x62 ;; link value INTC#
10327 dw 0xdef8 ;; IRQ bitmap INTC#
10328 db 0x63 ;; link value INTD#
10329 dw 0xdef8 ;; IRQ bitmap INTD#
10330 db 4 ;; physical slot (0 = embedded)
10331 db 0 ;; reserved
10332 ;; 6th slot entry: 5rd PCI slot
10333 db 0 ;; pci bus number
10334 db 0x30 ;; pci device number (bit 7-3)
10335 db 0x61 ;; link value INTA#
10336 dw 0xdef8 ;; IRQ bitmap INTA#
10337 db 0x62 ;; link value INTB#
10338 dw 0xdef8 ;; IRQ bitmap INTB#
10339 db 0x63 ;; link value INTC#
10340 dw 0xdef8 ;; IRQ bitmap INTC#
10341 db 0x60 ;; link value INTD#
10342 dw 0xdef8 ;; IRQ bitmap INTD#
10343 db 5 ;; physical slot (0 = embedded)
10344 db 0 ;; reserved
10345#ifdef VBOX
10346 ;; 7th slot entry: 6th PCI slot
10347 db 0 ;; pci bus number
10348 db 0x38 ;; pci device number (bit 7-3)
10349 db 0x62 ;; link value INTA#
10350 dw 0xdef8 ;; IRQ bitmap INTA#
10351 db 0x63 ;; link value INTB#
10352 dw 0xdef8 ;; IRQ bitmap INTB#
10353 db 0x60 ;; link value INTC#
10354 dw 0xdef8 ;; IRQ bitmap INTC#
10355 db 0x61 ;; link value INTD#
10356 dw 0xdef8 ;; IRQ bitmap INTD#
10357 db 6 ;; physical slot (0 = embedded)
10358 db 0 ;; reserved
10359 ;; 8th slot entry: 7th PCI slot
10360 db 0 ;; pci bus number
10361 db 0x40 ;; pci device number (bit 7-3)
10362 db 0x63 ;; link value INTA#
10363 dw 0xdef8 ;; IRQ bitmap INTA#
10364 db 0x60 ;; link value INTB#
10365 dw 0xdef8 ;; IRQ bitmap INTB#
10366 db 0x61 ;; link value INTC#
10367 dw 0xdef8 ;; IRQ bitmap INTC#
10368 db 0x62 ;; link value INTD#
10369 dw 0xdef8 ;; IRQ bitmap INTD#
10370 db 7 ;; physical slot (0 = embedded)
10371 db 0 ;; reserved
10372 ;; 9th slot entry: 8th PCI slot
10373 db 0 ;; pci bus number
10374 db 0x48 ;; pci device number (bit 7-3)
10375 db 0x60 ;; link value INTA#
10376 dw 0xdef8 ;; IRQ bitmap INTA#
10377 db 0x61 ;; link value INTB#
10378 dw 0xdef8 ;; IRQ bitmap INTB#
10379 db 0x62 ;; link value INTC#
10380 dw 0xdef8 ;; IRQ bitmap INTC#
10381 db 0x63 ;; link value INTD#
10382 dw 0xdef8 ;; IRQ bitmap INTD#
10383 db 8 ;; physical slot (0 = embedded)
10384 db 0 ;; reserved
10385 ;; 10th slot entry: 9th PCI slot
10386 db 0 ;; pci bus number
10387 db 0x50 ;; pci device number (bit 7-3)
10388 db 0x61 ;; link value INTA#
10389 dw 0xdef8 ;; IRQ bitmap INTA#
10390 db 0x62 ;; link value INTB#
10391 dw 0xdef8 ;; IRQ bitmap INTB#
10392 db 0x63 ;; link value INTC#
10393 dw 0xdef8 ;; IRQ bitmap INTC#
10394 db 0x60 ;; link value INTD#
10395 dw 0xdef8 ;; IRQ bitmap INTD#
10396 db 9 ;; physical slot (0 = embedded)
10397 db 0 ;; reserved
10398 ;; 11th slot entry: 10th PCI slot
10399 db 0 ;; pci bus number
10400 db 0x58 ;; pci device number (bit 7-3)
10401 db 0x62 ;; link value INTA#
10402 dw 0xdef8 ;; IRQ bitmap INTA#
10403 db 0x63 ;; link value INTB#
10404 dw 0xdef8 ;; IRQ bitmap INTB#
10405 db 0x60 ;; link value INTC#
10406 dw 0xdef8 ;; IRQ bitmap INTC#
10407 db 0x61 ;; link value INTD#
10408 dw 0xdef8 ;; IRQ bitmap INTD#
10409 db 10 ;; physical slot (0 = embedded)
10410 db 0 ;; reserved
10411 ;; 12th slot entry: 11th PCI slot
10412 db 0 ;; pci bus number
10413 db 0x60 ;; pci device number (bit 7-3)
10414 db 0x63 ;; link value INTA#
10415 dw 0xdef8 ;; IRQ bitmap INTA#
10416 db 0x60 ;; link value INTB#
10417 dw 0xdef8 ;; IRQ bitmap INTB#
10418 db 0x61 ;; link value INTC#
10419 dw 0xdef8 ;; IRQ bitmap INTC#
10420 db 0x62 ;; link value INTD#
10421 dw 0xdef8 ;; IRQ bitmap INTD#
10422 db 11 ;; physical slot (0 = embedded)
10423 db 0 ;; reserved
10424 ;; 13th slot entry: 12th PCI slot
10425 db 0 ;; pci bus number
10426 db 0x68 ;; pci device number (bit 7-3)
10427 db 0x60 ;; link value INTA#
10428 dw 0xdef8 ;; IRQ bitmap INTA#
10429 db 0x61 ;; link value INTB#
10430 dw 0xdef8 ;; IRQ bitmap INTB#
10431 db 0x62 ;; link value INTC#
10432 dw 0xdef8 ;; IRQ bitmap INTC#
10433 db 0x63 ;; link value INTD#
10434 dw 0xdef8 ;; IRQ bitmap INTD#
10435 db 12 ;; physical slot (0 = embedded)
10436 db 0 ;; reserved
10437 ;; 14th slot entry: 13th PCI slot
10438 db 0 ;; pci bus number
10439 db 0x70 ;; pci device number (bit 7-3)
10440 db 0x61 ;; link value INTA#
10441 dw 0xdef8 ;; IRQ bitmap INTA#
10442 db 0x62 ;; link value INTB#
10443 dw 0xdef8 ;; IRQ bitmap INTB#
10444 db 0x63 ;; link value INTC#
10445 dw 0xdef8 ;; IRQ bitmap INTC#
10446 db 0x60 ;; link value INTD#
10447 dw 0xdef8 ;; IRQ bitmap INTD#
10448 db 13 ;; physical slot (0 = embedded)
10449 db 0 ;; reserved
10450 ;; 15th slot entry: 14th PCI slot
10451 db 0 ;; pci bus number
10452 db 0x78 ;; pci device number (bit 7-3)
10453 db 0x62 ;; link value INTA#
10454 dw 0xdef8 ;; IRQ bitmap INTA#
10455 db 0x63 ;; link value INTB#
10456 dw 0xdef8 ;; IRQ bitmap INTB#
10457 db 0x60 ;; link value INTC#
10458 dw 0xdef8 ;; IRQ bitmap INTC#
10459 db 0x61 ;; link value INTD#
10460 dw 0xdef8 ;; IRQ bitmap INTD#
10461 db 14 ;; physical slot (0 = embedded)
10462 db 0 ;; reserved
10463 ;; 16th slot entry: 15th PCI slot
10464 db 0 ;; pci bus number
10465 db 0x80 ;; pci device number (bit 7-3)
10466 db 0x63 ;; link value INTA#
10467 dw 0xdef8 ;; IRQ bitmap INTA#
10468 db 0x60 ;; link value INTB#
10469 dw 0xdef8 ;; IRQ bitmap INTB#
10470 db 0x61 ;; link value INTC#
10471 dw 0xdef8 ;; IRQ bitmap INTC#
10472 db 0x62 ;; link value INTD#
10473 dw 0xdef8 ;; IRQ bitmap INTD#
10474 db 15 ;; physical slot (0 = embedded)
10475 db 0 ;; reserved
10476 ;; 17th slot entry: 16th PCI slot
10477 db 0 ;; pci bus number
10478 db 0x88 ;; pci device number (bit 7-3)
10479 db 0x60 ;; link value INTA#
10480 dw 0xdef8 ;; IRQ bitmap INTA#
10481 db 0x61 ;; link value INTB#
10482 dw 0xdef8 ;; IRQ bitmap INTB#
10483 db 0x62 ;; link value INTC#
10484 dw 0xdef8 ;; IRQ bitmap INTC#
10485 db 0x63 ;; link value INTD#
10486 dw 0xdef8 ;; IRQ bitmap INTD#
10487 db 16 ;; physical slot (0 = embedded)
10488 db 0 ;; reserved
10489 ;; 18th slot entry: 17th PCI slot
10490 db 0 ;; pci bus number
10491 db 0x90 ;; pci device number (bit 7-3)
10492 db 0x61 ;; link value INTA#
10493 dw 0xdef8 ;; IRQ bitmap INTA#
10494 db 0x62 ;; link value INTB#
10495 dw 0xdef8 ;; IRQ bitmap INTB#
10496 db 0x63 ;; link value INTC#
10497 dw 0xdef8 ;; IRQ bitmap INTC#
10498 db 0x60 ;; link value INTD#
10499 dw 0xdef8 ;; IRQ bitmap INTD#
10500 db 17 ;; physical slot (0 = embedded)
10501 db 0 ;; reserved
10502 ;; 19th slot entry: 18th PCI slot
10503 db 0 ;; pci bus number
10504 db 0x98 ;; pci device number (bit 7-3)
10505 db 0x62 ;; link value INTA#
10506 dw 0xdef8 ;; IRQ bitmap INTA#
10507 db 0x63 ;; link value INTB#
10508 dw 0xdef8 ;; IRQ bitmap INTB#
10509 db 0x60 ;; link value INTC#
10510 dw 0xdef8 ;; IRQ bitmap INTC#
10511 db 0x61 ;; link value INTD#
10512 dw 0xdef8 ;; IRQ bitmap INTD#
10513 db 18 ;; physical slot (0 = embedded)
10514 db 0 ;; reserved
10515 ;; 20th slot entry: 19th PCI slot
10516 db 0 ;; pci bus number
10517 db 0xa0 ;; pci device number (bit 7-3)
10518 db 0x63 ;; link value INTA#
10519 dw 0xdef8 ;; IRQ bitmap INTA#
10520 db 0x60 ;; link value INTB#
10521 dw 0xdef8 ;; IRQ bitmap INTB#
10522 db 0x61 ;; link value INTC#
10523 dw 0xdef8 ;; IRQ bitmap INTC#
10524 db 0x62 ;; link value INTD#
10525 dw 0xdef8 ;; IRQ bitmap INTD#
10526 db 19 ;; physical slot (0 = embedded)
10527 db 0 ;; reserved
10528 ;; 21st slot entry: 20th PCI slot
10529 db 0 ;; pci bus number
10530 db 0xa8 ;; pci device number (bit 7-3)
10531 db 0x60 ;; link value INTA#
10532 dw 0xdef8 ;; IRQ bitmap INTA#
10533 db 0x61 ;; link value INTB#
10534 dw 0xdef8 ;; IRQ bitmap INTB#
10535 db 0x62 ;; link value INTC#
10536 dw 0xdef8 ;; IRQ bitmap INTC#
10537 db 0x63 ;; link value INTD#
10538 dw 0xdef8 ;; IRQ bitmap INTD#
10539 db 20 ;; physical slot (0 = embedded)
10540 db 0 ;; reserved
10541 ;; 22nd slot entry: 21st PCI slot
10542 db 0 ;; pci bus number
10543 db 0xb0 ;; pci device number (bit 7-3)
10544 db 0x61 ;; link value INTA#
10545 dw 0xdef8 ;; IRQ bitmap INTA#
10546 db 0x62 ;; link value INTB#
10547 dw 0xdef8 ;; IRQ bitmap INTB#
10548 db 0x63 ;; link value INTC#
10549 dw 0xdef8 ;; IRQ bitmap INTC#
10550 db 0x60 ;; link value INTD#
10551 dw 0xdef8 ;; IRQ bitmap INTD#
10552 db 21 ;; physical slot (0 = embedded)
10553 db 0 ;; reserved
10554 ;; 23rd slot entry: 22nd PCI slot
10555 db 0 ;; pci bus number
10556 db 0xb8 ;; pci device number (bit 7-3)
10557 db 0x62 ;; link value INTA#
10558 dw 0xdef8 ;; IRQ bitmap INTA#
10559 db 0x63 ;; link value INTB#
10560 dw 0xdef8 ;; IRQ bitmap INTB#
10561 db 0x60 ;; link value INTC#
10562 dw 0xdef8 ;; IRQ bitmap INTC#
10563 db 0x61 ;; link value INTD#
10564 dw 0xdef8 ;; IRQ bitmap INTD#
10565 db 22 ;; physical slot (0 = embedded)
10566 db 0 ;; reserved
10567 ;; 24th slot entry: 23rd PCI slot
10568 db 0 ;; pci bus number
10569 db 0xc0 ;; pci device number (bit 7-3)
10570 db 0x63 ;; link value INTA#
10571 dw 0xdef8 ;; IRQ bitmap INTA#
10572 db 0x60 ;; link value INTB#
10573 dw 0xdef8 ;; IRQ bitmap INTB#
10574 db 0x61 ;; link value INTC#
10575 dw 0xdef8 ;; IRQ bitmap INTC#
10576 db 0x62 ;; link value INTD#
10577 dw 0xdef8 ;; IRQ bitmap INTD#
10578 db 23 ;; physical slot (0 = embedded)
10579 db 0 ;; reserved
10580 ;; 25th slot entry: 24th PCI slot
10581 db 0 ;; pci bus number
10582 db 0xc8 ;; pci device number (bit 7-3)
10583 db 0x60 ;; link value INTA#
10584 dw 0xdef8 ;; IRQ bitmap INTA#
10585 db 0x61 ;; link value INTB#
10586 dw 0xdef8 ;; IRQ bitmap INTB#
10587 db 0x62 ;; link value INTC#
10588 dw 0xdef8 ;; IRQ bitmap INTC#
10589 db 0x63 ;; link value INTD#
10590 dw 0xdef8 ;; IRQ bitmap INTD#
10591 db 24 ;; physical slot (0 = embedded)
10592 db 0 ;; reserved
10593 ;; 26th slot entry: 25th PCI slot
10594 db 0 ;; pci bus number
10595 db 0xd0 ;; pci device number (bit 7-3)
10596 db 0x61 ;; link value INTA#
10597 dw 0xdef8 ;; IRQ bitmap INTA#
10598 db 0x62 ;; link value INTB#
10599 dw 0xdef8 ;; IRQ bitmap INTB#
10600 db 0x63 ;; link value INTC#
10601 dw 0xdef8 ;; IRQ bitmap INTC#
10602 db 0x60 ;; link value INTD#
10603 dw 0xdef8 ;; IRQ bitmap INTD#
10604 db 25 ;; physical slot (0 = embedded)
10605 db 0 ;; reserved
10606 ;; 27th slot entry: 26th PCI slot
10607 db 0 ;; pci bus number
10608 db 0xd8 ;; pci device number (bit 7-3)
10609 db 0x62 ;; link value INTA#
10610 dw 0xdef8 ;; IRQ bitmap INTA#
10611 db 0x63 ;; link value INTB#
10612 dw 0xdef8 ;; IRQ bitmap INTB#
10613 db 0x60 ;; link value INTC#
10614 dw 0xdef8 ;; IRQ bitmap INTC#
10615 db 0x61 ;; link value INTD#
10616 dw 0xdef8 ;; IRQ bitmap INTD#
10617 db 26 ;; physical slot (0 = embedded)
10618 db 0 ;; reserved
10619 ;; 28th slot entry: 27th PCI slot
10620 db 0 ;; pci bus number
10621 db 0xe0 ;; pci device number (bit 7-3)
10622 db 0x63 ;; link value INTA#
10623 dw 0xdef8 ;; IRQ bitmap INTA#
10624 db 0x60 ;; link value INTB#
10625 dw 0xdef8 ;; IRQ bitmap INTB#
10626 db 0x61 ;; link value INTC#
10627 dw 0xdef8 ;; IRQ bitmap INTC#
10628 db 0x62 ;; link value INTD#
10629 dw 0xdef8 ;; IRQ bitmap INTD#
10630 db 27 ;; physical slot (0 = embedded)
10631 db 0 ;; reserved
10632 ;; 29th slot entry: 28th PCI slot
10633 db 0 ;; pci bus number
10634 db 0xe8 ;; pci device number (bit 7-3)
10635 db 0x60 ;; link value INTA#
10636 dw 0xdef8 ;; IRQ bitmap INTA#
10637 db 0x61 ;; link value INTB#
10638 dw 0xdef8 ;; IRQ bitmap INTB#
10639 db 0x62 ;; link value INTC#
10640 dw 0xdef8 ;; IRQ bitmap INTC#
10641 db 0x63 ;; link value INTD#
10642 dw 0xdef8 ;; IRQ bitmap INTD#
10643 db 28 ;; physical slot (0 = embedded)
10644 db 0 ;; reserved
10645 ;; 30th slot entry: 29th PCI slot
10646 db 0 ;; pci bus number
10647 db 0xf0 ;; pci device number (bit 7-3)
10648 db 0x61 ;; link value INTA#
10649 dw 0xdef8 ;; IRQ bitmap INTA#
10650 db 0x62 ;; link value INTB#
10651 dw 0xdef8 ;; IRQ bitmap INTB#
10652 db 0x63 ;; link value INTC#
10653 dw 0xdef8 ;; IRQ bitmap INTC#
10654 db 0x60 ;; link value INTD#
10655 dw 0xdef8 ;; IRQ bitmap INTD#
10656 db 29 ;; physical slot (0 = embedded)
10657 db 0 ;; reserved
10658#endif /* VBOX */
10659pci_routing_table_structure_end:
10660
10661#if !BX_ROMBIOS32
10662pci_irq_list:
10663 db 11, 10, 9, 5;
10664
10665pcibios_init_sel_reg:
10666 push eax
10667 mov eax, #0x800000
10668 mov ax, bx
10669 shl eax, #8
10670 and dl, #0xfc
10671 or al, dl
10672 mov dx, #0x0cf8
10673 out dx, eax
10674 pop eax
10675 ret
10676
10677pcibios_init_iomem_bases:
10678 push bp
10679 mov bp, sp
10680 mov eax, #0xe0000000 ;; base for memory init
10681 push eax
10682 mov ax, #0xc000 ;; base for i/o init
10683 push ax
10684 mov ax, #0x0010 ;; start at base address #0
10685 push ax
10686 mov bx, #0x0008
10687pci_init_io_loop1:
10688 mov dl, #0x00
10689 call pcibios_init_sel_reg
10690 mov dx, #0x0cfc
10691 in ax, dx
10692 cmp ax, #0xffff
10693 jz next_pci_dev
10694#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10695 mov dl, #0x04 ;; disable i/o and memory space access
10696 call pcibios_init_sel_reg
10697 mov dx, #0x0cfc
10698 in al, dx
10699 and al, #0xfc
10700 out dx, al
10701pci_init_io_loop2:
10702 mov dl, [bp-8]
10703 call pcibios_init_sel_reg
10704 mov dx, #0x0cfc
10705 in eax, dx
10706 test al, #0x01
10707 jnz init_io_base
10708 mov ecx, eax
10709 mov eax, #0xffffffff
10710 out dx, eax
10711 in eax, dx
10712 cmp eax, ecx
10713 je next_pci_base
10714 xor eax, #0xffffffff
10715 mov ecx, eax
10716 mov eax, [bp-4]
10717 out dx, eax
10718 add eax, ecx ;; calculate next free mem base
10719 add eax, #0x01000000
10720 and eax, #0xff000000
10721 mov [bp-4], eax
10722 jmp next_pci_base
10723init_io_base:
10724 mov cx, ax
10725 mov ax, #0xffff
10726 out dx, ax
10727 in ax, dx
10728 cmp ax, cx
10729 je next_pci_base
10730 xor ax, #0xfffe
10731 mov cx, ax
10732 mov ax, [bp-6]
10733 out dx, ax
10734 add ax, cx ;; calculate next free i/o base
10735 add ax, #0x0100
10736 and ax, #0xff00
10737 mov [bp-6], ax
10738next_pci_base:
10739 mov al, [bp-8]
10740 add al, #0x04
10741 cmp al, #0x28
10742 je enable_iomem_space
10743 mov byte ptr[bp-8], al
10744 jmp pci_init_io_loop2
10745#endif /* !VBOX */
10746enable_iomem_space:
10747 mov dl, #0x04 ;; enable i/o and memory space access if available
10748 call pcibios_init_sel_reg
10749 mov dx, #0x0cfc
10750 in al, dx
10751 or al, #0x07
10752 out dx, al
10753#ifdef VBOX
10754 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10755 call pcibios_init_sel_reg
10756 mov dx, #0x0cfc
10757 in eax, dx
10758 cmp eax, #0x20001022
10759 jne next_pci_dev
10760 mov dl, #0x10 ;; get I/O address
10761 call pcibios_init_sel_reg
10762 mov dx, #0x0cfc
10763 in ax, dx
10764 and ax, #0xfffc
10765 mov cx, ax
10766 mov dx, cx
10767 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10768 in ax, dx ;; reset is performed by reading the reset register
10769 mov dx, cx
10770 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10771 in eax, dx ;; reset is performed by reading the reset register
10772#endif /* VBOX */
10773next_pci_dev:
10774 mov byte ptr[bp-8], #0x10
10775 inc bx
10776 cmp bx, #0x0100
10777 jne pci_init_io_loop1
10778 mov sp, bp
10779 pop bp
10780 ret
10781
10782pcibios_init_set_elcr:
10783 push ax
10784 push cx
10785 mov dx, #0x04d0
10786 test al, #0x08
10787 jz is_master_pic
10788 inc dx
10789 and al, #0x07
10790is_master_pic:
10791 mov cl, al
10792 mov bl, #0x01
10793 shl bl, cl
10794 in al, dx
10795 or al, bl
10796 out dx, al
10797 pop cx
10798 pop ax
10799 ret
10800
10801pcibios_init_irqs:
10802 push ds
10803 push bp
10804 mov ax, #0xf000
10805 mov ds, ax
10806 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10807 mov al, #0x00
10808 out dx, al
10809 inc dx
10810 out dx, al
10811 mov si, #pci_routing_table_structure
10812 mov bh, [si+8]
10813 mov bl, [si+9]
10814 mov dl, #0x00
10815 call pcibios_init_sel_reg
10816 mov dx, #0x0cfc
10817 in eax, dx
10818 cmp eax, [si+12] ;; check irq router
10819 jne pci_init_end
10820 mov dl, [si+34]
10821 call pcibios_init_sel_reg
10822 push bx ;; save irq router bus + devfunc
10823 mov dx, #0x0cfc
10824 mov ax, #0x8080
10825 out dx, ax ;; reset PIRQ route control
10826 add dx, #2
10827 out dx, ax
10828 mov ax, [si+6]
10829 sub ax, #0x20
10830 shr ax, #4
10831 mov cx, ax
10832 add si, #0x20 ;; set pointer to 1st entry
10833 mov bp, sp
10834 mov ax, #pci_irq_list
10835 push ax
10836 xor ax, ax
10837 push ax
10838pci_init_irq_loop1:
10839 mov bh, [si]
10840 mov bl, [si+1]
10841pci_init_irq_loop2:
10842 mov dl, #0x00
10843 call pcibios_init_sel_reg
10844 mov dx, #0x0cfc
10845 in ax, dx
10846 cmp ax, #0xffff
10847 jnz pci_test_int_pin
10848 test bl, #0x07
10849 jz next_pir_entry
10850 jmp next_pci_func
10851pci_test_int_pin:
10852 mov dl, #0x3c
10853 call pcibios_init_sel_reg
10854 mov dx, #0x0cfd
10855 in al, dx
10856 and al, #0x07
10857 jz next_pci_func
10858 dec al ;; determine pirq reg
10859 mov dl, #0x03
10860 mul al, dl
10861 add al, #0x02
10862 xor ah, ah
10863 mov bx, ax
10864 mov al, [si+bx]
10865 mov dl, al
10866 mov bx, [bp]
10867 call pcibios_init_sel_reg
10868 mov dx, #0x0cfc
10869 and al, #0x03
10870 add dl, al
10871 in al, dx
10872 cmp al, #0x80
10873 jb pirq_found
10874 mov bx, [bp-2] ;; pci irq list pointer
10875 mov al, [bx]
10876 out dx, al
10877 inc bx
10878 mov [bp-2], bx
10879 call pcibios_init_set_elcr
10880pirq_found:
10881 mov bh, [si]
10882 mov bl, [si+1]
10883 add bl, [bp-3] ;; pci function number
10884 mov dl, #0x3c
10885 call pcibios_init_sel_reg
10886 mov dx, #0x0cfc
10887 out dx, al
10888next_pci_func:
10889 inc byte ptr[bp-3]
10890 inc bl
10891 test bl, #0x07
10892 jnz pci_init_irq_loop2
10893next_pir_entry:
10894 add si, #0x10
10895 mov byte ptr[bp-3], #0x00
10896 loop pci_init_irq_loop1
10897 mov sp, bp
10898 pop bx
10899pci_init_end:
10900 pop bp
10901 pop ds
10902 ret
10903#endif // !BX_ROMBIOS32
10904#endif // BX_PCIBIOS
10905
10906#if BX_ROMBIOS32
10907rombios32_init:
10908 ;; save a20 and enable it
10909 in al, 0x92
10910 push ax
10911 or al, #0x02
10912 out 0x92, al
10913
10914 ;; save SS:SP to the BDA
10915 xor ax, ax
10916 mov ds, ax
10917 mov 0x0469, ss
10918 mov 0x0467, sp
10919
10920 SEG CS
10921 lidt [pmode_IDT_info]
10922 SEG CS
10923 lgdt [rombios32_gdt_48]
10924 ;; set PE bit in CR0
10925 mov eax, cr0
10926 or al, #0x01
10927 mov cr0, eax
10928 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10929 db 0x66, 0xea
10930 dw rombios32_05
10931 dw 0x000f ;; high 16 bit address
10932 dw 0x0010
10933
10934use32 386
10935rombios32_05:
10936 ;; init data segments
10937 mov eax, #0x18
10938 mov ds, ax
10939 mov es, ax
10940 mov ss, ax
10941 xor eax, eax
10942 mov fs, ax
10943 mov gs, ax
10944 cld
10945
10946 ;; copy rombios32 code to ram (ram offset = 1MB)
10947 mov esi, #0xfffe0000
10948 mov edi, #0x00040000
10949 mov ecx, #0x10000 / 4
10950 rep
10951 movsd
10952
10953 ;; init the stack pointer
10954 mov esp, #0x00080000
10955
10956 ;; call rombios32 code
10957 mov eax, #0x00040000
10958 call eax
10959
10960 ;; return to 16 bit protected mode first
10961 db 0xea
10962 dd rombios32_10
10963 dw 0x20
10964
10965use16 386
10966rombios32_10:
10967 ;; restore data segment limits to 0xffff
10968 mov ax, #0x28
10969 mov ds, ax
10970 mov es, ax
10971 mov ss, ax
10972 mov fs, ax
10973 mov gs, ax
10974
10975 ;; reset PE bit in CR0
10976 mov eax, cr0
10977 and al, #0xFE
10978 mov cr0, eax
10979
10980 ;; far jump to flush CPU queue after transition to real mode
10981 JMP_AP(0xf000, rombios32_real_mode)
10982
10983rombios32_real_mode:
10984 ;; restore IDT to normal real-mode defaults
10985 SEG CS
10986 lidt [rmode_IDT_info]
10987
10988 xor ax, ax
10989 mov ds, ax
10990 mov es, ax
10991 mov fs, ax
10992 mov gs, ax
10993
10994 ;; restore SS:SP from the BDA
10995 mov ss, 0x0469
10996 xor esp, esp
10997 mov sp, 0x0467
10998 ;; restore a20
10999 pop ax
11000 out 0x92, al
11001 ret
11002
11003rombios32_gdt_48:
11004 dw 0x30
11005 dw rombios32_gdt
11006 dw 0x000f
11007
11008rombios32_gdt:
11009 dw 0, 0, 0, 0
11010 dw 0, 0, 0, 0
11011 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11012 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11013 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11014 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11015#endif // BX_ROMBIOS32
11016
11017
11018; parallel port detection: base address in DX, index in BX, timeout in CL
11019detect_parport:
11020 push dx
11021 add dx, #2
11022 in al, dx
11023 and al, #0xdf ; clear input mode
11024 out dx, al
11025 pop dx
11026 mov al, #0xaa
11027 out dx, al
11028 in al, dx
11029 cmp al, #0xaa
11030 jne no_parport
11031 push bx
11032 shl bx, #1
11033 mov [bx+0x408], dx ; Parallel I/O address
11034 pop bx
11035 mov [bx+0x478], cl ; Parallel printer timeout
11036 inc bx
11037no_parport:
11038 ret
11039
11040; serial port detection: base address in DX, index in BX, timeout in CL
11041detect_serial:
11042 push dx
11043 inc dx
11044 mov al, #0x02
11045 out dx, al
11046 in al, dx
11047 cmp al, #0x02
11048 jne no_serial
11049 inc dx
11050 in al, dx
11051 cmp al, #0x02
11052 jne no_serial
11053 dec dx
11054 xor al, al
11055 out dx, al
11056 pop dx
11057 push bx
11058 shl bx, #1
11059 mov [bx+0x400], dx ; Serial I/O address
11060 pop bx
11061 mov [bx+0x47c], cl ; Serial timeout
11062 inc bx
11063 ret
11064no_serial:
11065 pop dx
11066 ret
11067
11068rom_checksum:
11069 push ax
11070 push bx
11071 push cx
11072 xor ax, ax
11073 xor bx, bx
11074 xor cx, cx
11075 mov ch, [2]
11076 shl cx, #1
11077checksum_loop:
11078 add al, [bx]
11079 inc bx
11080 loop checksum_loop
11081 and al, #0xff
11082 pop cx
11083 pop bx
11084 pop ax
11085 ret
11086
11087rom_scan:
11088 ;; Scan for existence of valid expansion ROMS.
11089 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11090 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11091 ;; System ROM: only 0xE0000
11092 ;;
11093 ;; Header:
11094 ;; Offset Value
11095 ;; 0 0x55
11096 ;; 1 0xAA
11097 ;; 2 ROM length in 512-byte blocks
11098 ;; 3 ROM initialization entry point (FAR CALL)
11099
11100 mov cx, #0xc000
11101rom_scan_loop:
11102 mov ds, cx
11103 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11104 cmp [0], #0xAA55 ;; look for signature
11105 jne rom_scan_increment
11106 call rom_checksum
11107 jnz rom_scan_increment
11108 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11109
11110 ;; We want our increment in 512-byte quantities, rounded to
11111 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11112 test al, #0x03
11113 jz block_count_rounded
11114 and al, #0xfc ;; needs rounding up
11115 add al, #0x04
11116block_count_rounded:
11117
11118 xor bx, bx ;; Restore DS back to 0000:
11119 mov ds, bx
11120 push ax ;; Save AX
11121 ;; Push addr of ROM entry point
11122 push cx ;; Push seg
11123 push #0x0003 ;; Push offset
11124 mov bp, sp ;; Call ROM init routine using seg:off on stack
11125 db 0xff ;; call_far ss:[bp+0]
11126 db 0x5e
11127 db 0
11128 cli ;; In case expansion ROM BIOS turns IF on
11129 add sp, #2 ;; Pop offset value
11130 pop cx ;; Pop seg value (restore CX)
11131 pop ax ;; Restore AX
11132rom_scan_increment:
11133 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11134 ;; because the segment selector is shifted left 4 bits.
11135 add cx, ax
11136 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11137 jbe rom_scan_loop
11138
11139 xor ax, ax ;; Restore DS back to 0000:
11140 mov ds, ax
11141 ret
11142
11143#define LVT0 0xFEE00350
11144#define LVT1 0xFEE00360
11145
11146;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11147;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11148
11149setup_lapic:
11150 pushf
11151 cli ;; Interrupts would kill us!
11152 call pmode_enter
11153 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11154 mov eax, [esi]
11155 and eax, #0xfffe00ff
11156 or ah, #0x07
11157 mov [esi], eax
11158 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11159 mov eax, [esi]
11160 and eax, #0xfffe00ff
11161 or ah, #0x04
11162 mov [esi], eax
11163 call pmode_exit
11164 popf
11165 ret
11166
11167;; Enter and exit minimal protected-mode environment. May only be called from
11168;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11169;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11170;; address the entire 4GB address space.
11171
11172pmode_enter:
11173 push cs
11174 pop ds
11175 lgdt [pmbios_gdt_desc]
11176 mov eax, cr0
11177 or al, #0x1
11178 mov cr0, eax
11179 JMP_AP(0x20, really_enter_pm)
11180really_enter_pm:
11181 mov ax, #0x18
11182 mov ds, ax
11183 ret
11184
11185pmode_exit:
11186 mov eax, cr0
11187 and al, #0xfe
11188 mov cr0, eax
11189 JMP_AP(0xF000, really_exit_pm)
11190really_exit_pm:
11191 ret
11192
11193pmbios_gdt_desc:
11194 dw 0x30
11195 dw pmbios_gdt
11196 dw 0x000f
11197
11198pmbios_gdt:
11199 dw 0, 0, 0, 0
11200 dw 0, 0, 0, 0
11201 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11202 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11203 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11204 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11205
11206;; for 'C' strings and other data, insert them here with
11207;; a the following hack:
11208;; DATA_SEG_DEFS_HERE
11209
11210
11211;; the following area can be used to write dynamically generated tables
11212 .align 16
11213bios_table_area_start:
11214 dd 0xaafb4442
11215 dd bios_table_area_end - bios_table_area_start - 8;
11216
11217;--------
11218;- POST -
11219;--------
11220.org 0xe05b ; POST Entry Point
11221bios_table_area_end:
11222post:
11223
11224 xor ax, ax
11225
11226 ;; first reset the DMA controllers
11227 out 0x0d,al
11228 out 0xda,al
11229
11230 ;; then initialize the DMA controllers
11231 mov al, #0xC0
11232 out 0xD6, al ; cascade mode of channel 4 enabled
11233 mov al, #0x00
11234 out 0xD4, al ; unmask channel 4
11235
11236 ;; Examine CMOS shutdown status.
11237 mov AL, #0x0f
11238 out 0x70, AL
11239 in AL, 0x71
11240
11241 ;; backup status
11242 mov bl, al
11243
11244 ;; Reset CMOS shutdown status.
11245 mov AL, #0x0f
11246 out 0x70, AL ; select CMOS register Fh
11247 mov AL, #0x00
11248 out 0x71, AL ; set shutdown action to normal
11249
11250 ;; Examine CMOS shutdown status.
11251 mov al, bl
11252
11253 ;; 0x00, 0x09, 0x0D+ = normal startup
11254 cmp AL, #0x00
11255 jz normal_post
11256 cmp AL, #0x0d
11257 jae normal_post
11258 cmp AL, #0x09
11259 je normal_post
11260
11261 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11262 cmp al, #0x05
11263 je eoi_jmp_post
11264
11265#ifdef VBOX
11266 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11267 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11268 jmp normal_post
11269#else
11270 ;; Examine CMOS shutdown status.
11271 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11272 push bx
11273 call _shutdown_status_panic
11274#endif
11275
11276#if 0
11277 HALT(__LINE__)
11278 ;
11279 ;#if 0
11280 ; 0xb0, 0x20, /* mov al, #0x20 */
11281 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11282 ;#endif
11283 ;
11284 pop es
11285 pop ds
11286 popa
11287 iret
11288#endif
11289
11290normal_post:
11291 ; case 0: normal startup
11292
11293 cli
11294 mov ax, #0xfffe
11295 mov sp, ax
11296 xor ax, ax
11297 mov ds, ax
11298 mov ss, ax
11299
11300#ifndef VBOX
11301 ;; zero out BIOS data area (40:00..40:ff)
11302 mov es, ax
11303 mov cx, #0x0080 ;; 128 words
11304 mov di, #0x0400
11305 cld
11306 rep
11307 stosw
11308#else /* VBOX */
11309 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11310 mov es, ax
11311 xor di, di
11312 cld
11313 mov cx, #0x0239 ;; 569 words
11314 rep
11315 stosw
11316 inc di
11317 inc di
11318 mov cx, #0x7dc6 ;; 32198 words
11319 rep
11320 stosw
11321 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11322 ;; because we store the MP table there
11323 xor eax, eax
11324 xor bx, bx
11325memory_zero_loop:
11326 add bx, #0x1000
11327 cmp bx, #0x9000
11328 jae memory_cleared
11329 mov es, bx
11330 xor di, di
11331 mov cx, #0x4000
11332 rep
11333 stosd
11334 jmp memory_zero_loop
11335memory_cleared:
11336 mov es, bx
11337 xor di, di
11338 mov cx, #0x3f00
11339 rep
11340 stosd
11341 xor bx, bx
11342#endif
11343
11344 call _log_bios_start
11345
11346 ;; set all interrupts to default handler
11347 xor bx, bx ;; offset index
11348 mov cx, #0x0100 ;; counter (256 interrupts)
11349 mov ax, #dummy_iret_handler
11350 mov dx, #0xF000
11351
11352post_default_ints:
11353 mov [bx], ax
11354 add bx, #2
11355 mov [bx], dx
11356 add bx, #2
11357 loop post_default_ints
11358
11359 ;; set vector 0x79 to zero
11360 ;; this is used by 'gardian angel' protection system
11361 SET_INT_VECTOR(0x79, #0, #0)
11362
11363 ;; base memory in K 40:13 (word)
11364 mov ax, #BASE_MEM_IN_K
11365 mov 0x0413, ax
11366
11367
11368 ;; Manufacturing Test 40:12
11369 ;; zerod out above
11370
11371#ifndef VBOX
11372 ;; Warm Boot Flag 0040:0072
11373 ;; value of 1234h = skip memory checks
11374 ;; zerod out above
11375#endif /* !VBOX */
11376
11377
11378 ;; Printer Services vector
11379 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11380
11381 ;; Bootstrap failure vector
11382 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11383
11384 ;; Bootstrap Loader vector
11385 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11386
11387 ;; User Timer Tick vector
11388 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11389
11390 ;; Memory Size Check vector
11391 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11392
11393 ;; Equipment Configuration Check vector
11394 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11395
11396 ;; System Services
11397 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11398
11399 ;; EBDA setup
11400 call ebda_post
11401
11402 ;; PIT setup
11403 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11404 ;; int 1C already points at dummy_iret_handler (above)
11405 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11406 out 0x43, al
11407 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11408 out 0x40, al
11409 out 0x40, al
11410
11411 ;; Keyboard
11412 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11413 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11414
11415 xor ax, ax
11416 mov ds, ax
11417 mov 0x0417, al /* keyboard shift flags, set 1 */
11418 mov 0x0418, al /* keyboard shift flags, set 2 */
11419 mov 0x0419, al /* keyboard alt-numpad work area */
11420 mov 0x0471, al /* keyboard ctrl-break flag */
11421 mov 0x0497, al /* keyboard status flags 4 */
11422 mov al, #0x10
11423 mov 0x0496, al /* keyboard status flags 3 */
11424
11425
11426 /* keyboard head of buffer pointer */
11427 mov bx, #0x001E
11428 mov 0x041A, bx
11429
11430 /* keyboard end of buffer pointer */
11431 mov 0x041C, bx
11432
11433 /* keyboard pointer to start of buffer */
11434 mov bx, #0x001E
11435 mov 0x0480, bx
11436
11437 /* keyboard pointer to end of buffer */
11438 mov bx, #0x003E
11439 mov 0x0482, bx
11440
11441 /* init the keyboard */
11442 call _keyboard_init
11443
11444 ;; mov CMOS Equipment Byte to BDA Equipment Word
11445 mov ax, 0x0410
11446 mov al, #0x14
11447 out 0x70, al
11448 in al, 0x71
11449 mov 0x0410, ax
11450
11451
11452 ;; Parallel setup
11453 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11454 xor ax, ax
11455 mov ds, ax
11456 xor bx, bx
11457 mov cl, #0x14 ; timeout value
11458 mov dx, #0x378 ; Parallel I/O address, port 1
11459 call detect_parport
11460 mov dx, #0x278 ; Parallel I/O address, port 2
11461 call detect_parport
11462 shl bx, #0x0e
11463 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
11464 and ax, #0x3fff
11465 or ax, bx ; set number of parallel ports
11466 mov 0x410, ax
11467
11468 ;; Serial setup
11469 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11470 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11471 xor bx, bx
11472 mov cl, #0x0a ; timeout value
11473 mov dx, #0x03f8 ; Serial I/O address, port 1
11474 call detect_serial
11475 mov dx, #0x02f8 ; Serial I/O address, port 2
11476 call detect_serial
11477 mov dx, #0x03e8 ; Serial I/O address, port 3
11478 call detect_serial
11479 mov dx, #0x02e8 ; Serial I/O address, port 4
11480 call detect_serial
11481 shl bx, #0x09
11482 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11483 and ax, #0xf1ff
11484 or ax, bx ; set number of serial port
11485 mov 0x410, ax
11486
11487 ;; CMOS RTC
11488 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11489 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11490 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11491 ;; BIOS DATA AREA 0x4CE ???
11492 call timer_tick_post
11493
11494 ;; PS/2 mouse setup
11495 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11496
11497 ;; IRQ13 (FPU exception) setup
11498 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11499
11500 ;; Video setup
11501 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11502
11503#ifdef VBOX
11504 ;; moved the PIC initialization to another place as we need
11505 ;; some space for additions init calls. Otherwise this code
11506 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11507 call init_pic
11508#else /* !VBOX */
11509 ;; PIC
11510 mov al, #0x11 ; send initialisation commands
11511 out 0x20, al
11512 out 0xa0, al
11513 mov al, #0x08
11514 out 0x21, al
11515 mov al, #0x70
11516 out 0xa1, al
11517 mov al, #0x04
11518 out 0x21, al
11519 mov al, #0x02
11520 out 0xa1, al
11521 mov al, #0x01
11522 out 0x21, al
11523 out 0xa1, al
11524 mov al, #0xb8
11525 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11526#if BX_USE_PS2_MOUSE
11527 mov al, #0x8f
11528#else
11529 mov al, #0x9f
11530#endif
11531 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11532#endif /* !VBOX */
11533
11534#if BX_ROMBIOS32
11535 call rombios32_init
11536#else
11537 call pcibios_init_iomem_bases
11538 call pcibios_init_irqs
11539#endif
11540 call setup_lapic
11541 call rom_scan
11542
11543#if BX_USE_ATADRV
11544 ;;
11545 ;; ATA/ATAPI driver setup
11546 ;;
11547 call _ata_init
11548 call _ata_detect
11549 ;;
11550#endif
11551
11552#ifdef VBOX_WITH_SCSI
11553 ;;
11554 ;; SCSI driver setup
11555 ;;
11556 call _scsi_init
11557 ;;
11558#endif
11559
11560 call _print_bios_banner
11561
11562 ;;
11563 ;; Floppy setup
11564 ;;
11565 call floppy_drive_post
11566
11567 ;;
11568 ;; Hard Drive setup
11569 ;;
11570 call hard_drive_post
11571
11572#if BX_ELTORITO_BOOT
11573 ;;
11574 ;; eltorito floppy/harddisk emulation from cd
11575 ;;
11576 call _cdemu_init
11577 ;;
11578#endif // BX_ELTORITO_BOOT
11579
11580 sti ;; enable interrupts
11581 int #0x19
11582
11583.org 0xe2c3 ; NMI Handler Entry Point
11584nmi:
11585 ;; FIXME the NMI handler should not panic
11586 ;; but iret when called from int75 (fpu exception)
11587 call _nmi_handler_msg
11588 iret
11589
11590int75_handler:
11591 out 0xf0, al // clear irq13
11592 call eoi_both_pics // clear interrupt
11593 int 2 // legacy nmi call
11594 iret
11595
11596;-------------------------------------------
11597;- INT 13h Fixed Disk Services Entry Point -
11598;-------------------------------------------
11599.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11600int13_handler:
11601 //JMPL(int13_relocated)
11602 jmp int13_relocated
11603
11604.org 0xe401 ; Fixed Disk Parameter Table
11605
11606;----------
11607;- INT19h -
11608;----------
11609.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11610int19_handler:
11611
11612 jmp int19_relocated
11613;-------------------------------------------
11614;- System BIOS Configuration Data Table
11615;-------------------------------------------
11616.org BIOS_CONFIG_TABLE
11617db 0x08 ; Table size (bytes) -Lo
11618db 0x00 ; Table size (bytes) -Hi
11619db SYS_MODEL_ID
11620db SYS_SUBMODEL_ID
11621db BIOS_REVISION
11622; Feature byte 1
11623; b7: 1=DMA channel 3 used by hard disk
11624; b6: 1=2 interrupt controllers present
11625; b5: 1=RTC present
11626; b4: 1=BIOS calls int 15h/4Fh every key
11627; b3: 1=wait for extern event supported (Int 15h/41h)
11628; b2: 1=extended BIOS data area used
11629; b1: 0=AT or ESDI bus, 1=MicroChannel
11630; b0: 1=Dual bus (MicroChannel + ISA)
11631db (0 << 7) | \
11632 (1 << 6) | \
11633 (1 << 5) | \
11634 (BX_CALL_INT15_4F << 4) | \
11635 (0 << 3) | \
11636 (BX_USE_EBDA << 2) | \
11637 (0 << 1) | \
11638 (0 << 0)
11639; Feature byte 2
11640; b7: 1=32-bit DMA supported
11641; b6: 1=int16h, function 9 supported
11642; b5: 1=int15h/C6h (get POS data) supported
11643; b4: 1=int15h/C7h (get mem map info) supported
11644; b3: 1=int15h/C8h (en/dis CPU) supported
11645; b2: 1=non-8042 kb controller
11646; b1: 1=data streaming supported
11647; b0: reserved
11648db (0 << 7) | \
11649 (1 << 6) | \
11650 (0 << 5) | \
11651 (0 << 4) | \
11652 (0 << 3) | \
11653 (0 << 2) | \
11654 (0 << 1) | \
11655 (0 << 0)
11656; Feature byte 3
11657; b7: not used
11658; b6: reserved
11659; b5: reserved
11660; b4: POST supports ROM-to-RAM enable/disable
11661; b3: SCSI on system board
11662; b2: info panel installed
11663; b1: Initial Machine Load (IML) system - BIOS on disk
11664; b0: SCSI supported in IML
11665db 0x00
11666; Feature byte 4
11667; b7: IBM private
11668; b6: EEPROM present
11669; b5-3: ABIOS presence (011 = not supported)
11670; b2: private
11671; b1: memory split above 16Mb supported
11672; b0: POSTEXT directly supported by POST
11673db 0x00
11674; Feature byte 5 (IBM)
11675; b1: enhanced mouse
11676; b0: flash EPROM
11677db 0x00
11678
11679
11680
11681.org 0xe729 ; Baud Rate Generator Table
11682
11683;----------
11684;- INT14h -
11685;----------
11686.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11687int14_handler:
11688 push ds
11689 pusha
11690 xor ax, ax
11691 mov ds, ax
11692 call _int14_function
11693 popa
11694 pop ds
11695 iret
11696
11697
11698;----------------------------------------
11699;- INT 16h Keyboard Service Entry Point -
11700;----------------------------------------
11701.org 0xe82e
11702int16_handler:
11703
11704 sti
11705 push ds
11706 pushf
11707 pusha
11708
11709 cmp ah, #0x00
11710 je int16_F00
11711 cmp ah, #0x10
11712 je int16_F00
11713
11714 mov bx, #0xf000
11715 mov ds, bx
11716 call _int16_function
11717 popa
11718 popf
11719 pop ds
11720 jz int16_zero_set
11721
11722int16_zero_clear:
11723 push bp
11724 mov bp, sp
11725 //SEG SS
11726 and BYTE [bp + 0x06], #0xbf
11727 pop bp
11728 iret
11729
11730int16_zero_set:
11731 push bp
11732 mov bp, sp
11733 //SEG SS
11734 or BYTE [bp + 0x06], #0x40
11735 pop bp
11736 iret
11737
11738int16_F00:
11739 mov bx, #0x0040
11740 mov ds, bx
11741
11742int16_wait_for_key:
11743 cli
11744 mov bx, 0x001a
11745 cmp bx, 0x001c
11746 jne int16_key_found
11747 sti
11748 nop
11749#if 0
11750 /* no key yet, call int 15h, function AX=9002 */
11751 0x50, /* push AX */
11752 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11753 0xcd, 0x15, /* int 15h */
11754 0x58, /* pop AX */
11755 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11756#endif
11757 jmp int16_wait_for_key
11758
11759int16_key_found:
11760 mov bx, #0xf000
11761 mov ds, bx
11762 call _int16_function
11763 popa
11764 popf
11765 pop ds
11766#if 0
11767 /* notify int16 complete w/ int 15h, function AX=9102 */
11768 0x50, /* push AX */
11769 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11770 0xcd, 0x15, /* int 15h */
11771 0x58, /* pop AX */
11772#endif
11773 iret
11774
11775
11776
11777;-------------------------------------------------
11778;- INT09h : Keyboard Hardware Service Entry Point -
11779;-------------------------------------------------
11780.org 0xe987
11781int09_handler:
11782 cli
11783 push ax
11784
11785 mov al, #0xAD ;;disable keyboard
11786 out #0x64, al
11787
11788 mov al, #0x0B
11789 out #0x20, al
11790 in al, #0x20
11791 and al, #0x02
11792 jz int09_finish
11793
11794 in al, #0x60 ;;read key from keyboard controller
11795 sti
11796 push ds
11797 pusha
11798#ifdef BX_CALL_INT15_4F
11799 mov ah, #0x4f ;; allow for keyboard intercept
11800 stc
11801 int #0x15
11802 jnc int09_done
11803#endif
11804
11805 ;; check for extended key
11806 cmp al, #0xe0
11807 jne int09_check_pause
11808 xor ax, ax
11809 mov ds, ax
11810 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11811 or al, #0x02
11812 mov BYTE [0x496], al
11813 jmp int09_done
11814
11815int09_check_pause: ;; check for pause key
11816 cmp al, #0xe1
11817 jne int09_process_key
11818 xor ax, ax
11819 mov ds, ax
11820 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11821 or al, #0x01
11822 mov BYTE [0x496], al
11823 jmp int09_done
11824
11825int09_process_key:
11826 mov bx, #0xf000
11827 mov ds, bx
11828 call _int09_function
11829
11830int09_done:
11831 popa
11832 pop ds
11833 cli
11834 call eoi_master_pic
11835
11836int09_finish:
11837 mov al, #0xAE ;;enable keyboard
11838 out #0x64, al
11839 pop ax
11840 iret
11841
11842
11843;----------------------------------------
11844;- INT 13h Diskette Service Entry Point -
11845;----------------------------------------
11846.org 0xec59
11847int13_diskette:
11848 jmp int13_noeltorito
11849
11850;---------------------------------------------
11851;- INT 0Eh Diskette Hardware ISR Entry Point -
11852;---------------------------------------------
11853.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11854int0e_handler:
11855 push ax
11856 push dx
11857 mov dx, #0x03f4
11858 in al, dx
11859 and al, #0xc0
11860 cmp al, #0xc0
11861 je int0e_normal
11862 mov dx, #0x03f5
11863 mov al, #0x08 ; sense interrupt status
11864 out dx, al
11865int0e_loop1:
11866 mov dx, #0x03f4
11867 in al, dx
11868 and al, #0xc0
11869 cmp al, #0xc0
11870 jne int0e_loop1
11871int0e_loop2:
11872 mov dx, #0x03f5
11873 in al, dx
11874 mov dx, #0x03f4
11875 in al, dx
11876 and al, #0xc0
11877 cmp al, #0xc0
11878 je int0e_loop2
11879int0e_normal:
11880 push ds
11881 xor ax, ax ;; segment 0000
11882 mov ds, ax
11883 call eoi_master_pic
11884 mov al, 0x043e
11885 or al, #0x80 ;; diskette interrupt has occurred
11886 mov 0x043e, al
11887 pop ds
11888 pop dx
11889 pop ax
11890 iret
11891
11892
11893.org 0xefc7 ; Diskette Controller Parameter Table
11894diskette_param_table:
11895;; Since no provisions are made for multiple drive types, most
11896;; values in this table are ignored. I set parameters for 1.44M
11897;; floppy here
11898db 0xAF
11899db 0x02 ;; head load time 0000001, DMA used
11900db 0x25
11901db 0x02
11902db 18
11903db 0x1B
11904db 0xFF
11905db 0x6C
11906db 0xF6
11907db 0x0F
11908db 0x08
11909
11910
11911;----------------------------------------
11912;- INT17h : Printer Service Entry Point -
11913;----------------------------------------
11914.org 0xefd2
11915int17_handler:
11916 push ds
11917 pusha
11918 xor ax, ax
11919 mov ds, ax
11920 call _int17_function
11921 popa
11922 pop ds
11923 iret
11924
11925diskette_param_table2:
11926;; New diskette parameter table adding 3 parameters from IBM
11927;; Since no provisions are made for multiple drive types, most
11928;; values in this table are ignored. I set parameters for 1.44M
11929;; floppy here
11930db 0xAF
11931db 0x02 ;; head load time 0000001, DMA used
11932db 0x25
11933db 0x02
11934db 18
11935db 0x1B
11936db 0xFF
11937db 0x6C
11938db 0xF6
11939db 0x0F
11940db 0x08
11941db 79 ;; maximum track
11942db 0 ;; data transfer rate
11943db 4 ;; drive type in cmos
11944
11945.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11946 HALT(__LINE__)
11947 iret
11948
11949;----------
11950;- INT10h -
11951;----------
11952.org 0xf065 ; INT 10h Video Support Service Entry Point
11953int10_handler:
11954 ;; dont do anything, since the VGA BIOS handles int10h requests
11955 iret
11956
11957.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11958
11959;----------
11960;- INT12h -
11961;----------
11962.org 0xf841 ; INT 12h Memory Size Service Entry Point
11963; ??? different for Pentium (machine check)?
11964int12_handler:
11965 push ds
11966 mov ax, #0x0040
11967 mov ds, ax
11968 mov ax, 0x0013
11969 pop ds
11970 iret
11971
11972;----------
11973;- INT11h -
11974;----------
11975.org 0xf84d ; INT 11h Equipment List Service Entry Point
11976int11_handler:
11977 push ds
11978 mov ax, #0x0040
11979 mov ds, ax
11980 mov ax, 0x0010
11981 pop ds
11982 iret
11983
11984;----------
11985;- INT15h -
11986;----------
11987.org 0xf859 ; INT 15h System Services Entry Point
11988int15_handler:
11989 pushf
11990#if BX_APM
11991 cmp ah, #0x53
11992 je apm_call
11993#endif
11994 push ds
11995 push es
11996 cmp ah, #0x86
11997 je int15_handler32
11998 cmp ah, #0xE8
11999 je int15_handler32
12000 pusha
12001#if BX_USE_PS2_MOUSE
12002 cmp ah, #0xC2
12003 je int15_handler_mouse
12004#endif
12005 call _int15_function
12006int15_handler_mouse_ret:
12007 popa
12008int15_handler32_ret:
12009 pop es
12010 pop ds
12011 popf
12012 jmp iret_modify_cf
12013#if BX_APM
12014apm_call:
12015 jmp _apmreal_entry
12016#endif
12017
12018#if BX_USE_PS2_MOUSE
12019int15_handler_mouse:
12020 call _int15_function_mouse
12021 jmp int15_handler_mouse_ret
12022#endif
12023
12024int15_handler32:
12025 pushad
12026 call _int15_function32
12027 popad
12028 jmp int15_handler32_ret
12029
12030;; Protected mode IDT descriptor
12031;;
12032;; I just make the limit 0, so the machine will shutdown
12033;; if an exception occurs during protected mode memory
12034;; transfers.
12035;;
12036;; Set base to f0000 to correspond to beginning of BIOS,
12037;; in case I actually define an IDT later
12038;; Set limit to 0
12039
12040pmode_IDT_info:
12041dw 0x0000 ;; limit 15:00
12042dw 0x0000 ;; base 15:00
12043db 0x0f ;; base 23:16
12044
12045;; Real mode IDT descriptor
12046;;
12047;; Set to typical real-mode values.
12048;; base = 000000
12049;; limit = 03ff
12050
12051rmode_IDT_info:
12052dw 0x03ff ;; limit 15:00
12053dw 0x0000 ;; base 15:00
12054db 0x00 ;; base 23:16
12055
12056;;
12057;; Handler for unexpected hardware interrupts
12058;;
12059dummy_isr:
12060 push ds
12061 pushad
12062 xor ax, ax
12063 mov ds, ax
12064 call _dummy_isr_function
12065 popad
12066 pop ds
12067 iret
12068
12069;----------
12070;- INT1Ah -
12071;----------
12072.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12073int1a_handler:
12074#if BX_PCIBIOS
12075 cmp ah, #0xb1
12076 jne int1a_normal
12077 call pcibios_real
12078 jc pcibios_error
12079 retf 2
12080pcibios_error:
12081 mov bl, ah
12082 mov ah, #0xb1
12083 push ds
12084 pusha
12085 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12086 mov ds, ax ; on 16bit protected mode.
12087 jmp int1a_callfunction
12088int1a_normal:
12089#endif
12090 push ds
12091 pusha
12092 xor ax, ax
12093 mov ds, ax
12094int1a_callfunction:
12095 call _int1a_function
12096 popa
12097 pop ds
12098 iret
12099
12100;;
12101;; int70h: IRQ8 - CMOS RTC
12102;;
12103int70_handler:
12104 push ds
12105 pushad
12106 xor ax, ax
12107 mov ds, ax
12108 call _int70_function
12109 popad
12110 pop ds
12111 iret
12112
12113;---------
12114;- INT08 -
12115;---------
12116.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12117int08_handler:
12118 sti
12119 push eax
12120 push ds
12121 xor ax, ax
12122 mov ds, ax
12123
12124 ;; time to turn off drive(s)?
12125 mov al,0x0440
12126 or al,al
12127 jz int08_floppy_off
12128 dec al
12129 mov 0x0440,al
12130 jnz int08_floppy_off
12131 ;; turn motor(s) off
12132 push dx
12133 mov dx,#0x03f2
12134 in al,dx
12135 and al,#0xcf
12136 out dx,al
12137 pop dx
12138int08_floppy_off:
12139
12140 mov eax, 0x046c ;; get ticks dword
12141 inc eax
12142
12143 ;; compare eax to one days worth of timer ticks at 18.2 hz
12144 cmp eax, #0x001800B0
12145 jb int08_store_ticks
12146 ;; there has been a midnight rollover at this point
12147 xor eax, eax ;; zero out counter
12148 inc BYTE 0x0470 ;; increment rollover flag
12149
12150int08_store_ticks:
12151 mov 0x046c, eax ;; store new ticks dword
12152 ;; chain to user timer tick INT #0x1c
12153 //pushf
12154 //;; call_ep [ds:loc]
12155 //CALL_EP( 0x1c << 2 )
12156 int #0x1c
12157 cli
12158 call eoi_master_pic
12159 pop ds
12160 pop eax
12161 iret
12162
12163.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12164
12165
12166.org 0xff00
12167.ascii BIOS_COPYRIGHT_STRING
12168
12169#ifdef VBOX
12170// The SMBIOS header
12171.org 0xff30
12172.align 16
12173 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12174 db 0x00 ; checksum (set by biossums)
12175 db 0x1f ; EPS length, defined by standard
12176 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12177 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12178 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12179 db 0x00 ; Entry point revision
12180 db 0x00, 0x00, 0x00, 0x00, 0x00
12181
12182// The DMI header
12183 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12184 db 0x00 ; checksum (set by biossums)
12185 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12186 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12187 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12188 db VBOX_DMI_TABLE_VER ; DMI version
12189 db 0x00 ; Just for alignment
12190#endif
12191
12192;------------------------------------------------
12193;- IRET Instruction for Dummy Interrupt Handler -
12194;------------------------------------------------
12195.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12196dummy_iret_handler:
12197 iret
12198
12199.org 0xff54 ; INT 05h Print Screen Service Entry Point
12200 HALT(__LINE__)
12201 iret
12202
12203.org 0xfff0 ; Power-up Entry Point
12204 jmp 0xf000:post
12205
12206.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12207.ascii BIOS_BUILD_DATE
12208
12209.org 0xfffe ; System Model ID
12210db SYS_MODEL_ID
12211db 0x00 ; filler
12212
12213.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12214ASM_END
12215/*
12216 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12217 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12218 * This font is public domain
12219 */
12220static Bit8u vgafont8[128*8]=
12221{
12222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12223 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12224 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12225 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12226 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12227 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12228 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12229 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12230 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12231 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12232 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12233 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12234 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12235 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12236 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12237 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12238 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12239 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12240 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12241 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12242 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12243 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12244 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12245 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12246 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12247 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12248 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12249 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12250 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12251 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12252 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12253 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12255 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12256 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12257 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12258 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12259 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12260 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12261 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12262 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12263 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12264 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12265 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12266 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12267 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12268 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12269 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12270 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12271 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12272 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12273 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12274 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12275 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12276 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12277 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12278 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12279 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12280 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12281 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12282 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12283 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12284 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12285 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12286 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12287 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12288 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12289 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12290 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12291 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12292 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12293 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12294 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12295 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12296 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12297 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12298 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12299 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12300 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12301 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12302 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12303 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12304 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12305 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12306 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12307 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12308 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12309 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12310 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12311 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12312 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12313 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12314 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12315 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12316 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12318 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12319 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12320 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12321 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12322 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12323 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12324 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12325 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12326 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12327 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12328 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12329 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12330 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12331 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12332 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12333 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12334 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12335 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12336 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12337 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12338 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12339 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12340 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12341 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12342 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12343 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12344 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12345 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12346 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12347 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12348 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12349 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12350};
12351
12352ASM_START
12353.org 0xcc00
12354// bcc-generated data will be placed here
12355ASM_END
Note: See TracBrowser for help on using the repository browser.

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