VirtualBox

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

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

BIOS: removed generic vars mechanism

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

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