VirtualBox

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

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

BIOS: Shortened a ridiculously long loop.

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