VirtualBox

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

Last change on this file since 35098 was 35098, checked in by vboxsync, 14 years ago

BIOS: Properly initialize hdimap table.

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

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